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