Skip to content

Commit

Permalink
Refactor some elements of mixin service into new smaller components
Browse files Browse the repository at this point in the history
The main goal here is to reduce the amount of boilerplate required when
providing out simple implementations of the mixin service. Some mixin
end users are using extremely simple environments and this reduces the
boilerplate code in those implementations.
  • Loading branch information
Mumfrey committed Oct 16, 2019
1 parent 22909dc commit 03e8ad5
Show file tree
Hide file tree
Showing 9 changed files with 235 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import java.util.Map;
import java.util.Set;

import org.spongepowered.asm.service.IClassTracker;

import net.minecraft.launchwrapper.LaunchClassLoader;

/**
Expand All @@ -37,7 +39,7 @@
* them to perform some validation tasks, and insert entries for mixin "classes"
* into the invalid classes set.
*/
final class LaunchClassLoaderUtil {
final class LaunchClassLoaderUtil implements IClassTracker {

private static final String CACHED_CLASSES_FIELD = "cachedClasses";
private static final String INVALID_CLASSES_FIELD = "invalidClasses";
Expand Down Expand Up @@ -67,7 +69,7 @@ final class LaunchClassLoaderUtil {
this.classLoaderExceptions = LaunchClassLoaderUtil.<Set<String>>getField(classLoader, LaunchClassLoaderUtil.CLASS_LOADER_EXCEPTIONS_FIELD);
this.transformerExceptions = LaunchClassLoaderUtil.<Set<String>>getField(classLoader, LaunchClassLoaderUtil.TRANSFORMER_EXCEPTIONS_FIELD);
}

/**
* Get the classloader
*/
Expand All @@ -82,10 +84,27 @@ LaunchClassLoader getClassLoader() {
* @param name class name
* @return true if the class name exists in the cache
*/
boolean isClassLoaded(String name) {
@Override
public boolean isClassLoaded(String name) {
return this.cachedClasses.containsKey(name);
}

/* (non-Javadoc)
* @see org.spongepowered.asm.service.IMixinService#getClassRestrictions(
* java.lang.String)
*/
@Override
public String getClassRestrictions(String className) {
String restrictions = "";
if (this.isClassClassLoaderExcluded(className, null)) {
restrictions = "PACKAGE_CLASSLOADER_EXCLUSION";
}
if (this.isClassTransformerExcluded(className, null)) {
restrictions = (restrictions.length() > 0 ? restrictions + "," : "") + "PACKAGE_TRANSFORMER_EXCLUSION";
}
return restrictions;
}

/**
* Get whether the specified name or transformedName exist in either of the
* exclusion lists
Expand Down Expand Up @@ -143,7 +162,8 @@ boolean isClassTransformerExcluded(String name, String transformedName) {
*
* @param name class name
*/
void registerInvalidClass(String name) {
@Override
public void registerInvalidClass(String name) {
if (this.invalidClasses != null) {
this.invalidClasses.add(name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@
import org.spongepowered.asm.mixin.throwables.MixinException;
import org.spongepowered.asm.service.IClassBytecodeProvider;
import org.spongepowered.asm.service.IClassProvider;
import org.spongepowered.asm.service.IClassTracker;
import org.spongepowered.asm.service.ILegacyClassTransformer;
import org.spongepowered.asm.service.ITransformer;
import org.spongepowered.asm.service.ITransformerProvider;
import org.spongepowered.asm.service.MixinServiceAbstract;
import org.spongepowered.asm.util.Constants;
import org.spongepowered.asm.util.perf.Profiler;
Expand All @@ -72,7 +74,7 @@
/**
* Mixin service for launchwrapper
*/
public class MixinServiceLaunchWrapper extends MixinServiceAbstract implements IClassProvider, IClassBytecodeProvider {
public class MixinServiceLaunchWrapper extends MixinServiceAbstract implements IClassProvider, IClassBytecodeProvider, ITransformerProvider {

// Blackboard keys
public static final Keys BLACKBOARD_KEY_TWEAKCLASSES = Keys.of("TweakClasses");
Expand Down Expand Up @@ -259,6 +261,22 @@ public IClassBytecodeProvider getBytecodeProvider() {
return this;
}

/* (non-Javadoc)
* @see org.spongepowered.asm.service.IMixinService#getTransformerProvider()
*/
@Override
public ITransformerProvider getTransformerProvider() {
return this;
}

/* (non-Javadoc)
* @see org.spongepowered.asm.service.IMixinService#getClassTracker()
*/
@Override
public IClassTracker getClassTracker() {
return this.classLoaderUtil;
}

/* (non-Javadoc)
* @see org.spongepowered.asm.service.IClassProvider#findClass(
* java.lang.String)
Expand Down Expand Up @@ -315,40 +333,6 @@ public InputStream getResourceAsStream(String name) {
return Launch.classLoader.getResourceAsStream(name);
}

/* (non-Javadoc)
* @see org.spongepowered.asm.service.IMixinService#registerInvalidClass(
* java.lang.String)
*/
@Override
public void registerInvalidClass(String className) {
this.classLoaderUtil.registerInvalidClass(className);
}

/* (non-Javadoc)
* @see org.spongepowered.asm.service.IMixinService#isClassLoaded(
* java.lang.String)
*/
@Override
public boolean isClassLoaded(String className) {
return this.classLoaderUtil.isClassLoaded(className);
}

/* (non-Javadoc)
* @see org.spongepowered.asm.service.IMixinService#getClassRestrictions(
* java.lang.String)
*/
@Override
public String getClassRestrictions(String className) {
String restrictions = "";
if (this.classLoaderUtil.isClassClassLoaderExcluded(className, null)) {
restrictions = "PACKAGE_CLASSLOADER_EXCLUSION";
}
if (this.classLoaderUtil.isClassTransformerExcluded(className, null)) {
restrictions = (restrictions.length() > 0 ? restrictions + "," : "") + "PACKAGE_TRANSFORMER_EXCLUSION";
}
return restrictions;
}

/* (non-Javadoc)
* @see org.spongepowered.asm.service.IClassProvider#getClassPath()
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.spongepowered.asm.obfuscation.RemapperChain;
import org.spongepowered.asm.service.IMixinService;
import org.spongepowered.asm.service.ITransformer;
import org.spongepowered.asm.service.ITransformerProvider;
import org.spongepowered.asm.service.MixinService;
import org.spongepowered.asm.service.MixinServiceAbstract;
import org.spongepowered.asm.util.Constants;
Expand Down Expand Up @@ -1263,7 +1264,8 @@ public void audit() {
@Deprecated
public List<ITransformer> getTransformers() {
MixinEnvironment.logger.warn("MixinEnvironment::getTransformers is deprecated!");
return (List<ITransformer>)this.service.getTransformers();
ITransformerProvider transformers = this.service.getTransformerProvider();
return transformers != null ? (List<ITransformer>)transformers.getTransformers() : Collections.<ITransformer>emptyList();
}

/**
Expand All @@ -1275,7 +1277,10 @@ public List<ITransformer> getTransformers() {
@Deprecated
public void addTransformerExclusion(String name) {
MixinEnvironment.logger.warn("MixinEnvironment::addTransformerExclusion is deprecated!");
this.service.addTransformerExclusion(name);
ITransformerProvider transformers = this.service.getTransformerProvider();
if (transformers != null) {
transformers.addTransformerExclusion(name);
}
}

/* (non-Javadoc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@
import org.spongepowered.asm.mixin.transformer.throwables.InvalidMixinException;
import org.spongepowered.asm.mixin.transformer.throwables.MixinReloadException;
import org.spongepowered.asm.mixin.transformer.throwables.MixinTargetAlreadyLoadedException;
import org.spongepowered.asm.service.IClassTracker;
import org.spongepowered.asm.service.IMixinService;
import org.spongepowered.asm.service.MixinService;
import org.spongepowered.asm.util.Annotations;
import org.spongepowered.asm.util.Bytecode;
import org.spongepowered.asm.util.asm.ASM;
Expand Down Expand Up @@ -702,11 +702,6 @@ static DeclaredTarget of(Object target, MixinInfo info) {

}

/**
* Mixin service
*/
private static final IMixinService classLoaderUtil = MixinService.getService();

/**
* Global order of mixin infos, used to determine ordering between mixins
* with equivalent priority
Expand Down Expand Up @@ -843,7 +838,10 @@ static DeclaredTarget of(Object target, MixinInfo info) {
// Inject the mixin class name into the LaunchClassLoader's invalid
// classes set so that any classes referencing the mixin directly will
// cause the game to crash
MixinInfo.classLoaderUtil.registerInvalidClass(this.className);
IClassTracker tracker = this.service.getClassTracker();
if (tracker != null) {
tracker.registerInvalidClass(this.className);
}
}

// Read the class bytes and transform
Expand Down Expand Up @@ -906,13 +904,14 @@ protected List<DeclaredTarget> readDeclaredTargets(MixinClassNode classNode, boo
throw new InvalidMixinException(this, String.format("The mixin '%s' is missing an @Mixin annotation", this.className));
}

IClassTracker tracker = this.service.getClassTracker();
List<DeclaredTarget> declaredTargets = new ArrayList<DeclaredTarget>();
for (Object target : this.readTargets(mixin)) {
DeclaredTarget declaredTarget = DeclaredTarget.of(target, this);
if (declaredTarget == null) {
continue;
}
if (MixinInfo.classLoaderUtil.isClassLoaded(declaredTarget.name) && !this.isReloading()) {
if (tracker != null && tracker.isClassLoaded(declaredTarget.name) && !this.isReloading()) {
String message = String.format("Critical problem: %s target %s was loaded too early.", this, declaredTarget.name);
if (this.parent.isRequired()) {
throw new MixinTargetAlreadyLoadedException(this, message, declaredTarget.name);
Expand Down Expand Up @@ -1265,9 +1264,12 @@ private ClassNode loadMixinClass(String mixinClassName) throws ClassNotFoundExce
ClassNode classNode = null;

try {
String restrictions = this.service.getClassRestrictions(mixinClassName);
if (restrictions.length() > 0) {
this.logger.error("Classloader restrictions [{}] encountered loading {}, name: {}", restrictions, this, mixinClassName);
IClassTracker tracker = this.service.getClassTracker();
if (tracker != null) {
String restrictions = tracker.getClassRestrictions(mixinClassName);
if (restrictions.length() > 0) {
this.logger.error("Classloader restrictions [{}] encountered loading {}, name: {}", restrictions, this, mixinClassName);
}
}
classNode = this.service.getBytecodeProvider().getClassNode(mixinClassName, true);
} catch (ClassNotFoundException ex) {
Expand Down
62 changes: 62 additions & 0 deletions src/main/java/org/spongepowered/asm/service/IClassTracker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* This file is part of Mixin, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* 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;

/**
* Class trackers are responsible for interacting with the class loading process
* to for the purposes of tracking class load activity and class load
* restrictions. This service component is entirely optional and services can
* elect to return <tt>null</tt> if the platform does not support this
* functionality.
*/
public interface IClassTracker {

/**
* Register an invalid class with the service classloader
*
* @param className invalid class name
*/
public abstract void registerInvalidClass(String className);

/**
* Check whether the specified class was already loaded by the service
* classloader
*
* @param className class name to check
* @return true if the class was already loaded
*/
public abstract boolean isClassLoaded(String className);

/**
* Check whether the specified class name is subject to any restrictions in
* the context of this service
*
* @param className class name to check
* @return comma-separated list of restrictions, empty string if no
* restrictions apply
*/
public abstract String getClassRestrictions(String className);

}
61 changes: 14 additions & 47 deletions src/main/java/org/spongepowered/asm/service/IMixinService.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,20 @@ public interface IMixinService {
*/
public abstract IClassBytecodeProvider getBytecodeProvider();

// /**
// * Return the synthetic class registry for this service
// */
// public abstract ISyntheticClassRegistry getSyntheticClassRegistry();
/**
* Return the transformer provider for this service. <b>Note that unlike
* other service components, this component is allowed to be <tt>null</tt>
* for services which do not support transformers, or don't support
* interacting with them</b>!
*/
public abstract ITransformerProvider getTransformerProvider();

/**
* Return the class tracker for this service. <b>Note that unlike
* other service components, this component is allowed to be <tt>null</tt>
* for services which do not support this functionality</b>!
*/
public abstract IClassTracker getClassTracker();

/**
* Get additional platform agents for this service
Expand Down Expand Up @@ -130,49 +140,6 @@ public interface IMixinService {
*/
public abstract InputStream getResourceAsStream(String name);

/**
* Register an invalid class with the service classloader
*
* @param className invalid class name
*/
public abstract void registerInvalidClass(String className);

/**
* Check whether the specified class was already loaded by the service
* classloader
*
* @param className class name to check
* @return true if the class was already loaded
*/
public abstract boolean isClassLoaded(String className);

/**
* Check whether the specified class name is subject to any restrictions in
* the context of this service
*
* @param className class name to check
* @return comma-separated list of restrictions, empty string if no
* restrictions apply
*/
public abstract String getClassRestrictions(String className);

/**
* Get currently available transformers in the environment
*/
public abstract Collection<ITransformer> getTransformers();

/**
* Get currently available transformers in the environment
*/
public abstract Collection<ITransformer> getDelegatedTransformers();

/**
* Adds a transformer to the transformer exclusions list
*
* @param name Class transformer exclusion to add
*/
public abstract void addTransformerExclusion(String name);

/**
* Get the detected side name for this environment
*/
Expand Down
Loading

0 comments on commit 03e8ad5

Please sign in to comment.