diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderAdapter.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderAdapter.java index 1773c6da..f62c3a15 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderAdapter.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderAdapter.java @@ -2,6 +2,7 @@ package io.izzel.arclight.common.mod.util.remapper; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; +import cpw.mods.modlauncher.api.LamdbaExceptionUtils; import io.izzel.arclight.common.mod.ArclightMod; import io.izzel.arclight.common.mod.util.remapper.generated.RemappingURLClassLoader; import org.apache.logging.log4j.Marker; @@ -21,11 +22,14 @@ import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TypeInsnNode; import org.objectweb.asm.tree.VarInsnNode; +import java.lang.invoke.MethodType; import java.net.URLClassLoader; import java.nio.ByteBuffer; import java.security.SecureClassLoader; import java.util.Collection; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; public class ClassLoaderAdapter implements PluginTransformer { @@ -44,6 +48,27 @@ public class ClassLoaderAdapter implements PluginTransformer { private final Map classLoaderTypes = ImmutableMap.builder() .put(Type.getInternalName(URLClassLoader.class), Type.getInternalName(RemappingURLClassLoader.class)) .build(); + private final Set defineClassMethods = defineClassTypes.entrySet().stream() + .map(LamdbaExceptionUtils.rethrowFunction(entry -> { + MethodType type = MethodType.fromMethodDescriptorString(entry.getKey().getDescriptor(), getClass().getClassLoader()); + return new ClassLoaderRemapper.WrappedMethod("defineClass", type.parameterArray()); + })).collect(Collectors.toSet()); + + public static boolean isDefineClassMethod(Class cl, String bukkitName, Class[] pTypes) { + if (bukkitName.equals("defineClass") && ClassLoader.class.isAssignableFrom(cl)) { + return INSTANCE.defineClassMethods.contains(new ClassLoaderRemapper.WrappedMethod(bukkitName, pTypes)); + } else { + return false; + } + } + + public static boolean isDefineClassMethod(Class cl, String bukkitName, MethodType methodType) { + if (bukkitName.equals("defineClass") && ClassLoader.class.isAssignableFrom(cl)) { + return INSTANCE.defineClassMethods.contains(new ClassLoaderRemapper.WrappedMethod(bukkitName, methodType.parameterArray())); + } else { + return false; + } + } @Override public void handleClass(ClassNode node, ClassLoaderRemapper remapper) { diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderRemapper.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderRemapper.java index 4348d7b6..9844352b 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderRemapper.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderRemapper.java @@ -359,7 +359,7 @@ public class ClassLoaderRemapper extends JarRemapper { } - private static class WrappedMethod { + static class WrappedMethod { private final String name; private final Class[] pTypes; diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/generated/ArclightReflectionHandler.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/generated/ArclightReflectionHandler.java index 61039052..1fa2f345 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/generated/ArclightReflectionHandler.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/generated/ArclightReflectionHandler.java @@ -1,5 +1,7 @@ package io.izzel.arclight.common.mod.util.remapper.generated; +import io.izzel.arclight.api.Unsafe; +import io.izzel.arclight.common.mod.util.remapper.ClassLoaderAdapter; import io.izzel.arclight.common.mod.util.remapper.ClassLoaderRemapper; import org.objectweb.asm.Type; @@ -8,9 +10,13 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.security.CodeSource; +import java.security.Permissions; +import java.security.ProtectionDomain; @SuppressWarnings("unused") -public class ArclightReflectionHandler { +public class ArclightReflectionHandler extends ClassLoader { private static final String PREFIX = "net.minecraft."; @@ -46,6 +52,12 @@ public class ArclightReflectionHandler { // bukkit -> srg public static Method redirectGetMethod(Class cl, String bukkitName, Class... pTypes) throws NoSuchMethodException { + if (ClassLoaderAdapter.isDefineClassMethod(cl, bukkitName, pTypes)) { + Class[] classes = new Class[pTypes.length + 1]; + classes[0] = ClassLoader.class; + System.arraycopy(pTypes, 0, classes, 1, pTypes.length); + return ArclightReflectionHandler.class.getMethod(bukkitName, classes); + } Method method = remapper.tryMapMethodToSrg(cl, bukkitName, pTypes); if (method != null) { return method; @@ -56,6 +68,12 @@ public class ArclightReflectionHandler { // bukkit -> srg public static Method redirectGetDeclaredMethod(Class cl, String bukkitName, Class... pTypes) throws NoSuchMethodException { + if (ClassLoaderAdapter.isDefineClassMethod(cl, bukkitName, pTypes)) { + Class[] classes = new Class[pTypes.length + 1]; + classes[0] = ClassLoader.class; + System.arraycopy(pTypes, 0, classes, 1, pTypes.length); + return ArclightReflectionHandler.class.getDeclaredMethod(bukkitName, classes); + } Method method = remapper.tryMapMethodToSrg(cl, bukkitName, pTypes); if (method != null) { return method; @@ -147,6 +165,13 @@ public class ArclightReflectionHandler { // bukkit -> srg public static MethodHandle redirectFindVirtual(MethodHandles.Lookup lookup, Class cl, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException { + if (ClassLoaderAdapter.isDefineClassMethod(cl, name, methodType)) { + Class[] pTypes = methodType.parameterArray(); + Class[] classes = new Class[pTypes.length + 1]; + classes[0] = ClassLoader.class; + System.arraycopy(pTypes, 0, classes, 1, pTypes.length); + return lookup.findStatic(ArclightReflectionHandler.class, name, MethodType.methodType(Class.class, classes)); + } Method method = remapper.tryMapMethodToSrg(cl, name, methodType.parameterArray()); if (method != null) { return lookup.findVirtual(cl, method.getName(), methodType); @@ -197,4 +222,31 @@ public class ArclightReflectionHandler { String replace = remapper.mapType(canonicalName.replace('.', '/')).replace('/', '.'); return loader.loadClass(replace); } + + public static Class defineClass(ClassLoader loader, byte[] b, int off, int len) { + return defineClass(loader, null, b, off, len); + } + + public static Class defineClass(ClassLoader loader, String name, byte[] b, int off, int len) { + return defineClass(loader, name, b, off, len, (ProtectionDomain) null); + } + + public static Class defineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd) { + byte[] bytes = remapper.remapClass(b); + return Unsafe.defineClass(name, bytes, 0, bytes.length, loader, pd); + } + + public static Class defineClass(ClassLoader loader, String name, ByteBuffer b, ProtectionDomain pd) { + byte[] bytes = new byte[b.remaining()]; + b.get(bytes); + return defineClass(loader, name, bytes, 0, bytes.length, pd); + } + + public static Class defineClass(ClassLoader loader, String name, byte[] b, int off, int len, CodeSource cs) { + return defineClass(loader, name, b, off, len, new ProtectionDomain(cs, new Permissions())); + } + + public static Class defineClass(ClassLoader loader, String name, ByteBuffer b, CodeSource cs) { + return defineClass(loader, name, b, new ProtectionDomain(cs, new Permissions())); + } }