Skip to content

Commit

Permalink
Backport transformer changes from 1.8.9 ModPatcher, should fix TickPr…
Browse files Browse the repository at this point in the history
…ofiler/54
  • Loading branch information
LunNova committed Sep 2, 2016
1 parent cf7776b commit 86fa197
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 13 deletions.
154 changes: 141 additions & 13 deletions src/main/java/me/nallar/modpatcher/LaunchClassLoaderUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,30 @@

public enum LaunchClassLoaderUtil {
;
private static final String SPONGEPOWERED_MIXIN_TRANSFORMER_NAME = "org.spongepowered.asm.mixin.transformer.MixinTransformer$Proxy";
private static final String DEOBF_TRANSFORMER_NAME = "cpw.mods.fml.common.asm.transformers.DeobfuscationTransformer";
private static final List<String> DEOBF_TRANSFORMER_NAMES = Arrays.asList(
DEOBF_TRANSFORMER_NAME,
SPONGEPOWERED_MIXIN_TRANSFORMER_NAME
);
private static final List<String> WHITELISTED_TRANSFORMERS = Arrays.asList(
"cpw.mods.fml.common.asm.transformers.PatchingTransformer",
"cpw.mods.fml.common.asm.transformers.DeobfuscationTransformer"
);
private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("legacy.debugClassLoading", "false"));
private static final boolean DEBUG_FINER = DEBUG && Boolean.parseBoolean(System.getProperty("legacy.debugClassLoadingFiner", "false"));
private static final String ALREADY_LOADED_PROPERTY_NAME = "nallar.LaunchClassLoaderUtil.alreadyLoaded";
private static final HashMap<String, byte[]> cachedSrgClasses = new HashMap<String, byte[]>();
private static final String DUMP_TRANSFORMERS_PROPERTY_NAME = "nallar.LaunchClassLoaderUtil.dumpTransformers";
private static final String WARN_INCONSISTENT_TRANSFORMATION_PROPERTY_NAME = "nallar.LaunchClassLoaderUtil.warnForInconsistentTransformation";
private static final HashMap<String, byte[]> cachedSrgClasses = new HashMap<>();
static LaunchClassLoader instance;

private static List<IClassTransformer> transformers;
private static IClassTransformer[] srgTransformers;
private static IClassNameTransformer renameTransformer;
private static Set<String> classLoaderExceptions;
private static Set<String> transformerExceptions;
private static boolean warnedForInconsistentTransformation;

