Remap classes for Unsafe and redirect bridge classes (#138)
This commit is contained in:
parent
65ed2913f6
commit
2a01f3230a
|
@ -3,7 +3,9 @@ package io.izzel.arclight.api;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
public class Unsafe {
|
public class Unsafe {
|
||||||
|
@ -22,7 +24,18 @@ public class Unsafe {
|
||||||
Object base = unsafe.staticFieldBase(field);
|
Object base = unsafe.staticFieldBase(field);
|
||||||
long offset = unsafe.staticFieldOffset(field);
|
long offset = unsafe.staticFieldOffset(field);
|
||||||
lookup = (MethodHandles.Lookup) unsafe.getObject(base, offset);
|
lookup = (MethodHandles.Lookup) unsafe.getObject(base, offset);
|
||||||
defineClass = lookup.unreflect(ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class));
|
MethodHandle mh;
|
||||||
|
try {
|
||||||
|
Method sunMisc = unsafe.getClass().getMethod("defineClass", String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class);
|
||||||
|
mh = lookup.unreflect(sunMisc).bindTo(unsafe);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Class<?> jdkInternalUnsafe = Class.forName("jdk.internal.misc.Unsafe");
|
||||||
|
Field internalUnsafeField = jdkInternalUnsafe.getDeclaredField("theUnsafe");
|
||||||
|
Object internalUnsafe = unsafe.getObject(unsafe.staticFieldBase(internalUnsafeField), unsafe.staticFieldOffset(internalUnsafeField));
|
||||||
|
Method internalDefineClass = jdkInternalUnsafe.getMethod("defineClass", String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class);
|
||||||
|
mh = lookup.unreflect(internalDefineClass).bindTo(internalUnsafe);
|
||||||
|
}
|
||||||
|
defineClass = Objects.requireNonNull(mh);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@ -250,7 +263,7 @@ public class Unsafe {
|
||||||
|
|
||||||
public static Class<?> defineClass(String s, byte[] bytes, int i, int i1, ClassLoader classLoader, ProtectionDomain protectionDomain) {
|
public static Class<?> defineClass(String s, byte[] bytes, int i, int i1, ClassLoader classLoader, ProtectionDomain protectionDomain) {
|
||||||
try {
|
try {
|
||||||
return (Class<?>) defineClass.bindTo(classLoader).invoke(s, bytes, i, i1, protectionDomain);
|
return (Class<?>) defineClass.invokeExact(s, bytes, i, i1, classLoader, protectionDomain);
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
throwException(throwable);
|
throwException(throwable);
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -3,13 +3,17 @@ package io.izzel.arclight.common.mod.util.remapper;
|
||||||
import com.google.common.collect.HashMultimap;
|
import com.google.common.collect.HashMultimap;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
import io.izzel.arclight.api.Unsafe;
|
||||||
|
import io.izzel.arclight.common.mod.ArclightMod;
|
||||||
import io.izzel.arclight.common.mod.util.remapper.generated.ArclightReflectionHandler;
|
import io.izzel.arclight.common.mod.util.remapper.generated.ArclightReflectionHandler;
|
||||||
import io.izzel.arclight.common.util.ArrayUtil;
|
import io.izzel.arclight.common.util.ArrayUtil;
|
||||||
|
import io.izzel.tools.func.Func4;
|
||||||
import io.izzel.tools.product.Product;
|
import io.izzel.tools.product.Product;
|
||||||
import io.izzel.tools.product.Product2;
|
import io.izzel.tools.product.Product2;
|
||||||
import io.izzel.tools.product.Product4;
|
import org.apache.commons.lang3.ClassUtils;
|
||||||
import org.apache.logging.log4j.Marker;
|
import org.apache.logging.log4j.Marker;
|
||||||
import org.apache.logging.log4j.MarkerManager;
|
import org.apache.logging.log4j.MarkerManager;
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.Handle;
|
import org.objectweb.asm.Handle;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
|
@ -34,9 +38,11 @@ import java.nio.ByteBuffer;
|
||||||
import java.security.CodeSource;
|
import java.security.CodeSource;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.security.SecureClassLoader;
|
import java.security.SecureClassLoader;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.ListIterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class ArclightRedirectAdapter implements PluginTransformer {
|
public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
|
|
||||||
|
@ -45,7 +51,7 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
private static final String REPLACED_NAME = Type.getInternalName(ArclightReflectionHandler.class);
|
private static final String REPLACED_NAME = Type.getInternalName(ArclightReflectionHandler.class);
|
||||||
private static final Multimap<String, Product2<String, MethodInsnNode>> METHOD_MODIFY = HashMultimap.create();
|
private static final Multimap<String, Product2<String, MethodInsnNode>> METHOD_MODIFY = HashMultimap.create();
|
||||||
private static final Multimap<String, Product2<String, MethodInsnNode>> METHOD_REDIRECT = HashMultimap.create();
|
private static final Multimap<String, Product2<String, MethodInsnNode>> METHOD_REDIRECT = HashMultimap.create();
|
||||||
private static final Map<Method, Product4<String, Class<?>[], String, Class<?>[]>> METHOD_TO_HANDLER = new HashMap<>();
|
private static final Map<String, Func4<ClassLoaderRemapper, Method, Object, Object[], Object[]>> METHOD_TO_HANDLER = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
redirect(Field.class, "getName", "fieldGetName");
|
redirect(Field.class, "getName", "fieldGetName");
|
||||||
|
@ -81,10 +87,69 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
modify(ClassLoader.class, "defineClass", String.class, ByteBuffer.class, ProtectionDomain.class);
|
modify(ClassLoader.class, "defineClass", String.class, ByteBuffer.class, ProtectionDomain.class);
|
||||||
modify(SecureClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class, CodeSource.class);
|
modify(SecureClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class, CodeSource.class);
|
||||||
modify(SecureClassLoader.class, "defineClass", String.class, ByteBuffer.class, CodeSource.class);
|
modify(SecureClassLoader.class, "defineClass", String.class, ByteBuffer.class, CodeSource.class);
|
||||||
|
modify(classOf("sun.misc.Unsafe"), "defineClass", "unsafeDefineClass", String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class);
|
||||||
|
modify(classOf("jdk.internal.misc.Unsafe"), "defineClass", "unsafeDefineClass", String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class);
|
||||||
|
modify(classOf("jdk.internal.misc.Unsafe"), "defineClass0", "unsafeDefineClass", String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Product4<String, Class<?>[], String, Class<?>[]> getInvokeRule(Method method) {
|
public static Object[] runHandle(ClassLoaderRemapper remapper, Method method, Object src, Object[] param) {
|
||||||
return METHOD_TO_HANDLER.get(method);
|
Func4<ClassLoaderRemapper, Method, Object, Object[], Object[]> handler = METHOD_TO_HANDLER.get(methodToString(method));
|
||||||
|
if (handler != null) {
|
||||||
|
return handler.apply(remapper, method, src, param);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object runRedirect(ClassLoaderRemapper remapper, Method method, Object src, Object[] param) throws Throwable {
|
||||||
|
Func4<ClassLoaderRemapper, Method, Object, Object[], Object[]> handler = METHOD_TO_HANDLER.get(methodToString(method));
|
||||||
|
if (handler != null) {
|
||||||
|
Object[] ret = handler.apply(remapper, method, src, param);
|
||||||
|
return ((Method) ret[0]).invoke(ret[1], (Object[]) ret[2]);
|
||||||
|
}
|
||||||
|
return remapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void scanMethod(byte[] bytes) {
|
||||||
|
ClassReader reader = new ClassReader(bytes);
|
||||||
|
ArclightMod.LOGGER.debug(MARKER, "Scanning {}", reader.getClassName());
|
||||||
|
ClassNode node = new ClassNode();
|
||||||
|
reader.accept(node, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
|
||||||
|
for (MethodNode method : node.methods) {
|
||||||
|
for (ListIterator<AbstractInsnNode> iterator = method.instructions.iterator(); iterator.hasNext(); ) {
|
||||||
|
AbstractInsnNode instruction = iterator.next();
|
||||||
|
int opcode = instruction.getOpcode();
|
||||||
|
if (opcode >= Opcodes.INVOKEVIRTUAL && opcode <= Opcodes.INVOKEINTERFACE) {
|
||||||
|
if (iterator.nextIndex() < method.instructions.size() - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MethodInsnNode insnNode = (MethodInsnNode) instruction;
|
||||||
|
String key = insnNode.name + insnNode.desc;
|
||||||
|
if (METHOD_MODIFY.containsKey(key) || METHOD_REDIRECT.containsKey(key)) {
|
||||||
|
try {
|
||||||
|
Class<?> cl = Class.forName(insnNode.owner.replace('/', '.'));
|
||||||
|
Type[] argumentTypes = Type.getMethodType(insnNode.desc).getArgumentTypes();
|
||||||
|
Class<?>[] paramTypes = new Class<?>[argumentTypes.length];
|
||||||
|
for (int i = 0, argumentTypesLength = argumentTypes.length; i < argumentTypesLength; i++) {
|
||||||
|
Type type = argumentTypes[i];
|
||||||
|
paramTypes[i] = ClassUtils.getClass(type.getClassName());
|
||||||
|
}
|
||||||
|
Method target = methodOf(cl, insnNode.name, paramTypes);
|
||||||
|
if (target != null) {
|
||||||
|
Func4<ClassLoaderRemapper, Method, Object, Object[], Object[]> bridge = METHOD_TO_HANDLER.get(methodToString(target));
|
||||||
|
if (bridge != null) {
|
||||||
|
ArclightMod.LOGGER.debug(MARKER, "Creating bridge handler {}/{}{} to {}", node.name, method.name, method.desc, methodToString(target));
|
||||||
|
METHOD_TO_HANDLER.put(node.name + '/' + method.name + method.desc, new BridgeHandler(bridge, target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (opcode < Opcodes.ILOAD || opcode > Opcodes.ALOAD) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -242,7 +307,9 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addRule(boolean modifyArgs, Class<?> owner, String name, String handlerName, Class<?>... args) {
|
private static void addRule(boolean modifyArgs, Class<?> owner, String name, String handlerName, Class<?>... args) {
|
||||||
|
if (owner == null) return;
|
||||||
Method original = methodOf(owner, name, args);
|
Method original = methodOf(owner, name, args);
|
||||||
|
if (original == null) return;
|
||||||
Class<?>[] handlerArgs;
|
Class<?>[] handlerArgs;
|
||||||
if (!Modifier.isStatic(original.getModifiers())) {
|
if (!Modifier.isStatic(original.getModifiers())) {
|
||||||
handlerArgs = ArrayUtil.prepend(args, owner, Class[]::new);
|
handlerArgs = ArrayUtil.prepend(args, owner, Class[]::new);
|
||||||
|
@ -250,28 +317,40 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
handlerArgs = args;
|
handlerArgs = args;
|
||||||
}
|
}
|
||||||
Method handler = methodOf(ArclightReflectionHandler.class, "redirect" + capitalize(handlerName), handlerArgs);
|
Method handler = methodOf(ArclightReflectionHandler.class, "redirect" + capitalize(handlerName), handlerArgs);
|
||||||
|
while (handler == null) {
|
||||||
|
handlerArgs[0] = handlerArgs[0].getSuperclass();
|
||||||
|
handler = methodOf(ArclightReflectionHandler.class, "redirect" + capitalize(handlerName), handlerArgs);
|
||||||
|
}
|
||||||
METHOD_REDIRECT.put(name + Type.getMethodDescriptor(original), Product.of(Type.getInternalName(owner), methodNodeOf(handler)));
|
METHOD_REDIRECT.put(name + Type.getMethodDescriptor(original), Product.of(Type.getInternalName(owner), methodNodeOf(handler)));
|
||||||
Product2<String, Class<?>[]> handleProd;
|
String key = methodToString(original);
|
||||||
if (modifyArgs) {
|
if (modifyArgs) {
|
||||||
Method modifyHandler;
|
Method modifyHandler = methodOf(ArclightReflectionHandler.class, "handle" + capitalize(handlerName), handlerArgs);
|
||||||
try {
|
if (modifyHandler == null) {
|
||||||
modifyHandler = methodOf(ArclightReflectionHandler.class, "handle" + capitalize(handlerName), handlerArgs);
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
handlerArgs[0] = original.getReturnType();
|
handlerArgs[0] = original.getReturnType();
|
||||||
modifyHandler = methodOf(ArclightReflectionHandler.class, "handle" + capitalize(handlerName), handlerArgs);
|
modifyHandler = methodOf(ArclightReflectionHandler.class, "handle" + capitalize(handlerName), handlerArgs);
|
||||||
}
|
}
|
||||||
METHOD_MODIFY.put(name + Type.getMethodDescriptor(original), Product.of(Type.getInternalName(owner), methodNodeOf(modifyHandler)));
|
if (modifyHandler == null) {
|
||||||
handleProd = Product.of("handle" + capitalize(handlerName), handlerArgs);
|
throw new RuntimeException("No handler for " + original);
|
||||||
} else {
|
}
|
||||||
handleProd = Product.of(null, null);
|
METHOD_MODIFY.put(name + Type.getMethodDescriptor(original), Product.of(Type.getInternalName(owner), methodNodeOf(modifyHandler)));
|
||||||
|
METHOD_TO_HANDLER.put(key, new ModifyHandler("handle" + capitalize(handlerName), handlerArgs));
|
||||||
|
} else {
|
||||||
|
METHOD_TO_HANDLER.put(key, new RedirectHandler("redirect" + capitalize(handlerName), handlerArgs));
|
||||||
}
|
}
|
||||||
METHOD_TO_HANDLER.put(original, Product.of("redirect" + capitalize(handlerName), handlerArgs, handleProd._1, handleProd._2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String capitalize(String name) {
|
private static String capitalize(String name) {
|
||||||
return Character.toUpperCase(name.charAt(0)) + name.substring(1);
|
return Character.toUpperCase(name.charAt(0)) + name.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Class<?> classOf(String cl) {
|
||||||
|
try {
|
||||||
|
return Class.forName(cl);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Method methodOf(Class<?> owner, String name, Class<?>... args) {
|
private static Method methodOf(Class<?> owner, String name, Class<?>... args) {
|
||||||
try {
|
try {
|
||||||
return owner.getMethod(name, args);
|
return owner.getMethod(name, args);
|
||||||
|
@ -279,7 +358,7 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
try {
|
try {
|
||||||
return owner.getDeclaredMethod(name, args);
|
return owner.getDeclaredMethod(name, args);
|
||||||
} catch (NoSuchMethodException e2) {
|
} catch (NoSuchMethodException e2) {
|
||||||
throw new RuntimeException(e2);
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,6 +370,10 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
return new MethodInsnNode(Opcodes.INVOKESTATIC, owner, name, desc);
|
return new MethodInsnNode(Opcodes.INVOKESTATIC, owner, name, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String methodToString(Method method) {
|
||||||
|
return Type.getInternalName(method.getDeclaringClass()) + "/" + method.getName() + Type.getMethodDescriptor(method);
|
||||||
|
}
|
||||||
|
|
||||||
private static int toOpcode(int handleType) {
|
private static int toOpcode(int handleType) {
|
||||||
switch (handleType) {
|
switch (handleType) {
|
||||||
case Opcodes.H_INVOKEINTERFACE:
|
case Opcodes.H_INVOKEINTERFACE:
|
||||||
|
@ -328,4 +411,80 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
return new LdcInsnNode(i);
|
return new LdcInsnNode(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class ModifyHandler implements Func4<ClassLoaderRemapper, Method, Object, Object[], Object[]> {
|
||||||
|
|
||||||
|
private final String handlerName;
|
||||||
|
private final Class<?>[] handlerArgs;
|
||||||
|
|
||||||
|
public ModifyHandler(String handlerName, Class<?>[] handlerArgs) {
|
||||||
|
this.handlerName = handlerName;
|
||||||
|
this.handlerArgs = handlerArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] apply(ClassLoaderRemapper remapper, Method method, Object src, Object[] param) {
|
||||||
|
try {
|
||||||
|
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(handlerName, handlerArgs);
|
||||||
|
if (method.getParameterCount() > 0) {
|
||||||
|
if (handleMethod.getReturnType().isArray() && !Modifier.isStatic(method.getModifiers())) {
|
||||||
|
Object[] invoke = (Object[]) handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
||||||
|
return new Object[]{method, invoke[0], Arrays.copyOfRange(invoke, 1, invoke.length)};
|
||||||
|
} else {
|
||||||
|
return new Object[]{method, src, handleMethod.invoke(null, param)};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Object[]{handleMethod, null, new Object[]{method.invoke(src, param)}};
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Unsafe.throwException(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RedirectHandler implements Func4<ClassLoaderRemapper, Method, Object, Object[], Object[]> {
|
||||||
|
|
||||||
|
private final String handlerName;
|
||||||
|
private final Class<?>[] handlerArgs;
|
||||||
|
|
||||||
|
public RedirectHandler(String handlerName, Class<?>[] handlerArgs) {
|
||||||
|
this.handlerName = handlerName;
|
||||||
|
this.handlerArgs = handlerArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] apply(ClassLoaderRemapper remapper, Method method, Object src, Object[] param) {
|
||||||
|
try {
|
||||||
|
Method redirectMethod = remapper.getGeneratedHandlerClass().getMethod(handlerName, handlerArgs);
|
||||||
|
return new Object[]{redirectMethod, null, Modifier.isStatic(method.getModifiers()) ? param : ArrayUtil.prepend(param, src)};
|
||||||
|
} catch (Exception e) {
|
||||||
|
Unsafe.throwException(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class BridgeHandler implements Func4<ClassLoaderRemapper, Method, Object, Object[], Object[]> {
|
||||||
|
|
||||||
|
private final Func4<ClassLoaderRemapper, Method, Object, Object[], Object[]> bridge;
|
||||||
|
private final Method targetMethod;
|
||||||
|
|
||||||
|
private BridgeHandler(Func4<ClassLoaderRemapper, Method, Object, Object[], Object[]> bridge, Method targetMethod) {
|
||||||
|
this.bridge = bridge;
|
||||||
|
this.targetMethod = targetMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] apply(ClassLoaderRemapper remapper, Method method, Object src, Object[] param) {
|
||||||
|
boolean bridgeStatic = Modifier.isStatic(targetMethod.getModifiers());
|
||||||
|
if (bridgeStatic) {
|
||||||
|
Object[] ret = bridge.apply(remapper, this.targetMethod, null, param);
|
||||||
|
return new Object[]{method, src, ret[2]};
|
||||||
|
} else {
|
||||||
|
Object[] ret = bridge.apply(remapper, this.targetMethod, param[0], Arrays.copyOfRange(param, 1, param.length));
|
||||||
|
return new Object[]{method, src, ArrayUtil.prepend((Object[]) ret[2], ret[1])};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,7 @@ import io.izzel.arclight.api.ArclightVersion;
|
||||||
import io.izzel.arclight.api.Unsafe;
|
import io.izzel.arclight.api.Unsafe;
|
||||||
import io.izzel.arclight.common.mod.util.remapper.ArclightRedirectAdapter;
|
import io.izzel.arclight.common.mod.util.remapper.ArclightRedirectAdapter;
|
||||||
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderRemapper;
|
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderRemapper;
|
||||||
import io.izzel.arclight.common.util.ArrayUtil;
|
import io.izzel.arclight.common.mod.util.remapper.RemappingClassLoader;
|
||||||
import io.izzel.tools.product.Product4;
|
|
||||||
import org.apache.commons.collections.iterators.IteratorEnumeration;
|
import org.apache.commons.collections.iterators.IteratorEnumeration;
|
||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
|
@ -17,9 +16,7 @@ import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
@ -27,7 +24,6 @@ import java.security.CodeSource;
|
||||||
import java.security.Permissions;
|
import java.security.Permissions;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.security.SecureClassLoader;
|
import java.security.SecureClassLoader;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -378,52 +374,26 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] handleMethodInvoke(Method method, Object src, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
public static Object[] handleMethodInvoke(Method method, Object src, Object[] param) throws Throwable {
|
||||||
Product4<String, Class<?>[], String, Class<?>[]> invokeRule = ArclightRedirectAdapter.getInvokeRule(method);
|
Object[] ret = ArclightRedirectAdapter.runHandle(remapper, method, src, param);
|
||||||
if (invokeRule != null) {
|
if (ret != null) {
|
||||||
if (invokeRule._3 != null && method.getParameterCount() > 0) {
|
return ret;
|
||||||
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._3, invokeRule._4);
|
|
||||||
if (handleMethod.getReturnType().isArray() && !Modifier.isStatic(method.getModifiers())) {
|
|
||||||
Object[] invoke = (Object[]) handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
|
||||||
return new Object[]{method, invoke[0], Arrays.copyOfRange(invoke, 1, invoke.length)};
|
|
||||||
} else {
|
|
||||||
return new Object[]{method, src, handleMethod.invoke(null, param)};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Method redirectMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._1, invokeRule._2);
|
|
||||||
return new Object[]{redirectMethod, null, ArrayUtil.prepend(param, src)};
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return new Object[]{method, src, param};
|
return new Object[]{method, src, param};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object redirectMethodInvoke(Method method, Object src, Object[] param) throws Throwable {
|
public static Object redirectMethodInvoke(Method method, Object src, Object[] param) throws Throwable {
|
||||||
Product4<String, Class<?>[], String, Class<?>[]> invokeRule = ArclightRedirectAdapter.getInvokeRule(method);
|
Object ret = ArclightRedirectAdapter.runRedirect(remapper, method, src, param);
|
||||||
if (invokeRule != null) {
|
if (ret != remapper) {
|
||||||
if (invokeRule._3 != null && method.getParameterCount() > 0) {
|
return ret;
|
||||||
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._3, invokeRule._4);
|
|
||||||
if (handleMethod.getReturnType().isArray()) {
|
|
||||||
if (Modifier.isStatic(method.getModifiers())) {
|
|
||||||
return method.invoke(src, (Object[]) handleMethod.invoke(null, param));
|
|
||||||
} else {
|
|
||||||
Object[] result = (Object[]) handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
|
||||||
return method.invoke(result[0], Arrays.copyOfRange(result, 1, result.length));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return method.invoke(src, handleMethod.invoke(null, param));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Method redirectMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._1, invokeRule._2);
|
|
||||||
return redirectMethod.invoke(null, ArrayUtil.prepend(param, src));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return method.invoke(src, param);
|
return method.invoke(src, param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] handleDefineClass(ClassLoader loader, byte[] b, int off, int len) {
|
public static Object[] handleDefineClass(ClassLoader loader, byte[] b, int off, int len) {
|
||||||
byte[] bytes = remapper.remapClass(b);
|
byte[] bytes = transformOrAdd(loader, b);
|
||||||
return new Object[]{loader, bytes, 0, bytes.length};
|
return new Object[]{loader, bytes, 0, bytes.length};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,28 +402,28 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] handleDefineClass(ClassLoader loader, String name, byte[] b, int off, int len) {
|
public static Object[] handleDefineClass(ClassLoader loader, String name, byte[] b, int off, int len) {
|
||||||
byte[] bytes = remapper.remapClass(b);
|
byte[] bytes = transformOrAdd(loader, b);
|
||||||
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length};
|
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Class<?> redirectDefineClass(ClassLoader loader, String name, byte[] b, int off, int len) {
|
public static Class<?> redirectDefineClass(ClassLoader loader, String name, byte[] b, int off, int len) {
|
||||||
return redirectDefineClass(loader, name, b, off, len, (ProtectionDomain) null);
|
return redirectDefineClass(loader, name, b, off, len, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] handleDefineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd) {
|
public static Object[] handleDefineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd) {
|
||||||
byte[] bytes = remapper.remapClass(b);
|
byte[] bytes = transformOrAdd(loader, b);
|
||||||
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length, pd};
|
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length, pd};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Class<?> redirectDefineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd) {
|
public static Class<?> redirectDefineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd) {
|
||||||
byte[] bytes = remapper.remapClass(b);
|
byte[] bytes = transformOrAdd(loader, b);
|
||||||
return Unsafe.defineClass(new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length, loader, pd);
|
return Unsafe.defineClass(new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length, loader, pd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] handleDefineClass(ClassLoader loader, String name, ByteBuffer b, ProtectionDomain pd) {
|
public static Object[] handleDefineClass(ClassLoader loader, String name, ByteBuffer b, ProtectionDomain pd) {
|
||||||
byte[] bytes = new byte[b.remaining()];
|
byte[] bytes = new byte[b.remaining()];
|
||||||
b.get(bytes);
|
b.get(bytes);
|
||||||
bytes = remapper.remapClass(bytes);
|
bytes = transformOrAdd(loader, bytes);
|
||||||
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), ByteBuffer.wrap(bytes), pd};
|
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), ByteBuffer.wrap(bytes), pd};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,7 +434,7 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] handleDefineClass(SecureClassLoader loader, String name, byte[] b, int off, int len, CodeSource cs) {
|
public static Object[] handleDefineClass(SecureClassLoader loader, String name, byte[] b, int off, int len, CodeSource cs) {
|
||||||
byte[] bytes = remapper.remapClass(b);
|
byte[] bytes = transformOrAdd(loader, b);
|
||||||
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length, cs};
|
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length, cs};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,11 +445,38 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
public static Object[] handleDefineClass(SecureClassLoader loader, String name, ByteBuffer b, CodeSource cs) {
|
public static Object[] handleDefineClass(SecureClassLoader loader, String name, ByteBuffer b, CodeSource cs) {
|
||||||
byte[] bytes = new byte[b.remaining()];
|
byte[] bytes = new byte[b.remaining()];
|
||||||
b.get(bytes);
|
b.get(bytes);
|
||||||
bytes = remapper.remapClass(bytes);
|
bytes = transformOrAdd(loader, bytes);
|
||||||
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), ByteBuffer.wrap(bytes), cs};
|
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), ByteBuffer.wrap(bytes), cs};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Class<?> redirectDefineClass(SecureClassLoader loader, String name, ByteBuffer b, CodeSource cs) {
|
public static Class<?> redirectDefineClass(SecureClassLoader loader, String name, ByteBuffer b, CodeSource cs) {
|
||||||
return redirectDefineClass(loader, name, b, new ProtectionDomain(cs, new Permissions()));
|
return redirectDefineClass(loader, name, b, new ProtectionDomain(cs, new Permissions()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Object[] handleUnsafeDefineClass(Object unsafe, String name, byte[] bytes, int off, int len, ClassLoader loader, ProtectionDomain pd) {
|
||||||
|
bytes = transformOrAdd(loader, bytes);
|
||||||
|
return new Object[]{unsafe, new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length, loader, pd};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<?> redirectUnsafeDefineClass(Object unsafe, String name, byte[] bytes, int off, int len, ClassLoader loader, ProtectionDomain pd) {
|
||||||
|
return redirectDefineClass(loader, name, bytes, off, len, pd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] transformOrAdd(ClassLoader loader, byte[] bytes) {
|
||||||
|
RemappingClassLoader rcl = null;
|
||||||
|
while (loader != null) {
|
||||||
|
if (loader instanceof RemappingClassLoader) {
|
||||||
|
rcl = ((RemappingClassLoader) loader);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
loader = loader.getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rcl != null) {
|
||||||
|
return rcl.getRemapper().remapClass(bytes);
|
||||||
|
} else {
|
||||||
|
ArclightRedirectAdapter.scanMethod(bytes);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user