package com.github.fge.grappa.future; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Handle; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.H_INVOKESTATIC; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.RETURN; import static org.objectweb.asm.Opcodes.V1_8; public final class Tester { public static CallSite genCallSite(final MethodHandles.Lookup caller, final String invokedName, final MethodType invokedType, final String methodName) throws NoSuchMethodException, IllegalAccessException { final MethodHandles.Lookup lookup = MethodHandles.lookup(); final MethodHandle handle = lookup.findStatic( Tester.class, methodName, MethodType .methodType(void.class, String.class)); return new ConstantCallSite(handle); } public static void main(final String[] args) throws Throwable { Label line; final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); cw.visit(V1_8, ACC_PUBLIC, "pkg/MyClass", null, "java/lang/Object", new String[]{ "java/lang/Runnable" }); cw.visitSource("(generated)", "(generated)"); MethodVisitor visitor = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); visitor.visitCode(); visitor.visitVarInsn(ALOAD, 0); visitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); visitor.visitInsn(RETURN); visitor.visitMaxs(1, 1); visitor.visitEnd(); visitor = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null); visitor.visitCode(); line = new Label(); visitor.visitLabel(line); visitor.visitLineNumber(1, line); visitor.visitLdcInsn("Some argument"); final String desc1 = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;" + "Ljava/lang/invoke/MethodType;Ljava/lang/String;)" + "Ljava/lang/invoke/CallSite;"; final String desc2 = "(Ljava/lang/String;)V"; final String owner = "com/github/fge/grappa/future/Tester"; visitor.visitInvokeDynamicInsn("call", desc2, new Handle(H_INVOKESTATIC, owner, "genCallSite", desc1), "hello"); line = new Label(); visitor.visitLabel(line); visitor.visitLineNumber(2, line); visitor.visitLdcInsn("Another argument"); visitor.visitInvokeDynamicInsn("call", "(Ljava/lang/String;)V", new Handle( H_INVOKESTATIC, owner, "genCallSite", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;" + "Ljava/lang/invoke/MethodType;Ljava/lang/String;)" + "Ljava/lang/invoke/CallSite;"), "world"); visitor.visitInsn(RETURN); visitor.visitMaxs(1, 1); visitor.visitEnd(); cw.visitEnd(); new ClassLoader(Tester.class.getClassLoader()) {{ final byte[] bytes = cw.toByteArray(); final Class<?> cl = defineClass(null, bytes, 0, bytes.length); final Runnable r = (Runnable) cl.newInstance(); r.run(); }}; } private static void hello(final String arg) { System.err.println("Called hello(): " + arg); Thread.dumpStack(); } private static void world(final String arg) { System.err.println("Called world():" + arg); Thread.dumpStack(); } }