package de.take_weiland.mods.commons.reflect; import com.google.common.base.Function; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import javax.annotation.Nullable; import java.lang.invoke.MethodHandle; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import static org.objectweb.asm.Opcodes.*; import static org.objectweb.asm.commons.Method.getMethod; /** * @author diesieben07 */ final class MethodHandleStrategy extends ReflectionStrategy { @Override public <T> T createAccessor(Class<T> iface) { validateInterface(iface); String className = SCReflection.nextDynamicClassName(MethodHandleStrategy.class.getPackage()); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); cw.visit(V1_7, ACC_FINAL, className, null, "java/lang/Object", new String[] { Type.getInternalName(iface) }); GeneratorAdapter gen = new GeneratorAdapter(0, getMethod("void <init>()"), null, null, cw); gen.visitCode(); gen.loadThis(); gen.invokeConstructor(Type.getType(Object.class), getMethod("void <init>()")); gen.returnValue(); gen.endMethod(); ImmutableMap<Method, MethodHandle> handles = FluentIterable.from(Arrays.asList(iface.getDeclaredMethods())) .toMap(new Function<Method, MethodHandle>() { @Nullable @Override public MethodHandle apply(Method input) { return AccessorMemberParser.getTarget(input); } }); Type myType = Type.getObjectType(className); Type mhType = Type.getType(MethodHandle.class); int idx = 0; for (Map.Entry<Method, MethodHandle> entry : handles.entrySet()) { Method method = entry.getKey(); MethodHandle methodHandle = entry.getValue(); gen = new GeneratorAdapter(ACC_PUBLIC, getMethod(method), null, null, cw); gen.visitCode(); gen.getStatic(myType, "h" + idx, mhType); Type[] paramTypes = new Type[methodHandle.type().parameterCount()]; Type retType = Type.getType(methodHandle.type().returnType()); for (int param = 0; param < methodHandle.type().parameterCount(); param++) { gen.loadArg(param); paramTypes[param] = Type.getType(methodHandle.type().parameterType(param)); } gen.invokeVirtual(mhType, new org.objectweb.asm.commons.Method("invokeExact", retType, paramTypes)); gen.returnValue(); gen.endMethod(); idx++; } Type iteratorType = Type.getType(Iterator.class); gen = new GeneratorAdapter(ACC_STATIC | ACC_PUBLIC, getMethod("void <clinit>()"), null, null, cw); gen.visitCode(); for (idx = 0; idx < handles.size(); idx++) { gen.getStatic(Type.getType(MethodHandleStrategy.class), "staticData", iteratorType); gen.invokeInterface(iteratorType, getMethod("Object next()")); gen.checkCast(mhType); gen.putStatic(myType, "h" + idx, mhType); } gen.returnValue(); gen.endMethod(); for (idx = 0; idx < handles.size(); idx++){ cw.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, "h" + idx, mhType.getDescriptor(), null, null); } cw.visitEnd(); synchronized (MethodHandleStrategy.class) { staticData = handles.values().iterator(); try { //noinspection unchecked return (T) SCReflection.defineDynamicClass(cw.toByteArray()).newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } finally { staticData = null; } } } static Iterator<?> staticData; }