diff --git a/src/launchwrapper/java/org/spongepowered/asm/launch/platform/MixinPlatformAgentFMLLegacy.java b/src/launchwrapper/java/org/spongepowered/asm/launch/platform/MixinPlatformAgentFMLLegacy.java index ca195b70b..56a34f454 100644 --- a/src/launchwrapper/java/org/spongepowered/asm/launch/platform/MixinPlatformAgentFMLLegacy.java +++ b/src/launchwrapper/java/org/spongepowered/asm/launch/platform/MixinPlatformAgentFMLLegacy.java @@ -140,11 +140,7 @@ public class MixinPlatformAgentFMLLegacy extends MixinPlatformAgentAbstract impl @Override public AcceptResult accept(MixinPlatformManager manager, IContainerHandle handle) { - try { - this.clCoreModManager = MixinPlatformAgentFMLLegacy.getCoreModManagerClass(); - } catch (ClassNotFoundException ex) { - MixinPlatformAgentAbstract.logger.info("FML platform manager could not load class {}. Proceeding without FML support.", - ex.getMessage()); + if (this.getCoreModManagerClass() == null) { return AcceptResult.INVALID; } @@ -298,30 +294,6 @@ public String getPhaseProvider() { public void prepare() { this.initInjectionState |= MixinPlatformAgentFMLLegacy.isTweakerQueued(MixinPlatformAgentFMLLegacy.FML_TWEAKER_INJECTION); } - - /* (non-Javadoc) - * @see org.spongepowered.asm.launch.IMixinPlatformAgent - * #initPrimaryContainer() - */ - @Override - public void initPrimaryContainer() { - if (this.clCoreModManager != null) { -// MixinEnvironment.registerPhaseProvider(MixinPlatformAgentFMLLegacy.class.getName() + "$PhaseProvider"); - this.injectRemapper(); - } - } - - private void injectRemapper() { - try { - MixinPlatformAgentAbstract.logger.debug("Creating FML remapper adapter: {}", MixinPlatformAgentFMLLegacy.FML_REMAPPER_ADAPTER_CLASS); - Class clFmlRemapperAdapter = Class.forName(MixinPlatformAgentFMLLegacy.FML_REMAPPER_ADAPTER_CLASS, true, Launch.classLoader); - Method mdCreate = clFmlRemapperAdapter.getDeclaredMethod("create"); - IRemapper remapper = (IRemapper)mdCreate.invoke(null); - MixinEnvironment.getDefaultEnvironment().getRemappers().add(remapper); - } catch (Exception ex) { - MixinPlatformAgentAbstract.logger.debug("Failed instancing FML remapper adapter, things will probably go horribly for notch-obf'd mods!"); - } - } /* (non-Javadoc) * @see org.spongepowered.asm.launch.platform.IMixinPlatformAgent#inject() @@ -357,6 +329,30 @@ protected final boolean checkForCoInitialisation() { return !MixinPlatformAgentFMLLegacy.isTweakerQueued(MixinPlatformAgentFMLLegacy.FML_TWEAKER_DEOBF); } + /** + * Attempt to get the FML CoreModManager, tries the post-1.8 namespace first + * and falls back to 1.7.10 if class lookup fails + */ + private Class getCoreModManagerClass() { + if (this.clCoreModManager != null) { + return this.clCoreModManager; + } + + try { + try { + this.clCoreModManager = Class.forName(GlobalProperties.getString( + GlobalProperties.Keys.FML_CORE_MOD_MANAGER, MixinPlatformAgentFMLLegacy.CORE_MOD_MANAGER_CLASS)); + } catch (ClassNotFoundException ex) { + this.clCoreModManager = Class.forName(MixinPlatformAgentFMLLegacy.CORE_MOD_MANAGER_CLASS_LEGACY); + } + } catch (ClassNotFoundException ex) { + MixinPlatformAgentAbstract.logger.info("FML platform manager could not load class {}. Proceeding without FML support.", + ex.getMessage()); + } + + return this.clCoreModManager; + } + /** * Check whether a tweaker ending with tweakName has been enqueued * but not yet visited. @@ -373,19 +369,6 @@ private static boolean isTweakerQueued(String tweakerName) { return false; } - /** - * Attempt to get the FML CoreModManager, tries the post-1.8 namespace first - * and falls back to 1.7.10 if class lookup fails - */ - private static Class getCoreModManagerClass() throws ClassNotFoundException { - try { - return Class.forName(GlobalProperties.getString( - GlobalProperties.Keys.FML_CORE_MOD_MANAGER, MixinPlatformAgentFMLLegacy.CORE_MOD_MANAGER_CLASS)); - } catch (ClassNotFoundException ex) { - return Class.forName(MixinPlatformAgentFMLLegacy.CORE_MOD_MANAGER_CLASS_LEGACY); - } - } - @SuppressWarnings("unchecked") private static List getIgnoredMods(Class clCoreModManager) throws IllegalAccessException, InvocationTargetException { Method mdGetIgnoredMods = null; @@ -412,7 +395,22 @@ private static List getIgnoredMods(Class clCoreModManager) throws Ill */ @Override public void init() { - // Nothing to do here + if (this.getCoreModManagerClass() != null) { +// MixinEnvironment.registerPhaseProvider(MixinPlatformAgentFMLLegacy.class.getName() + "$PhaseProvider"); + this.injectRemapper(); + } + } + + private void injectRemapper() { + try { + MixinPlatformAgentAbstract.logger.debug("Creating FML remapper adapter: {}", MixinPlatformAgentFMLLegacy.FML_REMAPPER_ADAPTER_CLASS); + Class clFmlRemapperAdapter = Class.forName(MixinPlatformAgentFMLLegacy.FML_REMAPPER_ADAPTER_CLASS, true, Launch.classLoader); + Method mdCreate = clFmlRemapperAdapter.getDeclaredMethod("create"); + IRemapper remapper = (IRemapper)mdCreate.invoke(null); + MixinEnvironment.getDefaultEnvironment().getRemappers().add(remapper); + } catch (Exception ex) { + MixinPlatformAgentAbstract.logger.debug("Failed instancing FML remapper adapter, things will probably go horribly for notch-obf'd mods!"); + } } /* (non-Javadoc) diff --git a/src/launchwrapper/java/org/spongepowered/asm/service/mojang/MixinServiceLaunchWrapper.java b/src/launchwrapper/java/org/spongepowered/asm/service/mojang/MixinServiceLaunchWrapper.java index 82a11fb5d..2ef4c8980 100644 --- a/src/launchwrapper/java/org/spongepowered/asm/service/mojang/MixinServiceLaunchWrapper.java +++ b/src/launchwrapper/java/org/spongepowered/asm/service/mojang/MixinServiceLaunchWrapper.java @@ -81,7 +81,7 @@ public class MixinServiceLaunchWrapper extends MixinServiceAbstract implements I public static final Keys BLACKBOARD_KEY_TWEAKCLASSES = Keys.of("TweakClasses"); public static final Keys BLACKBOARD_KEY_TWEAKS = Keys.of("Tweaks"); - private static final String MIXIN_TWEAKER_CLASS = "org.spongepowered.asm.launch.MixinTweaker"; + private static final String MIXIN_TWEAKER_CLASS = MixinServiceAbstract.LAUNCH_PACKAGE + "MixinTweaker"; // Consts private static final String STATE_TWEAKER = MixinServiceAbstract.MIXIN_PACKAGE + "EnvironmentStateTweaker"; @@ -618,5 +618,5 @@ private static int findInStackTrace(String className, String methodName) { return 0; } - + } diff --git a/src/launchwrapper/java/org/spongepowered/asm/service/mojang/MixinServiceLaunchWrapperBootstrap.java b/src/launchwrapper/java/org/spongepowered/asm/service/mojang/MixinServiceLaunchWrapperBootstrap.java index 0b1aaaf49..bdb726ce2 100644 --- a/src/launchwrapper/java/org/spongepowered/asm/service/mojang/MixinServiceLaunchWrapperBootstrap.java +++ b/src/launchwrapper/java/org/spongepowered/asm/service/mojang/MixinServiceLaunchWrapperBootstrap.java @@ -35,6 +35,7 @@ public class MixinServiceLaunchWrapperBootstrap implements IMixinServiceBootstrap { private static final String SERVICE_PACKAGE = "org.spongepowered.asm.service."; + private static final String LAUNCH_PACKAGE = "org.spongepowered.asm.launch."; private static final String MIXIN_UTIL_PACKAGE = "org.spongepowered.asm.util."; private static final String LEGACY_ASM_PACKAGE = "org.spongepowered.asm.lib."; @@ -61,7 +62,8 @@ public void bootstrap() { // Essential ones Launch.classLoader.addClassLoaderExclusion(MixinServiceLaunchWrapperBootstrap.SERVICE_PACKAGE); - + Launch.classLoader.addClassLoaderExclusion(MixinServiceLaunchWrapperBootstrap.LAUNCH_PACKAGE); + // Important ones Launch.classLoader.addClassLoaderExclusion(MixinServiceLaunchWrapperBootstrap.ASM_PACKAGE); Launch.classLoader.addClassLoaderExclusion(MixinServiceLaunchWrapperBootstrap.LEGACY_ASM_PACKAGE); diff --git a/src/main/java/org/spongepowered/asm/launch/MixinBootstrap.java b/src/main/java/org/spongepowered/asm/launch/MixinBootstrap.java index 87067c653..4f6719100 100644 --- a/src/main/java/org/spongepowered/asm/launch/MixinBootstrap.java +++ b/src/main/java/org/spongepowered/asm/launch/MixinBootstrap.java @@ -24,6 +24,8 @@ */ package org.spongepowered.asm.launch; +import java.lang.reflect.Constructor; +import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; @@ -32,6 +34,9 @@ import org.spongepowered.asm.launch.platform.MixinPlatformManager; import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.MixinEnvironment.Phase; +import org.spongepowered.asm.mixin.throwables.MixinError; +import org.spongepowered.asm.service.IMixinInternal; +import org.spongepowered.asm.service.IMixinService; import org.spongepowered.asm.service.MixinService; /** @@ -63,11 +68,17 @@ public abstract class MixinBootstrap { */ public static final String VERSION = "0.8.3"; + /** + * Transformer factory + */ + private static final String MIXIN_TRANSFORMER_FACTORY_CLASS = "org.spongepowered.asm.mixin.transformer.MixinTransformer$Factory"; + /** * Log all the things */ private static final Logger logger = LogManager.getLogger("mixin"); + // These are Klass local, with luck this shouldn't be a problem private static boolean initialised = false; private static boolean initState = true; @@ -77,7 +88,7 @@ public abstract class MixinBootstrap { MixinService.boot(); MixinService.getService().prepare(); } - + /** * Platform manager instance */ @@ -134,6 +145,7 @@ static boolean start() { } MixinBootstrap.registerSubsystem(MixinBootstrap.VERSION); + MixinBootstrap.offerInternals(); if (!MixinBootstrap.initialised) { MixinBootstrap.initialised = true; @@ -207,4 +219,31 @@ private static void registerSubsystem(String version) { GlobalProperties.put(GlobalProperties.Keys.INIT, version); } + private static void offerInternals() { + IMixinService service = MixinService.getService(); + + try { + for (IMixinInternal internal : MixinBootstrap.getInternals()) { + service.offer(internal); + } + } catch (AbstractMethodError ex) { + // outdated service + ex.printStackTrace(); + } + } + + @SuppressWarnings("unchecked") + private static List getInternals() throws MixinError { + List internals = new ArrayList(); + try { + Class clTransformerFactory = (Class)Class.forName(MixinBootstrap.MIXIN_TRANSFORMER_FACTORY_CLASS); + Constructor ctor = clTransformerFactory.getDeclaredConstructor(); + ctor.setAccessible(true); + internals.add(ctor.newInstance()); + } catch (ReflectiveOperationException ex) { + throw new MixinError(ex); + } + return internals; + } + } diff --git a/src/main/java/org/spongepowered/asm/mixin/transformer/IMixinTransformer.java b/src/main/java/org/spongepowered/asm/mixin/transformer/IMixinTransformer.java index 183190c73..769ab93fc 100644 --- a/src/main/java/org/spongepowered/asm/mixin/transformer/IMixinTransformer.java +++ b/src/main/java/org/spongepowered/asm/mixin/transformer/IMixinTransformer.java @@ -52,6 +52,20 @@ public interface IMixinTransformer { */ public abstract List reload(String mixinClass, ClassNode classNode); + /** + * Called when the transformation reason is computing_frames. The only + * operation we care about here is adding interfaces to target classes but + * at the moment we don't have sufficient scaffolding to determine that + * without triggering re-entrance. Currently just a no-op in order to not + * cause a re-entrance crash under ModLauncher 7.0+. + * + * @param environment Current environment + * @param name Class transformed name + * @param classNode Class tree + * @return true if the class was transformed + */ + public abstract boolean computeFramesForClass(MixinEnvironment environment, String name, ClassNode classNode); + /** * Callback from the hotswap agent and LaunchWrapper Proxy, transform class * bytecode. This method delegates to class generation or class @@ -67,6 +81,43 @@ public interface IMixinTransformer { * @see ILegacyClassTransformer#transformClassBytes(String, String, byte[]) */ public abstract byte[] transformClassBytes(String name, String transformedName, byte[] basicClass); + + /** + * Apply mixins and postprocessors to the supplied class + * + * @param environment Current environment + * @param name Class transformed name + * @param classBytes Class bytecode + * @return Transformed bytecode + */ + public abstract byte[] transformClass(MixinEnvironment environment, String name, byte[] classBytes); + + /** + * Apply mixins and postprocessors to the supplied class + * + * @param environment Current environment + * @param name Class transformed name + * @param classNode Class tree + * @return true if the class was transformed + */ + public abstract boolean transformClass(MixinEnvironment environment, String name, ClassNode classNode); + + /** + * Generate the specified mixin-synthetic class + * + * @param environment Current environment + * @param name Class name to generate + * @return Generated bytecode or null if no class was generated + */ + public abstract byte[] generateClass(MixinEnvironment environment, String name); + + /** + * @param environment Current environment + * @param name Class transformed name + * @param classNode Empty classnode to populate + * @return True if the class was generated successfully + */ + public abstract boolean generateClass(MixinEnvironment environment, String name, ClassNode classNode); /** * Get the transformer extensions diff --git a/src/main/java/org/spongepowered/asm/mixin/transformer/IMixinTransformerFactory.java b/src/main/java/org/spongepowered/asm/mixin/transformer/IMixinTransformerFactory.java new file mode 100644 index 000000000..7e3b10ed8 --- /dev/null +++ b/src/main/java/org/spongepowered/asm/mixin/transformer/IMixinTransformerFactory.java @@ -0,0 +1,42 @@ +/* + * This file is part of Mixin, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.asm.mixin.transformer; + +import org.spongepowered.asm.launch.MixinInitialisationError; +import org.spongepowered.asm.service.IMixinInternal; + +/** + * Factory for the mixin transformer, concrete instances of this class are only + * provided to services since only the service should be able to decide when the + * mixin transformer is initialised. + */ +public interface IMixinTransformerFactory extends IMixinInternal { + + /** + * Create a new transformer. + */ + public abstract IMixinTransformer createTransformer() throws MixinInitialisationError; + +} diff --git a/src/main/java/org/spongepowered/asm/mixin/transformer/MixinTransformer.java b/src/main/java/org/spongepowered/asm/mixin/transformer/MixinTransformer.java index a9b09c74f..183248c5d 100644 --- a/src/main/java/org/spongepowered/asm/mixin/transformer/MixinTransformer.java +++ b/src/main/java/org/spongepowered/asm/mixin/transformer/MixinTransformer.java @@ -28,6 +28,7 @@ import java.util.List; import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.launch.MixinInitialisationError; import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.MixinEnvironment.Option; import org.spongepowered.asm.mixin.throwables.MixinException; @@ -41,10 +42,26 @@ /** * Transformer which manages the mixin configuration and application process */ -class MixinTransformer extends TreeTransformer implements IMixinTransformer { +final class MixinTransformer extends TreeTransformer implements IMixinTransformer { + + /** + * Impl of mixin transformer factory + */ + static class Factory implements IMixinTransformerFactory { + + /* (non-Javadoc) + * @see org.spongepowered.asm.mixin.transformer.IMixinTransformerFactory + * #createTransformer() + */ + @Override + public IMixinTransformer createTransformer() throws MixinInitialisationError { + return new MixinTransformer(); + } + + } private static final String MIXIN_AGENT_CLASS = "org.spongepowered.tools.agent.MixinAgent"; - + /** * Synthetic class registry */ @@ -70,7 +87,7 @@ class MixinTransformer extends TreeTransformer implements IMixinTransformer { */ private final MixinClassGenerator generator; - public MixinTransformer() { + MixinTransformer() { MixinEnvironment environment = MixinEnvironment.getCurrentEnvironment(); Object globalMixinTransformer = environment.getActiveTransformer(); @@ -190,6 +207,7 @@ public byte[] transformClassBytes(String name, String transformedName, byte[] ba * @param classNode Class tree * @return true if the class was transformed */ + @Override public boolean computeFramesForClass(MixinEnvironment environment, String name, ClassNode classNode) { // TODO compute added interfaces return false; @@ -203,6 +221,7 @@ public boolean computeFramesForClass(MixinEnvironment environment, String name, * @param classBytes Class bytecode * @return Transformed bytecode */ + @Override public byte[] transformClass(MixinEnvironment environment, String name, byte[] classBytes) { ClassNode classNode = this.readClass(classBytes); if (this.processor.applyMixins(environment, name, classNode)) { @@ -219,6 +238,7 @@ public byte[] transformClass(MixinEnvironment environment, String name, byte[] c * @param classNode Class tree * @return true if the class was transformed */ + @Override public boolean transformClass(MixinEnvironment environment, String name, ClassNode classNode) { return this.processor.applyMixins(environment, name, classNode); } @@ -230,6 +250,7 @@ public boolean transformClass(MixinEnvironment environment, String name, ClassNo * @param name Class name to generate * @return Generated bytecode or null if no class was generated */ + @Override public byte[] generateClass(MixinEnvironment environment, String name) { ClassNode classNode = MixinTransformer.createEmptyClass(name); if (this.generator.generateClass(environment, name, classNode)) { @@ -244,6 +265,7 @@ public byte[] generateClass(MixinEnvironment environment, String name) { * @param classNode Empty classnode to populate * @return True if the class was generated successfully */ + @Override public boolean generateClass(MixinEnvironment environment, String name, ClassNode classNode) { return this.generator.generateClass(environment, name, classNode); } diff --git a/src/main/java/org/spongepowered/asm/service/IMixinInternal.java b/src/main/java/org/spongepowered/asm/service/IMixinInternal.java new file mode 100644 index 000000000..2e354fd90 --- /dev/null +++ b/src/main/java/org/spongepowered/asm/service/IMixinInternal.java @@ -0,0 +1,32 @@ +/* + * This file is part of Mixin, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.asm.service; + +/** + * A mixin internal part, offered to services. + */ +public interface IMixinInternal { + +} diff --git a/src/main/java/org/spongepowered/asm/service/IMixinService.java b/src/main/java/org/spongepowered/asm/service/IMixinService.java index aa5c324f6..a4f068c62 100644 --- a/src/main/java/org/spongepowered/asm/service/IMixinService.java +++ b/src/main/java/org/spongepowered/asm/service/IMixinService.java @@ -62,6 +62,15 @@ public interface IMixinService { */ public abstract Phase getInitialPhase(); + /** + * Called when the subsystem is offering internal components to the service, + * the service can determine whether to retain or ignore the component based + * on its own requirements. + * + * @param internal Internal component being offered + */ + public abstract void offer(IMixinInternal internal); + /** * Called at the end of subsystem boot */ diff --git a/src/main/java/org/spongepowered/asm/service/MixinServiceAbstract.java b/src/main/java/org/spongepowered/asm/service/MixinServiceAbstract.java index 9e57708a3..b5c6a2465 100644 --- a/src/main/java/org/spongepowered/asm/service/MixinServiceAbstract.java +++ b/src/main/java/org/spongepowered/asm/service/MixinServiceAbstract.java @@ -26,7 +26,9 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -50,6 +52,7 @@ public abstract class MixinServiceAbstract implements IMixinService { // Consts protected static final String LAUNCH_PACKAGE = "org.spongepowered.asm.launch."; protected static final String MIXIN_PACKAGE = "org.spongepowered.asm.mixin."; + protected static final String SERVICE_PACKAGE = "org.spongepowered.asm.service."; /** * Logger @@ -62,6 +65,11 @@ public abstract class MixinServiceAbstract implements IMixinService { */ protected final ReEntranceLock lock = new ReEntranceLock(1); + /** + * All internals offered to this service + */ + private final Map, IMixinInternal> internals = new HashMap, IMixinInternal>(); + /** * Service agent instances */ @@ -104,20 +112,35 @@ public CompatibilityLevel getMinCompatibilityLevel() { public CompatibilityLevel getMaxCompatibilityLevel() { return null; } - + /* (non-Javadoc) - * @see org.spongepowered.asm.service.IMixinService#beginPhase() + * @see org.spongepowered.asm.service.IMixinService + * #offer(org.spongepowered.asm.service.IMixinInternal) */ @Override - public void beginPhase() { + public void offer(IMixinInternal internal) { + this.registerInternal(internal, internal.getClass()); + } + + @SuppressWarnings("unchecked") + private void registerInternal(IMixinInternal internal, Class clazz) { + for (Class iface : clazz.getInterfaces()) { + if (iface == IMixinInternal.class) { + this.internals.put((Class)clazz, internal); + } + this.registerInternal(internal, iface); + } } - /* (non-Javadoc) - * @see org.spongepowered.asm.service.IMixinService - * #checkEnv(java.lang.Object) - */ - @Override - public void checkEnv(Object bootSource) { + @SuppressWarnings("unchecked") + protected final T getInternal(Class type) { + for (Class internalType : this.internals.keySet()) { + if (type.isAssignableFrom(internalType)) { + return (T)this.internals.get(internalType); + } + } + + return null; } /* (non-Javadoc) @@ -130,6 +153,21 @@ public void init() { } } + /* (non-Javadoc) + * @see org.spongepowered.asm.service.IMixinService#beginPhase() + */ + @Override + public void beginPhase() { + } + + /* (non-Javadoc) + * @see org.spongepowered.asm.service.IMixinService + * #checkEnv(java.lang.Object) + */ + @Override + public void checkEnv(Object bootSource) { + } + /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService#getReEntranceLock() */ diff --git a/src/main/java/org/spongepowered/asm/util/Locals.java b/src/main/java/org/spongepowered/asm/util/Locals.java index f57974a6f..0ae2e21da 100644 --- a/src/main/java/org/spongepowered/asm/util/Locals.java +++ b/src/main/java/org/spongepowered/asm/util/Locals.java @@ -454,7 +454,8 @@ public static List generateLocalVariableTable(ClassNode class String desc = lastKnownType[j]; Type localType = local.getType(); if (localType != null) { - desc = "null".equals(localType.getInternalName()) ? Constants.OBJECT_DESC : localType.getDescriptor(); + desc = localType.getSort() >= Type.ARRAY && "null".equals(localType.getInternalName()) + ? Constants.OBJECT_DESC : localType.getDescriptor(); } localNodes[j] = new LocalVariableNode("var" + j, desc, null, label, null, j); diff --git a/src/modlauncher/java/org/spongepowered/asm/service/modlauncher/MixinServiceModLauncher.java b/src/modlauncher/java/org/spongepowered/asm/service/modlauncher/MixinServiceModLauncher.java index c7782f6e8..80791f9eb 100644 --- a/src/modlauncher/java/org/spongepowered/asm/service/modlauncher/MixinServiceModLauncher.java +++ b/src/modlauncher/java/org/spongepowered/asm/service/modlauncher/MixinServiceModLauncher.java @@ -31,11 +31,12 @@ import org.spongepowered.asm.launch.platform.container.ContainerHandleModLauncher; import org.spongepowered.asm.mixin.MixinEnvironment.CompatibilityLevel; import org.spongepowered.asm.mixin.MixinEnvironment.Phase; -import org.spongepowered.asm.mixin.transformer.MixinTransformationHandler; +import org.spongepowered.asm.mixin.transformer.IMixinTransformerFactory; import org.spongepowered.asm.service.IClassBytecodeProvider; import org.spongepowered.asm.service.IClassProvider; import org.spongepowered.asm.service.IClassTracker; import org.spongepowered.asm.service.IMixinAuditTrail; +import org.spongepowered.asm.service.IMixinInternal; import org.spongepowered.asm.service.ITransformerProvider; import org.spongepowered.asm.service.MixinServiceAbstract; import org.spongepowered.asm.util.IConsumer; @@ -114,6 +115,14 @@ public void onInit(IClassBytecodeProvider bytecodeProvider) { public void onStartup() { this.phaseConsumer.accept(Phase.DEFAULT); } + + @Override + public void offer(IMixinInternal internal) { + if (internal instanceof IMixinTransformerFactory) { + this.getTransformationHandler().offer((IMixinTransformerFactory)internal); + } + super.offer(internal); + } // TEMP @SuppressWarnings("deprecation") @@ -212,7 +221,7 @@ public IMixinAuditTrail getAuditTrail() { /** * Get (or create) the transformation handler */ - private IClassProcessor getTransformationHandler() { + private MixinTransformationHandler getTransformationHandler() { if (this.transformationHandler == null) { this.transformationHandler = new MixinTransformationHandler(); } diff --git a/src/modlauncher/java/org/spongepowered/asm/mixin/transformer/MixinTransformationHandler.java b/src/modlauncher/java/org/spongepowered/asm/service/modlauncher/MixinTransformationHandler.java similarity index 76% rename from src/modlauncher/java/org/spongepowered/asm/mixin/transformer/MixinTransformationHandler.java rename to src/modlauncher/java/org/spongepowered/asm/service/modlauncher/MixinTransformationHandler.java index 303efd2e8..303e1c7e8 100644 --- a/src/modlauncher/java/org/spongepowered/asm/mixin/transformer/MixinTransformationHandler.java +++ b/src/modlauncher/java/org/spongepowered/asm/service/modlauncher/MixinTransformationHandler.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.spongepowered.asm.mixin.transformer; +package org.spongepowered.asm.service.modlauncher; import java.util.EnumSet; @@ -32,9 +32,13 @@ import org.spongepowered.asm.launch.MixinLaunchPlugin; import org.spongepowered.asm.launch.Phases; import org.spongepowered.asm.mixin.MixinEnvironment; +import org.spongepowered.asm.mixin.transformer.IMixinTransformer; +import org.spongepowered.asm.mixin.transformer.IMixinTransformerFactory; import org.spongepowered.asm.service.ISyntheticClassInfo; import org.spongepowered.asm.service.ISyntheticClassRegistry; +import com.google.common.base.Preconditions; + import cpw.mods.modlauncher.api.ITransformerActivity; import cpw.mods.modlauncher.serviceapi.ILaunchPluginService.Phase; @@ -43,16 +47,16 @@ * application, post processing and synthetic class generation */ public class MixinTransformationHandler implements IClassProcessor { - + /** - * Lock for initialising the transformer + * Mixin transformer factory, from service */ - private final Object initialisationLock = new Object(); + private IMixinTransformerFactory transformerFactory; /** * Transformer pipeline instance */ - private MixinTransformer transformer; + private IMixinTransformer transformer; /** * Synthetic class registry, used so the processor knows when to respond to @@ -60,6 +64,11 @@ public class MixinTransformationHandler implements IClassProcessor { */ private ISyntheticClassRegistry registry; + void offer(IMixinTransformerFactory transformerFactory) { + Preconditions.checkNotNull(transformerFactory, "transformerFactory"); + this.transformerFactory = transformerFactory; + } + /* (non-Javadoc) * @see org.spongepowered.asm.launch.IClassProcessor#handlesClass( * org.objectweb.asm.Type, boolean, java.lang.String) @@ -89,18 +98,13 @@ public synchronized boolean processClass(Phase phase, ClassNode classNode, Type if (phase == Phase.BEFORE) { return false; } - - MixinTransformer transformer = null; + if (this.transformer == null) { - synchronized (this.initialisationLock) { - transformer = this.transformer; - if (transformer == null) { - transformer = this.transformer = new MixinTransformer(); - this.registry = transformer.getExtensions().getSyntheticClassRegistry(); - } + if (this.transformerFactory == null) { + throw new IllegalStateException("processClass called before transformer factory offered to transformation handler"); } - } else { - transformer = this.transformer; + this.transformer = this.transformerFactory.createTransformer(); + this.registry = this.transformer.getExtensions().getSyntheticClassRegistry(); } // Don't transform when the reason is mixin (side-loading in progress) @@ -111,14 +115,14 @@ public synchronized boolean processClass(Phase phase, ClassNode classNode, Type MixinEnvironment environment = MixinEnvironment.getCurrentEnvironment(); ISyntheticClassInfo syntheticClass = this.registry.findSyntheticClass(classType.getClassName()); if (syntheticClass != null) { - return transformer.generateClass(environment, classType.getClassName(), classNode); + return this.transformer.generateClass(environment, classType.getClassName(), classNode); } if (ITransformerActivity.COMPUTING_FRAMES_REASON.equals(reason)) { - return transformer.computeFramesForClass(environment, classType.getClassName(), classNode); + return this.transformer.computeFramesForClass(environment, classType.getClassName(), classNode); } - return transformer.transformClass(environment, classType.getClassName(), classNode); + return this.transformer.transformClass(environment, classType.getClassName(), classNode); } }