From a85f2cd3161da92d6ebbdde2746d5ed4d0fcf2bd Mon Sep 17 00:00:00 2001 From: Mumfrey Date: Tue, 14 Apr 2015 12:33:44 +0100 Subject: [PATCH] Transformer delegation list belongs in MixinEnvironment --- .../asm/mixin/MixinEnvironment.java | 117 ++++++++++++++++- .../asm/mixin/transformer/TreeInfo.java | 119 ++---------------- 2 files changed, 122 insertions(+), 114 deletions(-) diff --git a/src/main/java/org/spongepowered/asm/mixin/MixinEnvironment.java b/src/main/java/org/spongepowered/asm/mixin/MixinEnvironment.java index f8a5eab4..289acc25 100644 --- a/src/main/java/org/spongepowered/asm/mixin/MixinEnvironment.java +++ b/src/main/java/org/spongepowered/asm/mixin/MixinEnvironment.java @@ -27,15 +27,21 @@ package org.spongepowered.asm.mixin; import java.io.File; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Set; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.helpers.Booleans; import org.spongepowered.asm.launch.MixinBootstrap; import org.spongepowered.asm.mixin.transformer.MixinTransformer; import org.spongepowered.asm.util.PrettyPrinter; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import net.minecraft.launchwrapper.IClassNameTransformer; import net.minecraft.launchwrapper.IClassTransformer; import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.Launch; @@ -277,11 +283,22 @@ public class MixinEnvironment { } } + + /** + * Known re-entrant transformers, other re-entrant transformers will + * detected automatically + */ + private static final Set excludeTransformers = Sets.newHashSet( + "net.minecraftforge.fml.common.asm.transformers.EventSubscriptionTransformer", + "cpw.mods.fml.common.asm.transformers.EventSubscriptionTransformer", + "net.minecraftforge.fml.common.asm.transformers.TerminalTransformer", + "cpw.mods.fml.common.asm.transformers.TerminalTransformer" + ); // Blackboard keys private static final String CONFIGS_KEY = "mixin.configs"; private static final String TRANSFORMER_KEY = "mixin.transformer"; - + /** * Current (active) environment phase, set to NOT_INITIALISED until the * phases have been populated @@ -298,6 +315,11 @@ public class MixinEnvironment { */ private static MixinEnvironment currentEnvironment; + /** + * Logger + */ + private final Logger logger = LogManager.getLogger("mixin"); + /** * The phase for this environment */ @@ -318,6 +340,19 @@ public class MixinEnvironment { */ private Side side; + /** + * Local transformer chain, this consists of all transformers present at the + * init phase with the exclusion of the mixin transformer itself and known + * re-entrant transformers. Detected re-entrant transformers will be + * subsequently removed. + */ + private List transformers; + + /** + * Class name transformer (if present) + */ + private IClassNameTransformer nameTransformer; + private MixinEnvironment(Phase phase) { this.phase = phase; this.configsKey = MixinEnvironment.CONFIGS_KEY + "." + this.phase.name.toLowerCase(); @@ -473,7 +508,85 @@ public class MixinEnvironment { transformer.audit(); } } - + + /** + * Returns (and generates if necessary) the transformer delegation list for + * this environment. + */ + public List getTransformers() { + if (this.transformers == null) { + this.buildTransformerDelegationList(); + } + + return Collections.unmodifiableList(this.transformers); + } + + /** + * Adds a transformer to the transformer exclusions list + * + * @param name + */ + public void addTransformerExclusion(String name) { + MixinEnvironment.excludeTransformers.add(name); + + // Force rebuild of the list + this.transformers = null; + } + + /** + * Map a class name back to its obfuscated counterpart + * + * @param className + * @return obfuscated name for the specified deobfuscated reference + */ + public String unmap(String className) { + if (this.nameTransformer == null) { + this.buildTransformerDelegationList(); + } + + if (this.nameTransformer != null) { + return this.nameTransformer.unmapClassName(className); + } + + return className; + } + + /** + * Builds the transformer list to apply to loaded mixin bytecode. Since + * generating this list requires inspecting each transformer by name (to + * cope with the new wrapper functionality added by FML) we generate the + * list just once per environment and cache the result. + */ + private void buildTransformerDelegationList() { + this.logger.debug("Rebuilding transformer delegation list:"); + this.transformers = new ArrayList(); + for (IClassTransformer transformer : Launch.classLoader.getTransformers()) { + String transformerName = transformer.getClass().getName(); + boolean include = true; + for (String excludeClass : MixinEnvironment.excludeTransformers) { + if (transformerName.contains(excludeClass)) { + include = false; + break; + } + } + if (include && !transformerName.contains(MixinTransformer.class.getName())) { + this.logger.debug(" Adding: {}", transformerName); + this.transformers.add(transformer); + } else { + this.logger.debug(" Excluding: {}", transformerName); + } + } + + this.logger.debug("Transformer delegation list created with {} entries", this.transformers.size()); + + for (IClassTransformer transformer : Launch.classLoader.getTransformers()) { + if (transformer instanceof IClassNameTransformer) { + this.logger.debug("Found name transformer: {}", transformer.getClass().getName()); + this.nameTransformer = (IClassNameTransformer) transformer; + } + } + } + /* (non-Javadoc) * @see java.lang.Object#toString() */ diff --git a/src/main/java/org/spongepowered/asm/mixin/transformer/TreeInfo.java b/src/main/java/org/spongepowered/asm/mixin/transformer/TreeInfo.java index 2845bcc8..a4196d4f 100644 --- a/src/main/java/org/spongepowered/asm/mixin/transformer/TreeInfo.java +++ b/src/main/java/org/spongepowered/asm/mixin/transformer/TreeInfo.java @@ -27,12 +27,7 @@ package org.spongepowered.asm.mixin.transformer; import java.io.IOException; import java.io.InputStream; import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import net.minecraft.launchwrapper.IClassNameTransformer; import net.minecraft.launchwrapper.IClassTransformer; import net.minecraft.launchwrapper.Launch; @@ -44,44 +39,13 @@ import org.objectweb.asm.tree.ClassNode; import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.transformer.MixinTransformer.ReEntranceState; -import com.google.common.collect.Sets; - /** * Base class for "info" objects which use ASM tree API to do stuff, with things */ abstract class TreeInfo { - /** - * Known re-entrant transformers, other re-entrant transformers will - * detected automatically - */ - private static final Set excludeTransformers = Sets.newHashSet( - "net.minecraftforge.fml.common.asm.transformers.EventSubscriptionTransformer", - "cpw.mods.fml.common.asm.transformers.EventSubscriptionTransformer", - "net.minecraftforge.fml.common.asm.transformers.TerminalTransformer", - "cpw.mods.fml.common.asm.transformers.TerminalTransformer" - ); - private static final Logger logger = LogManager.getLogger("mixin"); - /** - * Local transformer chain, this consists of all transformers present at the - * init phase with the exclusion of the mixin transformer itself and known - * re-entrant transformers. Detected re-entrant transformers will be - * subsequently removed. - */ - private static List transformers; - - /** - * Class name transformer (if present) - */ - private static IClassNameTransformer nameTransformer; - - /** - * Current environment - */ - private static MixinEnvironment currentEnvironment; - /** * Re-entrance lock */ @@ -100,7 +64,7 @@ abstract class TreeInfo { * @param flags * @return ASM Tree view of the specified class */ - static ClassNode getClassNode(byte[] classBytes, int flags) { + protected static ClassNode getClassNode(byte[] classBytes, int flags) { ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(classBytes); classReader.accept(classNode, flags); @@ -112,11 +76,9 @@ abstract class TreeInfo { * @param runTransformers * @return Transformed class bytecode for the specified class */ - static byte[] loadClass(String className, boolean runTransformers) throws ClassNotFoundException, IOException { - TreeInfo.checkEnvironment(); - + protected static byte[] loadClass(String className, boolean runTransformers) throws ClassNotFoundException, IOException { String transformedName = className.replace('/', '.'); - String name = TreeInfo.unmap(transformedName); + String name = MixinEnvironment.getCurrentEnvironment().unmap(transformedName); byte[] classBytes = null; if ((classBytes = TreeInfo.getClassBytes(name, transformedName)) == null) { @@ -167,11 +129,9 @@ abstract class TreeInfo { * except the excluded transformers */ private static byte[] applyTransformers(String name, String transformedName, byte[] basicClass) { - final List transformers = TreeInfo.transformers; - - for (Iterator iter = transformers.iterator(); iter.hasNext();) { - IClassTransformer transformer = iter.next(); - + MixinEnvironment environment = MixinEnvironment.getCurrentEnvironment(); + + for (IClassTransformer transformer : environment.getTransformers()) { if (TreeInfo.lock != null) { // Clear the re-entrance semaphore TreeInfo.lock.clear(); @@ -180,12 +140,8 @@ abstract class TreeInfo { basicClass = transformer.transform(name, transformedName, basicClass); if (TreeInfo.lock != null && TreeInfo.lock.isSet()) { - // If the re-entrance semaphore was raised during the last transformation then we can assume - // that this transformer is re-entrant and remove it from our transformer chain. - iter.remove(); - // Also add it to the exclusion list so we can exclude it if the environment triggers a rebuild - TreeInfo.excludeTransformers.add(transformer.getClass().getName()); + environment.addTransformerExclusion(transformer.getClass().getName()); TreeInfo.lock.clear(); TreeInfo.logger.info("A re-entrant transformer '{}' was detected and will no longer process meta class data", @@ -195,65 +151,4 @@ abstract class TreeInfo { return basicClass; } - - /** - * Map a class name back to its obfuscated counterpart - * - * @param className - * @return obfuscated name for the specified deobfuscated reference - */ - static String unmap(String className) { - IClassNameTransformer nameTransformer = TreeInfo.nameTransformer; - if (nameTransformer != null) { - return nameTransformer.unmapClassName(className); - } - - return className; - } - - /** - * Check whether the current environment has changed - */ - private static void checkEnvironment() { - if (MixinEnvironment.getCurrentEnvironment() != TreeInfo.currentEnvironment) { - TreeInfo.buildTransformerDelegationList(); - TreeInfo.currentEnvironment = MixinEnvironment.getCurrentEnvironment(); - } - } - - /** - * Builds the transformer list to apply to loaded mixin bytecode. Since - * generating this list requires inspecting each transformer by name (to - * cope with the new wrapper functionality added by FML) we generate the - * list just once and cache the result. - */ - private static void buildTransformerDelegationList() { - TreeInfo.logger.debug("Building transformer delegation list:"); - TreeInfo.transformers = new ArrayList(); - for (IClassTransformer transformer : Launch.classLoader.getTransformers()) { - String transformerName = transformer.getClass().getName(); - boolean include = true; - for (String excludeClass : TreeInfo.excludeTransformers) { - if (transformerName.contains(excludeClass)) { - include = false; - break; - } - } - if (include && !transformerName.contains(MixinTransformer.class.getName())) { - TreeInfo.logger.debug(" Adding: {}", transformerName); - TreeInfo.transformers.add(transformer); - } else { - TreeInfo.logger.debug(" Excluding: {}", transformerName); - } - } - - TreeInfo.logger.debug("Transformer delegation list created with {} entries", TreeInfo.transformers.size()); - - for (IClassTransformer transformer : Launch.classLoader.getTransformers()) { - if (transformer instanceof IClassNameTransformer) { - TreeInfo.logger.debug("Found name transformer: {}", transformer.getClass().getName()); - TreeInfo.nameTransformer = (IClassNameTransformer) transformer; - } - } - } }