static {
boolean alreadyLoaded = System.getProperty(ALREADY_LOADED_PROPERTY_NAME) != null;
Expand All @@ -36,18 +50,35 @@ public enum LaunchClassLoaderUtil {
public static void addTransformer(IClassTransformer transformer) {
List<IClassTransformer> transformers = LaunchClassLoaderUtil.getTransformers();

int target = -1;
for (int i = 0; i < transformers.size(); i++) {
if (transformers.get(i).getClass().getName().equals(LaunchClassLoaderUtil.DEOBF_TRANSFORMER_NAME)) {
transformers.add(i + 1, transformer);
return;
}
IClassTransformer current = transformers.get(i);

if (current == transformer)
transformers.remove(i--);

String className = current.getClass().getName();
if (DEOBF_TRANSFORMER_NAMES.contains(className))
target = i;
}

PatcherLog.warn("Didn't find deobfuscation transformer " + LaunchClassLoaderUtil.DEOBF_TRANSFORMER_NAME + " in transformers list.\n" +
"Did you forget to set the SortingIndex for your coremod >= 1001? This message is expected in a deobf environment.");
transformers.add(transformer);
if (target == -1) {
PatcherLog.warn("Didn't find deobfuscation transformers " + DEOBF_TRANSFORMER_NAMES.toString() + " in transformers list.\n" +
"Did you forget to set the SortingIndex for your coremod >= 1001? This message is expected in a deobf environment.");
transformers.add(transformer);
} else {
transformers.add(target + 1, transformer);
}

buildSrgTransformList();
}

public static void dumpTransformersIfEnabled() {
if (System.getProperty(DUMP_TRANSFORMERS_PROPERTY_NAME) != null)
PatcherLog.info("Transformers: " + transformers.toString(), new Throwable());
}

@SuppressWarnings("unchecked")
public static List<IClassTransformer> getTransformers() {
if (transformers != null) {
return transformers;
Expand Down Expand Up @@ -81,6 +112,7 @@ private static IClassNameTransformer getRenameTransformer() {
}
}

@SuppressWarnings("unchecked")
private static Set<String> getClassLoaderExceptions() {
if (classLoaderExceptions != null) {
return classLoaderExceptions;
Expand All @@ -94,6 +126,20 @@ private static Set<String> getClassLoaderExceptions() {
}
}

@SuppressWarnings("unchecked")
private static Set<String> getTransformerExceptions() {
if (transformerExceptions != null) {
return transformerExceptions;
}
try {
Field f = instance.getClass().getDeclaredField("transformerExceptions");
f.setAccessible(true);
return transformerExceptions = (Set<String>) f.get(getInstance());
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public static boolean excluded(String name) {
for (final String exception : getClassLoaderExceptions()) {
if (name.startsWith(exception)) {
Expand All @@ -103,6 +149,15 @@ public static boolean excluded(String name) {
return false;
}

public static boolean allowedForSrg(String name) {
if (name.startsWith("net.minecraft") || name.startsWith("nallar.") || name.startsWith("me.nallar."))
return true;

// TODO: Extensibility, need to add to API for patcher use?

return false;
}

@SuppressWarnings("ConstantConditions")
private static byte[] runTransformer(final String name, final String transformedName, byte[] basicClass, final IClassTransformer transformer) {
try {
Expand All @@ -124,21 +179,54 @@ private static byte[] runTransformer(final String name, final String transformed
}
}

private static byte[] transformUpToSrg(final String name, final String transformedName, byte[] basicClass) {
public static void buildSrgTransformList() {
List<IClassTransformer> result = new ArrayList<>();

Iterable<IClassTransformer> transformers = getTransformers();
for (final IClassTransformer transformer : transformers) {
if (transformer == ModPatcher.getInstance()) {
cacheSrgBytes(transformedName, basicClass);
return basicClass;
srgTransformers = result.toArray(new IClassTransformer[0]);
return;
}

if (whitelisted(transformer))
result.add(transformer);

if (Objects.equals(transformer.getClass().getName(), DEOBF_TRANSFORMER_NAME)) {
srgTransformers = result.toArray(new IClassTransformer[0]);
return;
}
}

throw new RuntimeException("No SRG or ModPatcher transformer found when building SRG transformer list. " + Joiner.on(",\n").join(transformers));
}

private static boolean whitelisted(IClassTransformer transformer) {
for (String whitelistEntry : WHITELISTED_TRANSFORMERS)
if (transformer.getClass().getName().startsWith(whitelistEntry))
return true;

return false;
}

private static byte[] transformUpToSrg(final String name, final String transformedName, byte[] basicClass) {
if (srgTransformers == null)
throw new RuntimeException("Tried to call transformUpToSrg too early - haven't build SRG transformer list yet");

for (final IClassTransformer transformer : srgTransformers) {
basicClass = runTransformer(name, transformedName, basicClass, transformer);
}
throw new RuntimeException("No SRG transformer!" + Joiner.on(",\n").join(transformers));
return basicClass;
}

public static byte[] getSrgBytes(String name) {
final String transformedName = transformName(name);
name = untransformName(name);

if (!allowedForSrg(transformedName)) {
return null;
}

byte[] cached = cachedSrgClasses.get(transformedName);
if (cached != null) {
return cached;
Expand All @@ -152,13 +240,35 @@ public static byte[] getSrgBytes(String name) {
}

public static void cacheSrgBytes(String transformedName, byte[] bytes) {
// TODO: Cache for this (and the javassist classpool too?) should be wiped out after worlds load?

if (!allowedForSrg(transformedName)) {
return;
}

byte[] old = cachedSrgClasses.put(transformedName, bytes);
if (old != null && !Arrays.equals(bytes, old)) {
ModPatcher.pool.dropCache(transformedName);
PatcherLog.error(null, new Error("Inconsistent transformation results. Tried to cache different bytes for class " + transformedName + " to previous result after transformation."));
if (shouldWarnInconsistentTransformation())
PatcherLog.warn(null, new Error("Inconsistent transformation results. Tried to cache different bytes for class " + transformedName + " to previous result after transformation."));
}
}

private static boolean shouldWarnInconsistentTransformation() {
if (System.getProperty(WARN_INCONSISTENT_TRANSFORMATION_PROPERTY_NAME) != null)
return true;

if (!warnedForInconsistentTransformation) {
// non-threadsafe but it really doesn't matter if this shows up twice so I don't care
warnedForInconsistentTransformation = true;

PatcherLog.warn("One or more classes have inconsistent transformation results. To enable logging of this," +
" add -D" + WARN_INCONSISTENT_TRANSFORMATION_PROPERTY_NAME + "=true to your JVM parameters.");
}

return false;
}

public static byte[] getClassBytes(String name) {
if (name.startsWith("java/")) {
return null;
Expand All @@ -177,4 +287,22 @@ public static String transformName(String name) {
public static String untransformName(String name) {
return getRenameTransformer().unmapClassName(name);
}

public static void removeRedundantExclusions() {
removeRedundantExclusions(getTransformerExceptions());
removeRedundantExclusions(getClassLoaderExceptions());
}

private static void removeRedundantExclusions(Set<String> transformerExceptions) {
Iterator<String> parts = transformerExceptions.iterator();
while (parts.hasNext()) {
String part = parts.next();

for (String part2 : new HashSet<>(transformerExceptions)) {
if (!part.equals(part2) && part.startsWith(part2)) {
parts.remove();
}
}
}
}
}
2 changes: 2 additions & 0 deletions src/main/java/me/nallar/modpatcher/ModPatcherSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ private void initialised(LaunchClassLoader classLoader) {
classLoader.addTransformerExclusion("org.json");
LaunchClassLoaderUtil.instance = classLoader;
LaunchClassLoaderUtil.addTransformer(ModPatcher.getInstance());
LaunchClassLoaderUtil.dumpTransformersIfEnabled();
LaunchClassLoaderUtil.removeRedundantExclusions();
}

@Override
Expand Down

0 comments on commit 86fa197

Please sign in to comment.