SlideShare una empresa de Scribd logo
1 de 112
Descargar para leer sin conexión
invokedynamic
                            Tales from the Trenches




Sunday, 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 Hat
Sunday, February 3, 13
invokedynamic 101
                     • invokevirtual, invokestatic, etc
                      • Predefined behavior
                      • Based on simple VM primitives
                     • invokedynamic
                      • User-defined bytecode
                      • Primitives available as an IR
Sunday, 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 CallSite
Sunday, 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
                         site




Sunday, 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 handle
Sunday, 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 Beginning



Sunday, 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 yet

Sunday, 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 future
Sunday, 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 views

Sunday, 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...sorta
Sunday, 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: areturn




Sunday, 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 lands

Sunday, 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-build
Sunday, 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 invokedynamic




Sunday, 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.1




Sunday, 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
                         end

Sunday, February 3, 13
Mirah
                         class Foo
                           def initialize(a:int)
                             @a = a
                           end

                           def show
                             puts @a
                           end
                         end

Sunday, February 3, 13
Mirah
                         class Foo
                           def initialize(a:dynamic)
                             @a = a
                           end

                           def show
                             puts @a
                           end
                         end

Sunday, February 3, 13
Middle Ages



Sunday, 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 issue

Sunday, 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
  +DeoptimizeALot




Sunday, February 3, 13
2011

                     • Wrapping things up for FCS
                      • Focus on correctness
                      • Some JIT work landing for perf
                      • JRuby a primary test case

Sunday, 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 time
Sunday, 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 doesn't handle T_LONG and T_DOUBLE properly

  2011-06-22; 7057587: JSR 292 - crash with jruby in test/test_respond_to.rb




Sunday, 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 doesn't 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
  hasBeenInvalidated




Sunday, 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: don't 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 not




Sunday, 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 code

Sunday, 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 versions
Sunday, 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 site

Sunday, 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 issues

Sunday, 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

                         foo



Sunday, 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, permgen


Sunday, 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 this



Sunday, 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 prototype
Sunday, 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
                         end



Sunday, 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 API

Sunday, February 3, 13
Performance




Sunday, February 3, 13
Performance

                     • I believe, I really do




Sunday, February 3, 13
Performance

                     • I believe, I really do
                     • But it has gone back and forth




Sunday, February 3, 13
Performance

                     • I believe, I really do
                     • But it has gone back and forth
                     • And I have shamefully not contributed



Sunday, 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


Sunday, 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 2013

Sunday, 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 bugs


Sunday, 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/invokebinder
Sunday, 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 challenge


Sunday, 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 Era



Sunday, February 3, 13
Use in JRuby
                     • Dynamic calls
                     • Dynamic “constants”
                     • Global variables
                     • Thread events
                     • Lazy literals
                     • Instance variables
Sunday, 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 invalidations

Sunday, February 3, 13
Dyncall Guard
                     • GWT
                      • Exact type check for “final” types
                      • Metaclass identity
                        • Slightly weaker than Hotspot
                     • SwitchPoint
                      • Per-class modification guard
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
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
                         end


Sunday, 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
                     • PROFIT
Sunday, 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: retq
Sunday, 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 site

Sunday, February 3, 13
Constants

                     • Lexical lazily-defined variables
                      • Redefinable, but usually static
                     • Single global invalidator (SwitchPoint)
                      • Mostly due to lexical scoping
                     • Constant target

Sunday, February 3, 13
Global Variables

                     • Global, thread-local, frame-local
                      • Only global gets cached
                     • Per-variable guard
                     • Constant value
                     • Failover to lookup after N invalidations

Sunday, February 3, 13
Foo = 1
                         $bar = 1
                          
                         def get_foo
                           Foo
                         end
                          
                         def get_bar
                           $bar
                         end

Sunday, 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}
          retq



Sunday, 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 yadda




Sunday, 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}
          retq




Sunday, 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')}
      ...
        retq




