The State of JRuby: 1.5, AOT, Java 7
JRuby 1.5 is out, and InfoQ used that opportunity to catch up with JRuby's Charles Nutter to talk about the big changes in the release, the future of JRuby on the current and future JVMs, and more.
InfoQ What's the state of AOT in JRuby 1.5?
We've always had an ahead-of-time compiler, to produce pre-compiled Ruby code in .class files. But there were a few things missing:
* Those precompiled files would go on to generate "invokers", generated code stubs to bind all the methods and blocks in the file. This caused an additional classloading hit while simultaneously preventing precompiled scripts from working in environments where bytecode generation was forbidden (like applets or Android).
* There was no way to produce "real" Java classes. The .class files produced were 1:1 with .rb files, to provide a nice mechanism for precompiling scripts without generating scads of output. But in practice, that didn't go far enough, and what people really needed was a way to produce real-looking Java classes from Ruby code.
Both of these have been remedied in 1.5, with the addition of several flags:
--java and --javac allow you to generate "real" Java classes from Ruby classes in a given file. You can compile Java code against them, add annotations to them, implement interfaces, reflect their methods, and construct them like normal Java classes.
--handles generates at compile time all "invoker" handles that would have been generated at runtime. This means Ruby scripts can be "completely" precompiled, so that no runtime code generation needs to happen at all.
We also added a --sha1 flag, which produces .class files named based on the SHA1 hash of the actual Ruby source. By using this more standard naming, you can ship .rb files in any directory layout, with .class files somewhere in the classpath, and the association between .rb and .class is maintained.
InfoQ The release notes mentioned a setting 'jruby.jit.codeCache'; are these class files just cached between runs or are they related to AOT functionality?
Both, actually. If you use codeCache=<dir>along with -X+C to force all files to compile on load, you'll see it save off all files that are *actually* loaded during the run. Then ideally you can ship just those classes, rather than precompiling every file in every library (assuming your run touches all files actually needed when the app runs in production. If you use codeCache with normal execution, it will only save off the compiled method bodies that get hot enough to JIT. And if you want to just precompile the lot, you can combine --sha1 and --handles flags to jrubyc with either jarred up class files or codeCache to precompile the lot.
We're going to be putting together some documentation and howtos for all this, but I already blogged a bit about --sha1 and --handles used to precompile Ruby applications for Android.
InfoQ What are the limits of AOT, ie. is it possible to use eval(), metaprogramming, etc?
eval is possible as long as we ship with a parser and interpreter for Ruby code. The only limitation is whether that code will be able to JIT at runtime, which isn't possible in some environments (like Ruboto--JRuby on Android). We are also considering building a stripped-down JRuby runtime that only includes the pieces needed to run precompiled code; in that case, eval wouldn't be possible...but it might be worth it, since it would mean we wouldn't have to ship the parser, interpreter, AST classes, compiler, ASM (for bytecode generation), and potentially more.
If your metaprogramming requires eval, it's subject to the same requirements. But it always works as long as it doesn't require eval. Method and block bodies can be compiled "completely", so it's possible to use define_method and friends even when eval isn't available.
InfoQ What's the status of FFI and other methods for accessing native libraries?
In JRuby 1.5, we switched away from JNA (Java Native Access) and moved to JFFI (Java Foreign Function Interface). Wayne Meissner, our native binding expert, worked extensively on JNA, and he carried that knowledge over to JFFI to make it faster more efficient. All our native library logic, including our binding of POSIX functions not normally available on the JVM (JRuby can work with symlinks, open UNIX sockets, and more), pass through JFFI now, and we ship with JFFI's native bits for all the popular platforms and several weird ones (PPC-AIX! zLinux!).
InfoQ What's the state of to Wayne Meissner's JRuby Native Extension support?
Wayne mocked up an early prototype of a "Ruby C API" for JRuby, with the hope that community members would help us fill it out so we could run at least some of the many native extensions people have written. But working on such a layer is not for everyone, and it didn't move forward in the face of other bugs and features that we deemed more important.
However, there's good news: as part of the Ruby Summer of Code, JRuby will have a dedicated student this summer to help us work on the C extension support. I'm not sure if we'll be able to do enough for *most* extensions to work, but I think we'll be able to provide a safe subset that enables *some* extensions to work. I also hope that by drawing a line in the sand and only implementing the API calls we feel are "safely" implementable, we'll help provide some guidance for C Ruby moving forward.
InfoQ What's the state of 1.9 support?
We did a lot more work on Ruby 1.9 support in this release, and there are users running JRuby in 1.9 mode...but we didn't make a concentrated effort. And this is for a good reason; late last year, The Ruby 1.9.2 manager Yuki Sonoda (yugui) broke with the "Christmas release" tradition by saying that 1.9.2 needed more work and its release would be delayed into 2010. They're now approaching completion of 1.9.2, which means we'll soon have a "stable" version of 1.9 we can begin to chase in earnest. I'd say JRuby 1.6 is the release to watch for more "complete" 1.9 support.
InfoQ What's the state of the MLVM, the Java 7 work, eg. with
MLVM's most interesting and more mature component, invokedynamic, has mostly undergone lateral changes since this past fall. For example, the APIs have been improved, and the underlying implementation in Hotspot has advanced considerably. We've been tracking those changes and keeping JRuby's invokedynamic support in sync. We've also started to see JRuby+invokedynamic run slightly faster than JRuby on Java 6; That's very promising.
Another interesting development is the work on coroutine support for MLVM (and perhaps eventually for JVM proper). Lukas Stadler posted a blog entry recently where he reworked JRuby's Ruby 1.9 "fibers" support (you might know them as coroutines or threadlets or cooperatively-schedule microthreads) to use the coroutine support he'd worked on for Hotspot. The results were very impressive; JRuby fibers plus Lukas's continuations performed better than the green-threaded implementation in Ruby 1.9, a feat we'd thought impossible. Even better, it eliminated the use of native threads, which is how JRuby on standard JVM simulates coroutines now. I don't know if there's any chance of this getting into a real JVM release, but it would be greatly appreciated by any languages that need coroutines or threadlets.
InfoQ Any big plans for 1.6?
We have a few thoughts in mind:
* Continue integrating the rest of the Java platform by adding Maven support to Rake, extension support to jrubyc --java, and many more walkthroughs of using class-based frameworks with JRuby that were difficult or impossible to use before.
* Ruby 1.9.2 support. We've got a lot done, but there's a lot more to do. We definitely could use some community help here.
* A new look at performance in JRuby. We've continued to perform very well compared to the standard Ruby implementations, but there are specific domains where newer implementations like MacRuby and Rubinius easily outperform us. Some of that is due to intrinsic limitations of running on the JVM, like the need for 100% boxed numbers (which severely penalizes us on numeric algorithms). But a lot of it is because we haven't made a major perf push in JRuby since perhaps mid 2008. There's a lot of things we know we can improve...they're just a bit tricky.
InfoQ The JRuby team has written a book on JRuby - what's the target audience?
We have tried to make this book approachable for both Ruby developers interested in using the JVM or Java libraries, and for Java developers looking to move some of their code to Ruby (or some of their web applications to Rails). There's lots of walkthroughs, plenty of beginner-to-intermediate content, and we've got more chapters on the way.
Charles recently blogged about the plans for JRuby performance improvements in future releases.
InfoQ EngineYard now offers commercial JRuby support - any news about this?
Yes! Engine Yard is now offering support + services packages for JRuby users worried about safely investing in JRuby at their organizations. You can get remote customer support, dedicated bug-fixing hours, and even on-site time. We're hoping this will make it easier for large customers to make moves toward JRuby in confidence, and see it as a perfect complement to our top-notch OSS-style support that all users receive (as time permits, of course).
Roy Rapoport Aug 28, 2014