Thursday, May 14, 2009

BiteScript 0.0.2 Scripting Examples

I just released BiteScript 0.0.2, which mainly fixes some issues defining packages and non-public classes.

BiteScript is basically just a simple DSL for generating JVM bytecode. I use it in Duby and now in the "ruby2java" compiler we'll be using to turn Ruby classes into Java classes.

I've blogged about BiteScript here before, but I realized today I never posted any simple "hello world" examples. So here's a few of them, all using the command-line "scripting" mode.

First, the simplest version:

main do
ldc "Hello, world!"
aprintln
returnvoid
end

Obviously this is using a predefined "aprintln" macro, since there's no "aprintln" opcode on the JVM. Here's a longer version that shows how a macro would be defined, and accepts one argument
import java.lang.System
import java.io.PrintStream

macro :aprintln do
getstatic System, :out, PrintStream
swap
invokevirtual PrintStream, println, [Object]
end

macro :aprint do
getstatic System, :out, PrintStream
swap
invokevirtual PrintStream, print, [Object]
end

main do
ldc "Hello, "
aprint
aload 0
aaload 0
aprintln
returnvoid
end

And of course this is just Ruby code, so you can just use Ruby to alter the generation of code:
main do
5.times do
ldc "Wow!"
aprintln
end
returnvoid
end

These "BiteScripts" can all be either run with the "bite" command or compiled with the "bitec" command:
$ bite examples/using_ruby.bs 
Wow!
Wow!
Wow!
Wow!
Wow!

$ bitec examples/using_ruby.bs

$ javap -c examples/using_ruby
Compiled from "examples.using_ruby.bs"
public class examples.using_ruby extends java.lang.Object{
public static void main(java.lang.String[]);
Code:
0: ldc #9; //String Wow!
2: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream;
5: swap
6: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
9: ldc #9; //String Wow!
11: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream;
14: swap
15: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
18: ldc #9; //String Wow!
20: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream;
23: swap
24: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
27: ldc #9; //String Wow!
29: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream;
32: swap
33: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
36: ldc #9; //String Wow!
38: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream;
41: swap
42: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
45: return

}

This last example shows the resulting JVM bytecode as well.

Future plans for BiteScript include making it have better error detection (right now it just falls back on the JVM bytecode verifier, which is not the most descriptive thing in the world) and improving the API to more easily handle all the various combinations of class, field, and method modifiers. I'd also like to make it detect if you're doing bad things to the stack to save you the hassle of interpreting verification errors that may not happen until runtime.

Anyway, give it a try and feel free to contribute; the code is all Ruby, wrapping the ASM bytecode library, so anyone that knows Ruby can tweak it. The project page and wiki are hosted at Kenai.com: http://kenai.com/projects/jvmscript

And if you're not up on the JVM or JVM bytecodes, the JVM Specification is an easy-to-read complete reference for code targeting the JVM, and here is my favorite JVM opcode quickref.

Help JRuby by Fixing RubySpecs

A number of you have asked how you can help JRuby development. Well there's actually an easy way: fix RubySpec failures.

You may have noticed we periodically update our RubySpec "stable" revision number, and usually have to file a few bugs. This isn't because we don't want to fix those issues...on the contrary, we would love to fix them. We just don't have enough manpower, and there's usually harder issues we need to tackle first.

But most of the failures are easy to fix, and a lot of JRuby newcomers have gotten their feet wet fixing them. So here's a short guide on how to run the specs and fix them quickly.

1. Get a JRuby working copy and build it

This is as simple as 'git clone git://github.com/jruby/jruby.git', then 'cd jruby' and 'ant'. You'll need Apache Ant 1.7 and Java 5/1.5 or higher (grab "Java SE Development Kit" from the Java SE downloads page.

2. Run the CI spec run

We have a clean spec run that should be clean for you before you start. Just run "ant spec-short" and it will pull the mspec and rubyspec repositories, roll them to the stable versions, and run all known good specs. Now you're ready to investigate specific failures.

3. Run specific spec files with bugs reported

You can look in Jira under the "RubySpec" category, or look under spec/tags/ruby for "tag" files listing failing specs and Jira bug numbers. Once you find something you'd like to investigate, run that spec file using "bin/jruby spec/mspec/bin/mspec <path/to/spec/file>". For example to set the Range#initialize failures I just reported, run "bin/jruby spec/mspec/bin/mspec spec/ruby/core/range/initialize_spec.rb".

Now you can proceed to fixing it.

4. Identify where the problem is.

Most of the core classes are pretty easy to locate. Any classes in the "core" specs will have a Java class named Ruby, like RubyArray, RubyRange, and so on. They're generally located in src/org/jruby. If you know any Java, these files are pretty easy to follow, and we're standing by on IRC or on the mailing list to hold your hand at the start.

5. Create a patch and submit it to the bug

Once you have a working fix, you can go ahead create a patch, either with "git diff > somefile.patch" or by committing it to your local repository and using "git format-patch -1" to create a formatted patch for the topmost commit. Some git-fu may be necessary, so I usually just use "git diff".

That's all there is to it! You'll be a JRuby contributor in no time!

fork and exec on the JVM? JRuby to the Rescue!

Today David R. MacIver pinged me in #scala and asked "headius: Presumably you guys have spent quite a lot of time trying to make things like system("vim") work correctly in JRuby and failing? i.e. I'm probably wasting my time to attempt similar?"

My first answer was "yes", since there's no direct way to exec a program like vim (which wants a real terminal) and have it work on the JVM. The JVM's process launching gives the newly-spawned processes the child side of piped streams, which you then have to manually pump (which is what we do in JRuby's system, backtick, and exec methods). Under these circumstances, vim may start up, but it's certainly not functional.

But then I got to thinking...if you were doing this in C, you'd fork+exec and all would be happy. But we can't fork+exec on the JVM..OR CAN WE?

As you should know by now, JRuby ships with FFI, a library that allows you to bind any arbitrary C function in Ruby code. So getting fork+exec to work was a simple matter of writing a little Ruby code:

require 'ffi'

module Exec
extend FFI::Library

attach_function :my_exec, :execl, [:string, :string, :varargs], :int
attach_function :fork, [], :int
end

vim1 = '/usr/bin/vim'
vim2 = 'vim'
if Exec.fork == 0
Exec.my_exec vim1, vim2, :pointer, nil
end

Process.waitall

Running that with JRuby (I tried master, David tried 1.3.0RC1, and 1.2.0 works too) brings up a full-screen vim session, just like you'd expect, and it all just works. No other JVM language can do this so quickly and easily.

We'll probably try to generalize this into an optional library JRubyists can load (require 'jruby/real_exec' or similar) and perhaps add fork and exec to jna-posix so that the other JVM languages can have sweet, sweet process launching too.

JRuby rocks.

Update: The biggest problem with using fork+exec in this way is that you can't guarantee *nothing* happens between the fork call and the exec call. If, for example, the JVM decides to GC or move memory around, you can have a fatal crash at the JVM process level. Because of that, I don't recommend using fork + exec via FFI in JRuby, even though it's pretty cool.

However, since this post I've learned of the "posix_spawn" function available on most Unix variants. It's basically fork + exec in a single function, plus most of the typical security and IO tweaks you might do after forking and before execing. It's definitely my recommended alternative to fork+exec for JRuby, and to make that easier I've bundled it up as the "spoon" gem (gem install spoon) which provides spawn and spawnp to JRuby users directly. Here's an example session using Spoon to launch JRuby as a daemon. If you just need fork+exec on the JVM, posix_spawn or the Spoon gem are the best way to do it.

Wednesday, May 13, 2009

JRuby Nailgun Support in 1.3.0

I've merged changes into master (to be 1.3 soon) that should make Nailgun easier to use. And 1.3 will be the first release to include all NG stuff in the binary dist.

  • jruby --ng-server starts up a server. You can manage it however you like
  • jruby --ng uses the Nailgun client instead of launching a new JVM for the command you run. You'll just need to run make in tool/nailgun to build the ng executable (already built for you on Windows).
Future improvements will include having --ng start up the server for you if you haven't started it, passing signals through (don't expect signals to work at all right now), better management of threads and commands, and so on. But it's a good start, and people can try to play with it and report issues more easily now.

Heres a sample session:
~/projects/jruby ➔ cd tool/nailgun/ ; make ; cd -
Building ng client. To build a Windows binary, type 'make ng.exe'
gcc -Wall -pedantic -s -O3 -o ng src/c/ng.c
ld warning: option -s is obsolete and being ignored
/Users/headius/projects/jruby

~/projects/jruby ➔ jruby --ng-server
NGServer started on all interfaces, port 2113.
^Z
[1]+ Stopped jruby --ng-server

~/projects/jruby ➔ bg
[1]+ jruby --ng-server &

~/projects/jruby ➔ jruby --ng -e "puts 1"
1

~/projects/jruby ➔ time jruby -e "puts 1"
1

real 0m0.609s
user 0m0.482s
sys 0m0.119s

~/projects/jruby ➔ time jruby --ng -e "puts 1"
1

real 0m0.073s
user 0m0.010s
sys 0m0.018s

Update: For those not familiar, "NailGun is a client, protocol, and server for running Java programs from the command line without incurring the JVM startup overhead. Programs run in the server (implemented in java), triggered by the client (written in C), which handles all I/O."

Update 2: It's been brought to my attention that we no longer ship a pre-configured Makefile for the ng client, so your build command line should actually look like:
~/projects/jruby ➔ cd tool/nailgun/ ; ./configure ; make ; cd -
Alternatively, you can run "ant build-ng" in the JRuby root, which will do largely the same thing for you using Ant.

Thursday, April 30, 2009

Stand and Be Counted

In the spirit of Nick Sieger's short statement on the recent uproar over Matt Aimonetti's "pr0n star" talk, I'm posting my one and only blog response to the whole thing.

Unlike Nick, I too often have used this blog as a soapbox. And too often I've ground my personal axe against projects that may or may not have deserved it. I'm human, I'm passionate and proud of my work, and I'm defensive of what we've accomplished, so I don't think this is surprising. I also see the same passion and pride in the Ruby community at large, and it's why I'm much more interested in attending Ruby conferences than Java conferences, where many attendees just seem to be going through the motions. And I know I've crossed a line at times, making or taking things too personal, and hopefully I've apologized or corrected myself whenever that's happened. If not, mea culpa.

But there's a disturbing trend in the Ruby community I haven't had to deal with since high school: in preference to open inclusion, more and more Rubyists seem to choose exclusivity.

This recent firestorm has continued in large part, I believe, because of the poor initial response by folks involved. Rather than recognize that there are people with different views, taking offense at different ideas and images, some decided to say "fuck you, this is who I am" and further alienate those people. I certainly don't expect we as passionate individuals won't commit occasional faux pas, especially when trying to be funny or provocative and especially when coming from different backgrounds that may be more or less accepting of certain behaviors. But to claim no responsibility for an obvious mistake, indeed to claim it's somehow the fault of the offended, or American sensibility, or political correctness...well that's just sophomoric.

I think to some extent we can understand (but not excuse) such behavior by realizing that the Ruby (or perhaps the Rails) community is largely a very *young* community. That's a large part of why this community is so passionate, why they're so committed to their ideals, why they're so opinionated, why they're so much more fun to hang out with than many 30-year programmers from other communities who've had the life sucked out of them. It's also a reason so many in the Ruby (or perhaps the Rails) community seem to act like they're in high school, forming cliques, sitting at their own tables, snubbing the new kids or the weird kids or anyone they perceive as "trying to be cool."

Have you been invited to any exclusive Ruby communities? I've been invited to a couple, and without exception I've found the idea offensive every time. In some cities, there are now multiple tiers of Ruby group: one for the proles, where anyone is welcome and everyone is either new to Ruby, a little weird, or both; and then perhaps one or two levels of more "exclusive" groups, usually more "advanced" and sometimes invite-only but generally exclusionary in some way.

There's also a technical "coolness" exclusivity many projects have had to cope with. Folks working on JRuby and IronRuby, for example, have had to deal with perceptions that they're either less "cool" because of their platform of choice or at least somehow less "Ruby" because they're not following the same golden path everyone else follows. Or perhaps their employers are out to take over Ruby, or they're going to infect Ruby with a bunch more "new" people who don't "get it". All the while the folks that use and work on these projects are working just as hard as anyone else to bring Ruby to the world, staying true to what makes Ruby special, and largely going against the grain in their original communities as well. Being snubbed, mocked, or attacked is often their reward.

You start to see a pattern here, yes?

