• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Invokedynamic: Tales from the Trenches
 

Invokedynamic: Tales from the Trenches

on

  • 2,297 views

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

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

Statistics

Views

Total Views
2,297
Views on SlideShare
2,236
Embed Views
61

Actions

Likes
10
Downloads
48
Comments
0

4 Embeds 61

https://twitter.com 38
https://twimg0-a.akamaihd.net 15
https://si0.twimg.com 7
http://tweetedtimes.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Invokedynamic: Tales from the Trenches Invokedynamic: Tales from the Trenches Presentation Transcript

    • invokedynamic Tales from the TrenchesSunday, February 3, 13
    • 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
    • invokedynamic 101 • invokevirtual, invokestatic, etc • Predefined behavior • Based on simple VM primitives • invokedynamic • User-defined bytecode • Primitives available as an IRSunday, February 3, 13
    • 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
    • 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
    • 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
    • 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
    • Promises • “JRuby plus invokedynamic will be fast” • “The fully-working optimized OpenJDK indy impl is just around the corner”Sunday, February 3, 13
    • The BeginningSunday, February 3, 13
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • registerBootstrapMethod static { Linkage.registerBootstrapMethod( SimpleExample.class, MethodHandles.findStatic( DynamicInvokerThingy.class, "bootstrap", Linkage.BOOTSTRAP_METHOD_TYPE)); }Sunday, February 3, 13
    • 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
    • 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
    • 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
    • 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
    • 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
    • Sunday, February 3, 13
    • Sunday, February 3, 13
    • 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
    • ...Could Be This class Foo def initialize(a) @a = a end def show puts @a end endSunday, February 3, 13
    • Mirah class Foo def initialize(a:int) @a = a end def show puts @a end endSunday, February 3, 13
    • Mirah class Foo def initialize(a:dynamic) @a = a end def show puts @a end endSunday, February 3, 13
    • Middle AgesSunday, February 3, 13
    • 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
    • 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
    • 2011 • Wrapping things up for FCS • Focus on correctness • Some JIT work landing for perf • JRuby a primary test caseSunday, February 3, 13
    • 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
    • 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
    • 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
    • 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
    • What to Do?Sunday, February 3, 13
    • What to Do? • GA indy perf slower than non-indy!Sunday, February 3, 13
    • What to Do? • GA indy perf slower than non-indy! • Enable indy, knowing perf is bad?Sunday, February 3, 13
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • def foo bar end def bar baz end def baz sleep end fooSunday, February 3, 13
    • 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
    • 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
    • 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
    • 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
    • How Good Is It? • We’ll come back to thisSunday, February 3, 13
    • 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
    • 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
    • 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
    • Other Pain • Performance • Debugging • Security • MethodHandle APISunday, February 3, 13
    • PerformanceSunday, February 3, 13
    • Performance • I believe, I really doSunday, February 3, 13
    • Performance • I believe, I really do • But it has gone back and forthSunday, February 3, 13
    • Performance • I believe, I really do • But it has gone back and forth • And I have shamefully not contributedSunday, February 3, 13
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • Symbolic Arguments • Easier to follow than indices • Easier to adapt to different signatures • Arity less of a challengeSunday, February 3, 13
    • 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
    • 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
    • Modern EraSunday, February 3, 13
    • Use in JRuby • Dynamic calls • Dynamic “constants” • Global variables • Thread events • Lazy literals • Instance variablesSunday, February 3, 13
    • 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
    • Dyncall Guard • GWT • Exact type check for “final” types • Metaclass identity • Slightly weaker than Hotspot • SwitchPoint • Per-class modification guardSunday, February 3, 13
    • 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
    • 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
    • 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
    • public static boolean testMetaclass( RubyClass metaclass, IRubyObject self) { return metaclass == ((RubyBasicObject)self).getMetaClass(); } Icky Hotspot artifact...Sunday, February 3, 13
    • def foo self end   def bar foo end   100_000.times do bar endSunday, February 3, 13
    • 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
    • # 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
    • # 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
    • 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
    • Constants • Lexical lazily-defined variables • Redefinable, but usually static • Single global invalidator (SwitchPoint) • Mostly due to lexical scoping • Constant targetSunday, February 3, 13
    • 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
    • Foo = 1 $bar = 1   def get_foo Foo end   def get_bar $bar endSunday, February 3, 13
    • # 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
    • # 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
    • # 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
    • # 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
    • Better Than Java? • Constant folding • Lazy static finals can’t fold in Hotspot • SwitchPoint + constant value can! • Broke several benchmarks :-)Sunday, February 3, 13
    • 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
    • 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
    • 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
    • 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
    • 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
    • Thread Events • Rare cross-thread interrupts • kill, raise exception • Guard call sites, method entry, backedge • Invalidates everything...hmmmSunday, February 3, 13
    • 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
    • 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
    • JRuby/Java 7 JRuby/Java 7 + indySunday, February 3, 13
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • Thank you! • headius@headius.com, @headius • github/headius/invokebinder • github/headius/rubyflux • github/mirah/mirah • blog.headius.comSunday, February 3, 13