1. The invokedynamic work from the Da Vinci Machine Project has come a long way. In fact, it has started to make it's way into OpenJDK 7 builds. To try the bleeding edge version out for yourself, follow these instructions to patch and build your own. But, be warned, it's a bit tricky to get started. You may find that these examples will work with OpenJDK 7 binaries (sooner or later they should!). For those who haven't heard about this work yet, invokedynamic, which is a part of JSR-292, allows a program to dynamically call methods with (potentially) the same performance characteristics as static calls. Here is about the simplest invokedynamic program you can write:


    import java.dyn.CallSite;
    import java.dyn.InvokeDynamic;
    import java.dyn.Linkage;
    import java.dyn.MethodType;
    import java.dyn.MethodHandles;

    public class Example {
    public static void main(String... av) throws Throwable {
    for (String a : av) {
    InvokeDynamic.call(a);
    }
    InvokeDynamic.call2(av[0]);
    }

    public static void foo(String x) {
    System.out.println("Hello, " + x);
    }

    static { Linkage.registerBootstrapMethod("linkDynamic"); }
    private static CallSite linkDynamic(Class caller, String name, MethodType type) {
    System.out.println("linking:" + name);
    CallSite c = new CallSite(caller, name, type);
    c.setTarget(MethodHandles.lookup().findStatic(Example1.class, "foo",
    MethodType.make(void.class, String.class)));
    return c;
    }
    }


    First notice the linkDynamic method. The static initializer above it registers that method as a special bootstrap method that invokedynamic will use when you want to call a method dynamically. The interesting bit to notice are the two calls to methods on InvokeDynamic. InvokeDynamic has no actual methods of its own. You can call any method on it (here I use "call" and "call2", but it could just as well have been "foo123" or "sasquatch") When you make these calls, control is passed to the bootstrap method (linkDynamic in this case). linkDynamic gets passed the Class of the caller, the name that was used ("call" and "call2" in this program) and the MethodType of the call, which specifieds the signature of the dynamic call.


    To compile the above code, execute:


    javac -XDinvokedynamic Example.java


    To run it:

    java -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic Example a b c


    Which should produce:

    linking:call
    Hello, a
    Hello, b
    Hello, c
    linking:call2
    Hello, a

    Notice that we called "call" three times, but it only needed to be linked once. We then called call2 and it was separately linked. Had we invoked call2 again it would not have needed linking. Next in my exploration, I'll wire it up with some Python internal dispatch logic:

    package org.python.compiler;

    import java.dyn.CallSite;
    import java.dyn.InvokeDynamic;
    import java.dyn.Linkage;
    import java.dyn.MethodType;
    import java.dyn.MethodHandle;
    import java.dyn.MethodHandles;
    import java.dyn.MethodType;

    import org.python.core.Py;
    import org.python.core.PyCode;
    import org.python.core.PyFunction;
    import org.python.core.PyInteger;
    import org.python.core.PyObject;
    import org.python.core.PyString;
    import org.python.core.PyTuple;
    import org.python.core.ThreadState;

    public class IndyTest {

    public static void run() throws Throwable {
    PyObject result = InvokeDynamic.foo(new PyInteger(4), Py.None,
    Py.EmptyObjects, new PyTuple());
    System.out.println("result = " + result);
    }

    static { Linkage.registerBootstrapMethod("linkDynamic"); }
    private static CallSite linkDynamic(Class caller, String name, MethodType type) {
    System.out.println("linkDynamic...");
    CallSite site = new CallSite(caller, name, type);
    ThreadState ts = Py.getThreadState();
    PyCode func_code = ((PyFunction)ts.frame.getname(name)).func_code;

    MethodType oneArgCall = MethodType.make(
    PyObject.class, //return type
    ThreadState.class, // state
    PyObject.class, // arg1
    PyObject.class, // globals
    PyObject[].class, // defaults
    PyObject.class // closure
    );
    MethodHandle call = MethodHandles.lookup().findVirtual(PyCode.class, "call", oneArgCall);
    call = MethodHandles.insertArguments(call, 0, func_code, ts);
    call = MethodHandles.convertArguments(call, type);
    site.setTarget(call);

    return site;
    }
    }



    There is a bit more going on here. In short, we look up the current state of the Jython interpreter when this is invoked and look for a function called "foo". We pass the PyInteger 4 (plus some boilerplate at the end -- in the future we should be able to only pass the 4, but MethodHandles.insertArguments can only add three arguments at the moment.) to the foo(), and then print the result out. Again "foo" is bound the first time it is called. When we create a CallSite, grab the current ThreadState and get our "foo" object from the current Jython frame. We then create a MethodType that corresponds to the way that we call Jython methods internally, and use methods off of MethodHandles (insertArguments and convertArguments) to coerce our call to the internal call semantics. Then our "foo" call is permanently bound to the function we found. Ultimately this is not what we will want since "foo" could be rebound in Jython in a number of ways. We'll get to this problem in a future post. To try this code out, we need a Jython program with a foo method:


    def foo(x):
    print "hello %s!" % x
    foo("test")

    from org.python.compiler import IndyTest
    IndyTest.run()

    def foo(x):
    print "goodbye %s!" % x
    foo("test")

    IndyTest.run()


    Run it like this (requires a Jython 2.5 install and we need to call Jython with --boot to put the Jython internals into the boot classpath):

    jython --boot -J-XX:+EnableMethodHandles -J-XX:+EnableInvokeDynamic indy.py



    hello test!
    foo = 1
    linkDynamic...
    hello 4!
    result = None
    goodbye test!
    foo = 2
    hello 4!
    result = None


    The first IndyTest.run() looks great (hello 4!) -- but the second call still emits "hello 4!" even though foo() has been redefined. We'll look at fixing this in the next post.

    By the way, to *really* learn about the guts of invokedynamic look to the posts from John Rose and Fredrik Öhrström along with the Da Vinci Machine site.
    0

    Add a comment

About Me
About Me
Subscribe
Subscribe
Links
Blog Archive
Blog Roll
Blog Roll
Loading
Dynamic Views theme. Powered by Blogger. Report Abuse.