So let's spell it out. I like the Ruby community because it's filled with people who love playing with new technology, without biases and prejudices getting in the way. My closest friends in the community are people like me, who find it repugnant that being opinionated has been too often equated with being rude and boorish, exclusionary and sophomoric, or simply mean. We are all here because of our love of technology, all here because we didn't feel like we fit in other places that weren't so passionate about beautiful code and fresh ideas. We are all here because we don't care if you're male or female, religious or irreligious, young or old, experienced or inexperienced, beautiful or plain, conservative or liberal, tall or short, fat or thin, foreign or domestic, gay or straight, black or white, or any grey areas in-between. We are all here because we love that more and more people like us join the community every day...the same people some of us immediately judge and box into their own subcool subgroups.

I don't want to join your damn clique. I don't think it's ok to set people aside or treat them like dirt because they don't believe what you believe or because they have their own way of thinking and acting or because they're not as worldly and mature and oh-so-smug as you are. I don't believe in "rock stars" and I don't believe that dubious title gives anyone the right to be an asshole to others or to have free reign to act any way they choose. I don't care what kind of car you drive, what house you live in, or what clothes you wear...and I sure as hell don't care how many people follow you on Twitter.

What I do care about is whether you're interested in sitting down and hacking out some code, looking at new projects with an open mind, helping someone new (maybe me) improve their skills, being part of something larger than yourself. If you promise not to treat me like a weirdo or a rock star, I promise to talk openly about your ideas, to show you the heart and soul of my code, and to freely share my thoughts...no matter who you are. I hope you'll attend my presentations and/or try out my projects, and in exchange I'll try to do the same the same for you. I hope you'll walk up to me at conferences and tell me about whatever "crazy" or "stupid" idea you have, and I guarantee to listen since it's probably not as crazy or stupid as you think. And I expect you to do the same for everyone else in the community and not treat me or anyone else any differently.

Now, let's move forward and get back to hacking and having fun!

Saturday, April 25, 2009

Setting up Typo on JRuby

I figured I'd give Typo a try on JRuby today. It has been working for quite a while, but with the GlassFish gem improving so much I thought it would be good to write up an updated walkthrough. It's pretty simple.

BTW, is Typo still the preeminent blog package for Rails? I certainly don't want to be out of fashion.

