Running JRuby with all indy stuff enabled, for great justice

Charles Oliver Nutter headius at headius.com
Tue Jun 7 07:25:02 PDT 2011


Since I'm guessing perf investigation is set aside for the moment to
help eliminate bugs and crashers, I wanted to describe how to run
JRuby in a mode that utilizes invokedynamic as much as is currently
possible in JRuby.

First off, a property to enable everything:
jruby.invokedynamic.all=true will turn on all current uses of
invokedynamic in JRuby:

* Direct invocation of unframed, non-varargs Ruby to Java invocations
* Direct invocation of unframed, non-varargs Ruby to Ruby invocations
* Invocation via DynamicMethod stubs for remaining non-super invocations
* SwitchPoint constant lookup cache invalidation

This covers the majority of invocations from Ruby code and at least
one caching mechanism. All the invocation paths have at least a few
layered handles, with the DynamicMethod paths having the most
complexity.

I am also attempting to get JRuby's test suite to run clean with
invokedynamic enabled. From the JRuby source dir, you will be able to
run "ant test-compiled-indy" to run with JRuby's JIT threshold set to
0 (to force methods to JIT before execution) and with all
invokedynamic stuff turned on (using the property above). I don't
think the suite runs to completion currently, but I'm working on it.
For now it may be easier to run files directly.

A few heavy-hitting tests (that hit many paths in a single file):

test/mri/sample/test.rb (a first line of defense with many Ruby code
forms all in one file)
test/testCompiler.rb (tests a number of basic Ruby code forms run
through JRuby's compiler)

Of course most test* scripts under test/ are useful. Until the full
test run works properly, it might be worth stitching together as many
of them as you can into a local subset test run.

A few interesting flags for JRuby:

* -X<property-like> (equivalent to passing -Djruby.<property-like> to
underlying JVM)
* -X+C (force files to compile-on-load, rather than interpret first)
* -d (enable debug logging, such as errors when -X+C fails)
* property jruby.jit.logging.verbose=true or
-Xjit.logging.verbose=true (log when Ruby methods fail to JIT)
* property jruby.invokedynamic.log.binding=true (log methods bound via
invokedynamic and how they are bound...see above three invocation
paths)
* property jruby.invokedynamic.maxfail=# (2 by default) (number of
cache misses at which to degrade the invokedynamic binding to a simple
IC. Up to this limit JRuby will chain GWT together as a PIC)

A few interesting files:

* src/org/jruby/runtime/invokedynamic/InvokeDynamicSupport.java (all
binding plumbing for invokedynamic-based invocation)
* src/org/jruby/compiler/impl/InvokeDynamicCacheCompiler.java (caching
and lazy literal construction via invokedynamic)
* src/org/jruby/RubyInstanceConfig.java (config object for a JRuby
instance; search for invokedynamic to see other properties)

Caveats:

* JRuby utilizes some native code for POSIX features missing from the
JDK (file stat'ing, full UNIX permissions, child process control, unix
sockets, etc). The library for this has been tested and loads properly
against OS X universal builds, but does not appear to work properly
against some (all?) non-universal OpenJDK OS X builds. It should work
fine on Linux or Solaris against any OpenJDK build. You can disable
the use of this native library via property jruby.native.enabled=false
or -Xnative.enabled=false passed to JRuby.
* There may be class verification errors under some circumstances due
to JRuby's compiler emitting some dead code that ASM handles badly
(rewriting into unverifiable code and/or bad stack maps). I'm working
with ASM guys to try to fix ASM (fixing JRuby would require some deep
modifications to the compiler to recognize dead code paths).
* Because these are test runs, they will often not test bound
invocations of invokedynamic call sites. In other words, many
invocations will only be hit once, bind their call site, and then do a
slow path invocation that first time. This will lower the number of
dynamic invocations fully utilizing invokedynamic.

---

Hopefully this will help roust out remaining bugs and crashers in
invokedynamic, like the "tak" crash I reported in the performance
thread. Please let me know if there's anything I can do to help.

- Charlie


More information about the mlvm-dev mailing list