Sunday, 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')}
    ...
      retq




Sunday, 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')}
    ...
      retq




Sunday, 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...hmmm

Sunday, 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 options
Sunday, 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 + indy




Sunday, 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          mandelbrot



Sunday, 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         mandelbrot



Sunday, 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         mandelbrot



Sunday, 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 second

Sunday, 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 iteration


Sunday, 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.com

Sunday, February 3, 13

Más contenido relacionado

La actualidad más candente

Charla ruby nscodermad
Charla ruby nscodermadCharla ruby nscodermad
Charla ruby nscodermadnscoder_mad
 
Objective-C A Beginner's Dive (with notes)
Objective-C A Beginner's Dive (with notes)Objective-C A Beginner's Dive (with notes)
Objective-C A Beginner's Dive (with notes)Altece
 
Javascript in the cloud
Javascript in the cloudJavascript in the cloud
Javascript in the cloudMostafa Eweda
 
JRuby in Java Projects
JRuby in Java ProjectsJRuby in Java Projects
JRuby in Java Projectsjazzman1980
 
JVM: A Platform for Multiple Languages
JVM: A Platform for Multiple LanguagesJVM: A Platform for Multiple Languages
JVM: A Platform for Multiple LanguagesKris Mok
 
Aloha on-rails-2009
Aloha on-rails-2009Aloha on-rails-2009
Aloha on-rails-2009John Woodell
 
RVM and Ruby Interpreters @ RSC Roma 03/2011
RVM and Ruby Interpreters @ RSC Roma 03/2011RVM and Ruby Interpreters @ RSC Roma 03/2011
RVM and Ruby Interpreters @ RSC Roma 03/2011Marcello Barnaba
 
Expert JavaScript Programming
Expert JavaScript ProgrammingExpert JavaScript Programming
Expert JavaScript ProgrammingYoshiki Shibukawa
 
Connecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyConnecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyNick Sieger
 
Java notes | All Basics |
Java notes | All Basics |Java notes | All Basics |
Java notes | All Basics |ShubhamAthawane
 

La actualidad más candente (18)

Charla ruby nscodermad
Charla ruby nscodermadCharla ruby nscodermad
Charla ruby nscodermad
 
Objective-C A Beginner's Dive (with notes)
Objective-C A Beginner's Dive (with notes)Objective-C A Beginner's Dive (with notes)
Objective-C A Beginner's Dive (with notes)
 
近未来的並列 LL
近未来的並列 LL近未来的並列 LL
近未来的並列 LL
 
GWT-Basics
GWT-BasicsGWT-Basics
GWT-Basics
 
JRuby in The Enterprise
JRuby in The EnterpriseJRuby in The Enterprise
JRuby in The Enterprise
 
Javascript in the cloud
Javascript in the cloudJavascript in the cloud
Javascript in the cloud
 
Tdd patterns1
Tdd patterns1Tdd patterns1
Tdd patterns1
 
JRuby in Java Projects
JRuby in Java ProjectsJRuby in Java Projects
JRuby in Java Projects
 
JRuby and You
JRuby and YouJRuby and You
JRuby and You
 
JVM: A Platform for Multiple Languages
JVM: A Platform for Multiple LanguagesJVM: A Platform for Multiple Languages
JVM: A Platform for Multiple Languages
 
Základy GWT
Základy GWTZáklady GWT
Základy GWT
 
Gpgpu intro
Gpgpu introGpgpu intro
Gpgpu intro
 
Aloha on-rails-2009
Aloha on-rails-2009Aloha on-rails-2009
Aloha on-rails-2009
 
RVM and Ruby Interpreters @ RSC Roma 03/2011
RVM and Ruby Interpreters @ RSC Roma 03/2011RVM and Ruby Interpreters @ RSC Roma 03/2011
RVM and Ruby Interpreters @ RSC Roma 03/2011
 
Expert JavaScript Programming
Expert JavaScript ProgrammingExpert JavaScript Programming
Expert JavaScript Programming
 