Prerequisites:

  1. MySQL already set up and working, with TCP sockets enabled (or I guess you can use SQLite too)
  2. Java (sudo apt-get install sun-java6-jdk or whatever's appropriate for your platform)
  3. JRuby (download, unpack, put bin/ in PATH)
  4. Appropriate gems installed (rails, activerecord-jdbcmysql-adapter, glassfish or mongrel)
The process:
  1. Download Typo. The gem unfortunately tries to install native extensions like sqlite3 and mysql (I sure wish they wouldn't do that!)
  2. Unpack the Typo zip wherever you want your blog site to live and cd into that directory
  3. Edit config/database.yml.example to your liking, replacing "mysql" with "jdbcmysql" and save it as config/database.yml
  4. Create the database:
    jruby -S rake db:create RAILS_ENV=production
  5. Migrate the database:
    jruby -S rake db:migrate RAILS_ENV=production
  6. Run the server:
    glassfish -p <port> -e production [and whatever other options you want]
    or
    jruby script/server -p <port> -e production
  7. Set up Apache to point at your new Typo instance (optional)
That's all there is to it! You'll want to be the first one to hit your new blog, so you can set up your admin account and lock down the server.

Perhaps it's time I finally moved my blog off Blogger and on to a JRuby-hosted server, eh?

Suggestions, improvements to this process? Add to comments and I'll update the post.

Apache + JRuby + Rails + GlassFish = Easy Deployment!

It occurred to me today that a lot of people probably want a JRuby deployment option that works with a front-end web server. I present for you the trivial steps required to host a JRuby server behind Apache.


Update: It's worth mentioning that this works fine with JRuby + Mongrel too, though Mongrel doesn't automatically multithread without this patch and Rails' production.rb config.threadsafe! line uncommented. The GlassFish gem will automatically multithread with several JRuby instances (in the same server process) by default or a single JRuby instance with config.threadsafe! uncommented.

Prerequisites:
  1. Apache with mod_proxy_http enabled (sudo a2enmod proxy_http on Ubuntu)
  2. Java (sudo apt-get install sun-java6-jdk or the openjdk flavors if you like)
  3. JRuby (download, unpack, put bin/ in PATH)
  4. gems appropriate to run your app with JRuby (e.g. rails, activerecord-jdbcsqlite3-adapter, etc)
  5. production DB all set to go
Ok. I'm no Apache expert, so I'm sure there's some tweaking necessary for this. Please add your tweaks and suggestions in comments. But basically, all you need to do is run your app using the GlassFish gem and set up Apache to proxy to it. It's that simple.
  1. Install the glassfish gem
    gem install glassfish
  2. From your application directory, run glassfish with these options:
    glassfish -p <port> -e production -c <context> -d
  3. Add ProxyPass and ProxyPassReverse lines to Apache (whereever is appropriate on your system) for the GlassFish server instance. For example, if <port> is 9000 and <context> is foo:
    ProxyPass /foo http://localhost:9000/foo
    ProxyPassReverse /foo http://localhost:9000/foo
  4. Reload Apache config, however is appropriate for your system
You'll now be able to access your app via http://servername/foo, and requests will all proxy to the GlassFish server instance.

This doesn't do anything to manage the server instance, but since GlassFish can start up as a daemon now, it should be easy to wire into whatever you normally use for that.

A few caveats:
  • I had some trouble getting mod_proxy to allow requests to proxy through. There's probably a right way I'm not doing, so I won't say what I did. If you know the ideal mod_proxy config for this sort of thing, post it in comments
  • Although the GlassFish gem is really nice already, we're still working minor kinks out of it and it may still have minor bugs. If you run into something, let us know and we'll get it fixed (and of course, you can use this mod_proxy setup with Mongrel too, if you like).
  • I'd love to get some help putting together something that manages servers similar to Phusion Passenger, because that's really the only missing piece here.
I'll update this post as suggestions come in. Enjoy!

Update: Dberg suggests the following improvement:
the one thing you want to remember to do also is to exclude the static assets that normally get served out of rails. To do this simply add some proxypass exclude lines like

ProxyPass /images !
ProxyPass /javascripts !
ProxyPass /stylesheets

Then make sure DocumentRoot is set to the right place for these files and you will get a slight performance boost !
Thanks for that!

Wednesday, April 22, 2009

The Future: Part One

There's been a lot of supposition about the future lately, and I've certainly read and succumbed to the temptation of the prognosticator. I'm not going to comment on any of the players or put forward my own suppositions about what might happen. What I will do here is talk about what *should* happen.

It's apparent that the Java platform is at a crossroads. One path leads to irrelevance, be it through general apathy that important technologies are getting sidelined, or through active emigration due to bureaucratic processes and waterfall platform evolution. The other path leads to a bright, open future, where polyglots romp and play with fresh new languages and developers have freedom to use whatever tools they feel are necessary for a given job. Given the large investment many of us have in this platform, we need to start talking now about which direction we want to go.

I've been doing a lot of thinking about the future of the Java platform and my future developing for it, and I've come up with a few things I believe must happen soon to ensure the future of the JVM and the applications and languages built for it.

Languages

As you might expect from me, the first area involves supporting many languages on the JVM. Over the past three years we've seen a spectacular transformation take place. The "Java" VM has become a truly multi-language platform. People are putting into production applications running all sorts of languages, often writing absolutely no Java to do so. And this is how things must be...this is how the platform is going to survive.

As I see it there are currently three primary players in the language domain: JRuby, Scala, and Groovy (in no particular order). I include these three due to the relative completeness of their implementations, vague popularity metrics, and availability of production use cases. These three languages, one static and two dynamic, bear further exploration.

JRuby represents the promise of off-platform languages being brought to the JVM. Rather than creating a language specifically tailored to fit well into the JVM's type system and limitations, we have managed to take a drastically different language and implement enough of it to be the only "alternative" implementation realistically considered for production applications. And in doing so we've had to stretch the platform. We've created native binding libraries, wired in POSIX functions the JDK doesn't provide, implemented our own core types like Strings, Arrays, and regular expressions, and done all this while managing to deliver the best performing compatible Ruby implementation available. And where the other two primary language contenders largely pull developers from other areas of the Java platform, JRuby actually brings in many developers that might not otherwise ever use the JVM. JRuby stretches and grows the platform.

Groovy is the second dynamic language under consideration. Groovy represents taking the best features of a number of dynamic languages and wiring them into a Java-like syntax that's easy for existing Java developers to learn. Groovy provides a solid dynamic language foundation without breaking Java type-system requirements like ahead-of-time compiled classes and static method signatures, allowing it to enlist directly in newer APIs that depend on those requirements. And while many developers come to Groovy from other areas of the Java platform, they might also have completely left the platform if not for Groovy. Groovy provides for Java developers a "dynamic layer" that doesn't require them to learn a new platform and a new set of libraries. And so Groovy's strength is in maintaining the platform and stemming the bleeding of developers to off-platform dynamic languages.

Scala, it must be stated, is the current heir apparent to the Java throne. No other language on the JVM seems as capable of being a "replacement for Java" as Scala, and the momentum behind Scala is now unquestionable. While Scala is not a dynamic language, it has many of the characteristics of popular dynamic languages, through its rich and flexible type system, its sparse and clean syntax, and its marriage of functional and object paradigms. The supposed weakness of Scala as being "too complicated" or "too rich" can be countered by developing coding standards, creating more robust editors and tools, and by better educating polyglots on how best to use Scala. Scala represents the rebirth of static-typed languages on the JVM, and like JRuby it has also begun to stretch the capabilities of the platform in ways Java never could.

Among the secondary players I include language implementations like Jython, Clojure, and Rhino. While still in early days of adoption (or in Jython and Rhino's cases, early days of re-awakening), they represent similar aspects to the primary three languages. For purposes of discussion, we'll leave it at that for now.

In order for the platform to embrace these and many future languages, several things need to happen:

  • Ongoing work on these languages must be funded in such a way as to avoid product lock-in. Funding them by tying them to specific technologies will only fracture development communities, and likely damage any existing open-source contributor base.
  • There must be paid support offerings for these languages outside of specific products. For people interested in running JRuby on Rails, Grails, or Liftweb, there must be support channels they can follow, regardless of product bundling attempts. In the JRuby world, for example, we receive many requests for paid support, either in the form of hired guns to optimize an application or through targeting resources to critical bugs. And so far, we have been unable to offer such support.
  • We must continue the work started on the OpenJDK and MLVM projects. OpenJDK has enabled such projects as Shark (Hotspot on LLVM) and the MLVM (JVM extensions for non-Java language features), and we must see these efforts through to completion.
  • Finally, we need a "languages czar" that can coordinate the technical aspects of these various projects and help direct resources where needed. This would largely be a community-cultivating role, but as a sort of "open-source manager" to ensure development efforts are both cooperating and not being needlessly duplicated.
I believe it's absolutely vital that these tasks be met, or we risk the future of the platform entirely. And losing must not be an option, lest we fall back into proprietary alternatives controlled by a single entity.

More to come.

Monday, April 13, 2009

JRuby Moves to Git

We have successfully migrated JRuby development to Git!

The main repository is on the JRuby kenai.com project, but most folks will just want to clone the official mirror on Github. The mirror lags by no more than five minutes, and we'll eliminate that lag soon.

Kenai: git://kenai.com/jruby~main
Github: git://github.com/jruby/jruby.git

The Github repository is also attached to the official Github "jruby" user.

The CI server has already been updated to point at the new repository on kenai, and nightly builds have been running for several days. If you just want to grab a current nightly snapshot, you can do that from github's capabilities or by visiting the nightly build page:

http://jruby.headius.com:8080/hudson/job/jruby-dist/

The old SVN repository on Codehaus is now defunct for JRuby development and will not be updated any more. We will likely remove the JRuby branches and trunk soon and replace them with a README pointing to the new repository locations.

Why Git?

We've known for a long time that we wanted to move to a distributed SCM, and had narrowed it down to Mercurial and Git.

For a long time Mercurial was the front-runner, partly because we were more familiar with it and partly because kenai.com, the site where we're moving JRuby's project hosting (and a JRuby on Rails-based site, btw), only supported Subversion and Mercurial.

But a few things changed our minds over the past couple months:
  • Kenai added git support
  • We realized that we'd get more Rubyists contributing if we had a mirror on Github
  • We became more comfortable with Git
Ultimately, the move to Git mostly came down to politics: Rubyists like Git better, and we're a Ruby-related project. Had we been Jython, we'd probably have chosen Mercurial.

Enjoy!

Thursday, April 02, 2009

How JRuby Makes Ruby Fast

At least once a year there's a maelstrom of posts about a new Ruby implementation with stellar numbers. These numbers are usually based on very early experimental code, and they are rarely accompanied by information on compatibility. And of course we love to see crazy performance numbers, so many of us eat this stuff up.

Posting numbers too early is a real disservice to any project, since they almost certainly don't represent the eventual real-world performance people will see. It encourages folks to look to the future, but it also marginalizes implementations that already provide both compatibility and performance, and ignores how much work it has taken to get there. Given how much we like to see numbers, and how thirsty the Ruby community is for "a fastest Ruby", I don't know whether this will ever change.

I thought perhaps a discussion about the process of optimizing JRuby might help folks understand what's involved in building a fast, compatible Ruby implementation, so that these periodic shootouts don't get blown out of proportion. Ruby can be fast, certainly even faster than JRuby is today. But getting there while maintaining compatibility is very difficult.

Performance Optimization, JRuby-style

The truth is it's actually very easy to make small snippits of Ruby code run really fast, especially if you optimize for the benchmark. But is it useful to do so? And can we extrapolate eventual production performance from these early numbers?

We begin our exploration by running JRuby in interpreted mode, which is the slowest way you can run JRuby. We'll be using the "tak" benchmark, since it's simple and easy to demonstrate relative performance at each optimization level.
# Takeuchi function performance, tak(24, 16, 8)
def tak x, y, z
if y >= x
return z
else
return tak( tak(x-1, y, z),
tak(y-1, z, x),
tak(z-1, x, y))
end
end

require "benchmark"

N = (ARGV.shift || 1).to_i

Benchmark.bm do |make|
N.times do
make.report do
i = 0
while i<10
tak(24, 16, 8)
i+=1
end
end
end
end

And here's our first set of results. I have provided Ruby 1.8.6 and Ruby 1.9.1 numbers for comparison.
Ruby 1.8.6p114:
➔ ruby bench/bench_tak.rb 5
user system total real
17.150000 0.120000 17.270000 ( 17.585128)
17.170000 0.140000 17.310000 ( 17.946869)
17.180000 0.160000 17.340000 ( 18.234570)
17.180000 0.150000 17.330000 ( 17.779536)
18.790000 0.190000 18.980000 ( 19.560232)

Ruby 1.9.1p0:
➔ ruby191 bench/bench_tak.rb 5
user system total real
3.570000 0.030000 3.600000 ( 3.614855)
3.570000 0.030000 3.600000 ( 3.615341)
3.560000 0.020000 3.580000 ( 3.608843)
3.570000 0.020000 3.590000 ( 3.591833)
3.570000 0.020000 3.590000 ( 3.640205)

JRuby 1.3.0-dev, interpreted, client VM
➔ jruby -X-C bench/bench_tak.rb 5
user system total real
24.981000 0.000000 24.981000 ( 24.903000)
24.632000 0.000000 24.632000 ( 24.633000)
25.459000 0.000000 25.459000 ( 25.459000)
29.122000 0.000000 29.122000 ( 29.122000)
29.935000 0.000000 29.935000 ( 29.935000)

Ruby 1.9 posts some nice numbers here, and JRuby shows how slow it can be when doing no optimizations at all. The first change we look at, and which we recommend to any users seeking best-possible performance out of JRuby, is to use the JVM's "server" mode, which optimizes considerably better.
JRuby 1.3.0-dev, interpreted, server VM
➔ jruby --server -X-C bench/bench_tak.rb 5
user system total real
8.262000 0.000000 8.262000 ( 8.192000)
7.789000 0.000000 7.789000 ( 7.789000)
8.012000 0.000000 8.012000 ( 8.012000)
7.998000 0.000000 7.998000 ( 7.998000)
8.000000 0.000000 8.000000 ( 8.000000)

The "server" VM differs from the default "client" VM in that it will optimistically inline code across calls and optimize the resulting code as a single unit. This obviously allows it to eliminate costly x86 CALL operations, but even more than that it allows optimizing algorithms which span multiple calls. By default, OpenJDK will attempt to inline up to 9 levels of calls, so long as they're monomorphic (only one valid target), not too big, and no early assumptions are changed by later code (like if a monomorphic call goes polymorphic later on). In this case, where we're not yet compiling Ruby code to JVM bytecode, this inlining is mostly helping JRuby's interpreter, core classes, and method-call logic. But already we're 3x faster than interpreted JRuby on the client VM.

The next optmization will be to turn on the compiler. I've modified JRuby for the next couple runs to *only* compile and not do any additional optimizations. We'll discuss those optimizations as I add them back.
JRuby 1.3.0-dev, compiled (unoptimized), server VM:
➔ jruby --server -J-Djruby.astInspector.enabled=false bench/bench_tak.rb 5
user system total real
5.436000 0.000000 5.436000 ( 5.376000)
3.655000 0.000000 3.655000 ( 3.655000)
3.662000 0.000000 3.662000 ( 3.662000)
3.683000 0.000000 3.683000 ( 3.683000)
3.668000 0.000000 3.668000 ( 3.668000)

By compiling, without doing any additional optimizations, we're able to improve performance 2x again. Because we're now JITing Ruby code as JVM bytecode, and the JVM eventually JITs JVM bytecode to native code, our Ruby code actually starts to benefit from the JVM's built-in optimizations. We're making better use of the system CPU and not making nearly as many calls as we would from the interpreter (since the interpreter is basically a long chain of calls for each low-level Ruby operation.

Next, we'll turn on the simplest and oldest JRuby compiler optimization, "heap scope elimination".
JRuby 1.3.0-dev, compiled (heap scope optz), server VM:
➔ jruby --server bench/bench_tak.rb 5
user system total real
4.014000 0.000000 4.014000 ( 3.942000)
2.776000 0.000000 2.776000 ( 2.776000)
2.760000 0.000000 2.760000 ( 2.760000)
2.769000 0.000000 2.769000 ( 2.769000)
2.768000 0.000000 2.768000 ( 2.769000)

The "heap scope elimination" optimization eliminates the use of an in-memory store for local variables. Instead, when there's no need for local variables to be accessible outside the context of a given method, they are compiled as Java local variables. This allows the JVM to put them into CPU registers, making them considerably faster than reading or writing them from/to main memory (via a cache, but still slower than registers). This also makes JRuby ease up on the JVM's memory heap, since it no longer has to allocate memory for those scopes on every single call. This now puts us comfortably faster than Ruby 1.9, and it represents the set of optimizations you see in JRuby 1.2.0.

Is this the best we can do? No, we can certainly do more, and some such experimental optimizations are actually already underway. Let's continue our exploration by turning on another optimization similar to the previous one: "backtrace-only frames".
JRuby 1.3.0-dev, compiled (heap scope + bracktrace frame optz), server VM:
➔ jruby --server -J-Djruby.compile.frameless=true bench/bench_tak.rb 5
user system total real
3.609000 0.000000 3.609000 ( 3.526000)
2.600000 0.000000 2.600000 ( 2.600000)
2.602000 0.000000 2.602000 ( 2.602000)
2.598000 0.000000 2.598000 ( 2.598000)
2.602000 0.000000 2.602000 ( 2.602000)

Every Ruby call needs to store information above and beyond local variables. There's the current "self", the current method visibility (used for defining new methods), which class is currently the "current" one, backref and lastline values ($~ and $_), backtrace information (caller's file and line), and some other miscellany for handling long jumps (like return or break in a block). In most cases, this information is not used, and so storing it and pushing/popping it for every call wastes precious time. In fact, other than backtrace information (which needs to be present to provide Ruby-like backtrace output), we can turn most of the frame data off. This is where we start to break Ruby a bit, though there are ways around it. But you can see we get another small boost.

What if we eliminate frames entirely and just use the JVM's built-in backtrace logic? It turns out that having any pushing/popping of frames, even with only backtrace data, still costs us quite a bit of performance. So let's try "heap frame elimination":
JRuby 1.3.0-dev, compiled (heap scope + heap frame optz), server VM:
➔ jruby --server -J-Djruby.compile.frameless=true bench/bench_tak.rb 5
user system total real
2.955000 0.000000 2.955000 ( 2.890000)
1.904000 0.000000 1.904000 ( 1.904000)
1.843000 0.000000 1.843000 ( 1.843000)
1.823000 0.000000 1.823000 ( 1.823000)
1.813000 0.000000 1.813000 ( 1.813000)

By eliminating frames entirely, we're a good 33% faster than the fastest "fully framed" run you'd get with stock JRuby 1.2.0. You'll notice the command line here is the same; that's because we're venturing into more and more experimental code, and in this case I've actually forced "frameless" to be "no heap frame" instead of "backtrace-only heap frame". And what do we lose with this change? We no longer would be able to produce a backtrace containing only Ruby calls, so you'd see some JRuby internals in the trace, similar to how Rubinius shows Rubinius internals. But we're getting respectably fast now.

Next up we'll turn on some optimizations for math operators.
JRuby 1.3.0-dev, compiled (heap scope, heap frame, fastops optz), server VM:
➔ jruby --server -J-Djruby.compile.frameless=true -J-Djruby.compile.fastops=true bench/bench_tak.rb 5
user system total real
2.291000 0.000000 2.291000 ( 2.225000)
1.335000 0.000000 1.335000 ( 1.335000)
1.337000 0.000000 1.337000 ( 1.337000)
1.344000 0.000000 1.344000 ( 1.344000)
1.346000 0.000000 1.346000 ( 1.346000)

Most of the time, when calling + or - on an object, we do the full Ruby dynamic dispatch cycle. Dispatch involves retrieving the target object's metaclass, querying for a method (like "+" or "-"), and invoking that method with the appropriate arguments. This works fine for getting us respectable performance, but we want to take things even further. So JRuby has experimental "fast math" operations to turn most Fixnum math operators into static calls rather than dynamic ones, allowing most math operations to inline directly into the caller. And what do we lose? This version of "fast ops" makes it impossible to override Fixnum#+ and friends, since whenever we call + on a Fixnum it's going straight to the code. But it gets us another nearly 30% improvement.

Up to now we've still also been updating a lot of per-thread information. For every line, we're tweaking a per-thread field to say what line number we're on. We're also pinging a set of per-thread fields to handle the unsafe "kill" and "raise" operations on each thread...basically we're checking to see if another thread has asked the current one to die or raise an exception. Let's turn all that off:

JRuby 1.3.0-dev, compiled (heap scope, heap frame, fastops, threadless, positionless optz), server VM:
➔ jruby --server -J-Djruby.compile.frameless=true -J-Djruby.compile.fastops=true -J-Djruby.compile.positionless=true -J-Djruby.compile.threadless=true bench/bench_tak.rb 5
user system total real
2.256000 0.000000 2.256000 ( 2.186000)
1.304000 0.000000 1.304000 ( 1.304000)
1.310000 0.000000 1.310000 ( 1.310000)
1.307000 0.000000 1.307000 ( 1.307000)
1.301000 0.000000 1.301000 ( 1.301000)

We get a small but measurable performance boost from this change as well.

The experimental optimizations up to this point (other than threadless) comprise the set of options for JRuby's --fast option, shipped in 1.2.0. The --fast option additionally tries to statically inspect code to determine whether these optimizations are safe. For example, if you're running with --fast but still access backrefs, we're going to create a frame for you anyway.

We're not done yet. I mentioned earlier the JVM gets some of its best optimizations from its ability to profile and inline code at runtime. Unfortunately in current JRuby, there's no way to inline dynamic calls. There's too much plumbing involved. The upcoming "invokedynamic" work in Java 7 will give us an easier path forward, making dynamic calls as natural to the JVM as static calls, but of course we want to support Java 5 and Java 6 for a long time. So naturally, I have been maintaining an experimental patch that eliminates most of that plumbing and makes dynamic calls inline on Java 5 and Java 6.
JRuby 1.3.0-dev, compiled ("--fast", dyncall optz), server VM:
➔ jruby --server --fast bench/bench_tak.rb 5
user system total real
2.206000 0.000000 2.206000 ( 2.066000)
1.259000 0.000000 1.259000 ( 1.259000)
1.258000 0.000000 1.258000 ( 1.258000)
1.269000 0.000000 1.269000 ( 1.269000)
1.270000 0.000000 1.270000 ( 1.270000)

We improve again by a small amount, always edging the performance bar higher and higher. In this case, we don't lose compatibility, we lose stability. The inlining modification breaks method_missing and friends, since I have not yet modified the call pipeline to support both inlining and method_missing. And there's still a lot of extra overhead here that can be eliminated. But in general we're still mostly Ruby, and even with this change you can run a lot of code.

This represents the current state of JRuby. I've taken you all the way from slow, compatible execution, through fast, compatible execution, and all the way to faster, less-compatible execution. There's certainly a lot more we can do, and we're not yet as fast as some of the incomplete experimental Ruby VMs. But we run Ruby applications, and that's no small feat. We will continue making measured steps, always ensuring compatibility first so each release of JRuby is more stable and more complete than the last. If we don't immediately leap to the top of the performance heap, there's always good reasons for it.

Performance Optimization, Duby-style

As a final illustration, I want to show the tak performance for a language that looks like Ruby, and tastes like Ruby, but boasts substantially better performance: Duby.
def tak(x => :fixnum, y => :fixnum, z => :fixnum)
unless y < x
z
else
tak( tak(x-1, y, z),
tak(y-1, z, x),
tak(z-1, x, y))
end
end

puts "Running tak(24,16,8) 1000 times"

i = 0
while i<1000
tak(24, 16, 8)
i+=1
end

This is the Takeuchi function written in Duby. It looks basically like Ruby, except for the :fixnum type hints in the signature. Here's a timing of the above script (which calls tak the same as before but 1000 times instead of 5 times), running on the server JVM:
➔ time jruby -J-server bin/duby examples/tak.duby
Running tak(24,16,8) 1000 times

real 0m13.657s
user 0m14.529s
sys 0m0.450s

So what you're seeing here is that Duby can run "tak(24,16,8)", the same function we tested in JRuby above, in an average of 0.013 seconds--nearly two orders of magnitude faster than the fastest JRuby optimizations above and at least an order of magnitude faster than the fastest incomplete, experimental implementations of Ruby. What does this mean? Absolutely nothing, because Duby is not Ruby. But it shows how fast a Ruby-like language can get, and it shows there's a lot of runway left for JRuby to optimize.

Be a (Supportive) Critic!

So the next time someone posts an article with crazy-awesome performance numbers for a Ruby implementation, by all means applaud the developers and encourage their efforts, since they certainly deserve credit for finding new ways to optimize Ruby. But then ask yourself and the article's author how much of Ruby the implementation actually supports, because it makes a big difference.

Update, April 4: Several people told me I didn't go quite far enough in showing that by breaking Ruby you could get performance. And after enough cajoling, I was convinced to post one last modification: recursion optimization.
JRuby 1.3.0-dev, compiled ("--fast", dyncall optz, recursion optz), server VM:
➔ jruby --server --fast bench/bench_tak.rb 5
user system total real
0.524000 0.000000 0.524000 ( 0.524000)
0.338000 0.000000 0.338000 ( 0.338000)
0.325000 0.000000 0.325000 ( 0.325000)
0.299000 0.000000 0.299000 ( 0.299000)
0.310000 0.000000 0.310000 ( 0.310000)

Woah! What the heck is going on here? In this case, JRuby's compiler has been hacked to turn recursive "functional calls", i.e. calls to an implicit "self" receiver, into direct calls. The logic behind this is that if you're calling the current method from the current method, you're going to always dispatch back to the same piece of code...so why do all the dynamic call gymnastics? This fits a last piece into the JVM inlining-optimization puzzle, allowing mostly-recursive benchmarks like Takeuchi to inline more of those recursive calls. What do we lose? Well, I'm not sure yet. I haven't done enough testing of this optimization to know whether it breaks Ruby in some subtle way. It may work for 90% of cases, but fail for an undetectable 10%. Or it may be something we can determine statically, or something for which we can add an inexpensive guard. Until I know, it won't go into a release of JRuby, at least not as a default optimization. But it's out there, and I believe we'll find a way.

It is also, incidentally, only a few times slower than a pure Java version of the same benchmark, provided Java is using all boxed numerics too.

Sunday, March 29, 2009

On Benchmarking

Sigh. It must be that time of year again. Another partially-completed Ruby implementation has started to get overhyped because of early performance numbers.


MacRuby has been mentioned on this blog before. It's a reimplementation of Ruby 1.9 targeting the Objective-C runtime--and now, targeting LLVM for immediately compiling Ruby code to native code. Initial performance results running some of my benchmark show an interesting mixed bag. For some, MacRuby's new "experimental" branch performs very well, in some cases a few times faster than JRuby. For others, performance is slow enough there must be something wrong. And there's a large number of my benchmarks that don't even run, due to broken features they'll be fixing over the next several months.

And yet, at least one Rubyist has already seen fit to declare MacRuby "the fastest Ruby implementation around". Really? When it's crashing for about half the scripts I ran and extremely slow for many others?

He bases this assertion on running the benchmarks MacRuby includes in its own repository. Because MacRuby usually performs much better on those benchmarks than Ruby 1.9, he has decided they're now "the fastest Ruby". Do we have to do this hype dance every year?

Look, I know I'm biased. I want JRuby to be the best Ruby implementation possible. I want it to be fast, and if possible, the fastest. I also want it to run existing Ruby applications and integrate well with Java libraries and applications and continue to be one of the best choices for running Ruby. So I can understand that it sounds like I'm throwing stones by pouring water on such a breathless proclamation as "fastest Ruby implementation around". But seriously guys...haven't we learned anything?

MacRuby's experimental branch is just that: experimental. Lots of stuff is fast, but lots of stuff is broken or slow. I'm sure the MacRuby guys are going to get everything resolved and working, and I'll admit these early results drive me to work on JRuby performance even harder. But I also know from experience that many of the missing features are exactly those that make Ruby performance a really difficult problem. That's why we've always focused on compatibility first (almost to a fault); it's really easy to paint yourself into a corner.

But this post isn't about MacRuby. They're doing awesome work, and I have no doubt at least some of the performance numbers will stick. This post is about the evils of benchmarking, especially prematurely.

Around this time last year, MagLev (Ruby based on the Gemstone VM) posted some crazy benchmarks and shocked the Ruby world at RailsConf. They had numbers even more stunning than MacRuby, running some simple numerical benchmarks orders of magnitude faster than either Ruby 1.8 or 1.9. Several Ruby bloggers immediately posted not just their enthusiasm, but their belief that MagLev had won the performance battle without ever firing a shot.

And I believe it was a great disservice to the MagLev team.

MagLev was, last spring, a very primitive and early implementation. It could run some useful Ruby code, but the majority of the core classes had not yet been implemented and very little work had been done on compatibility. Now we're approaching a year later, and MagLev is still in development, still closed source, still at a private alpha stage of life. Again, I'll admit I'm biased, so I need to state that I believe MagLev is also a really cool technology, at least as cool as MacRuby or JRuby. In many ways and for many domains both of them are going to be more compelling than JRuby, and I have no illusions that JRuby will never get leapfrogged in performance. But we need to remember a really important fact: these implementations are not done.

I could post blog entries with every experimental branch of JRuby I've ever tested. I could show you "fib" numbers 3-5 times faster than current JRuby and 10 times faster than Ruby 1.9. But honestly, what would be the point? I know it's experimental, I know we need to get there in a careful, measured way, and I know that my best experiments may never be reflected in real-world, real-application performance. And yet it seems like people just love to latch on to these early contenders, hyping them to death almost before they're out of the starting gate.

Listen, people: Ruby is hard to implement. Oh, it may look easy at a glance, and you can probably get 70, 80, or even 90% of the way pretty quickly. But there's some crazy stuff in that last 10% or 5% that totally blindsides you if you're not looking for it. An early Ruby implementation has not run that last mile of Ruby implementation, and it takes almost as much work to get there as it does to run the first 90%.

So let's try to be adults about this and give new implementations time to actually finish before we whip the community into a frenzy. Every time we go overboard in our declarations, we look like amateurs. And as certain as I am that MacRuby is going to be a major contender for the "fastest Ruby" crown, I think we'd be wise to hold judgment until it and other young Ruby implementations are actually finished.

Saturday, March 28, 2009

BiteScript 0.0.1 - A Ruby DSL for JVM Bytecode

I have finally released the first version of BiteScript, my little DSL for generating JVM bytecode. Install it as a gem with "gem install bitescript".

require 'bitescript'

include BiteScript

fb = FileBuilder.build(__FILE__) do
public_class "SimpleLoop" do
public_static_method "main", void, string[] do
aload 0
push_int 0
aaload
label :top
dup
aprintln
goto :top
returnvoid
end
end
end

fb.generate do |filename, class_builder|
File.open(filename, 'w') do |file|
file.write(class_builder.generate)
end
end

BiteScript grew out of my work on Duby. I did not want to call directly into a Java bytecode API like ASM, so I wrapped it with a nice Ruby-like layer. I also wanted the option of having blocks of bytecode look like raw assembly, but also callable as an API.

Currently only two projects I know of make use of BiteScript: Duby and the upcoming Ruby-to-Java "compiler2" in JRuby, which will also be released as a gem.

For a longer example, you can look at tool/compiler2.rb in JRuby, lib/duby/jvm/jvm_compiler.rb in Duby, or an example implementation of Fibonacci in BiteScript.

I'm open to suggestions for how to improve the API, and I'd also like to add the missing Java 5 features. The better BiteScript works, the better Duby and "compiler2" will work.

For folks interested in using BiteScript, the JVM Specification is an easy-to-read complete reference for targeting the JVM, and here is my favorite JVM opcode quickref.

Thursday, March 12, 2009

More Compiling Ruby to Java Types

I did another pass on compiler2, and managed to wire in signature support. So let's look at a couple examples:

class MyRubyClass
def helloWorld
puts "Hello from Ruby"
end
def goodbyeWorld(a)
puts a
end

signature :helloWorld, [] => Java::void
signature :goodbyeWorld, [java.lang.String] => Java::void
end

In this case we have our friend MyRubyClass once again, with helloWorld and goodbyeWorld methods. You'll recall from my previous post that these two methods originally compiled as returning IRubyObject, and goodbyeWorld compiled as receiving a single IRubyObject parameter.

But with signature support, things are so much cooler! The two "signature" lines at the bottom of the class (syntax and structure are totally up for debate) associated signatures with the two methods. helloWorld receives no parameters and has a void return type. goodbyeWorld receives a single String parameter and has a void return type.

The compiler takes this new information, and produces a more normal-looking set of Java signatures:
Compiled from "MyObject.java.rb"
public class MyObject extends org.jruby.RubyObject{
static {};
public MyObject();
public void helloWorld();
public void goodbyeWorld(java.lang.String);
}

Huzzah! There's almost nothing here to give away that we're actually dealing with Ruby code under the covers. And the code that consumes this is just as simple:
public class MyObjectTest {
public static void main(String[] args) {
MyObject obj = new MyObject();
obj.helloWorld();
obj.goodbyeWorld("hello");
}
}

And that's literally all there is to it. Here's a more advanced example:
class MyRubyClass
%w[boolean byte short char int long float double].each do |type|
java_type = Java.send type
eval "def #{type}Method(a); a; end"
signature "#{type}Method", [java_type] => java_type
end
end

This time we're actually *generating* the methods, looping over a list of Java primitives and eval'ing a method for each. So this is *runtime* generation of methods, like any good Rubyist loves to do. And of course, this is absolutely no problem for compiler2:
Compiled from "MyObject2.java.rb"
public class MyObject2 extends org.jruby.RubyObject{
static {};
public MyObject2();
public double doubleMethod(double);
public int intMethod(int);
public char charMethod(char);
public short shortMethod(short);
public boolean booleanMethod(boolean);
public float floatMethod(float);
public long longMethod(long);
public byte byteMethod(byte);
}

All the methods are there, just as you'd expect them! Fantastic!!! (Though the ordering is a little peculiar; I think that's because we don't have an ordered method table in our class impl. Does it matter?)

Even better, the above methods are doing the same type coercion on the way in and out that we do for any other Java-based method calling. So your integral numerics are presented to Ruby as Fixnums, floating-point numerics are Floats, and booleans come through as Ruby true or false.

There's certainly more work to be done:
  • There's no support for overloads at the moment, but I'll likely provide a method aliasing facility so you can define multiple Ruby methods and then say which one maps to which overload. And of course, you'll be able to define multiple overloads that go to the same method body if you wish.
  • I also have not wired in varargs, but it will be an easy match to Ruby's restargs. And optional arguments could automatically generate different-arity Java signatures.
  • Annotations will also be trivial to add; it's just a matter of attaching appropriate metadata and having compiler2 emit them. So you'll be able to use JavaEE 5, JUnit4, and any other frameworks that depend on having annotations present.
Of course this is all checked into JRuby trunk, so feel free to give it a try. Stop by JRuby mailing lists or IRC if you have questions. And it's all still written in Ruby; signature support bloated the compiler up to a whopping 178 lines of code, most of that for dealing with the JVM opcodes for primitive types.

This is just the beginning!

Tuesday, March 10, 2009

Compiling Ruby to Java Types

"Compiler #2" as it has been affectionately called is a compiler to turn normal Ruby classes into Java classes, so they can be constructed and called by normal Java code. When I asked for 1.3 priorities, this came out way at the top. Tom thought perhaps I asked for trouble putting it on the list, and he's probably right (like asking "prioritize these: sandwich, pencil, shiny gold ring with 5kt diamond, banana"), but I know this has been a pain point for people.

I have just landed an early prototype of the compiler on trunk. I made a few decisions about it today:

  • It will use my bytecode DSL "BiteScript", just like Duby does
  • It will use the *runtime* definition of a class to generate the Java version
The second point is an important one. Instead of having an offline compiler that inspects a file and generates code from it, the compiler will actually used the runtime class to create a Java version. This means you'll be able to use all the usual metaprogramming facilities, and at whatever point the compiler picks up your class it will see all those methods.

Here's an example:

# myruby.rb
require 'rbconfig'

class MyRubyClass
def helloWorld
puts "Hello from Ruby"
end
if Config::CONFIG['host_os'] =~ /mswin32/
def goodbyeWorld(a)
puts a
end
else
def nevermore(*a)
puts a
end
end
end

Here we have a class that defines two methods. The first, always defined, is helloWorld. The second is conditionally either goodbyeWorld or nevermore, based on whether we're on Windows. Yes, it's a contrived example...bear with me.

The compiler2 prototype can be invoked as follows (assuming bitescript is checked out into ../bitescript):

jruby -I ../bitescript/lib/ tool/compiler2.rb MyObject MyRubyClass myruby

A breakdown of these arguments is as follows:
  • -I ../bitescript/lib includes bitescript
  • tool/compiler2.rb is the compiler itself
  • MyObject is the name we'd like the Java class to have
  • MyRubyClass is the name of the Ruby class we want it to front
  • myruby is the library we want it to require to load that class
Running this on OS X and dumping the resulting Java class gives us:

Compiled from "MyObject.java.rb"
public class MyObject extends org.jruby.RubyObject{
static {};
public MyObject();
public org.jruby.runtime.builtin.IRubyObject helloWorld();
public org.jruby.runtime.builtin.IRubyObject nevermore(org.jruby.runtime.builtin.IRubyObject[]);
}

The first thing to notice is that the compiler has generated a method for nevermore, since I'm not on Windows. I believe this will be unique among dynamic languages on the JVM: we will make the *runtime* set of methods available through the Java type, not just the static set present at compile time.

Because there are no type signatures specified for MyRubyClass, all types have defaulted to IRubyObject. Type signature logic will come along shortly. And notice also this extends RubyObject; a limitation of the current setup is that you won't be able to use compiler2 to create subclasses. That will come later.

Once you've run this, you've got a MyObject that can be instantiated and used directly. Behind the scenes, it uses a global JRuby instance, so JRuby's still there and you still need it in classpath, but you won't have to instantiate a runtime, pass it around, and so on. It should make integrating JRuby into Java frameworks that want a real class much easier.

So, thoughts? Questions? Have a look at the code under tool/compiler2.rb in JRuby's repository. The entire compiler is so far only 78 lines of Ruby code.

Saturday, February 28, 2009

Help Us Set Priorities for JRuby 1.3

With JRuby 1.2 almost out the door, I want to talk a bit about where we should go with JRuby 1.3. There's always more work to do, but in this case there's a few different directions we could probably go.

Some obvious items will continue to see work:

  • 1.9 libraries, interp, compiler, parser
  • 1.8.6 bugs
  • "Pure ruby" application support, like Rails deployment stuff (Warbler, AR-JDBC)
But there's other areas that we may want to prioritize:
  • 1.8.7 support
  • Ruby execution performance (how fast do you want it?)
  • Specific library performance (YAML, IO, Java)
  • More Java integration improvement/refactoring (esp. subclassing)
  • "Compiler #2" to produce normal Java classes from Ruby
  • Improvements to AOT compilation (all-at-once, eliminate runtime codegen)
  • Expand support for embedded/mobile platforms
And there's a number of internal chores to work on too:
  • Start generating most of the call path, to reduce duplicate code
  • Specific-arity optimizations for block yield (could be big)
  • Compiler cleanup and refactoring
  • Modularization of core classes that aren't valid on applet, Android, secured envs, etc; also may allow shipping smaller runtimes
  • More startup perf work; I have a few ideas
As always, there's way more tasks than the few of us committing to JRuby can work on, so I think we need to hear from users what's important. Any of these? Other items?

Friday, February 27, 2009

JRuby on Java ME

A number of folks have asked us over the years whether JRuby could run on a Java ME-enabled device. I've always said I believed it would be possible with enough trimming. Strip out all the libraries that ME doesn't support, and you should be left with a runnable "core" of JRuby. Roy Ben Hayun, formerly of Symbian and (I believe) now working at Sun, actually proved it possible but difficult back in 2006 with his JRubyME project, a stripped down JRuby 0.9.8. But that didn't have compiler support, and we were still dog slow in 2006. Has JRuby, with two years of work behind it, grown too complex to run on an embedded device? Is the Rhodes project right when they say JRuby is too large for this to work?

Tony Arcieri, of Revactor fame, put a bug in my ear about Java ME again this week. He's interested in running Ruby on a device hosting the Connected Device Configuration (CDC) level of Java ME. Specifically, the device in question supports CDC plus the APIs included in the Personal Basis Profile (PBP). CDC is probably about the smallest ME profile JRuby could reasonably run in, since anything lower (like CLDC, the Connected Limited Device Configuration) and you're reduced to the most basic collections, IO, and utility APIs.

So, I'm happy to announce that the JRuby CDC Project has spawned out of the JRuby codebase.

Here's what it looks like running, using Sun's reference implementation of CDC+PBP:

~/cdc/Optimized_nosym$ bin/cvm -classpath ../jruby.jar org.jruby.Main -X-C -e "[1,2,3].each {|i| puts i}"
1
2
3

The "cvm" is Sun's reference implementation of an embedded JVM, and this particular package includes the PBP level APIs as well. The jruby.jar here is the one I've stripped in the jruby-cdc project, but with the additional step of retroweaving it back to Java 1.3-compatible bytecode.

My intention with this is to get it running with a base set of Ruby classes but with Java integration still functional. That will allow most basic Ruby scripts to work while providing access to the rest of the Java APIs for bits I had to rip out (like IO APIs)

It's only running interpreted right now, just like the Android version of JRuby, but as in that case I expect most people will want to precompile Ruby code and ship it all as one unit.

Why bother? Well, there are still a lot of Java ME devices out there. And while the device you carry in your pocket may be growing beyond Java ME, the set-top box or Blu-Ray player in your living room is just starting to reach that level. The technology is still sound, if perhaps less obvious than an iPhone or Android. And hey, we want "Ruby everywhere," don't we?

Where do we go from here? I think this and Ruboto are proof that damn near anything is possible with JRuby. It really only took me a couple days of trimming to get this far. Fully supporting Android in Ruboto will not take long, and other "mini ruby" profiles are possible for other platforms and use cases as well. It just takes a little imagination, and maybe a few late-night hacking sessions.

Now...for my next trick...

Wednesday, February 25, 2009

Ruboto Is Your Friend

Ok, so I intentionally made my last post a bit of a "tease". You can't fault me for trying to drum up a little buzz, yeah? And hey, I spent almost as long fiddling with that logo as I did hacking JRuby to run on Android. Here it is again, just for good measure:


On Monday night, the local Ruby group (Ruby Users of Minnesota, or RUM...great buncha guys) hosted three talks: one on Android development, one on iPhone development, and one on migrating from Struts to JRuby a bit at a time. The Android talk kinda hooked me, even though I was working on last-minute JRuby 1.2RC1 issues and not really paying much attention (sorry, Justin).

I'd considered getting JRuby working on Android before, since it's compatible with most Java 1.5 language features, has a much more extensive library than any of the Java ME profiles (which hopefully will be remedied in future ME profiles), and represented the best chance for "mobile JRuby" to date. I had tweeted about it, scammed for a free G1 phone, and briefly browsed the online docs. I had even downloaded it back in early January...but I'd never bothered to try.

So late Monday night, I tried. And about an hour later it was running.

What I Did

There's really two sides to the Android SDK. There's the drag-and-drop fluffy-stuffy GUI in the form of a plugin for Eclipse. That was my first stop; I got it installed, created a sample project, and ran it in the emulator. It worked as expected, and I'll admit it made me want an Android phone a bit more. I'll be the first to admit I've been skeptical of Android, but at this point it's hard to argue with a totally open platform, especially since it has a shipping device now. So yeah, SDK plus sample app was easy and appetite-whetting.

Then I tried to pull in JRuby's main jar file. Nothing seemed to work right. I got errors about not having defined an "application" in some XML file, even though it was there. There was no obvious information on how to add third-party libraries to my app, and I certainly may have done it the wrong way. And of course my lack of knowledge about the structure of an Android app probably didn't help. But ultimately, since I didn't really need a full-on application, I started to dig around in the SDK for "another way".

Not one for reading documentation, I immediately started running the executables under "tools" with --help and guessing at combinations of arguments. Immediately I saw "emulator" and started that. Yay, an emulator! Then I saw dx, which looked intriguing. A-ha! It's the tool for converting an existing class or jar into Dalvik bytecode. A bit more fidding with flags, and I finally found the right incantation:

dx -JXmx1024M --dex --output=ruboto.jar jruby.jar

For the newbs: that's -JXmx1024M to allow dx to use up to a gig of memory, --dex to convert to Dalvik bytecode, and --output to specify an output file.

So, suddenly I had what I assumed was a Dalvik-ready ruboto.jar file. A quick jar -t confirmed that everything appeared to be there, along with a "classes.dex" file.
...
builtin/yaml.rb
builtin/yaml/store.rb
builtin/yaml/syck.rb
classes.dex
com/sun/jna/darwin/libjnidispatch.jnilib
com/sun/jna/freebsd-amd64/libjnidispatch.so
com/sun/jna/freebsd-i386/libjnidispatch.so
...

There were also a bunch of warnings about "Ignoring InnerClasses attribute for an anonymous inner class that doesn't come with an associated EnclosingMethod attribute." but warnings don't stop a true adventurer. I pressed on!

So, the next step was getting it into the emulator, eh? Hmm. Well there's no "upload" option in the emulator's OS X menu, and nothing obvious in the Android UI. There must be a tool. Like maybe a debugging tool of some kind... like a "jdb" but for Android. Hmm.....this "adb" executable looks promising...
$ ~/android-sdk-mac_x86-1.0_r2/tools/adb --help
Android Debug Bridge version 1.0.20
...

Ahh, bingo. And one of the adb subcommands was "push" for pushing files to the device. A few minutes and experiments later, I figured out incantation #2:
$ ~/android-sdk-mac_x86-1.0_r2/tools/adb push ruboto.jar ruboto.jar
failed to copy 'ruboto.jar' to 'ruboto.jar': Read-only file system

Or at least, I almost had it. Obviously the device was being closed-minded about the whole thing. So back to adb to run another subcommand and have a look around:
$ ~/android-sdk-mac_x86-1.0_r2/tools/adb shell
# ls
sqlite_stmt_journals
cache
sdcard
etc
system
sys
sbin
proc
init.rc
init.goldfish.rc
init
default.prop
data
root
dev

Hmm. "data". That looks promising. I mean, a "data" directory couldn't possibly be read-only, right? So let's give that a try.
$ ~/android-sdk-mac_x86-1.0_r2/tools/adb push ruboto.jar data/ruboto.jar
1702 KB/s (3249363 bytes in 1.863s)

BING! We have liftoff!

Ok, so we've "dexed" the jar, uploaded it to the emulator, and now we want to run it. Back into the shell we go!

There's obviously an sbin above, but it's pretty slim:
# ls sbin
adbd

Another debugging thingy I suppose. Maybe I'll have a look at that later. What about under "system"? I've gotten used to the bulk of my system living under something called "system" from running OS X. And as in that case, "system" was much more populous, with a bin directory containing all sorts of goodies. However one of them jumped out at me immediately:
# ls system/bin
am
app_process
cat
chmod
cmp
dalvikvm
date
dbus-daemon
dd
...

Oh, goodie, "dalvikvm". Could it possibly be the equivalent of the "java" command on a desktop? Could it really be that easy?
# dalvikvm -help

dalvikvm: [options] class [argument ...]
dalvikvm: [options] -jar file.jar [argument ...]

The following standard options are recognized:
-classpath classpath
...

It could! My hands began to tremble. My heart began to pound. Could I simply do
dalvikvm -jar ruboto.jar -e "puts 'hello'"

And expect it to work?
# dalvikvm -jar data/ruboto.jar -e "puts 'hello'"
-jar not yet handled
Dalvik VM unable to locate class 'data/ruboto/jar'
java.lang.NoClassDefFoundError: data.ruboto.jar
...

Curses! Ignoring for the moment how strange it seemed to have a -jar flag that simply doesn't work, I tried specifying -classpath and org.jruby.Main.

Aaaaaaaand...

It blew up with my first official JRuby-on-Android exception!
# dalvikvm -classpath ruboto.jar org.jruby.Main -e "puts 'hello'"
HugeEnumSet.java:102:in `next': java.lang.ArrayIndexOutOfBoundsException
from HugeEnumSet.java:52:in `next'
from Ruby.java:1237:in `initErrno'
...

Hmm. The code in question simply iterated over an EnumSet. After thinking through a few scenarios, I concluded this was not JRuby's fault. It seemed that I had discovered my first Android bug, the first time I tried to run anything on it. And that made me sad.

But only for a moment! The code in question turned out to be unimportant for a normal application; it was simply iterating over a set of Errno enums we use to report errors. Commented it out, and I was on to my next issue:
(I've lost the original error, but it was a VerifyError loading org.jruby.Ruby since it referenced BeanManager which referenced JMX classes. There is no JMX on Android.

Ok, VerifyError because of missing JMX stuff...that's no problem, I can just disable it for now. So, one more attempt, and if it fails I'm going to start doing iPhone development I SWEAR.
# dalvikvm -classpath data/ruboto.jar org.jruby.Main -e "puts 'hello'"
Error, could not compile; pass -d or -J-Djruby.jit.logging.verbose=true for more details
hello

SUCCESS!

More Details

Ok, so we all agree Android dodged a bullet there. But what's the real status of JRuby on Android?

It turns out there were very few changes necessary. I fixed the EnumSet stuff by just iterating over an Errno[] (EnumSet was not actually needed). I fixed the JMX stuff by creating a BeanManagerFactory (yay GOF) that loaded the JMX version via reflection, falling back on a dummy if that failed. And I fixed some warnings Dalvik was spouting about default BufferedReader and BufferedInputStream constructors by hardcoding specific buffer sizes (I think Dalvik is wrong here, and I'm arguing my case on the android-platform ML). And that's really all there was to it. JRuby pretty much "just worked".

Of course you see the "could not compile" error up there. What's up with that?

JRuby normally runs mixed-mode, interpreting Ruby code for a while and eventually compiling it down to Java bytecode if it's used enough. But we do try to immediately compile the target script, since it doesn't cost much and gives you better cold-start performance for simple scripts. The error above was simply JRuby reporting that it could not compile my little -e script. Why couldn't it? Because the JRuby compiler is generating JVM bytecode, not Dalvik bytecode. Dalvik does not run JVM bytecode. Here's the actual error you get:
# dalvikvm -classpath data/ruboto.jar org.jruby.Main -d -e "puts 'hello'"
could not compile: -e because of: "can't load this type of class file"
java.lang.UnsupportedOperationException: can't load this type of class file
at java.lang.VMClassLoader.defineClass(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:261)
at org.jruby.util.JRubyClassLoader.defineClass(JRubyClassLoader.java:22)
...

So that's caveat #1: this is currently only running in interpreted mode. To avoid the compiler warning, you can pass -X-C to JRuby to disable compilation entirely.

Unfortunately, interpretation means JRuby is none too fast at the moment. That may not matter if you're scripting a "real" app, but we'll definitely find ways to improve performance soon. That may mean providing an all-at-once compilation tool for Ruby code (we have an ahead-of-time (AOT) compiler right now, but it's per-file, and still expects to generate some code at runtime), or it may mean a second compiler that generates Dalvik bytecode. Either way...it's coming.

Caveat #2 is that a large number of libraries aren't working, especially any that depend on native code:
# dalvikvm -classpath data/ruboto.jar org.jruby.Main -X-C -e "require 'readline'"
-e:1:in `require': library `readline' could not be loaded: java.lang.VerifyError: org.jruby.ext.Readline (LoadError)
from -e:1
# dalvikvm -classpath data/ruboto.jar org.jruby.Main -X-C -e "require 'ffi'"
-e:1:in `require': library `ffi' could not be loaded: java.lang.ExceptionInInitializerError (LoadError)
from -e:1

And so on. There's nothing to say these libraries can't be made to work, but they're not working yet. And thankfully, our most important library seems to work fine:
# dalvikvm -classpath data/ruboto.jar org.jruby.Main -X-C -e "require 'java'; puts java.lang.System.get_property('java.vendor')"
The Android Project

And that leads me to caveat #3, better demonstrated than explained:
# dalvikvm -classpath data/ruboto.jar org.jruby.Main -X-C -e "require 'java'; import 'android.content.Context'"
Class.java:-2:in `getDeclaredMethods': java.lang.NoSuchMethodException
from ClassCache.java:137:in `getDeclaredMethods'
from Class.java:666:in `getDeclaredMethods'
from JavaClass.java:1738:in `getMethods'
...

Bummer, dude. There seems to be some feature (i.e. a bug) preventing some Android core classes from reflecting properly, which means that for the moment you may not be able to access them in JRuby.

Next Steps

Overall, I think it was a great success. We obviously weren't doing anything in critical JRuby code that Android could not handle. Kudos to the Android team for that, and kudos to us for still supporting Java 1.5. But success in software only leads to more opportunities:
  • All the changes necessary to run JRuby on Android have already been shipped in JRuby 1.2RC1. So you can grab those files and dex them yourself, or wait for me to add Android-related build targets.
  • Android's default stack size is incredibly small, 8kb. So for all but the most trivial Ruby code you're going to want to bump it up with -Xss. See the final snippit at the bottom of this post for an example. And of course you all know about using -Xmx to increase the max heap; it applies to Android as well.
  • I need to report the bugs I've found in Android's bug tracker and provide some steps to reproduce them. I'll probably get to this in the next couple days. Hopefully they can be fixed quickly, and hopefully patched Android doesn't take too long to filter out to users.
  • Meanwhile, I'll probably start poking at an all-at-once compilation mode, since I think that's simpler initially than emitting Dalvik bytecode. It's already done in my head. You'll run a command to "fully compile" a target script or scripts, and it will create the .class file it does now along with all the method binding .class files it normally generates at runtime. I've been planning this feature for a while anyway. With the "completely compiled" Ruby code you should be able to just "dex" it and upload to the device.
  • Given that most people will probably want to ship precompiled code, and given the fact that many libraries will never work, we need to modularize JRuby a bit more so we can rip out unsupported libraries, parser guts, interpreter guts, and compiler guts. That should shrink the total size of the binary substantially. And I have other ideas for shrinking it too.
  • We in the JRuby community also need to start brainstorming how to use this newfound power. Assuming the above items are all completed soon, what will we want to do with JRuby on Android? Build apps entirely in Ruby? Script existing ones? What Ruby features would we be willing to drop in order to boost Android-based performance a bit more? Hopefully this discussion can start in the comments and continue on the JRuby mailing lists.
The Bottom Line

JRuby works on Android, that much is certain. The remaining issues will get worked out. And I dare say this is probably the best way to get Ruby on any embedded device yet; after dexing, it's literally just "upload and run". So there's a great opportunity here. I'm excited.

And just one more example to show that not just JRuby itself, but also Ruby libraries that ship with it work (using the "complete" JRuby jar in this case):
# dalvikvm -Xss128k -classpath data/ruboto.jar org.jruby.Main -X-C -e "require 'irb'; IRB.start"
trap not supported or not allowed by this VM
irb(main):001:0> puts "Hello, JRuby on Android!"
Hello, JRuby on Android!
=> nil
irb(main):002:0>

Tuesday, February 24, 2009

Domo Arigato, Mr. Ruboto

# cat test.rb
require 'java'
import java.lang.System

class Ruboto
def greet(who)
puts "Hello, #{who}!"
end
end

name = System.get_property('java.runtime.name')
Ruboto.new.greet(name)

# dalvikvm -classpath ruboto.jar org.jruby.Main -X-C test.rb
Hello, Android Runtime!




Portions of this page are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 2.5 Attribution License.

Wednesday, February 18, 2009

JRuby 1.2: Coping With Bugs

We get a lot of bug reports on the JRuby project. No, it's not because JRuby's a buggy POS. It's because we're implementing the core of an entire platform. It's hard.

Over the past year or so we kinda let the bug tracker go a little wild. We've never had more than two full-time people on the project, and community contributions wax and wane with the seasons, so we've had to choose our battles. For some amount of time, we would focus on performance, since without a reasonably-performing implementation, nobody would choose to use JRuby. Then we'd cycle back to fixing bugs, usually in the last couple weeks before a release. So the flow of bug fixes waxed and waned with our release cycles.

The problem with this approach was that we really couldn't keep up with all the reports coming in and continue to work on the "unreported issues" of JRuby like performance. So something had to give, and it was sometimes the bugs.

Roughly around September, we crossed an important threshold: 500 open bugs. They dated as far back as 2006 (we moved to Codehaus in 2006), and across the entire release sequence of JRuby; there were even some bug reports against pre-1.0 versions. From September until about mid-January, we worked to keep the number of open bugs below 500. Sometimes it would peek above, but we were generally successful.

About mid-January, I figured it was time to really bite the bullet, and I started walking from the oldest bug forward. It has been a long slog, but I'm making great progress.

So far, I've managed to whittle the total number of bugs down from 506 to 326, and that's with a couple dozen more filed in the past two weeks. The majority of these were either already fixed or invalid/incomplete bugs, but I've also made a concentrated effort to focus on and fix as many as possible. At the very least, I've made an attempt on every single one.

During that process, I learned a bit about how my brain works. During the past year, if I didn't know immediately how to fix a bug I often walked away from it and worked on something fun like compiler optimization. But during this latest bug hunt, because I did not want to just punt all those bugs one more time, I did something a little different.

Whenever I encountered a bug that seemed difficult or that I simply didn't want to fix, I would do one of two things:

  • Take a break. Often this meant I had reached my limit and needed a breather. A little Wii, a glass of scotch, a movie...anything to take my mind of it for a bit.
  • Count to ten. Sometimes, after reading through the bug, all I really needed was a moment for my brain to start "wondering" about the solution. Once the wheels started turning, I was almost compelled to dig deeper.
As a result, many long-standing bugs--including bugs I thought we would never fix--are now resolved and ready for the 1.2 release. I'm going on three weeks now of 12-hour days trying to fix what seems like an endless stream of bugs, but the end is in sight. And I want to stress that this level of effort has never happened in a single release. There's as much work in JRuby 1.2 as in multiple 1.1.x releases combined. I'll be blogging more of these posts over the next couple weeks.

For your amusement, here is the complete list of bugs we have resolved during the past nine weeks, since shortly after the 1.1.6 release. These aren't all fixes, but even the "already fixed", "won't fix", "not a bug", or "incomplete" ones were reviewed, tested, and considered. A couple of these I just applied patches or marked resolved based on someone else's work. And of course we're not done with JRuby 1.2 yet. Just you wait and see :)

Bugs Resolved (Fixed, Won't Fix, Not A Bug, or Incomplete Information), Past Nine Weeks:

(in the order they were resolved)

JRUBY-2538

File#chmod always returns -1, fails rubyspec

JRUBY-1505

Solidify public APIs separate from those that might change

JRUBY-3208

ant task api-docs runs out of memory, patch included

JRUBY-3221

Rubinius -bad instanceof tests in RubiniusMachine for attempt at fast path evaluation

JRUBY-3232

Zlib::GzipReader.each_line yields compressed data

JRUBY-3244

[PATCH] Support atime updates via utime

JRUBY-3249

Testing errors in test_java_mime.rb

JRUBY-3250

test_java_pkcs7.rb - Problem coercing Bignum into class java.math.BigInteger

JRUBY-2992

Bad cast in jruby-openssl X509Utils

JRUBY-3204

IO.read and IO.readlines do not take a block

JRUBY-3251

ConcurrencyError bug when installing Merb on JRuby

JRUBY-3248

jruby can't load file produced with jrubyc

JRUBY-3257

RaiseException#printStrackTrace doesn't deal well with nil messages

JRUBY-3259

sqlite db file on MRI is put in db dir. We put it in CWD.

JRUBY-3260

:date is stored as integer (not date) in sqlite3

JRUBY-2425

NPE at Connection Shutdown

JRUBY-2329

java.lang.NullPointerException when trying to connect to a Oracle XE database

JRUBY-3023

Renaming indexed columns fails

JRUBY-2384

Rails migrations fail with: undefined method `create_database' for class `#'

JRUBY-2400

ActiveRecord/JRuby Memory leak in update_attributes!()

JRUBY-2040

new samples/jnlp dir: includes both unsigned and signed examples that work in Java 1.5 and 1.6

JRUBY-3270

using activerecord 'to_xml' method crashes JRuby (and debugger)

JRUBY-3277

Constant lookup should omit topmost lexical scope; not bail out on first Object-hosting lexical scope

JRUBY-3278

Array#reduce is undefined

JRUBY-3187

JRuby command line scripts do not work with spaces in the path

JRUBY-3267

patch attached to update eclipse .classpath to refer to bytelist-1.0.1.jar

JRUBY-3280

patch attached to update eclipse .classpath to add new jars in build_lib/

JRUBY-3276

New IO#readpartial and IO#seek spec failures

JRUBY-3256

jruby -S script/console fails in Rails application

JRUBY-3199

IllegalArgumentException in X509V3CertificateGenerator when executing Hoe's rake gem running on SoyLatte JDK

JRUBY-3275

New ARGF spec failures

JRUBY-3287

Add public RubyInstanceConfig#setCompatVersion

JRUBY-3171

loading rake breaks import

JRUBY-3290

Float range to restrictive in FFI code

JRUBY-2826

Array#pack('w') is broken (exceptions and wrong results)

JRUBY-3116

ArrayIndexOutOfBoundsException in tmail

JRUBY-2522

Can not execute JRuby 1.1.1 "ant test" with IBM JDK

JRUBY-2426

JRuby trunk does not build with IBM JVM 1.5

JRUBY-3042

undefined method `quote' for Regexp:Class (NoMethodError) when runs gem list on AIX with IBM JAVA 1.5

JRUBY-1950

'-i flag not supported

JRUBY-3302

Doesn't biuld on windows for ffi problem

JRUBY-3303

[1.9] splat of array at front of assignment broken (same for other grammatical constructs)

JRUBY-3307

tempfile.rb sucks in JRuby

JRUBY-3305

Fixnums & Floats should be coerced to the narrowest java.lang.Number when passed to a java method that expects Object

JRUBY-2768

jdbc_mysql.rb should not enforce the utf8_bin collation on table creation

JRUBY-2115

Error doing add_column with Derby and jdbc-adapter-0.7.2

JRUBY-2967

[PATCH] Derby handling of binary/date/time fields. hsqldb handling of binary fields.

JRUBY-2647

[activerecord-jdbcsqlite3 adapter] Date/Datetime/Time fields simplification to INTEGER sqlite storage type is not correctly handled

JRUBY-3073

JRuby script engine does not load on IBM JDK

JRUBY-3109

Update stdlib to an appropriate 1.8.6 patchlevel

JRUBY-2541

Time assumes UTC timezone

JRUBY-3254

Make JRuby's Time#local behave more like MRI

JRUBY-2740

BigDecimal#precs fails two new rubyspec tests

JRUBY-3298

Kernel.srand calls #to_i on number

JRUBY-2987

Kernel#system does not work correctly

JRUBY-3242

Performance degradation on write operations

JRUBY-2128

error accessing JRuby DRb server from MRI DRb client

JRUBY-3268

JRuby DRb client cannot connect to MRI DRb server

JRUBY-3274

Many new Array#pack failures in updated RubySpecs

JRUBY-3147

Time#_load RubySpec failures

JRUBY-3146

Time#_dump RubySpec failures

JRUBY-3148

Array#fill spec failures

JRUBY-3142

Dir.pwd correctly displays dirs with unicode characters in them

JRUBY-2609

spec --line does not work with JRuby

JRUBY-3317

require "tempfile"; Dir.tmpdir fails

JRUBY-2364

The private keyword doesn't change visiblity of previously called methods with same send/call site

JRUBY-2796

Missing constant in Process::Constants on Mac OS X (darwin)

JRUBY-3226

Including more than one java interface stops Test::Unit execution

JRUBY-3035

Get Rails tests running in a CI server somewhere before 1.1.6 release, to ensure no future breakages

JRUBY-3318

If 'jruby' executable is a relative symlink, JRuby won't start

JRUBY-3328

Incorrect behavior for case/when when true or false are the first conditions

JRUBY-3269

SystemStackError with YAML.dump

JRUBY-3229

Javasand does not compile with JRuby 1.1.5

JRUBY-3333

idea

JRUBY-3332

ConcurrentModificationException In Application Startup

JRUBY-3329

Major divergence in threading behaviour between Ruby 1.8.6 and JRuby 1.1.6

JRUBY-3308

Deadlock between RubyModule.includeModule() and RubyClass.invalidateCacheDescendants()

JRUBY-3324

Error in string encoding conversion

JRUBY-3340

String#unpack('m') fails with ArrayIndexOutOfBoundsException

JRUBY-3341

The body of POST requests is not passing through jruby-rack

JRUBY-3312

JRuby can double slash ("//") the directory given by __FILE__ when "everything" suits this thing to happen. :-)

JRUBY-2884

jdbc_postgre.rb issue handling nil booleans

JRUBY-2208

Memory Leak in ActiveRecord-jdbc or JRubyEngine used with BeanScriptingFramework

JRUBY-2897

jdbc_postgre.rb needs microsecond support

JRUBY-2995

activerecord jdbc derby adapter should quote columns called "year"

JRUBY-2949

jdbcderby adapter should ignore :limit for INTEGER

JRUBY-2718

jdbcsqlite3 at JRuby on Rails do not work properly

JRUBY-3344

Update H2 to a later version

JRUBY-3342

Wrabler escapes config.ru twice

JRUBY-3282

Upgrade to derby 10.4.2.0 to allow unique constraints with nullable columns

JRUBY-2767

Mistake in selecting identity with H2/HSQLDB

JRUBY-2433

java.lang.IllegalArgumentException in debug mode when using CLOB

JRUBY-3310

Race condition in JRuby when Active Support is overriding Kernel.require

JRUBY-3127

Inconsistent DynamicScope instances in evalScriptlet

JRUBY-3339

java.lang.ArrayIndexOutOfBoundsException in RubyArray.java

JRUBY-3351

Tempfile defaults to a directory that does not exist on Windows

JRUBY-3353

String#unpack invalid output

JRUBY-3361

Compiled case/when blows up with arrays as when clauses

JRUBY-3362

attr_accessor, attr_reader, attr_writer, and attr not obeying visibility

JRUBY-1034

Post parse processing of the result comment placing as example

JRUBY-48

Ability to write JUnit4+ tests in JRuby

JRUBY-1572

Allow visible fields from inherited Java classes show up as instance variables (@foo)

JRUBY-2108

IOWaitLibrary ready? returns nil when ready

JRUBY-1895

JRUBY-1890 IO.popen does not support "-"

JRUBY-852

jirb exits on ESC followed by any arrow key followed by return

JRUBY-2015

"RAILS_ROOT" cannot be put on a place different from "Context root" in Goldspike.

JRUBY-2139

jruby.compile.frameless=true cause "Superclass method 'initialize' disabled."

JRUBY-2174

Method#to_proc.call invocations much slower than normal Method#call invocations

JRUBY-2170

Very unverbose message when problem with native library exists

JRUBY-3338

jIRB cannot get any input with Polish characters (utf-8) on Mac OSX

JRUBY-2252

Kernel#exec should not raise SystemExit

JRUBY-1855

EOF handling in case of reading program from standard input

JRUBY-1997

System.gc() is extremely expensive when calling Java code from JRuby

JRUBY-821

getting in $SAFE level 4 freezes

JRUBY-1770

weakref-based singleton class "attached" can blow up in certain unusual circumstances

JRUBY-1555

DST bug in second form of Time.local

JRUBY-1872

next statement should return the argument passed, not nil

JRUBY-2214

Pure-Java version of lstat doesn't fail on non-existing file

JRUBY-1901

standardize and publish public API for embedders

JRUBY-2211

SNMP Requests does not timeout properly

JRUBY-2298

We should generate method binding code with APT

JRUBY-2305

File output cuts off at a certain point?

JRUBY-2306

NPE in org.jruby.RubyIO.flush

JRUBY-2288

UDP locking problems when receiving from multiple senders on same port

JRUBY-2333

usage of unexistant variable in REXML::SourceFactory

JRUBY-2346

Nailgun does not compile under HP-UX

JRUBY-2353

Process.kill breaks up JRuby, while works in MRI on Windows

JRUBY-2369

'ant spec' failures on on MacOS

JRUBY-2168

test_io (test_copy_dev_null) fails under WinXP

JRUBY-2410

Multiple assignment could be made faster by not returning unused array

JRUBY-2389

java.util.ConcurrentModificationException

JRUBY-929

Java input/output streams from Ruby string's backing byte array

JRUBY-1681

Pathological slowdown in Array#insert

JRUBY-1470

FileTest methods only work with string arguments

JRUBY-1576

multi-byte character encoding probrem

JRUBY-2119

Jruby shell script don't work on KSH shell

JRUBY-3360

Pure-Java tempfile does not use a #make_tmpname callback

JRUBY-2518

Dir["some glob"] doesn't work for files inside a jar

JRUBY-3367

Dir.glob processes nested braces incorrectly

JRUBY-3366

Faulty marshalling error blows up in ActiveSupport

JRUBY-2027

Problems with the H2 jdbc adapter, schema metadata behavior

JRUBY-2417

Make fields immutable where possible

JRUBY-1565

ReWriteVisitor transforms Fixnums into base 10 despite their original format

JRUBY-2917

Missing peephole optimizations in parser, compiler

JRUBY-2542

DATA.flock causes ClassCastException

JRUBY-2545

Recursively locking on a mutex results in deadlock

JRUBY-2285

Regression: rubyspec run with -V option breaks JRuby

JRUBY-2120

Wrong stacktraces from exceptions about wrong number of arguments

JRUBY-1639

Exception when stopping WEBrick running the new rails application

JRUBY-2534

jdbcpostgresql adapter inserts invalid number literals into generated SQL, causes exceptions

JRUBY-3375

'attr' implementation is incompatible with MRI 1.9.1 behavior

JRUBY-3365

Objects with custom to_yaml methods break collection to_yaml

JRUBY-2603

Couple of new rubyspec failures for URI library

JRUBY-2465

2 digit year resolves to 1st century rather than 20th when using postgres timestamp with timezone + activerecord-jdbcpostgresql-adapter

JRUBY-2672

BasicSocket#close_read and #close_write not working

JRUBY-2655

TCPSocket.new('localhost', 2001) connects on the wrong interface

JRUBY-2759

Time Zone "MET" maps to Asia/Tehran

JRUBY-2758

Class Socket is missing #bind

JRUBY-2761

Thread#wakeup fails when sleep is called with a parameter

JRUBY-2772

Zlib::Deflate doesn't appear to deflate

JRUBY-3289

ArgumentError: dump format error() when unmarshalling Rails session and EOFError when unmarshalling hash with containing value of type ActionController::Flash::FlashHash

JRUBY-3228

Some error saving to a Rails session [Marshalling bug?]

JRUBY-2792

Net::HTTP spec failures in get_print spec; IO not getting expected "print" call

JRUBY-2804

IO.popen of 'yes' process hangs on close

JRUBY-2755

Precompiled scripts do not set initial position information correctly

JRUBY-2484

unicode symbol not supported as in MRI

JRUBY-2817

File.chown works with 64bit JDK, but raises NotImplementedError on 32 bit JDK

JRUBY-2912

MS SQL-Server - Create/Drop Database bug

JRUBY-2815

System triggered from inside of tracing behaves oddly

JRUBY-3069

dbd-jdbc: Support Ruby DBI Statement.fetch_scroll

JRUBY-3235

dbd-jdbc: Add helper functions to wrap already existing jdbc Connection and Statement objects

JRUBY-3068

dbd-jdbc: Override Ruby DBI's default database return value coercion for Date / Time / Timestamp columns

JRUBY-3067

dbd-jdbc: Register a handler for DBI 0.4.x's default parameter binding type coercion

JRUBY-1345

Files added to a module via Kernel.autoload are not automatically loaded if the class they contain is extended

JRUBY-2727

ActiveScaffold 1.1.1 fails with JRuby 1.1.2, probable path problem

JRUBY-2699

If user's PATH contains '.' and 'jruby' resolves to './jruby', JRUBY_HOME is incorrectly set to '.', leading to 'NoClassDefFoundError'

JRUBY-2820

Most Etc methods behave diferently on Windows under x32 and x64 JVMs

JRUBY-2841

String#<<>

JRUBY-2844

Memcache session store does not work across multiple application servers

JRUBY-2845

'-S switch breaks if you have directory in pwd matching name of file in bin/PATH

JRUBY-2849

CCE using proc{} in AR callbacks

JRUBY-2862

Improve JRuby::Commands' handling of bindir

JRUBY-2861

Cannot call super inside a method that overrides a protected method on Java base class

JRUBY-2868

ThreadService.getRubyThreadFromThread supports only one non-rubynative thread at a time.

JRUBY-2782

"No such file or directory (IOError)" when JAR file named in java.class.path but not active filesystem

JRUBY-2901

JRuby does not support options in shebang line

JRUBY-2846

gem generate_index broken

JRUBY-2832

Rails static page caching won't generally work with Java ServletFilter unless some serious hack with the cache directory is found

JRUBY-414

Serialization of wrapped Java objects could be handled as user-marshalled data by Marshal

JRUBY-2921

Newly overridden methods are not called if the old superclass method has already been called

JRUBY-2661

specs hang under Apple Java 5

JRUBY-2933

Ruby runtimes are pinned to memory due to ChannelStream

JRUBY-1578

Incomplete HTTS response from Microsoft IIS servers using net/https

JRUBY-2941

popen IO lockup with multiple threads

JRUBY-2925

Java Integration can now instantiate Java classes with no public constructor

JRUBY-2802

JRuby wrapped Java objects formerly exposed readers for non-public fields

JRUBY-2504

JAR URLs are inconsistently supported by APIs that access the filesystem

JRUBY-1846

Kernel::fork should use forkall(2) on solaris instead of fork(2)

JRUBY-2395

Have to call setPaint instead of assigning to g.paint

JRUBY-1401

Pathname#realpath fails for Windows drive letters

JRUBY-2296

convertToRuby does not work if to_s does not return a String (but for example nil)

JRUBY-2904

Need a better solution for tracking Java object wrappers

JRUBY-1327

When define_method replaces an inherited Java method, the ruby_case_version is not replaced

JRUBY-2951

repeated popen call may throw NULL pointer exception

JRUBY-2974

multi-byte exception message turned into garbled characters when Java Exception nested NativeException.

JRUBY-2980

String#<<>

JRUBY-2981

alias_method_chain pattern is extremely show on jruby

JRUBY-2982

Unicode regular expressions by UTF-8 don't work

JRUBY-2988

jirb does not echo characters to the terminal after suspend and resume in the shell

JRUBY-2997

Dir[] results in NPE depending on permissions

JRUBY-3000

integration issues with Java classes containing inner classes

JRUBY-3007

Message method value of Exception is missing in Java when exception raised in ruby

JRUBY-3016

Nested Class/Enum issue with JRockit

JRUBY-3011

java classes with non-public constructors are incorrectly instantiated

JRUBY-2999

Regression: Inheriting method with same name from two Java interfaces causes Java classloader error

JRUBY-2700

jdbcsqlite3 adapter does not respect default parameter

JRUBY-3026

[Derby] Allow select/delete/update conditions with comparison to NULL using '='

JRUBY-3288

jruby-openssl: SSLSocket.syswrite error for big (>16k) data

JRUBY-3017

DRb "premature header" error on JRuby client

JRUBY-2766

Create caching mechanism for all our many calls to callMethod from Java code

JRUBY-3200

insert statement returns null from the postgresql jdbc adapter

JRUBY-2996

Migration step with create_table with string column with :default => "" fails due to missing default value in SQL

JRUBY-2184

ActiveRecord is slower on JRuby than on MRI

JRUBY-3202

url style Postgres configuration is broken in rake.

JRUBY-1854

def is almost 3x slower in JRuby

JRUBY-2618

Table does not exist error possibly caused by upper case table name

JRUBY-3003

ArrayStoreException in compiler when calling Array.fill

JRUBY-2180

break performance is slower than MRI, sometimes slower than interpreted

JRUBY-2304

active_scaffold - No such file or directory

JRUBY-3386

Array#eql? rubyspec failure

JRUBY-3387

Array#== rubyspec failure

JRUBY-3054

Thread#status is "run" when thread is blocking on condition variable

JRUBY-3390

RubySpec: Numeric#coerce calls #to_f to convert other if self responds to #to_f

JRUBY-3055

permission javax.management.MBeanServerPermission "createMBeanServer";

JRUBY-3072

Using a ruby Numeric to set a parameter with a signature of java.lang.Integer causes a java.lang.ClassCastException

JRUBY-3082

1.1.4 unable to use 'logging' gem (works in 1.1.3)

JRUBY-3398

Attributes defined from Java tried to use current frame for visibility

JRUBY-3397

defined? CONST is not following proper constant lookup rules

JRUBY-3089

Digest::Base stores in memory all bytes passed to the digest, causing OutOfMemoryError

JRUBY-3125

Some Socket constants not supported.

JRUBY-3128

Different jruby behaviour that ruby 1.8.6/1.8.7/1.9 when running file that is named as one of required file.

JRUBY-3175

Cloning java byte array returns incorrect object

JRUBY-3177

ConcurrentModificationException

JRUBY-3178

http spec tests fail when webrick starts on address 0.0.0.0

JRUBY-2548

JRuby conversion of String to Java String is arcane

JRUBY-3174

FFI MemoryPointer#get_string(0, x) gets confused by null byte in the buffer

JRUBY-2896

jruby -S picks up script from local directory

JRUBY-3163

Incorrect namespace for CipherError

JRUBY-1853

define_method methods do not display the correct stack trace, may not be using frame safely

JRUBY-2855

Classpath search order is not respected by require when classpath includes both jars and directories

JRUBY-3222

Problems with migrations where direct type specified

JRUBY-2424

running with -rprofile with multithreaded test causes NPE

JRUBY-2691

Update sybase driver to pass simple unit tests with jtds and verify it works with the new dialect keyword

JRUBY-3065

New public LoadService#findFileToLoad method

JRUBY-2261

ThreadContext should use SoftReference instead of WeakReference

JRUBY-2116

import org.eclipse.jface.dialogs.MessageDialog -- causes java.lang.NullPointerException

JRUBY-2898

Exception trying to use BSF (java.lang.NoClassDefFoundError: org/apache/bsf/util/BSFEngineImp)

JRUBY-2003

rexml pretty printing wrap() error

JRUBY-752

undef'ing and redef'ing methods should give disabled message?

JRUBY-2262

Java toString() mapping to invoke(... to_s ...).toString() doesn

JRUBY-3121

Glassfish Gem 0.9.0 does not work with JRuby 1.1.5

JRUBY-551

JRUBY-549 bfts test_file_test failures

JRUBY-2248

Problem with active_scaffold defaults defined in application.rb

JRUBY-2446

httprequest error for a SOAP request to a Rails ActiveWebService

JRUBY-3005

Stomp gem hangs in Stomp::Client#subscribe

JRUBY-3180

Class in default package can't be reopened under Java namespace

JRUBY-3047

IO.select sometime reports Unable to establish loopback

JRUBY-2851

JDBC adapter in JAR file not being picked up by java.lang.Class.forName in 1.1.3 (worked in 1.1.2)

JRUBY-2313

Automatically convert RubyFile to java.io.File

JRUBY-2328

Overriding require causes eval to give wrong __FILE__ in certain circumstances

JRUBY-2794

Failure in String#crypt specs, Mac OS X, Soylatte

JRUBY-2137

ENV[] is case sensitive on Windows

JRUBY-2797

File.expand_path rubyspec failure on Mac OS X, Soylatte

JRUBY-2608

Examine whether -Xrs flag to JVM could be used to improve our signal-handling logic

JRUBY-2675

jirb + jline do not work in cygwin

JRUBY-2521

Compilation Warning for Sun proprietary API using

JRUBY-2263

Running merb under a concurrent load causes ArrayIndexOutOfBoundsExceptions

JRUBY-2706

File.stat('/home') treated as a relative path

JRUBY-2557

NPE when yielding method

JRUBY-2860

EOFError while consuming REST web service from glassfish v3

JRUBY-2835

rails image_tag generates url get 404

JRUBY-3095

chmod_R broken

JRUBY-2830

String#unpack with 'w' is completely unimplemented

JRUBY-3038

Unable to insert YAML into t.text field (behavior different from Ruby 1.8.6)

JRUBY-3004

Excess warnings when using rake TestTask

JRUBY-1606

File.expand_path does not work as expected

JRUBY-750

defineAlias reports original name and not aliased one in stack traces

JRUBY-1201

TCPSocket.new(dest_adrr, dest_port, src_addr, src_port) missing from JRuby

JRUBY-3160

REXML returns error for add_attribute

JRUBY-2732

org.jruby.util.RubyInputStream is unused

JRUBY-2455

"jruby" script failed to find JRUBY_HOME leads to class not found

JRUBY-3190

method `module_eval' for main:Object should be undefined?

JRUBY-2950

Net::IMAP#authenticate stalls / blocks in recent versions of JRuby

JRUBY-1542

1.1b1 doesn't build with gcj 4.2

JRUBY-2788

Make Time.now monotonically increasing

JRUBY-3296

Etc.getpwuid should raise TypeError if invalid type

JRUBY-3167

loadpath and classpath problem

JRUBY-2983

JRuby crashes after running 110 RSpec examples

JRUBY-3085

Add constant caching for Colon2 and Colon3 (specific module and Object cases)

JRUBY-3207

super error message is inaccurate when superclass doesn't implement method.

JRUBY-2979

File#getc fails on illegal seek when reading from /dev/ttyS0 on Linux

JRUBY-3076

RubyUDPSocket.send tries to do inet address lookup, pauses too long for inet6 failure

JRUBY-2555

CLONE -JIT max and JIT threshold should be adjusted for improvements in JRuby over the past months

JRUBY-3407

FFI Stack Level Too Deep on Library.send(:method, args)

JRUBY-3410

Add -y flag to debug the parser

JRUBY-3103

Compiler closures use two different binding mechanisms, need better construction and caching logic

JRUBY-3179

JRuby can't handle do/end blocks within String-inlined expressions

JRUBY-3316

Group expression class path fails to parse

JRUBY-3151

OpenSSL::Random#pseudo_bytes raises ArgumentError on negative arguments

JRUBY-3088

"RStone" port of PyStone is slower on JRuby than 1.9

JRUBY-3120

Regression: error serializing array of objects with custom to_yaml def to yaml

JRUBY-3211

builder library is slower in JRuby than in MRI

JRUBY-1884

handling of file close while reading differs from mri

JRUBY-3214

load and require don't work correctly for .class files

JRUBY-3218

Import is sometimes confused by unquoted class name

JRUBY-3224

Array#to_java with java object reference doesn't carry over object identity

JRUBY-1079

IO.sysopen not defined

JRUBY-3071

Illegal seek error trying to read() from pipe

JRUBY-3152

Process.times returns invalid values

JRUBY-3064

Process.uid does not work on non-natve platforms (jna-posix)

JRUBY-2757

Compiled argument processing and arity checking are too large, too much bytecode

JRUBY-3061

NKF(unsupported Q encode stream)

JRUBY-3105

Embedding JRuby-Rack (non-war deployment)

JRUBY-3077

Update ruby_test tests and incorporate changes into build

JRUBY-2970

Timeout.rb is not working in special cases (Thread may block whole application).

JRUBY-3253

Lack of default jruby.home in embedded usage causes NPE

JRUBY-3063

File::link using CIFS raises Errno::EEXIST error if the 'old_file' is open while Matz Ruby raises Errno::ETXTBSY

JRUBY-3252

Iterative String concatenation operations in JRuby degrade faster than in MRI.

JRUBY-3255

jruby -S script/server fails in Rails application

JRUBY-3258

after installing minigems (and after minigem setup gems not working on 1.1.6)

JRUBY-1235

DRb hangs when transferring Ruby objects created in Java

JRUBY-3271

Java Stacktrace and exception is swallowed

JRUBY-2063

Wrong monitor handling in o.j.util.ChannelStream.read

JRUBY-2131

Select with nil arrays should throw an exception