Performing DynamicInvoke From Java - A Step By Step Journey

The secret is in the boot strapping!
This post shows a simple pattern to make Java a fully dynamic language using dynamic class creation and invokedynamic. It is a step by step exploration of the subject written as I was developing the idea:

Java 7 sees the invokedynamic game changing opt code. It allows optimized invokation of dynamically defined methods by patching little combinatorial trees directly into the JVM bytecode structure. But - YOU CANNOT GET TO IT FROM JAVA. I was not standing for that - so here is my story of working around this limitation and by so doing creating a pattern for fully dynamic Java.

The JVM has a powerful dynamic a loading system. In other words, it is very dynamic already. So, my solution to leveraging the new dynamic method system is to create invokedynamic classes on the fly and load them into the JVM. Yes - that is double dynamic, loving it already!

My first step was to get a really simple class and convert it into and ASM definition to give a template to work off. Here is a snipped from my bash history:

 1033  gedit Simple.java
 1034  ls
 1035  javac Simple.java
 1036  javac Simple.java
 1037  javac Simple.java
 1038  javac Simple.java
 1039  java -classpath ../asm-4.0_RC1/lib/asm-4.0_RC1.jar:../asm-4.0_RC1/lib/asm-util-4.0_RC1.jar org.objectweb.asm.util.ASMifierClassVisitor Simple.class 

The listing might make you realise I am no longer used to writing Java outside of Eclipse - took me 4 goes to get it right! That embarrassment out the way - here is my Java class definition:

public class Simple
{
    public static void main(String args)
    {
        long l;
        System.out.println("Will call an arbirary JVM method using invokedynamic!");
        System.out.println("=====================================================");
        for(l=0;l<10;++l)
        {
            System.out.println("Ln: " + l);
        }
    }   
}

Which... is still wrong. Can you spot the problem? I'll fix it in assembler in a few moments. bash command 1039 converted the class file produced by javac into a little program which I imported into Eclipse and tidied it up a bit to give:
 
package com.nerdscentral.dynamics;

//import java.util.*;
import java.io.FileOutputStream;

import org.objectweb.asm.*;
//import org.objectweb.asm.attrs.*;

public class SimpleExample implements Opcodes 
{
    public static void main(String args[])
    {
        try 
        {
            byte[] classFile = dump();
            FileOutputStream fso = new FileOutputStream("Simple.class");
            fso.write(classFile);
            fso.close();
        }
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }

    public static byte[] dump () throws Exception 
    {

        ClassWriter cw = new ClassWriter(0);
        FieldVisitor fv;
        MethodVisitor mv;
        AnnotationVisitor av0;

        cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "Simple", null, "java/lang/Object", null);

        {
            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }

        {
            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "(Ljava/lang/String;)V", null, null);
            mv.visitCode();
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("Will call an arbitrary JVM method using invokedynamic!");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("======================================================");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            mv.visitInsn(LCONST_0);
            mv.visitVarInsn(LSTORE, 1);
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitFrame(Opcodes.F_APPEND,1, new Object[] {Opcodes.LONG}, 0, null);
            mv.visitVarInsn(LLOAD, 1);  
            mv.visitLdcInsn(new Long(10L));
            mv.visitInsn(LCMP);
            Label l1 = new Label();
            mv.visitJumpInsn(IFGE, l1);
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
            mv.visitInsn(DUP);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V");
            mv.visitLdcInsn("Ln: ");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
            mv.visitVarInsn(LLOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(J)Ljava/lang/StringBuilder;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            mv.visitVarInsn(LLOAD, 1);
            mv.visitInsn(LCONST_1);
            mv.visitInsn(LADD);
            mv.visitVarInsn(LSTORE, 1);
            mv.visitJumpInsn(GOTO, l0);
            mv.visitLabel(l1);
            mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
            mv.visitInsn(RETURN);
            mv.visitMaxs(4, 3);
            mv.visitEnd();
        }
        cw.visitEnd();

        return cw.toByteArray();
    }
}
 
Running this program makes a little file Simple.class. But it does not work:
 
[ajt@localhost DynamicSupport]$ java Simple
Exception in thread "main" java.lang.NoSuchMethodError: main
 

