FYI, for JRuby I did not use langtools and instead pulled the branch of ASM that supports invokedynamic. It did need an additional patch, however, since it was not properly calculating stack manipulations.

The branch is here:

svn://svn.forge.objectweb.org/svnroot/asm/branches/invokedynamic

And the patch is attached.

I have pushed all the working changes to the "invokedynamic" branch in our git repository at kenai.com. Feel free to check it out. After some rest I'll try to get the remaining call paths wired in, and then start looking for ways to improve performance and inlining potential.

- Charlie

Charles Oliver Nutter wrote:
Ok! I have managed to dispatch single-arg method calls using the new invokedynamic!

The logic is fairly primitive right now: http://gist.github.com/113440

Rather than try to introduce method handles throughout the system, this current design simply replaces my existing CallSite logic with invokedynamic. The dynamic call from Ruby code passes threadcontext, caller object, target object, and arguments through invokedynamic, which is then bootstrapped with a new dyn.CallSite instance and my GuardedMethodHandle. GMH simply asks the cached CacheEntry tuple if it's still valid for the incoming type, and then either dispatches through to the JRuby DynamicMethod object or re-looks-up the method and reinstalls in the dyn.CallSite.

So far it appears to be at least no slower doing it this way, but I'm hoping we'll be able to coax more performance out of this.

It's also pretty crashy right now; several tests I tried simply blew up. I can provide dumps and reproduction cases on demand.

Comments welcome...time to get some sleep.

Charles Oliver Nutter wrote:
Ok, talking out loud here...feel free to jump in any time.

Assuming a totally dynamic class structure that has no relationship to java.lang.Class...

1. The initial bootstrap would return an "InitialLookupMethodHandle" that knows how to do two things: do a slow lookup of the method (installing it back into the call site), and return the result of invoking it. 2. Upon first call, "ILMH" would grab the metaClass from the receiver object and do appropriate lookup logic. It would then install a GuardedMethodHandle wrapping the target method into the original call site, and proceed to do an initial invocation of the target method. 3. GuardedMethodHandle would repeatedly check its invalidation status (my volatile class-hierarchy token) and either go straight through to the wrapped target or cause a re-lookup and re-install of the method 4. GuardedMethodHandles could be further broken down into MonomorphicCachingHandle, PolymorphicCachingHandle, and other types like I have in JRuby for Object#send, respond_to?, method_missing and so on.

Again this all hinges on those intermediate handles not getting in the way of inlining, or the whole thing starts to fall apart.

Sounding about right?

- Charlie

Charles Oliver Nutter wrote:
I've read through Fidgety a few times and I think I'm starting to get it.

So the idea is that you would install a MethodHandle into the call site that knows how to handle the incoming objects and (potentially) re-patch the call site with a new method?

Is there any guarantee that the code in the MethodHandle will be inlined through? I may have missed some discussion on this, but I want to be absolutely clear on this point. If I wire up things exactly as in Fidgety's "Guard" method handle, will (e.g.) Hotspot inline all the way through? What are the edge cases?

I may have enough to get this wired now...starting to see where the old pieces fit into the new structure. Hints still welcome :)

- Charlie

Charles Oliver Nutter wrote:
Ok, I've been puzzling over the demos for a few hours, and I'm confused.

With the iteration from this fall, where the full set of args were available during the bootstrap, I was able to actually inspect the receiver object and get information from it. Now I don't see how I can do that.

Imagine this case:

* All objects are of type RubyObject
* The method table is just a hash contained within RubyObject#getMetaClass

When doing a dynamic call against one of those objects, there's now no way for me to call getMetaClass on the receiver object to get its method table, and no way for me to look up a named method in that table.

I'll keep hunting, but if someone has a hint I'd appreciate it.

What I need is essentially this:

... bootstrapDynamic(Object receiver, Class caller, String name, MethodType type) { MethodHandle handle = ((RubyClass)receiver).getMetaClass().findMethodHandle(name, type);
   CallSite callSite = new CallSite(caller, name, type);
   callSite.setTarget(handle);
   return callSite;
}

I just don't see how I can get access to *my* method tables from within the bootstrap now, since they don't live on a Class or in a global location anywhere. And how would I bootstrap an interpreted method?

- Charlie
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Index: src/org/objectweb/asm/Frame.java
===================================================================
--- src/org/objectweb/asm/Frame.java    (revision 1381)
+++ src/org/objectweb/asm/Frame.java    (working copy)
@@ -1163,7 +1163,11 @@
             case Opcodes.INVOKESTATIC:
             case Opcodes.INVOKEINTERFACE:
             case Opcodes.INVOKEDYNAMIC:
-                pop(item.strVal3);
+                if (opcode == Opcodes.INVOKEDYNAMIC) {
+                    pop(item.strVal2);
+                } else {
+                    pop(item.strVal3);
+                }
                 if (opcode != Opcodes.INVOKESTATIC && opcode != 
Opcodes.INVOKEDYNAMIC) {
                     t1 = pop();
                     if (opcode == Opcodes.INVOKESPECIAL
@@ -1172,7 +1176,11 @@
                         init(t1);
                     }
                 }
-                push(cw, item.strVal3);
+                if (opcode == Opcodes.INVOKEDYNAMIC) {
+                    push(cw, item.strVal2);
+                } else {
+                    push(cw, item.strVal3);
+                }
                 break;
             case Opcodes.NEW:
                 push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, 
arg));
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to