Varnish Oscon 2009
Varnish Oscon 2009Varnish Oscon 2009
Varnish Oscon 2009
 
Connecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyConnecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRuby
 
Java notes | All Basics |
Java notes | All Basics |Java notes | All Basics |
Java notes | All Basics |
 

Similar a Invokedynamic: Tales from the Trenches

Red Dirt Ruby Conference
Red Dirt Ruby ConferenceRed Dirt Ruby Conference
Red Dirt Ruby ConferenceJohn Woodell
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.jsTroy Miles
 
Yet Another Replication Tool: RubyRep
Yet Another Replication Tool: RubyRepYet Another Replication Tool: RubyRep
Yet Another Replication Tool: RubyRepDenish Patel
 
Introduction to node.js by Ran Mizrahi @ Reversim Summit
Introduction to node.js by Ran Mizrahi @ Reversim SummitIntroduction to node.js by Ran Mizrahi @ Reversim Summit
Introduction to node.js by Ran Mizrahi @ Reversim SummitRan Mizrahi
 
JRuby - The Best of Java and Ruby
JRuby - The Best of Java and RubyJRuby - The Best of Java and Ruby
JRuby - The Best of Java and RubyEvgeny Rahman
 
Extending Spring for Custom Usage
Extending Spring for Custom UsageExtending Spring for Custom Usage
Extending Spring for Custom UsageJoshua Long
 
Welcome to the Symfony2 World - FOSDEM 2013
 Welcome to the Symfony2 World - FOSDEM 2013 Welcome to the Symfony2 World - FOSDEM 2013
Welcome to the Symfony2 World - FOSDEM 2013Lukas Smith
 
Ab(Using) the MetaCPAN API for Fun and Profit v2013
Ab(Using) the MetaCPAN API for Fun and Profit v2013Ab(Using) the MetaCPAN API for Fun and Profit v2013
Ab(Using) the MetaCPAN API for Fun and Profit v2013Olaf Alders
 
Designing Puppet: Roles/Profiles Pattern
Designing Puppet: Roles/Profiles PatternDesigning Puppet: Roles/Profiles Pattern
Designing Puppet: Roles/Profiles PatternPuppet
 
Asynchronous Awesome
Asynchronous AwesomeAsynchronous Awesome
Asynchronous AwesomeFlip Sasser
 
Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013   Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013 Pablo Godel
 
1 Introduction to JAVA.pptx
1 Introduction to JAVA.pptx1 Introduction to JAVA.pptx
1 Introduction to JAVA.pptxKabiles07
 
PhoneGap in a Day
PhoneGap in a DayPhoneGap in a Day
PhoneGap in a DayTroy Miles
 
Intro to JavaScript Testing
Intro to JavaScript TestingIntro to JavaScript Testing
Intro to JavaScript TestingRan Mizrahi
 
Introduction to JRuby
Introduction to JRubyIntroduction to JRuby
Introduction to JRubyajuckel
 

Similar a Invokedynamic: Tales from the Trenches (20)

Red Dirt Ruby Conference
Red Dirt Ruby ConferenceRed Dirt Ruby Conference
Red Dirt Ruby Conference
 
Using SQLite
Using SQLiteUsing SQLite
Using SQLite
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.js
 
Yet Another Replication Tool: RubyRep
Yet Another Replication Tool: RubyRepYet Another Replication Tool: RubyRep
Yet Another Replication Tool: RubyRep
 
Introduction to node.js by Ran Mizrahi @ Reversim Summit
Introduction to node.js by Ran Mizrahi @ Reversim SummitIntroduction to node.js by Ran Mizrahi @ Reversim Summit
Introduction to node.js by Ran Mizrahi @ Reversim Summit
 
JRuby - The Best of Java and Ruby
JRuby - The Best of Java and RubyJRuby - The Best of Java and Ruby
JRuby - The Best of Java and Ruby
 