javap -verbose Simple shows the problem out clearly:
 
public static void main(java.lang.String);
  Code:
   Stack=4, Locals=3, Args_size=1
   0:   getstatic       #16; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc     #18; //String Will call an arbirary JVM method using invokedynamic!
 

I have gotten the signature for the argument to main incorrect. I have used a String not a String[]. The fix is simple enough - add [ before the argument in the asm definition for the method signature:
 
            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
 

That little fix in place and invoking the class from the command line does this:
 
Will call an arbitrary JVM method using invokedynamic!
=====================================================
Ln: 0
Ln: 1
Ln: 2
Ln: 3
Ln: 4
Ln: 5
Ln: 6
Ln: 7
Ln: 8
Ln: 9
 

The next step is to make the creation and invocation of the generated class into the same process. The next block of code is rather large, so I will go through it step by step after giving the whole thing:
 
package com.nerdscentral.dynamics;

import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;

import org.objectweb.asm.*;

public class SimpleExample implements Opcodes 
{
    public interface IExecutable
    {
        public void execute();
    }
    
    public static class DynamicLoader extends URLClassLoader
    {
        public DynamicLoader(URL[] urls)
        {
            super(urls);
        }        
               
        public Class<?> loadFromBytes(byte[] classDefinition)
        {
            Class<?> clazz=defineClass(null,classDefinition, 0,classDefinition.length);
            resolveClass(clazz);
            return clazz;
        }
        
    }

    public static class BootStrap
    {
        public static void main(DynamicLoader dl)
        {
            try 
            {
                (new BootStrap()).execute(dl);
            } catch (Exception e) 
            {
                e.printStackTrace();
            }
                   
        }

        public void execute(DynamicLoader dl)
        {
            byte[] classFile;
            try
            {
                classFile = dump();
                Class<?> simpleExample = dl.loadFromBytes(classFile);                
                Constructor<?> cons=simpleExample.getConstructor(new Class<?>[0]);
                IExecutable toExecute = (IExecutable) cons.newInstance(new Object[0]);
                // Now (finally) we have a direct JVM linked way of calling our dynamically 
                // created class instances.
                toExecute.execute();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }        

        }

    
    }
    
    // Boot strap myself
    public static void main(String args[])
    {
        try
        {
             DynamicLoader dl = new DynamicLoader(urls);
            Class<?> clazz = dl.loadClass("com.nerdscentral.dynamics.SimpleExample$BootStrap");
            java.lang.reflect.Method m=clazz.getDeclaredMethod("main", new Class<?>[]{DynamicLoader.class});
            m.invoke(null,new Object[]{dl});
        }
        catch(Throwable t)
        {
            t.printStackTrace();
        }
        
    }

    public static byte[] dump () throws Exception 
    {

        ClassWriter cw = new ClassWriter(0);
        MethodVisitor mv;

        // void visit(int version, int access, String name, String signature, String superName, String[] interfaces) 
        cw.visit
        (
            V1_6, ACC_PUBLIC + ACC_SUPER, 
            "com/nerdscentral/dynamics/Simple", 
            null, 
            "java/lang/Object", 
            new String[]{"com/nerdscentral/dynamics/SimpleExample$IExecutable"}
        );

        {
            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }

        {
            mv = cw.visitMethod(ACC_PUBLIC, "execute", "()V", null, null);
            mv.visitCode();
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("Will call an arbitrary JVM method using invokedynamic!");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("======================================================");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            mv.visitInsn(LCONST_0);
            mv.visitVarInsn(LSTORE, 1);
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitFrame(Opcodes.F_APPEND,1, new Object[] {Opcodes.LONG}, 0, null);
            mv.visitVarInsn(LLOAD, 1);  
            mv.visitLdcInsn(new Long(10L));
            mv.visitInsn(LCMP);
            Label l1 = new Label();
            mv.visitJumpInsn(IFGE, l1);
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
            mv.visitInsn(DUP);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V");
            mv.visitLdcInsn("Ln: ");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
            mv.visitVarInsn(LLOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(J)Ljava/lang/StringBuilder;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            mv.visitVarInsn(LLOAD, 1);
            mv.visitInsn(LCONST_1);
            mv.visitInsn(LADD);
            mv.visitVarInsn(LSTORE, 1);
            mv.visitJumpInsn(GOTO, l0);
            mv.visitLabel(l1);
            mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
            mv.visitInsn(RETURN);
            mv.visitMaxs(4, 3);
            mv.visitEnd();
        }
        cw.visitEnd();

        return cw.toByteArray();
    }
}
 
If you ever had any doubt that the JVM is already dynamic, this should get rid of them. This code creates new bytecode on the fly and executes it. The bytecode, which has been created and loaded on the fly, will become elegable for compilation using the JIT compiler if it is executed enough times. This means the JVM, even without invokedynamic, is able to dynamically create and compile to machine instructions arbitrarily complex functionality. We can take hold of this amazing ability and harness it to use invokedynamic directly from Java even though Java as a language has no syntax to support it its self.

Whilst the code above is very powerful, it is also very heavy. The kind of engineering that is going on there is completely inappropriate for a dynamic language which needs to be light on its feet. So, this is only a stepping stone to getting to invokedynamic.

How Does By Class-On-The-Fly Code Work? 
The code does a dance with class loaders. The issue is that loading a class from a byte array containing its bytecode is done using the defineClass method on a class loader. But, that method is protected, so it cannot be directly accessed on the default class loader we get when the our program first starts up. We could hack around that using reflection to bypass the protection of this method. However, I hate doing that because it is deliberately breaking the Java/JVM model. The solution is to create a ClassLoader which is a subclass of URLClassLoader (because that is a concrete sub-class of ClassLoader - we are not going to use the URL bit). Our new ClassLoader, I called DynamicLoader, has a method loadBytes which takes a byte array representation of the bytecode for a class and uses defineClass to load that class so that it can be used.

The snag with this is that the new class is not available to the JVM verifier at the point that the classes consuming our new class are loaded. This means we cannot directly reference our new class form existing code. The solution is to define an interface which has on it the methods which the new class will implement. When we create an instance of our new class, we can cast it to the interface. Then we invoked methods and access fields in the new class at full JVM speed with out any indirection. This is what the piece of code below does:
 
                classFile = dump();
                Class<?> simpleExample = dl.loadFromBytes(classFile);                
                Constructor<?> cons=simpleExample.getConstructor(new Class<?>[0]);
                IExecutable toExecute = (IExecutable) cons.newInstance(new Object[0]);
                // Now (finally) we have a direct JVM linked way of calling our dynamically 
                // created class instances.
                toExecute.execute();
 

This code uses our new DynamicLoader instance to load the on-the-fly class. It then uses reflection to get to the object constructor. From that it constructs an object and then casts that object to IExecutable, The cast operation is the runtime safeguard. The JVM verifier knows that data flowing past that cast must be of type IExecutable and so it is safe to directly access its members with JVM primatives line invokevirtual.

'All' I need to do now is change the assembled class to have a method in it which has invokeddynamic and then I can call that method from Java. So here is the finished thing and then I will talk through it:
 
package com.nerdscentral.dynamics;

import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MutableCallSite;


import org.objectweb.asm.*;

public class SimpleExample implements Opcodes 
{
    private static boolean do32bit = false;
    
    public interface IExecutable
    {
        public void execute();
    }
    
    public static class DynamicLoader extends URLClassLoader
    {
        public DynamicLoader(URL[] urls)
        {
            super(urls);
        }        
        
        public Class<?> loadFromBytes(byte[] classDefinition)
        {
            Class<?> clazz=defineClass(null,classDefinition, 0,classDefinition.length);
            resolveClass(clazz);
            return clazz;
        }
        
    }

    public static class BootStrap
    {
        public static void main(DynamicLoader dl)
        {
            try 
            {
                (new BootStrap()).execute(dl);
            } catch (Exception e) 
            {
                e.printStackTrace();
            }
                   
        }

        public void execute(DynamicLoader dl)
        {
            byte[] classFile;
            try
            {
                classFile = dump();
                Class<?> simpleExample = dl.loadFromBytes(classFile);                
                Constructor<?> cons=simpleExample.getConstructor(new Class<?>[0]);
                IExecutable toExecute = (IExecutable) cons.newInstance(new Object[0]);
                // Now (finally) we have a direct JVM linked way of calling our dynamically 
                // created class instances.
                
                // To PROVE that this is true dyamic but full JVM optimzed code we will run it
                // ten times and what the time taken drop off dramatically when the JVM chooses
                // to compile the called method!
                for(int i=0;i<10;++i)
                {
                    toExecute.execute();
                }
                // Now we can change the dynamic method to a different one on the fly
                if(do32bit)
                {
                    SimpleExample.setToLong();
                }
                else
                {
                    SimpleExample.setToInteger();
                }
                // Run again with a new method dynamically placed
                // where the old one was!
                // It will still optimize
                for(int i=0;i<10;++i)
                {
                    toExecute.execute();
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            } 
        }
    }
    
    // Boot strap myself
    public static void main(String args[])
    {
        try
        {
            do32bit = args.length > 0 && args[0].equals("32");
            DynamicLoader dl = new DynamicLoader(new URL[0]);
            Class<?> clazz = dl.loadClass("com.nerdscentral.dynamics.SimpleExample$BootStrap");
            java.lang.reflect.Method m=clazz.getDeclaredMethod("main", new Class<?>[]{DynamicLoader.class});
            m.invoke(null,new Object[]{dl});
        }
        catch(Throwable t)
        {
            t.printStackTrace();
        }
        
    }

    public static byte[] dump () throws Exception 
    {

        ClassWriter cw = new ClassWriter(0);
        MethodVisitor mv;

        // void visit(int version, int access, String name, String signature, String superName, String[] interfaces) 
        cw.visit
        (
            V1_7, ACC_PUBLIC + ACC_SUPER, 
            "com/nerdscentral/dynamics/Simple", 
            null, 
            "java/lang/Object", 
            new String[]{"com/nerdscentral/dynamics/SimpleExample$IExecutable"}
        );

        {
            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }

        {
            mv = cw.visitMethod(ACC_PUBLIC, "execute", "()V", null, null);
            mv.visitCode();
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("Will call an arbitrary JVM method using invokedynamic!");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("======================================================");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("Making dynamic call:");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            // Insert the dynamic call
            makeInvokeDynamic(mv);
            mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
            mv.visitInsn(RETURN);
            mv.visitMaxs(4, 1);
            mv.visitEnd();
        }
        cw.visitEnd();

        return cw.toByteArray();
    }
    
    static MutableCallSite _callSite = null;
    static MethodHandles.Lookup _lookup = null;
    public static CallSite bootstrap
    (
        MethodHandles.Lookup lookup,
        String name,
        java.lang.invoke.MethodType type
    )
    {
        System.out.println(">>>> Entering Boot Strap");
        _lookup = lookup;
        // that to which we bootstrap depends on the first parameter
        // passed to the application!
        java.lang.reflect.Method m=null;
        try
        {
            if(do32bit)
            {
                System.out.println("Do a 32bit calculation");
                m=SimpleExample.class.getMethod("performCalcShort", new Class[0]);
            }
            else
            {
                System.out.println("Do a 64bit calculation");
                m=SimpleExample.class.getMethod("performCalcLong", new Class[0]);
            }            
            System.out.println("<<<<< Leaving Boot Strap");
            return _callSite=(new MutableCallSite(lookup.unreflect(m)));
        }
        catch (Exception e)
        {
            e.printStackTrace();
            // Blow up here rather than let then thing go on
            // throwing more exceptions
            System.exit(-1);
        }
        // This code path never gets reached but the compiler
        // is not clever enough to know that :(
        return _callSite;
        
    }
    
    /** Reset the dynamic method to use longs */
    public static void setToLong()
    {
        java.lang.reflect.Method m;
        try
        {
            m = SimpleExample.class.getMethod("performCalcLong", new Class[0]);
            _callSite.setTarget(_lookup.unreflect(m));
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /** Reset the dynamic method to use shorts */
    public static void setToInteger()
    {
        java.lang.reflect.Method m;
        try
        {
            m = SimpleExample.class.getMethod("performCalcShort", new Class[0]);
            _callSite.setTarget(_lookup.unreflect(m));
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    public static void performCalcLong()
    {
        System.out.println("Performing A Bench Mark In 64Bit Space");
        System.out.println("--------------------------------------");
        long t = System.currentTimeMillis();
        long[] ar=new long[1024];
        for(int x=0;x<ar.length;++x)
        {
            for(int y=0;y<ar.length;++y)
            {
                ar[x]=ar[y]+1l;
            }
        }
        System.out.println(".... took: " + (System.currentTimeMillis()-t) + " milli seconds");
    }
    
    public static void performCalcShort()
    {
        System.out.println("Performing A Bench Mark In 32Bit Space");
        System.out.println("--------------------------------------");
        long t = System.currentTimeMillis();
        int[] ar=new int[1024];
        for(int x=0;x<ar.length;++x)
        {
            for(int y=0;y<ar.length;++y)
            {
                ar[x]=ar[y]+1;
            }
        }
        System.out.println(".... took: " + (System.currentTimeMillis()-t) + " milli seconds");
    }
    
    private static void  makeInvokeDynamic(MethodVisitor mv)
    {
        /* From the ASM Docs:
        - Overhaul of the support of invokedynamic to support the new encoding
          and bootstrap method arguments.
          Practically, this means that invokedynamic doesn't trigger a call to 
          MethodVisitor.visitMethodInsn but use a specific new method:
          visitInvokeDynamicInsn(String name, String desc, MethodHandle bsm, Object... args)
        
        - Two new constants org.objectweb.asm.MethodHandle and org.objectweb.asm.MethodType
          can be used either in visitLdcInsn() or as last arguments of visitInvokeDynamicInsn.
          org.objectweb.asm.MethodHandle encodes a constant method handle and
          org.objectweb.asm.MethodType encodes a constant method type.
        
        Here is the snippet of how generate an instruction invokedynamic foo()V that will
        call as bootstrap method bootstrapName with two bootstrap constants "bar" and 3.
        */
        // This creates a boot strap definition
        try
        {
            java.lang.invoke.MethodType mt = java.lang.invoke.MethodType.methodType
            (
                java.lang.invoke.CallSite.class,
                java.lang.invoke.MethodHandles.Lookup.class,
                java.lang.String.class,
                java.lang.invoke.MethodType.class
            );
            System.out.println(mt.toMethodDescriptorString());
            org.objectweb.asm.MethodHandle bootstrap = new org.objectweb.asm.MethodHandle
            (
                Opcodes.MH_INVOKESTATIC, 
                "com/nerdscentral/dynamics/SimpleExample", 
                "bootstrap",
                mt.toMethodDescriptorString()
            );
            mv.visitInvokeDynamicInsn("runCalculation", "()V", bootstrap,new Object[0]);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.exit(-1);
        }
    }
}
 


Be under no illusions here, this code is a pile of hacks. It is a million miles from production code. That is not an issue - it is here to prove a concept. (Note also that I have usde the style of everything being inner classes to make it easy to write about and post self contained code blocks). Anyone is welcome to do anything they want with it other than use it unchanged and complain if it breaks or breaks their system! A 'thankyou' is always welcome as well.

It proved quite hard to write this code because there was (at the time of writing) very little information on the internet about using invokedynamic and especially with ASM. The new version of ASM (4.0) had only just been released and there were no good tutorials which I could find (maybe I did not look hard enough). So, without any more talking around the subject let's get down to how it works:
 
            java.lang.invoke.MethodType mt = java.lang.invoke.MethodType.methodType
            (
                java.lang.invoke.CallSite.class,
                java.lang.invoke.MethodHandles.Lookup.class,
                java.lang.String.class,
                java.lang.invoke.MethodType.class
            );
            System.out.println(mt.toMethodDescriptorString());
            org.objectweb.asm.MethodHandle bootstrap = new org.objectweb.asm.MethodHandle
            (
                Opcodes.MH_INVOKESTATIC, 
                "com/nerdscentral/dynamics/SimpleExample", 
                "bootstrap",
                mt.toMethodDescriptorString()
            );
            mv.visitInvokeDynamicInsn("runCalculation", "()V", bootstrap,new Object[0]);
 

The above it the key to the whole thing. It is a helper method which creates the invokedynamic op-codes in my on-the-fly created class. To make life easier I have used the a MethodType object to form the call signature for my bootstrap method. Then I create a MethodHandle (the ASM one - which represents how to create a MethodHandle in byte code, not to be confused with java.lang.invoke.MethodHandle). That method handle represents to the ASM assembler how to define the filed in my on-the-fly class which will hold the necessary information for the JVM to call the boot strap method. In other words, the JVM will work its way through my class, find 'invokedynamic' and think 'I do not have a CallSite for this invokedynamic I better call the bootstrap to make one' and I have provided the information on what boot strap it will call.

Note (because I got this wrong and lost a lot of time) that I have used the Opcodes.MH_INVOKESTATIC in the creation of the org.objectweb.asm.MethodHandle for the bootstrap. This is because it is defined as a static method. If you are bootstrapping using different things you will need to use different op-codes. I think the one for reading the CallSite from a static field, for example, is MH_GETSTATIC.

The final bit of this code causes the field defining the boot strap and the invoke dynamic op-code to be written into the method of my on-the-fly class:
 
...
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("Making dynamic call:");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            // Insert the dynamic call
            makeInvokeDynamic(mv);
            mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
            mv.visitInsn(RETURN);
            mv.visitMaxs(4, 1);
...
 

In the above we can see where I have called makeInvokeDynamic in the middle of the execute method. Now let us see some of the 'dynamic' of invokedynamic:
 
    // Note that there is a static field do32bit which is set by a command line argument.

    static MutableCallSite _callSite = null;
    static MethodHandles.Lookup _lookup = null;
    public static CallSite bootstrap
    (
        MethodHandles.Lookup lookup,
        String name,
        java.lang.invoke.MethodType type
    )
    {
        System.out.println(">>>> Entering Boot Strap");
        _lookup = lookup;
        // that to which we bootstrap depends on the first parameter
        // passed to the application!
        java.lang.reflect.Method m=null;
        try
        {
            if(do32bit)
            {
                System.out.println("Do a 32bit calculation");
                m=SimpleExample.class.getMethod("performCalcShort", new Class[0]);
            }
            else
            {
                System.out.println("Do a 64bit calculation");
                m=SimpleExample.class.getMethod("performCalcLong", new Class[0]);
            }            
            System.out.println("<<<<< Leaving Boot Strap");
            return _callSite=(new MutableCallSite(lookup.unreflect(m)));
        }
        catch (Exception e)
        {
            e.printStackTrace();
            // Blow up here rather than let then thing go on
            // throwing more exceptions
            System.exit(-1);
        }
        // This code path never gets reached but the compiler
        // is not clever enough to know that :(
        return _callSite;
        
    }

 
So what is all this ...
 
    static MutableCallSite _callSite = null;
    static MethodHandles.Lookup _lookup = null;
 
... about? I use these two fields to store the MethodHandles.Lookup object which passed to the boot strap method and the CallSite object I created in the boot strap method. The JVM associates the CallSite object with the invokedynamic I have placed into the on-the-fly method. So, by storing the Lookup and CallSite I can change the MethodHandle bound to the invokesynamic at will. This is that these methods do:
 
    /** Reset the dynamic method to use longs */
    public static void setToLong()
    {
        java.lang.reflect.Method m;
        try
        {
            m = SimpleExample.class.getMethod("performCalcLong", new Class[0]);
            _callSite.setTarget(_lookup.unreflect(m));
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /** Reset the dynamic method to use shorts */
    public static void setToInteger()
    {
        java.lang.reflect.Method m;
        try
        {
            m = SimpleExample.class.getMethod("performCalcShort", new Class[0]);
            _callSite.setTarget(_lookup.unreflect(m));
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

As long as the invokedynamic is called once (to boot strap it - hence the name) I can then reset it at will with this pattern. The boot strap method its self chooses to install the integer or long bench mark based on a field do32bit. I set that field based on if there is a command line argument '32'. Then this ...
 
                for(int i=0;i<10;++i)
                {
                    toExecute.execute();
                }
                // Now we can change the dynamic method to a different one on the fly
                if(do32bit)
                {
                    SimpleExample.setToLong();
                }
                else
                {
                    SimpleExample.setToInteger();
                }
                // Run again with a new method dynamically placed
                // where the old one was!
                // It will still optimize
                for(int i=0;i<10;++i)
                {
                    toExecute.execute();
                }
 
 
... code executes which ever dynamic method was installed first at the call site then it swaps over to the other one and executes that. I execute each ten times to get a post JIT bench mark.

Note well: the statement I have highlighted in red is that which causes the boot strap to be run. The boot strap is run only once on the first iteration of the loop. If I were to set the MethodHandle in the CallSite to null at any point then the boot strap would be called again the next time I invoked toExcecute.execute().

Here is the output of my application (edited):
 
(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Will call an arbitrary JVM method using invokedynamic!
======================================================
Making dynamic call:
>>>> Entering Boot Strap
Do a 32bit calculation
<<<<< Leaving Boot Strap
Performing A Bench Mark In 32Bit Space
--------------------------------------
.... took: 10 milli seconds
Will call an arbitrary JVM method using invokedynamic!
======================================================
Making dynamic call:
Performing A Bench Mark In 32Bit Space
--------------------------------------
.... took: 17 milli seconds
Will call an arbitrary JVM method using invokedynamic!
======================================================
Making dynamic call:
Performing A Bench Mark In 32Bit Space
--------------------------------------
.... took: 0 milli seconds

++++ SNIP ++++

Will call an arbitrary JVM method using invokedynamic!
======================================================
Making dynamic call:
Performing A Bench Mark In 32Bit Space
--------------------------------------
.... took: 1 milli seconds
Will call an arbitrary JVM method using invokedynamic!
======================================================
Making dynamic call:
Performing A Bench Mark In 64Bit Space
--------------------------------------
.... took: 8 milli seconds

++++ SNIP ++++

Will call an arbitrary JVM method using invokedynamic!
======================================================
Making dynamic call:
Performing A Bench Mark In 64Bit Space
--------------------------------------
.... took: 1 milli seconds
 

The above was generated with the command line argument 32. If I run the same application without that command line argument I the output starts:
 
(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Will call an arbitrary JVM method using invokedynamic!
======================================================
Making dynamic call:
>>>> Entering Boot Strap
Do a 64bit calculation
<<<<< Leaving Boot Strap
Performing A Bench Mark In 64Bit Space
--------------------------------------
.... took: 9 milli seconds
Will call an arbitrary JVM method using invokedynamic!
======================================================
Making dynamic call:
Performing A Bench Mark In 64Bit Space
--------------------------------------
.... took: 15 milli seconds
 

We can see that the bootstrap method has indeed installed a different method handle at the invokedynamic call site and so the 64 bit bench mark is run first! Also, we can clearly see the effect of the bench mark methods being JIT compiled where the invocation time drops dramatically to 0->1 milli seconds. Finally, for this post, I will increase the number of calculations in the bench mark methods to actually see the difference between long and integer. The bench marks have a nested loop system which swaps elements of an array and adds one to the element being swapped. I have found this to be a very effective and reliable benchmark of JVM mathematical performance:
 
Will call an arbitrary JVM method using invokedynamic!
======================================================
Making dynamic call:
Performing A Bench Mark In 64Bit Space
--------------------------------------
.... took: 95 milli seconds

+++++ SNIP +++++

Will call an arbitrary JVM method using invokedynamic!
======================================================
Making dynamic call:
Performing A Bench Mark In 32Bit Space
--------------------------------------
.... took: 77 milli seconds
 
This is actually the sort of thing I was starting out to look at (just got distracted). We can see from this that on 64bit Fedora 14 in Java 7 the overhead of using long instead of int is around 15%.

If I get time, I will take this pattern and apply it to benchmarking mono and polymorphic dispatch models from invokedynamic. But that might have to wait for another day!