Getting back into indy, binding straight through
Charles Oliver Nutter
headius at headius.com
Tue Jul 27 13:50:37 PDT 2010
I'm slowly getting back into indy stuff :) I'm still running off a
build from March, though, since ASM doesn't support the latest
changes.
Anyway, I mentioned at JVMLS that I thought I could get indy to patch
through to the actual target method in my existing indy stuff. I said
I could do it by today, but I was delayed...I have done it now :)
I've only got it wired up for one arity case, but here's what it looks
like (with some of the handles still in there...these should disappear
as they're supported by the inlining, I presume):
Old backtrace for def foo; 1 + 1; end
at org.jruby.RubyFixnum.op_plus(RubyFixnum.java:328)
at org.jruby.RubyFixnum$i_method_1_0$RUBYINVOKER$op_plus.call(org/jruby/RubyFixnum$i_method_1_0$RUBYINVOKER$op_plus.gen:65535)
at sun.dyn.FilterGeneric$F7.invoke_F7(FilterGeneric.java:844)
at sun.dyn.FilterGeneric$F6.invoke_F6(FilterGeneric.java:758)
at sun.dyn.MethodHandleImpl$GuardWithTest.invoke_L5(MethodHandleImpl.java:830)
at ruby.__dash_e__.method__0$RUBY$foo(-e:1)
Because the current indy stuff binds to our DynamicMethod subclass
(RubyFixnum$i_method_1_0$RUBYINVOKER$op_plus), we have at least one
extra bounce and a lot more argument juggling because the
DynamicMethod.call paths are complicated.
With the modified version, the fast path binds straight through to the
actual target method with no intermediate wrapper:
at org.jruby.RubyFixnum.op_plus(RubyFixnum.java:328)
at sun.dyn.FilterGeneric$F3.invoke_V0(FilterGeneric.java:565)
(at sun.dyn.MethodHandleImpl$GuardWithTest.invoke_L5(MethodHandleImpl.java:830))
at ruby.__dash_e__.method__0$RUBY$foo(-e:1)
The GuardWithTest is not yet in my toy code, but I inserted it where
it would be. You can see that once the handles fold away, there's no
intermediate code between the caller and the callee.
The interesting thing to me here is that since I know the actual
target method in these cases, I can decorate the handle chain with the
wrapper logic normally contained in the DynamicMethod subclass, which
means with indy we *don't have to generate our intermediate
pseudo-handles at all*. That's a tremendous win, for a few reasons: 1.
that logic will no longer count against our inlining budgets (at least
one stack frame and probably a good dozen+ bytecodes; and 2. I've
wrangled raw ASM in the pseudo-handle generation logic way too many
times to want to continue doing it :)
Of course it also means we don't have the memory/size costs of
generating those classes ourselves.
I'm sure I can do this same thing for field/instance variable
accesses, Ruby-to-Java calls, and more, and actually do iterative
optimizations without an interpreter or tiered compilation. That's
pretty cool.
- Charlie
More information about the mlvm-dev
mailing list