Rails Intro & Tutorial
Rails Intro & TutorialRails Intro & Tutorial
Rails Intro & Tutorial
 
App Engine Meetup
App Engine MeetupApp Engine Meetup
App Engine Meetup
 
Extending Spring for Custom Usage
Extending Spring for Custom UsageExtending Spring for Custom Usage
Extending Spring for Custom Usage
 
Welcome to the Symfony2 World - FOSDEM 2013
 Welcome to the Symfony2 World - FOSDEM 2013 Welcome to the Symfony2 World - FOSDEM 2013
Welcome to the Symfony2 World - FOSDEM 2013
 
Ab(Using) the MetaCPAN API for Fun and Profit v2013
Ab(Using) the MetaCPAN API for Fun and Profit v2013Ab(Using) the MetaCPAN API for Fun and Profit v2013
Ab(Using) the MetaCPAN API for Fun and Profit v2013
 
Designing Puppet: Roles/Profiles Pattern
Designing Puppet: Roles/Profiles PatternDesigning Puppet: Roles/Profiles Pattern
Designing Puppet: Roles/Profiles Pattern
 
Asynchronous Awesome
Asynchronous AwesomeAsynchronous Awesome
Asynchronous Awesome
 
Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013   Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013
 
SignalR
SignalRSignalR
SignalR
 
1 Introduction to JAVA.pptx
1 Introduction to JAVA.pptx1 Introduction to JAVA.pptx
1 Introduction to JAVA.pptx
 
PhoneGap in a Day
PhoneGap in a DayPhoneGap in a Day
PhoneGap in a Day
 
All The Little Pieces
All The Little PiecesAll The Little Pieces
All The Little Pieces
 
Intro to JavaScript Testing
Intro to JavaScript TestingIntro to JavaScript Testing
Intro to JavaScript Testing
 
Introduction to JRuby
Introduction to JRubyIntroduction to JRuby
Introduction to JRuby
 

Más de Charles Nutter

The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018Charles Nutter
 
Down the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM WonderlandDown the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM WonderlandCharles Nutter
 
Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016Charles Nutter
 
JRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMCharles Nutter
 
JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015Charles Nutter
 
JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015Charles Nutter
 
Fast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible JavaFast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible JavaCharles Nutter
 
Open Source Software Needs You!
Open Source Software Needs You!Open Source Software Needs You!
Open Source Software Needs You!Charles Nutter
 
InvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method HandlesInvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method HandlesCharles Nutter
 
Over 9000: JRuby in 2015
Over 9000: JRuby in 2015Over 9000: JRuby in 2015
Over 9000: JRuby in 2015Charles Nutter
 
Doing Open Source the Right Way
Doing Open Source the Right WayDoing Open Source the Right Way
Doing Open Source the Right WayCharles Nutter
 
Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014Charles Nutter
 
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013Charles Nutter
 
Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013Charles Nutter
 
Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013Charles Nutter
 
The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013Charles Nutter
 
Why JRuby? - RubyConf 2012
Why JRuby? - RubyConf 2012Why JRuby? - RubyConf 2012
Why JRuby? - RubyConf 2012Charles Nutter
 
Aloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRubyAloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRubyCharles Nutter
 

Más de Charles Nutter (20)

The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018
 
Down the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM WonderlandDown the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM Wonderland
 
Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016
 
JRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVM
 
JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015
 
JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015
 
Fast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible JavaFast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible Java
 
Open Source Software Needs You!
Open Source Software Needs You!Open Source Software Needs You!
Open Source Software Needs You!
 
InvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method HandlesInvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method Handles
 
Over 9000: JRuby in 2015
Over 9000: JRuby in 2015Over 9000: JRuby in 2015
Over 9000: JRuby in 2015
 
Doing Open Source the Right Way
Doing Open Source the Right WayDoing Open Source the Right Way
Doing Open Source the Right Way
 
