Invokedynamic: Tales from the Trenches

  • 2,028 views
Uploaded on

Talk on the history of JRuby and invokedynamic given at FOSDEM 2013.

Talk on the history of JRuby and invokedynamic given at FOSDEM 2013.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
2,028
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
55
Comments
0
Likes
10

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. invokedynamic Tales from the TrenchesSunday, February 3, 13
  • 2. Me • Charles Oliver Nutter • Programmer my whole life • Professional Java since 1996 • headius@headius.com, @headius • “Full time” JRuby guy • Sun (06-09), Engine Yard (09-12), Red HatSunday, February 3, 13
  • 3. invokedynamic 101 • invokevirtual, invokestatic, etc • Predefined behavior • Based on simple VM primitives • invokedynamic • User-defined bytecode • Primitives available as an IRSunday, February 3, 13
  • 4. invokedynamic 101 • Emit invokedynamic bytecode • Name + signature + bootstrap pointer • On first call, bootstrap called • Name + signature + lookup context • Return a CallSite • Subsequent calls go through CallSiteSunday, February 3, 13
  • 5. Terminology • Invokedynamic: bytecode or JSR 292 • Call site: place in code where a call is made • Bootstrap: method called to set up indy call siteSunday, February 3, 13
  • 6. Terminology • Method handle: endpoint (call, field, ...) or logic (branches, arg manip, ...) to wrap an endpoint handle • Guard: logic to ensure site is bound to the proper target • GWT: guard-with-test, branch based on user test • SwitchPoint: on-until-off branch handleSunday, February 3, 13
  • 7. Promises • “invokedynamic should be no slower than invokeinterface” • “all Hotspot optimizations should apply through indy sites” • “SwitchPoint should be ‘free’ when valid”Sunday, February 3, 13
  • 8. Promises • “JRuby plus invokedynamic will be fast” • “The fully-working optimized OpenJDK indy impl is just around the corner”Sunday, February 3, 13
  • 9. The BeginningSunday, February 3, 13
  • 10. 2006 • Tom Enebo and I join Sun Microsystems • Working on JRuby full time • Dream come true! • Sun officially starts promoting JVM as a multi-language platform • Needed some work to get there...Sunday, February 3, 13
  • 11. 2007 • Talks start between JRuby and John Rose • How does JRuby work? • What do we need? • JSR 292 restarts with John Rose leading • Not much to see yetSunday, February 3, 13
  • 12. 2008 • Early design work in JSR • Ola Bini represented JRuby • Few working builds • John Rose private builds • Multi-Language VM (Da Vinci) later on • We banked on the futureSunday, February 3, 13
  • 13. 2008 • “A First Taste of InvokeDynamic” • http://blog.headius.com/2008/09/first- taste-of-invokedynamic.html • 11 Sept, 2008 • ~7000 words, ~26k viewsSunday, February 3, 13
  • 14. JRuby 1.1.5 • First version with indy support • Based on early proposal • invokeinterface on java.dyn.Dynamic • Dynamic type treated specially • Manual bootstrap setup • Worked...sortaSunday, February 3, 13
  • 15. java.dyn.Dynamic public java.lang.Object doDynamicCall(java.lang.Object); Code: 0: aload_1 1: invokeinterface #3; //Method java/dyn/Dynamic.myDynamicMethod:()V 4: areturnSunday, February 3, 13
  • 16. registerBootstrapMethod static { Linkage.registerBootstrapMethod( SimpleExample.class, MethodHandles.findStatic( DynamicInvokerThingy.class, "bootstrap", Linkage.BOOTSTRAP_METHOD_TYPE)); }Sunday, February 3, 13
  • 17. 2009 • Continuing evolution of JSR 292 • We tracked design changes • Performance work deferred • We kept up the faith :-) • First RI rev landsSunday, February 3, 13
  • 18. Running on What? • Still no standard builds for OS X • MLVM repo • Based on bsd-port • External, periodic dump of indy work • Incubator for other projects • Henri Gomez: openjdk-osx-buildSunday, February 3, 13
  • 19. hotspot 2009-04-21; 6655646: dynamic languages need dynamically linked call sites Summary: invokedynamic instruction (JSR 292 RI) 2009-07-21; 6862576: vmIntrinsics needs cleanup in order to support JSR 292 intrinsics Summary: remove useless lazy evaluation of intrinsics; add LAST_COMPILER_INLINE to help categorize them 2009-09-15; 6863023: need non-perm oops in code cache for JSR 292 Summary: Make a special root-list for those few nmethods which might contain non-perm oops. 2009-12-16; 6829192: JSR 292 needs to support 64-bit x86 Summary: changes for method handles and invokedynamicSunday, February 3, 13
  • 20. jdk 2009-05-05; 6829144: JSR 292 JVM features need a provisional Java API Summary: JDK API and runtime (partial) for anonk, meth, indy 2009-10-21; 6891770: JSR 292 API needs initial unit tests Summary: backport working mlvm regression test to M3 implementation of JSR 292; requires jtreg 4.1Sunday, February 3, 13
  • 21. Meanwhile... • Mirah: statically-typed, Ruby-like language • Because why not • Local type inference • No runtime library • .java and .class backends • Way more interest than I expected...Sunday, February 3, 13
  • 22. Sunday, February 3, 13
  • 23. Sunday, February 3, 13
  • 24. What If This... public class Foo { private int a; public Foo(int a) { this.a = a; } public void show() { System.out.println(a); } }Sunday, February 3, 13
  • 25. ...Could Be This class Foo def initialize(a) @a = a end def show puts @a end endSunday, February 3, 13
  • 26. Mirah class Foo def initialize(a:int) @a = a end def show puts @a end endSunday, February 3, 13
  • 27. Mirah class Foo def initialize(a:dynamic) @a = a end def show puts @a end endSunday, February 3, 13
  • 28. Middle AgesSunday, February 3, 13
  • 29. 2010 • Performance work starts a bit • Back and forth with Hotspot team • Testing JRuby, dumping assembly • Things start to look promising • Inlining thresholds biggest issueSunday, February 3, 13
  • 30. 2010-01-05; 6829187: compiler optimizations required for JSR 292 2010-01-13; 6912065: final fields in objects need to support inlining optimizations for JSR 292 2010-01-29; 6917766: JSR 292 needs its own deopt handler 2010-02-01; 6921352: JSR 292 needs its own deopt handler 2010-02-01; 6921799: JSR 292 call sites should not be fixed-up 2010-02-23; 6928839: JSR 292 typo in x86 _adapter_check_cast 2010-03-08; 6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64 2010-03-09; 6919934: JSR 292 needs to support x86 C1 2010-03-16; 6934494: JSR 292 MethodHandles adapters should be generated into their own CodeBlob 2010-03-17; 6934966: JSR 292 add C1 logic for saved SP over MethodHandle calls 2010-03-18; 6932091: JSR 292 x86 code cleanup 2010-03-31; 6939731: JSR 292 Zero build fix after 6934494 2010-04-29; 6829193: JSR 292 needs to support SPARC 2010-05-01; 6939134: JSR 292 adjustments to method handle invocation 2010-05-21; 6930772: JSR 292 needs to support SPARC C1 2010-05-25; 6934104: JSR 292 needs to support SPARC C2 2010-06-09; 6939203: JSR 292 needs method handle constants 2010-07-15; 6964498: JSR 292 invokedynamic sites need local bootstrap methods 2010-09-24; 6986944: JSR 292 assert(caller_nm->is_method_handle_return(caller_frame.pc())) failed: must be MH call site 2010-09-29; 6987634: JSR 292 assert(start_bci() >= 0 && start_bci() < code_size()) failed: correct osr_bci argument 2010-10-11; 6829194: JSR 292 needs to support compressed oops 2010-10-13; 6987555: JSR 292 unboxing to a boolean value fails on big-endian SPARC 2010-10-18; 6991596: JSR 292 unimplemented adapter_opt_i2i and adapter_opt_l2i on SPARC 2010-10-30; 6981777: implement JSR 292 EG adjustments from summer 2010 2010-10-30; 6984311: JSR 292 needs optional bootstrap method parameters 2010-11-04; 6997459: JSR 292 after 6994093 getting: on return to interpreted call, restored SP is corrupted 2010-11-09; 6998737: JSR 292: Remove the plug guarding the use of compressed oops 2010-11-30; 7001363: java/dyn/InvokeDynamic should not be a well-known class in the JVM 2010-12-22; 7007377: JSR 292 MethodHandlesTest.testCastFailure fails on SPARC with -Xcomp +DeoptimizeALotSunday, February 3, 13
  • 31. 2011 • Wrapping things up for FCS • Focus on correctness • Some JIT work landing for perf • JRuby a primary test caseSunday, February 3, 13
  • 32. Java 7 GA • Changes within couple months of release • Signature polymorphism • Minor API and naming adjustments • java.lang.invoke package name • Performance still dismal • JIT work not completed in timeSunday, February 3, 13
  • 33. 2011-04-25; 7030715: JSR 292 JRuby test/test_super_call_site_caching.rb asserts with +DoEscapeAnalysis 2011-05-10; 7042122: JSR 292: adjust various inline thresholds for JSR 292 API methods and method handle adapters 2011-05-17; 7045513: JSR 292 inlining causes crashes in methodHandleWalk.cpp 2011-05-26; 7047961: JSR 292 MethodHandleWalk swap args doesnt handle T_LONG and T_DOUBLE properly 2011-06-22; 7057587: JSR 292 - crash with jruby in test/test_respond_to.rbSunday, February 3, 13
  • 34. 2011-02-11; 7013417: JSR 292 needs to support variadic method handle calls 2011-02-11; 7012650: implement JSR 292 EG adjustments through January 2010 2011-02-11; 7013730: JSR 292 reflective operations should report errors with standard exception types 2011-02-15; 7016261: JSR 292 MethodType objects should be serializable 2011-02-15; 7014755: JSR 292 member lookup interaction with security manager 2011-02-15; 7016520: JSR 292 rules for polymorphic signature processing must be in package-info 2011-03-18; 6839872: remove implementation inheritance from JSR 292 APIs 2011-03-23; 7012648: move JSR 292 to package java.lang.invoke and adjust names 2011-04-07; 6817525: turn on method handle functionality by default for JSR 292 2011-05-12; 7034977: JSR 292 MethodHandle.invokeGeneric should be renamed MethodHandle.invoke 2011-05-17; 7044892: JSR 292: API entry points sometimes throw the wrong exceptions or doesnt throw the expected one 2011-05-26; 7032323: code changes for JSR 292 EG adjustments to API, through Public Review 2011-06-03; 7051206: JSR 292 method name SwitchPoint.isValid is misleading to unwary users; should be hasBeenInvalidatedSunday, February 3, 13
  • 35. INVOKEDYNAMIC vcall:foo(LThreadContext;LIRubyObject;LIRubyObject;)LIRubyObject; [ // handle kind 0x6 : INVOKESTATIC InvocationLinker.invocationBootstrap( (LMethodHandles$Lookup;LString;LMethodType;LString;I)LCallSite;) // arguments: "-e", 1 ]Sunday, February 3, 13
  • 36. What to Do?Sunday, February 3, 13
  • 37. What to Do? • GA indy perf slower than non-indy!Sunday, February 3, 13
  • 38. What to Do? • GA indy perf slower than non-indy! • Enable indy, knowing perf is bad?Sunday, February 3, 13
  • 39. What to Do? • GA indy perf slower than non-indy! • Enable indy, knowing perf is bad? • Disable, despite promises of future perf?Sunday, February 3, 13
  • 40. What to Do? • GA indy perf slower than non-indy! • Enable indy, knowing perf is bad? • Disable, despite promises of future perf? • Detect JVM version?Sunday, February 3, 13
  • 41. What to Do? • GA indy perf slower than non-indy! • Enable indy, knowing perf is bad? • Disable, despite promises of future perf? • Detect JVM version? • Detect VM version?Sunday, February 3, 13
  • 42. 2011-08-31; 7078382: JSR 292: dont count method handle adapters against inlining budgets 2011-09-02; 7071709: JSR 292: switchpoint invalidation should be pushed not pulled 2011-09-08; 7085860: JSR 292: implement CallSite.setTargetNormal and setTargetVolatile as native methods 2011-10-12; 7092712: JSR 292: unloaded invokedynamic call sites can lead to a crash with signature types not on BCP 2011-10-24; 7090904: JSR 292: JRuby junit test crashes in PSScavengeRootsClosure::do_oop 2011-10-25; 7094138: JSR 292: JRuby junit test fails in CallSite.setTargetNormal: obj->is_oop() failed: sanity check 2011-11-17; 7108383: JSR 292: JRuby bench_define_method_methods.rb: assert(slow_jvms != NULL) failed: miss path must notSunday, February 3, 13
  • 43. Java 7u2 • Performance work finally released! • JRuby users put indy into production • NoClassDefFound era (ha!) begins • To this day, no 100% working Hotspot indy! • ...and apparently J9 is not much better • Maybe we should have Java syntax for indy?Sunday, February 3, 13
  • 44. NCDFE Bug • Method handles operate at bootstrap level • Must be able to bind user-loaded classes • Handle impl only handled first type right • Subsequent types presented incorrectly • NCDFE resulted in JITed codeSunday, February 3, 13
  • 45. NCDFE Workarounds • Load everything on bootstrap • JRuby does this for noverify • Not practical for server setups • Erase all types to bootstrap classes • Introduced checkcasts hurt perf • Impossible to maintain both versionsSunday, February 3, 13
  • 46. Other Issues • Inlining thresholds must be special-cased • Native handles are opaque • Native handles are expensive to create • Native handles are hard to inspect • Many optz can’t cross indy siteSunday, February 3, 13
  • 47. 2012 • Rewrite of Hotspot’s 292 subsystem • Mostly-native moves into Java code • LambdaForm instead of native • @ForceInline hints added for JIT purposes • Erases types, avoiding NCDFE issuesSunday, February 3, 13
  • 48. LambdaForm • Java objects represent MH chain • Unjitted, call directly through LFs • LF “compiler” emits bytecoded adapters • Bytecode inlined, optimized as normal • JIT becomes more important • Not universally loved...Sunday, February 3, 13
  • 49. def foo bar end def bar baz end def baz sleep end fooSunday, February 3, 13
  • 50. at LF pre-JIT org.jruby.RubyKernel.sleep(RubyKernel.java:801) at org.jruby.RubyKernel$INVOKER$s$0$1$sleep.call(RubyKernel$INVOKER$s$0$1$sleep.gen) at org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:642) at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:197) at java.lang.invoke.LambdaForm$DMH/692342133.invokeVirtual_LLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/1395089624.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/1254526270.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1744347043.invokeSpecial_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112)Sunday, February 3, 13
  • 51. Anonymous Classes at java.lang.invoke.LambdaForm$LFI/1395089624.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) • Shared class metadata • Patched versions of existing classes • Reduced impact on symbol table, permgenSunday, February 3, 13
  • 52. at org.jruby.RubyKernel.sleep(RubyKernel.java:801) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at org.jruby.RubyKernel$INVOKER$s$0$1$sleep.call(RubyKernel$INVOKER$s$0$1$sleep.gen) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) sleep at org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:642) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:197) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/692342133.invokeVirtual_LLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1191747167.invokeSpecial_LLLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/662441761.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LL_L(LambdaForm.java:1097) at java.lang.invoke.LambdaForm$LFI/1395089624.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/1395089624.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/662441761.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$MH/1190524793.invokeExact_MT(LambdaForm$MH) at java.lang.invoke.LambdaForm$LFI/1254526270.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:599) at java.lang.invoke.LambdaForm$DMH/1744347043.invokeSpecial_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at org.jruby.runtime.invokedynamic.InvocationLinker.invocationFallback(InvocationLinker.java:138) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1304836502.invokeStatic_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1191747167.invokeSpecial_LLLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1151020327.invokeSpecial_LLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$LFI/1254526270.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm$MH/1451043227.linkToCallSite(LambdaForm$MH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at ruby.__dash_e__.method__0$RUBY$foo(-e:1) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$DMH/1304836502.invokeStatic_LLLL_L(LambdaForm$DMH) foo at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1151020327.invokeSpecial_LLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$LFI/1254526270.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1744347043.invokeSpecial_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/662441761.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LL_L(LambdaForm.java:1097) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1191747167.invokeSpecial_LLLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm$LFI/662441761.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$MH/1190524793.invokeExact_MT(LambdaForm$MH) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:599) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at org.jruby.runtime.invokedynamic.InvocationLinker.invocationFallback(InvocationLinker.java:138) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1304836502.invokeStatic_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/1395089624.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1151020327.invokeSpecial_LLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$LFI/1254526270.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1191747167.invokeSpecial_LLLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$MH/1451043227.linkToCallSite(LambdaForm$MH) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at ruby.__dash_e__.method__1$RUBY$bar(-e:1) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1304836502.invokeStatic_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) bar at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$DMH/1151020327.invokeSpecial_LLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$DMH/1191747167.invokeSpecial_LLLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$LFI/1254526270.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1744347043.invokeSpecial_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/1395089624.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/662441761.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LL_L(LambdaForm.java:1097) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$DMH/1191747167.invokeSpecial_LLLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$LFI/662441761.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$MH/1190524793.invokeExact_MT(LambdaForm$MH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:599) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at org.jruby.runtime.invokedynamic.InvocationLinker.invocationFallback(InvocationLinker.java:138) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1304836502.invokeStatic_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$DMH/1151020327.invokeSpecial_LLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$LFI/1254526270.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1191747167.invokeSpecial_LLLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$MH/1451043227.linkToCallSite(LambdaForm$MH) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at ruby.__dash_e__.method__2$RUBY$baz(-e:1) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/662441761.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1304836502.invokeStatic_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LL_L(LambdaForm.java:1097) baz at java.lang.invoke.LambdaForm$DMH/1151020327.invokeSpecial_LLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/1395089624.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/662441761.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$MH/1190524793.invokeExact_MT(LambdaForm$MH) at java.lang.invoke.LambdaForm$LFI/1254526270.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:599) at java.lang.invoke.LambdaForm$DMH/1744347043.invokeSpecial_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at org.jruby.runtime.invokedynamic.InvocationLinker.invocationFallback(InvocationLinker.java:138) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$DMH/1304836502.invokeStatic_LLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1191747167.invokeSpecial_LLLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1151020327.invokeSpecial_LLLLL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NFI/792791759.invoke_LLLLLL_L(LambdaForm$NFI) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$LFI/1254526270.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm$MH/1451043227.linkToCallSite(LambdaForm$MH) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at ruby.__dash_e__.__file__(-e:1) top-level of script at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLLL_L(LambdaForm.java:1112) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm$LFI/874088044.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$NamedFunction.invoke_LLLL_L(LambdaForm.java:1107) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625) at java.lang.invoke.LambdaForm$DMH/1627674070.invokeStatic_LL_L(LambdaForm$DMH) at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:604) at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:1136) at java.lang.invoke.LambdaForm$LFI/1837543557.interpret_L(LambdaForm$LFI) at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:625)Sunday, February 3, 13
  • 53. Java Release? • Work-in-progress until recent months • Only made it to OpenJDK8 this fall • Targeted for 7u12/14 right now • Approval seems to be going well • Still no 100% working indy release!Sunday, February 3, 13
  • 54. How Good Is It? • We’ll come back to thisSunday, February 3, 13
  • 55. Meanwhile... • RubyFlux: Ruby to .java compiler • Dynamic calls converted to virtual • Generated superclass with all methods • method_missing, send, etc possible • Eclipse JDT for generating source • Early prototypeSunday, February 3, 13
  • 56. def foo bar end def bar self end a = 100_000_000 while a > 0 foo; foo; foo; foo; foo a -= 1 endSunday, February 3, 13
  • 57. public class foo_bar extends RObject { public static void main(String[] args) { new foo_bar().$main(); } public void $main() { RObject $last = RNil; RObject a = RNil; $last = a = new RFixnum(100000000L); while (a.$greater(new RFixnum(0L)).toBoolean()) { $last = foo(); $last = foo(); $last = foo(); $last = foo(); $last = foo(); $last = a = a.$minus(new RFixnum(1L)); ; } $last = RNil; ; } public RObject foo() { RObject $last = RNil; $last = bar(); return $last; } public RObject bar() { RObject $last = RNil; $last = RNil; return $last; } }Sunday, February 3, 13
  • 58. Other Pain • Performance • Debugging • Security • MethodHandle APISunday, February 3, 13
  • 59. PerformanceSunday, February 3, 13
  • 60. Performance • I believe, I really doSunday, February 3, 13
  • 61. Performance • I believe, I really do • But it has gone back and forthSunday, February 3, 13
  • 62. Performance • I believe, I really do • But it has gone back and forth • And I have shamefully not contributedSunday, February 3, 13
  • 63. Performance • I believe, I really do • But it has gone back and forth • And I have shamefully not contributed • Other than whining and providing benchesSunday, February 3, 13
  • 64. Performance • I believe, I really do • But it has gone back and forth • And I have shamefully not contributed • Other than whining and providing benches • I vow to change this in 2013Sunday, February 3, 13
  • 65. Debugging • MethodHandle errors are often cryptic • No MH chain inspection • Backward binding flips brain ugh bad • Errors may occur after repeated calls • Site rebinding bugs • PIC bugs • Failure path bugsSunday, February 3, 13
  • 66. Security • With great power...comes great exploits • Recent hacks related to indy, MHs • I knew at least one would come out • ...so I helped test recent fixes • Imagine building reflection API today • In the presence of stack hacks!Sunday, February 3, 13
  • 67. MethodHandle API • MH API is very bare bones, low level • InvokeBinder - fluent DSL for MH chains • Build forward, not backward • Track signature, arg names • Many conveniences • https://github.com/headius/invokebinderSunday, February 3, 13
  • 68. MethodHandle mh = MethodHandles.insertArguments( otherMH, index arg1, arg2); mh = MethodHandles.dropArguments(mh, 1, Blah.class) mh = MethodHandles.permuteArguments( mh, MethodType.methodType( String.class, Object.class, int.class new int[] {0, 1, 4, 5}); mh = MethodHandles.explicitCastArguments( mh, MethodType.methodType( String.class, Object.class, int.class);Sunday, February 3, 13
  • 69. Argument Manipulation MethodHandle mh = Binder .from(String.class, String.class, String.class) // String w(String, String) .drop(1, String.class) // String x(String) .insert(0, hello) // String y(String, String) .cast(String.class, CharSequence.class, Object.class) // String z(CharSequence, Object) .invoke(someTargetHandle); MethodHandle m11 = lookup         .findStatic(Demo1.class, "twoArgs",                 MethodType.methodType(String.class, String.class, String.class)); m11 = MethodHandles.permuteArguments(        m11,         MethodType.methodType(String.class, String.class, String.class, int.class),         1, 0); MethodHandle m12 = Binder.from(String.class, String.class, String.class, int.class)        .permute(1, 0)         .invokeStatic(lookup, Demo1.class, "initials"); m12.invoke("one", "two", 3); // => "[two,one]"Sunday, February 3, 13
  • 70. Argument Manipulation MethodHandle mh = Binder .from(String.class, String.class, String.class) // String w(String, String) .drop(1, String.class) // String x(String) .insert(0, hello) // String y(String, String) .cast(String.class, CharSequence.class, Object.class) // String z(CharSequence, Object) .invoke(someTargetHandle); MethodHandle m11 = lookup         .findStatic(Demo1.class, "twoArgs",                 MethodType.methodType(String.class, String.class, String.class)); m11 = MethodHandles.permuteArguments(        m11,         MethodType.methodType(String.class, String.class, String.class, int.class),         1, 0); MethodHandle m12 = Binder.from(String.class, String.class, String.class, int.class)        .permute(1, 0)         .invokeStatic(lookup, Demo1.class, "initials"); m12.invoke("one", "two", 3); // => "[two,one]"Sunday, February 3, 13
  • 71. try/finally MethodHandle post = Binder .from(void.class, String[].class) .invokeStatic(lookup, BinderTest.class, "finallyLogic");   MethodHandle handle = Binder .from(void.class, String[].class) .tryFinally(post) .invokeStatic(lookup, BinderTest.class, "bodyOfCode");Sunday, February 3, 13
  • 72. try/finally MethodHandle exceptionHandler = Binder .from(target.type().insertParameterTypes(0, Throwable.class).changeReturnType(void.class)) .drop(0) .invoke(post);   MethodHandle rethrow = Binder .from(target.type().insertParameterTypes(0, Throwable.class)) .fold(exceptionHandler) .drop(1, target.type().parameterCount()) .throwException();   target = MethodHandles.catchException(target, Throwable.class, rethrow);   // if target returns a value, we must return it regardless of post MethodHandle realPost = post; if (target.type().returnType() != void.class) { // modify post to ignore return value MethodHandle newPost = Binder .from(target.type().insertParameterTypes(0, target.type().returnType()).changeReturnType(void.class)) .drop(0) .invoke(post);   // fold post into an identity chain that only returns the value realPost = Binder .from(target.type().insertParameterTypes(0, target.type().returnType())) .fold(newPost) .drop(1, target.type().parameterCount()) .identity(); }   return MethodHandles.foldArguments(realPost, target);Sunday, February 3, 13
  • 73. Symbolic Arguments • Easier to follow than indices • Easier to adapt to different signatures • Arity less of a challengeSunday, February 3, 13
  • 74. MethodHandle mh = MethodHandles.insertArguments( otherMH, 0 arg1, arg2); mh = MethodHandles.dropArguments(mh, 1, Blah.class) mh = MethodHandles.permuteArguments( mh, MethodType.methodType( String.class, Object.class, int.class new int[] {0, 1, 4, 5}); mh = MethodHandles.explicitCastArguments( mh, MethodType.methodType( String.class, Object.class, int.class);Sunday, February 3, 13
  • 75. Args By Name // Incoming args for DynamicMethod.call private static final Signature DYNAMIC_METHOD_SIG = Signature .returning(IRubyObject.class) .appendArg("method", DynamicMethod.class) .appendArg("context", ThreadContext.class) .appendArg("self", IRubyObject.class) .appendArg("selfClass", RubyModule.class) .appendArg("name", String.class);   // Only want context and self private static final Signature CONTEXT_AND_SELF = DYNAMIC_METHOD_SIG .permute("context", "self");   // Easy generic transformations from one sig to another private static MethodHandle dynamicCallTarget(Signature from, Signature to) { return SmartBinder .from(from) .fold("selfClass", from.asFold(RubyClass.class).permuteTo(PGC, "context", "self")) .permute(to) .cast(to) .invokeVirtualQuiet(lookup(), "call") .handle(); }Sunday, February 3, 13
  • 76. Modern EraSunday, February 3, 13
  • 77. Use in JRuby • Dynamic calls • Dynamic “constants” • Global variables • Thread events • Lazy literals • Instance variablesSunday, February 3, 13
  • 78. Dynamic Calls • Per-class mutable method tables • Consistent call signature • Bootstrap binds fallback path • Fallback binds guards + target • Call site fails out after N invalidationsSunday, February 3, 13
  • 79. Dyncall Guard • GWT • Exact type check for “final” types • Metaclass identity • Slightly weaker than Hotspot • SwitchPoint • Per-class modification guardSunday, February 3, 13
  • 80. if (self instanceof RubySymbol || self instanceof RubyFixnum || self instanceof RubyFloat || self instanceof RubyNil || self instanceof RubyBoolean.True || self instanceof RubyBoolean.False) {   test = selfTest .insert(1, "selfJavaType", self.getClass()) .cast(boolean.class, Object.class, Class.class) .invoke(TEST_CLASS);   } else {   selfTest = selfTest.insert(0, "selfClass", selfClass);   test = selfTest .cast(boolean.class, RubyClass.class, IRubyObject.class) .invoke(TEST); }   gwt = createGWT(test, target, fallback, entry, site, curry); // wrap in switchpoint for mutation invalidation gwt = switchPoint.guardWithTest( gwt, curry ? insertArguments(fallback, 0, site) : fallback);Sunday, February 3, 13
  • 81. if (self instanceof RubySymbol || self instanceof RubyFixnum || self instanceof RubyFloat || self instanceof RubyNil || self instanceof RubyBoolean.True || self instanceof RubyBoolean.False) {   test = selfTest .insert(1, "selfJavaType", self.getClass()) .cast(boolean.class, Object.class, Class.class) .invoke(TEST_CLASS);   } else {   selfTest = selfTest.insert(0, "selfClass", selfClass);   test = selfTest .cast(boolean.class, RubyClass.class, IRubyObject.class) .invoke(TEST); }   gwt = createGWT(test, target, fallback, entry, site, curry); // wrap in switchpoint for mutation invalidation gwt = switchPoint.guardWithTest( gwt, curry ? insertArguments(fallback, 0, site) : fallback);Sunday, February 3, 13
  • 82. if (self instanceof RubySymbol || self instanceof RubyFixnum || self instanceof RubyFloat || self instanceof RubyNil || self instanceof RubyBoolean.True || self instanceof RubyBoolean.False) {   test = selfTest .insert(1, "selfJavaType", self.getClass()) .cast(boolean.class, Object.class, Class.class) .invoke(TEST_CLASS);   } else {   selfTest = selfTest.insert(0, "selfClass", selfClass);   test = selfTest .cast(boolean.class, RubyClass.class, IRubyObject.class) .invoke(TEST); }   gwt = createGWT(test, target, fallback, entry, site, curry); // wrap in switchpoint for mutation invalidation gwt = switchPoint.guardWithTest( gwt, curry ? insertArguments(fallback, 0, site) : fallback);Sunday, February 3, 13
  • 83. public static boolean testMetaclass( RubyClass metaclass, IRubyObject self) { return metaclass == ((RubyBasicObject)self).getMetaClass(); } Icky Hotspot artifact...Sunday, February 3, 13
  • 84. def foo self end   def bar foo end   100_000.times do bar endSunday, February 3, 13
  • 85. HERE BE DRAGONS • x86_64 ASM output from Hotspot • Google “hotspot printassembly” • hsdis shared lib • Drop into JVM dylib dir • -XX:+UnlockDiagnosticVMOptions -XX: +PrintAssembly • PROFITSunday, February 3, 13
  • 86. # parm0: rsi:rsi = $01_dyncall # parm1: rdx:rdx = org/jruby/runtime/ThreadContext # parm2: rcx:rcx = org/jruby/runtime/builtin/IRubyObject # parm3: r8:r8 = org/jruby/runtime/Block... 0x000000010c8e266c: test %rdx,%rdx 0x000000010c8e266f: je 0x000000010c8e26b5 ;*ifnull ; - java.lang.Class::cast@1 (line 3008) ; - java.lang.invoke.LambdaForm$MH/1631862159::guard@12 ; - java.lang.invoke.LambdaForm$MH/783286238::linkToCallSite@14 ; - $01_dyncall::method__1$RUBY$bar@3 (line 6) 0x000000010c8e2671: mov 0x8(%rcx),%r11d ; implicit exception: dispatches to 0x000000010c8e26f1 0x000000010c8e2675: cmp $0x21f1a6ba,%r11d ; {metadata(org/jruby/RubyObject)} 0x000000010c8e267c: jne 0x000000010c8e26d5 0x000000010c8e267e: mov %rcx,%r10 ;*checkcast ; - org.jruby.runtime.invokedynamic.InvocationLinker::testMetaclass@2 (line 694) ; - java.lang.invoke.LambdaForm$DMH/1348949648::invokeStatic_LL_I@11 ; - java.lang.invoke.LambdaForm$MH/591137559::convert@26 ; - java.lang.invoke.LambdaForm$MH/1638215613::guard@17 ; - java.lang.invoke.LambdaForm$DMH/476800120::invokeSpecial_LLLL_L@16 ; - java.lang.invoke.LambdaForm$MH/1631862159::guard@50 ; - java.lang.invoke.LambdaForm$MH/783286238::linkToCallSite@14 ; - $01_dyncall::method__1$RUBY$bar@3 (line 6) 0x000000010c8e2681: mov 0x14(%r10),%ebp ;*getfield metaClass ; - org.jruby.RubyBasicObject::getMetaClass@1 (line 517) ; - org.jruby.runtime.invokedynamic.InvocationLinker::testMetaclass@5 (line 694) ; - java.lang.invoke.LambdaForm$DMH/1348949648::invokeStatic_LL_I@11 ; - java.lang.invoke.LambdaForm$MH/591137559::convert@26 ; - java.lang.invoke.LambdaForm$MH/1638215613::guard@17 ; - java.lang.invoke.LambdaForm$DMH/476800120::invokeSpecial_LLLL_L@16 ; - java.lang.invoke.LambdaForm$MH/1631862159::guard@50 ; - java.lang.invoke.LambdaForm$MH/783286238::linkToCallSite@14 ; - $01_dyncall::method__1$RUBY$bar@3 (line 6) 0x000000010c8e2685: cmp $0x2576cde9,%ebp ; {oop(a org/jruby/MetaClass)} 0x000000010c8e268b: jne 0x000000010c8e269c ;*if_acmpne ; - org.jruby.runtime.invokedynamic.InvocationLinker::testMetaclass@8 (line 694) ; - java.lang.invoke.LambdaForm$DMH/1348949648::invokeStatic_LL_I@11 ; - java.lang.invoke.LambdaForm$MH/591137559::convert@26 ; - java.lang.invoke.LambdaForm$MH/1638215613::guard@17 ; - java.lang.invoke.LambdaForm$DMH/476800120::invokeSpecial_LLLL_L@16 ; - java.lang.invoke.LambdaForm$MH/1631862159::guard@50 ; - java.lang.invoke.LambdaForm$MH/783286238::linkToCallSite@14 ; - $01_dyncall::method__1$RUBY$bar@3 (line 6) 0x000000010c8e268d: mov %rcx,%rax 0x000000010c8e2690: add $0x30,%rsp 0x000000010c8e2694: pop %rbp 0x000000010c8e2695: test %eax,-0x18e369b(%rip) # 0x000000010afff000 ; {poll_return} 0x000000010c8e269b: retqSunday, February 3, 13
  • 87. # parm0: rsi:rsi = $01_dyncall # parm1: rdx:rdx = org/jruby/runtime/ThreadContext # parm2: rcx:rcx = org/jruby/runtime/builtin/IRubyObject # parm3: r8:r8 = org/jruby/runtime/Block... mov 0x8(%rcx),%r11d ; implicit exception: dispatches to 0x000000010c8e26f1 cmp $0x21f1a6ba,%r11d ; {metadata(org/jruby/RubyObject)} jne 0x000000010c8e26d5 mov %rcx,%r10 ;*checkcast ; - InvocationLinker::testMetaclass@2 (line 694) mov 0x14(%r10),%ebp ;*getfield metaClass ; - RubyBasicObject::getMetaClass@1 (line 517) ; - InvocationLinker::testMetaclass@5 (line 694) cmp $0x2576cde9,%ebp ; {oop(a org/jruby/MetaClass)} jne 0x000000010c8e269c ;*if_acmpne ; - InvocationLinker::testMetaclass@8 (line 694) mov %rcx,%rax... retq + safepoint checks...Sunday, February 3, 13
  • 88. Better Than Java? • Polymorphic calls • Hotspot inlines up to bimorphic • JRuby: trimorphic PIC, configurable • Smarter type checks possible • Eliminate boxing at call siteSunday, February 3, 13
  • 89. Constants • Lexical lazily-defined variables • Redefinable, but usually static • Single global invalidator (SwitchPoint) • Mostly due to lexical scoping • Constant targetSunday, February 3, 13
  • 90. Global Variables • Global, thread-local, frame-local • Only global gets cached • Per-variable guard • Constant value • Failover to lookup after N invalidationsSunday, February 3, 13
  • 91. Foo = 1 $bar = 1   def get_foo Foo end   def get_bar $bar endSunday, February 3, 13
  • 92. # parm0: rsi:rsi = $06_constants # parm1: rdx:rdx = org/jruby/runtime/ThreadContext # parm2: rcx:rcx = org/jruby/runtime/builtin/IRubyObject # parm3: r8:r8 = org/jruby/runtime/Block # [sp+0x50] (sp of caller) mov %eax,-0x14000(%rsp) push %rbp sub $0x40,%rsp ;*synchronization entry ; - $06_constants::method__0$RUBY$get_foo@-1 (line 5) test %rsi,%rsi je 0x000000010d5d464c ;*ifnull ; - java.lang.Class::cast@1 (line 3008) ; - $06_constants::method__0$RUBY$get_foo@2 (line 5) test %rdx,%rdx je 0x000000010d5d466d ;*ifnull ; - java.lang.Class::cast@1 (line 3008) ; - $06_constants::method__0$RUBY$get_foo@2 (line 5) movabs $0x12c9a2e88,%rax ;*synchronization entry ; - $06_constants::method__0$RUBY$get_foo@-1 (line 5) ; {oop(a org/jruby/RubyFixnum)} add $0x40,%rsp pop %rbp test %eax,-0x95364b(%rip) # 0x000000010cc81000 ; {poll_return} retqSunday, February 3, 13
  • 93. # parm0: rsi:rsi = $06_constants # parm1: rdx:rdx = org/jruby/runtime/ThreadContext # parm2: rcx:rcx = org/jruby/runtime/builtin/IRubyObject # parm3: r8:r8 = org/jruby/runtime/Block # [sp+0x50] (sp of caller) ... movabs $0x12c9a2e88,%rax ;*synchronization entry ; - $06_constants::method__0$RUBY$get_foo@-1 (line 5) ; {oop(a org/jruby/RubyFixnum)} ... retq + safepoint yadda yaddaSunday, February 3, 13
  • 94. # parm0: rsi:rsi = $06_constants # parm1: rdx:rdx = org/jruby/runtime/ThreadContext # parm2: rcx:rcx = org/jruby/runtime/builtin/IRubyObject # parm3: r8:r8 = org/jruby/runtime/Block # [sp+0x30] (sp of caller) mov %eax,-0x14000(%rsp) push %rbp sub $0x20,%rsp ;*synchronization entry ; - $06_constants::method__1$RUBY$get_bar@-1 (line 13) test %rdx,%rdx je 0x00000001057275e7 ;*ifnull ; - java.lang.Class::cast@1 (line 3008) ; - $06_constants::method__1$RUBY$get_bar@1 (line 17) movabs $0x7f6bef838,%rax ;*synchronization entry ; - $06_constants::method__1$RUBY$get_bar@-1 (line 13) ; {oop(a org/jruby/RubyFixnum)} add $0x20,%rsp pop %rbp test %eax,-0x18405e6(%rip) # 0x0000000103ee7000 ; {poll_return} retqSunday, February 3, 13
  • 95. # parm0: rsi:rsi = $06_constants # parm1: rdx:rdx = org/jruby/runtime/ThreadContext # parm2: rcx:rcx = org/jruby/runtime/builtin/IRubyObject # parm3: r8:r8 = org/jruby/runtime/Block # [sp+0x30] (sp of caller) ... movabs $0x7f6bef838,%rax ;*synchronization entry ; - $06_constants::method__1$RUBY$get_bar@-1 (line 13) ; {oop(a org/jruby/RubyFixnum)} ... retqSunday, February 3, 13
  • 96. Better Than Java? • Constant folding • Lazy static finals can’t fold in Hotspot • SwitchPoint + constant value can! • Broke several benchmarks :-)Sunday, February 3, 13
  • 97. Better Than Java? • Constant folding Fixed in 7 • Lazy static finals can’t fold in Hotspot • SwitchPoint + constant value can! • Broke several benchmarks :-)Sunday, February 3, 13
  • 98. public class JavaLazyFinal { private static final long FINAL = System.currentTimeMillis(); private static long accum = 0 ;   public static void main(String[] args) { for (int i = 0; i < 1000000; i++) { accumulate(); } System.out.println(accum); }   public static void accumulate() { accum += FINAL; } }Sunday, February 3, 13
  • 99. Java 6 # {method} accumulate ()V in JavaLazyFinal # [sp+0x20] (sp of caller) ... 1063a6726: movabs $0x7fb283d70,%r10 ; {oop(JavaLazyFinal)} 1063a6730: mov 0x258(%r10),%r8d ;*getstatic FINAL ... retq ... movabs $0x7f6bef838,%rax ;*synchronization entry ; - $06_constants::method__1$RUBY$get_bar@-1 (line 13) ; {oop(a org/jruby/RubyFixnum)} ... retqSunday, February 3, 13
  • 100. Java 7 {0x0000000102e40460} accumulate ()V in JavaLazyFinal # [sp+0x20] (sp of caller) ... movabs $0x13c88b682e5,%r10 ... retq ... movabs $0x7f6bef838,%rax ;*synchronization entry ; - $06_constants::method__1$RUBY$get_bar@-1 (line 13) ; {oop(a org/jruby/RubyFixnum)} ... retqSunday, February 3, 13
  • 101. Instance Variables • Per-class mutable table of “fields” • Class maps names to offsets • Type guard • Specificity is up for debate... • Offset cached in MH chain directly • Future: true Java fields?Sunday, February 3, 13
  • 102. Thread Events • Rare cross-thread interrupts • kill, raise exception • Guard call sites, method entry, backedge • Invalidates everything...hmmmSunday, February 3, 13
  • 103. Thread Event Guard • Global SwitchPoint • Target is a no-op • Fallback checks thread events • On event, invalidate SP • All code thrown out • Looking at hybrid volatile + SP optionsSunday, February 3, 13
  • 104. Lazy Literals • Numbers, Strings, Regexp, True/False/Nil • Local caching of JRuby runtime • ConstantCallSite for runtime-isolated • MutableCallSite for runtime-specific • Classloader fails us here anyway • Do isolated constant handles pointing at same objects fold away?Sunday, February 3, 13
  • 105. JRuby/Java 7 JRuby/Java 7 + indySunday, February 3, 13
  • 106. JRuby/Java 7 JRuby/Java 7 + indy 5 Times faster than Ruby 2.0.0pre1 3.75 2.5 1.25 0 base64 richards neural mandelbrotSunday, February 3, 13
  • 107. JRuby/Java 7 JRuby/Java 7 + indy 5 Times faster than Ruby 2.0.0pre1 3.75 3.973 3.434 2.99 2.5 2.519 2.048 1.25 0 base64 richards neural mandelbrotSunday, February 3, 13
  • 108. JRuby/Java 7 JRuby/Java 7 + indy 5 Times faster than Ruby 2.0.0pre1 4.107 3.75 3.973 3.84 3.434 2.946 2.99 2.5 2.519 2.048 1.25 0 base64 richards neural mandelbrotSunday, February 3, 13
  • 109. Smooth sort of a small array JRuby 90593 Rubinius 2.0.0rc1 60232.3 MagLev 23954.5 MacRuby 0.12 19609.5 Ruby 2.0.0 19590.7 Ruby 1.9.3 11439 Ruby 1.8.7 4750 0 25000 50000 75000 100000 Iterations per secondSunday, February 3, 13
  • 110. red/black tree, pure Ruby versus native jruby + Java ext 0.1 jruby + Ruby 0.29 ruby-2.0.0 + C ext 0.51 ruby-1.9.3 + C ext 0.51 rbx-2.0.0rc1 + Ruby 0.51 macruby-0.12 + Ruby 1.19 maglev + Ruby 1.39 ruby-2.0.0 + Ruby 2.48 ruby-1.9.3 + Ruby 3.96 0 1 2 3 4 Runtime per iterationSunday, February 3, 13
  • 111. Future • Ongoing tuning of JIT, inlining • Reduce perf cliff for unjitted or uninlined • Partial inlining helping a lot here • Inlining through closure receivers • Tie inlining to closure-receiving site? • Better EA! value types? tagged values? • Android!Sunday, February 3, 13
  • 112. Thank you! • headius@headius.com, @headius • github/headius/invokebinder • github/headius/rubyflux • github/mirah/mirah • blog.headius.comSunday, February 3, 13