JRuby: The Hard Parts
JRuby: The Hard PartsJRuby: The Hard Parts
JRuby: The Hard Parts
 
Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014
 
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
 
Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013
 
Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013
 
Down the Rabbit Hole
Down the Rabbit HoleDown the Rabbit Hole
Down the Rabbit Hole
 
The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013
 
Why JRuby? - RubyConf 2012
Why JRuby? - RubyConf 2012Why JRuby? - RubyConf 2012
Why JRuby? - RubyConf 2012
 
Aloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRubyAloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRuby
 

Invokedynamic: Tales from the Trenches

  • 1. invokedynamic Tales from the Trenches Sunday, 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 Hat Sunday, February 3, 13
  • 3. invokedynamic 101 • invokevirtual, invokestatic, etc • Predefined behavior • Based on simple VM primitives • invokedynamic • User-defined bytecode • Primitives available as an IR Sunday, 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 CallSite Sunday, 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 site Sunday, 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 handle Sunday, 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
  • 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 yet Sunday, 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 future Sunday, 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 views Sunday, 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...sorta Sunday, 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: areturn Sunday, 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 lands Sunday, 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-build Sunday, 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 invokedynamic Sunday, 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.1 Sunday, 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
  • 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 end Sunday, February 3, 13
  • 26. Mirah class Foo def initialize(a:int) @a = a end def show puts @a end end Sunday, February 3, 13
  • 27. Mirah class Foo def initialize(a:dynamic) @a = a end def show puts @a end end Sunday, 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 issue Sunday, 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 +DeoptimizeALot Sunday, February 3, 13
  • 31. 2011 • Wrapping things up for FCS • Focus on correctness • Some JIT work landing for perf • JRuby a primary test case Sunday, 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 time Sunday, 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 doesn't handle T_LONG and T_DOUBLE properly 2011-06-22; 7057587: JSR 292 - crash with jruby in test/test_respond_to.rb Sunday, 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 doesn't 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 hasBeenInvalidated Sunday, 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: don't 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 not Sunday, 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 code Sunday, 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 versions Sunday, 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 site Sunday, 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 issues Sunday, 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 foo Sunday, 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, permgen Sunday, 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 this Sunday, 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 prototype Sunday, 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 end Sunday, 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 API Sunday, February 3, 13
  • 60. Performance • I believe, I really do Sunday, February 3, 13
  • 61. Performance • I believe, I really do • But it has gone back and forth Sunday, February 3, 13
  • 62. Performance • I believe, I really do • But it has gone back and forth • And I have shamefully not contributed Sunday, 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 benches Sunday, 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 2013 Sunday, 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 bugs Sunday, 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/invokebinder Sunday, 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 challenge Sunday, 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
  • 77. Use in JRuby • Dynamic calls • Dynamic “constants” • Global variables • Thread events • Lazy literals • Instance variables Sunday, 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 invalidations Sunday, February 3, 13
  • 79. Dyncall Guard • GWT • Exact type check for “final” types • Metaclass identity • Slightly weaker than Hotspot • SwitchPoint • Per-class modification guard Sunday, 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 end Sunday, 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 • PROFIT Sunday, 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: retq Sunday, 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 site Sunday, February 3, 13
  • 89. Constants • Lexical lazily-defined variables • Redefinable, but usually static • Single global invalidator (SwitchPoint) • Mostly due to lexical scoping • Constant target Sunday, 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 invalidations Sunday, February 3, 13
  • 91. Foo = 1 $bar = 1   def get_foo Foo end   def get_bar $bar end Sunday, 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} retq Sunday, 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 yadda Sunday, 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} retq Sunday, 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')} ... retq Sunday, 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')} ... retq Sunday, 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')} ... retq Sunday, 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...hmmm Sunday, 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 options Sunday, 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 + indy Sunday, 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 mandelbrot Sunday, 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 mandelbrot Sunday, 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 mandelbrot Sunday, 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 second Sunday, 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 iteration Sunday, 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.com Sunday, February 3, 13