<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-20975090</id><updated>2012-01-12T05:24:31.193-06:00</updated><category term='ruby'/><category term='application bundle'/><category term='gsoc'/><category term='meetup'/><category term='file structure'/><category term='magic'/><category term='glassfish'/><category term='irb'/><category term='os x'/><category term='macruby'/><category term='applet'/><category term='open source'/><category term='presentation'/><category term='ruby compiler'/><category term='grails'/><category term='gpl'/><category term='python'/><category term='compilation'/><category term='javapolis'/><category term='enterprise'/><category term='rails'/><category term='ruby 2.0'/><category term='sun'/><category term='eclipse'/><category term='rubinius'/><category term='invokedynamic'/><category term='programming languages'/><category term='jsr292'/><category term='tech days'/><category term='jsr223'/><category term='humor'/><category term='scripting'/><category term='java'/><category term='jdk'/><category term='yarv'/><category term='dynamic dispatch'/><category term='jvm'/><category term='netbeans'/><category term='mcgovern'/><category term='jruby on rails'/><category term='ironruby'/><category term='jruby release'/><category term='dynamic languages'/><category term='groovy'/><category term='mongrel'/><category term='quick outline'/><category term='tiobe'/><category term='jruby'/><category term='methods'/><category term='jython'/><category term='jsr270'/><category term='compiler'/><category term='keywords'/><title type='text'>Headius</title><subtitle type='html'>Helping Ruby and Java Evolve Together</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://headius.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default?start-index=101&amp;max-results=100'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>299</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-20975090.post-1291323690218813261</id><published>2011-01-19T14:31:00.001-06:00</published><updated>2011-01-19T14:32:26.849-06:00</updated><title type='text'>JRuby on Rails on Amazon Elastic Beanstalk</title><content type='html'>Amazon this week announced &lt;a href="http://aws.amazon.com/elasticbeanstalk/"&gt;Elastic Beanstalk&lt;/a&gt;, a managed &lt;a href="http://tomcat.apache.org/"&gt;Apache Tomcat&lt;/a&gt; service for AWS. Naturally, I had to try JRuby on it.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First, the bad:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;AWSEB is really slow to deploy stuff. Several times it got "stuck" and I waited for more than 30 minutes for it to recover. It did not appear to be an app issue, since the app came up just fine.&lt;/li&gt;&lt;li&gt;The default instance size is t1.micro. I was able to get a Rails app to boot there, but it's a very underpowered size.&lt;/li&gt;&lt;li&gt;It appears to start up JVMs with 256MB of memory max and 64MB of permgen. For a larger app, or one with many Rails instances, that might not be enough. For a "threadsafe" Rails app, though, it's plenty.&lt;/li&gt;&lt;li&gt;The default EC2 load balancer for the new Beanstalk instance is set to ping the "/" URL. If you don't rig up a / route in your Rails app (like I forgot to do) the app will come up for a few minutes and immediately get taken out.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;And the good news: it works great once you get past the hassles! Here's the process that worked for my app (assuming app is already build and ready for deploy).&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Preparing the app:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Ensure jruby-openssl is in Gemfile. Rails seems to want it in production mode.&lt;/li&gt;&lt;li&gt;Edit config/environments/production.rb to enable threadsafe mode.&lt;/li&gt;&lt;li&gt;`warble`&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Preparing Elastic Beanstalk:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Create a new instance, specifying the .war file Warbler created above as the app to deploy&lt;/li&gt;&lt;li&gt;There is no step two&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Once the instance has been prepared, you may want to resize it to something larger than t1.micro if it's meant to be a real app...but it should boot ok.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://i.min.us/ieh0Hc.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 452px; height: 420px;" src="http://i.min.us/ieh0Hc.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Have fun!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-1291323690218813261?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/1291323690218813261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=1291323690218813261' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1291323690218813261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1291323690218813261'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2011/01/jruby-on-rails-on-amazon-elastic.html' title='JRuby on Rails on Amazon Elastic Beanstalk'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-6030879933587376895</id><published>2011-01-05T18:04:00.004-06:00</published><updated>2011-01-05T20:14:27.612-06:00</updated><title type='text'>Representing Non-Unicode Text on the JVM</title><content type='html'>JRuby is an implementation of Ruby, and in order to achieve the high level of compatibility we boast we've had to put in some extra work. Probably the biggest area is in management of String data.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Strings in Ruby 1.8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ruby 1.8 did not differentiate between strings of bytes or strings of characters. A String was just an array of bytes, and the representation of those bytes was dependent on how you used them. You could do regular expression matches against non-text binary sequences (used by some to parse binary formats like PNG). You could treat them as UTF-8 text by setting global encoding variables to assume UTF-8 in literal strings. And you could use the same methods for dealing with strings of bytes you would with strings of characters...split, gsub, and so on. The lack of a character abstraction was painful, but the ability to do character-string operations against byte-strings was frequently useful.&lt;br /&gt;&lt;br /&gt;In order to support all this, we were forced in JRuby to also represent strings as byte[]. This was not an easy decision. Java's strings are all UTF-16 internally. By moving to byte[]-based strings, we lost many benefits of being on the JVM, like built-in regular expression support, seamless passing of strings to Java methods, and easy interaction with any Java libraries that accept, return, or manipulate Java strings. We eventually had to implement our own regexp engines (or the byte[]-to-char[]-to-byte[] overhead would kill us) and calls from Ruby to Java still pay a cost to pass Strings.&lt;br /&gt;&lt;br /&gt;But we got a lot out of it too. We would not have been able to represent binary content easily with a char[]-based string, since it would either get garbled (when Java tried to decode it) or we'd have to force the data into only the lower byte of each char, doubling the size of all strings in memory. We have some of the fastest String IO capabilities of any JVM language, since we never have to decode text. And most importantly, we've achieved an incredibly high level of compatibility with C Ruby that would have been difficult or impossible forcing String data into char[].&lt;br /&gt;&lt;br /&gt;There's also another major benefit: we can support Ruby 1.9's "multilingualization".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Strings in Ruby 1.9&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ruby 1.9 still represents all string data as byte[] internally, but it adds an additional field to all strings: Encoding (there's also "code range", but it's merely an internal optimization).&lt;br /&gt;&lt;br /&gt;The biggest problem with encoded text in MRI was that you never knew what a string's encoding was supposed to be; the String object itself only aggregated byte[], and if you ever ended up with mixed encodings in a given app, you'd be in trouble. Rails even introduced its own "Chars" type specifically to deal with the lack of encoding support.&lt;br /&gt;&lt;br /&gt;In Ruby 1.9, however, Strings know their own encoding. Strings can be forced to a specific encoding or transcoded to another. IO streams are aware of (and configurable for) external and internal encodings, and there's also default external and internal encodings. And you can still deal with raw binary data in the same structure and with the same String-manipulating features. For a full discussion of encoding support in Ruby 1.9, see &lt;a href="http://yehudakatz.com/"&gt;Yehuda Katz&lt;/a&gt;'s excellent post on &lt;a href="http://yehudakatz.com/2010/05/05/ruby-1-9-encodings-a-primer-and-the-solution-for-rails/"&gt;Ruby 1.9 Encodings: A Primer&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;As part of JRuby 1.6, we've been working on getting much closer to 100% compatible with Ruby 1.9. Of course this has meant working on encoding support. Luckily, we had a hacking machine some years ago in Marcin Mielzynski, who implemented not only our encoding-agnostic regexp engine (a port of Oniguruma from C), but also our byte[]-based String logic and almost all of our Encoding support. The remaining work has trickled in over the subsequent years, leading up the the last few months of heavy activity on 1.9 support.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;How It Works&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You might find it interesting to know how all this works, since JRuby is a JVM-based language where Strings are supposed to be UTF-16 always.&lt;br /&gt;&lt;br /&gt;First off, String, implemented by the &lt;a href="https://github.com/jruby/jruby/blob/master/src/org/jruby/RubyString.java"&gt;RubyString&lt;/a&gt; class. RubyString aggregates an Encoding and an array of bytes, using a structure we call &lt;a href="https://github.com/jruby/bytelist/blob/master/src/org/jruby/util/ByteList.java"&gt;ByteList&lt;/a&gt;. ByteList represents an arbitrary array of bytes, a view into them, and an encoding. All operations against a String operate within RubyString's code against ByteLists.&lt;br /&gt;&lt;br /&gt;IO streams, implemented by &lt;a href="https://github.com/jruby/jruby/blob/master/src/org/jruby/RubyIO.java"&gt;RubyIO&lt;/a&gt; (and subclasses) and ChannelStream/ChannelDescriptor, accept and return ByteList instances. ByteList is the text/binary currency of JRuby...our java.lang.String.&lt;br /&gt;&lt;br /&gt;Regexp is implemented in &lt;a href="http://"&gt;RubyRegexp&lt;/a&gt; using &lt;a href="https://github.com/jruby/joni"&gt;Joni&lt;/a&gt;, our Java port of the Oniguruma regular expression library. Oniguruma accepts byte arrays and uses encoding-specific information at match time to know what constitutes a character in that byte array. It is the only regular expression engine on the JVM capable of dealing with encodings other than UTF-16.&lt;br /&gt;&lt;br /&gt;The JRuby parser also ties into encoding, using it on a per-file basis to know how to encode each literal string it encounters. Literal strings in the AST are held in &lt;a href="https://github.com/jruby/jruby/blob/master/src/org/jruby/ast/StrNode.java"&gt;StrNode&lt;/a&gt;, which aggregates a ByteList and constructs new String instances from it.&lt;br /&gt;&lt;br /&gt;The compiler is an interesting case. Ideally we would like all literal strings to still go into the class file's constant pool, so that they can be loaded quickly and live as part of the class metadata. In order to do this, the byte[]-based string content is forced into a char[], which is forced into a java.lang.String that goes in the constant pool. At load time, we unpack the bytes and return them to a ByteList that knows their actual encoding. Dare I claim that JRuby is the first JVM language to allow representing literal strings in encodings other than UTF-16?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What It Means For You&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;At the end of the day, how are you affected by all this? How is your life improved?&lt;br /&gt;&lt;br /&gt;If you are a Ruby user, you can count on JRuby having solid support for Ruby 1.9's "M17N" strings. That may not be complete for JRuby 1.6, but we intend to take it as far as possible. JRuby 1.6 *will* have the lion's share of M17N in-place and working.&lt;br /&gt;&lt;br /&gt;If you are a JVM user...JRuby represents the *only* way you can deal with arbitrarily-encoded text without converting it to UTF-16 Unicode. At a minimum, this means JRuby has the potential to deal with raw wire data much more efficiently than libraries that have to up-convert to UTF-16 and downconvert back to UTF-8. It may also mean encodings without complete representation in Unicode (like Japanese "emoji" characters) can *only* be losslessly processed using JRuby, since forcing them into UTF-16 would either destroy them or mangle characters. And of course no other JVM language provides JRuby's capabilities for using String-like operations against arbitrary binary data. That's gotta be worth something!&lt;br /&gt;&lt;br /&gt;I want to also take this opportunity to again thank Marcin for his work on JRuby in the past; Tom Enebo for his suffering through encoding-related parser work the past few weeks; Yukihiro "Matz" Matsumoto for adding encoding support to Ruby; and all JRuby committers and contributors who have helped us sort out M17N for JRuby 1.6.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-6030879933587376895?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/6030879933587376895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=6030879933587376895' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/6030879933587376895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/6030879933587376895'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2011/01/representing-non-unicode-text-on-jvm.html' title='Representing Non-Unicode Text on the JVM'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-2529660961304795268</id><published>2011-01-04T05:31:00.004-06:00</published><updated>2011-01-04T05:53:08.022-06:00</updated><title type='text'>Flat and Graph Profiles for JRuby 1.6</title><content type='html'>&lt;div&gt;Sometimes it's the little things that make all the difference in the world.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;For a long time, we've extolled the virtues of the amazing JVM tool ecosystem. There's literally dozens of profiling, debugging, and monitoring tools, making JRuby perhaps the best Ruby tool ecosystem you can get. But there's a surprising lack of tools for command-line use, and that's an area many Rubyists take for granted.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;To help improve the situation, we recently got the ruby-debug maintainers to ship our JRuby version, so&lt;a href="http://blog.headius.com/2010/12/jruby-finally-installs-ruby-debug-gem.html"&gt; JRuby has easy-to-use command-line Ruby debugging support&lt;/a&gt;. You can simply "gem install ruby-debug" now, so we'll stop shipping it in JRuby 1.6.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;We also shipped a basic "flat" instrumented profiler for JRuby 1.5.6. It's almost shocking how few command-line profiling tools there are available for JVM users; most require you to boot up a GUI and click a bunch of buttons to get any information at all. Even when there are tools for profiling, they're often bad at reporting results for non-Java languages like JRuby. So we decided to whip out a --profile flag that gives you a basic, flat, instrumented profile of your code.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;To continue this trend, we enlisted the help of &lt;a href="http://danlucraft.com/"&gt;Dan Lucraft&lt;/a&gt; of the &lt;a href="http://redcareditor.com/"&gt;RedCar&lt;/a&gt; project to expand our profiler to include "graph" profiling results. Dan previously implemented JRuby support for the "ruby-prof" project, a native extension to C Ruby, in the form of "&lt;a href="https://github.com/danlucraft/jruby-prof"&gt;jruby-prof&lt;/a&gt;" (which you can install and use today on any recent JRuby release). He was a natural to work on the built-in profiling support.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;For the uninitiated, "flat" profiles just show how much time each method body takes, possibly with downstream aggregate times and total aggregate times. This is what you usually get from built-in command-line profilers like the "hprof" profiler that ships with Hotspot/OpenJDK. Here's a "flat" profile for a simple piece of code.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;pre&gt;~/projects/jruby ➔ jruby --profile.flat -e "def foo; 100000.times { (2 ** 200).to_s }; end; foo"&lt;br /&gt;Total time: 0.99&lt;br /&gt;&lt;br /&gt;    total        self    children       calls  method&lt;br /&gt;----------------------------------------------------------------&lt;br /&gt;     0.99        0.00        0.99           1  Object#foo&lt;br /&gt;     0.99        0.08        0.90           1  Fixnum#times&lt;br /&gt;     0.70        0.70        0.00      100000  Bignum#to_s&lt;br /&gt;     0.21        0.21        0.00      100000  Fixnum#**&lt;br /&gt;     0.00        0.00        0.00         145  Class#inherited&lt;br /&gt;     0.00        0.00        0.00           1  Module#method_added&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;A "graph" profile shows the top N call stacks from your application's run, breaking them down by how much time is spent in each method. It gives you a more complete picture of where time is being spent while running your application. Here's a "graph" profile (abbreviated) for the same code.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;pre&gt;~/projects/jruby ➔ jruby --profile.graph -e "def foo; 100000.times { (2 ** 200).to_s }; end; foo"&lt;br /&gt;%total   %self    total        self    children                 calls  name&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;100%     0%        1.00        0.00        1.00                     0  (top)&lt;br /&gt;                   1.00        0.00        1.00                   1/1  Object#foo&lt;br /&gt;                   0.00        0.00        0.00               145/145  Class#inherited&lt;br /&gt;                   0.00        0.00        0.00                   1/1  Module#method_added&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;                   1.00        0.00        1.00                   1/1  (top)&lt;br /&gt; 99%     0%        1.00        0.00        1.00                     1  Object#foo&lt;br /&gt;                   1.00        0.09        0.91                   1/1  Fixnum#times&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;                   1.00        0.09        0.91                   1/1  Object#foo&lt;br /&gt; 99%     8%        1.00        0.09        0.91                     1  Fixnum#times&lt;br /&gt;                   0.70        0.70        0.00         100000/100000  Bignum#to_s&lt;br /&gt;                   0.21        0.21        0.00         100000/100000  Fixnum#**&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;                   0.70        0.70        0.00         100000/100000  Fixnum#times&lt;br /&gt; 69%    69%        0.70        0.70        0.00                100000  Bignum#to_s&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;                   0.21        0.21        0.00         100000/100000  Fixnum#times&lt;br /&gt; 21%    21%        0.21        0.21        0.00                100000  Fixnum#**&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;                   0.00        0.00        0.00               145/145  (top)&lt;br /&gt;  0%     0%        0.00        0.00        0.00                   145  Class#inherited&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;                   0.00        0.00        0.00                   1/1  (top)&lt;br /&gt;  0%     0%        0.00        0.00        0.00                     1  Module#method_added&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;As you can see, you get a much better picture of why certain methods are taking up time and what component calls are contributing most to that time.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;We haven't settled on the final command-line flags, but look for the new graph profiling (and the cleaned-up flat profile) to ship with JRuby 1.6 (real soon now!)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-2529660961304795268?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/2529660961304795268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=2529660961304795268' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2529660961304795268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2529660961304795268'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2011/01/flat-and-graph-profiles-for-jruby-16.html' title='Flat and Graph Profiles for JRuby 1.6'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-6034650160414346690</id><published>2010-12-23T16:01:00.002-06:00</published><updated>2010-12-23T16:15:05.386-06:00</updated><title type='text'>Improved JRuby Startup by Deferring Gem Plugins</title><content type='html'>Another present for you JRubyists out there!&lt;br /&gt;&lt;br /&gt;JRuby has had notoriously bad startup times. Not as bad as, say, IronRuby (sorry guys!), but definitely a big fat hit every time you need to run some Ruby code from the command line. Some of this overhead was related to JRuby, and we've steadily worked to improve that over the years. Some of it is due to the JVM, most commonly due to running on the "server" Hotspot VM or another JVM that does not have an interpreter (both of which start up considerably slower than Hotspot/OpenJDK's "client" mode). I've blogged &lt;a href="http://blog.headius.com/2010/03/jruby-startup-time-tips.html"&gt;tips and tricks for JRuby startup&lt;/a&gt; before, and these mostly apply to vanilla JRuby startup performance.&lt;br /&gt;&lt;br /&gt;However, a large part of the overhead was not specifically due to JRuby or the JVM, but to RubyGems. RubyGems in version 1.3 added support for "plugins", whereby gems could include a specially-named file to extend the functionality of RubyGems itself. Most of these plugins added command-line tools like "gem push" for pushing a new gem to gemcutter.org (now built-in for pushing to rubygems.org). Unfortunately, the feature was originally added by having RubyGems do a full scan of all installed gems on every startup. If you only had a few gems, this was a minor problem. If you had more than a few, it became a big fat O(N) problem, where each of those N could be arbitrarily complex in themselves.&lt;br /&gt;&lt;br /&gt;The good news is that it looks like my proposed change – &lt;a href="http://rubyforge.org/pipermail/rubygems-developers/2010-December/005898.html"&gt;making plugin scanning happen *only* when using the "gem" command&lt;/a&gt; – appears likely to be approved for RubyGems 1.4, due out reasonably soon.&lt;br /&gt;&lt;br /&gt;Here's the &lt;a href="https://gist.github.com/751969"&gt;patch&lt;/a&gt; and the impact to RubyGems startup times are below. The first two times are without the patch, with the first time against a "cold" filesystem. The final time is with the patch in place. In all cases, it's against my local JRuby working copy, which has around 500 gems installed.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jruby -e "t = Time.now; require 'rubygems'; puts Time.now - t"&lt;br /&gt;17.09&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ jruby -e "t = Time.now; require 'rubygems'; puts Time.now - t"&lt;br /&gt;6.959&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ git stash pop&lt;br /&gt;# On branch master&lt;br /&gt;# Changed but not updated:&lt;br /&gt;#   (use "git add &amp;lt;file&amp;gt;..." to update what will be committed)&lt;br /&gt;#   (use "git checkout -- &amp;lt;file&amp;gt;..." to discard changes in working directory)&lt;br /&gt;#&lt;br /&gt;# modified:   lib/ruby/site_ruby/1.8/rubygems.rb&lt;br /&gt;# modified:   lib/ruby/site_ruby/1.8/rubygems/gem_runner.rb&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ jruby -e "t = Time.now; require 'rubygems'; puts Time.now - t"&lt;br /&gt;0.481&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It's truly a shocking difference, and it's easy to see why JRuby (plus RubyGems) has had such a bad startup-time reputation.&lt;br /&gt;&lt;br /&gt;I've already made this change locally to JRuby's copy of RubyGems, which should help any users working against JRuby master. The change will almost certainly ship in JRuby 1.6, with RCs showing up in the next couple weeks. So with this change and my &lt;a href="http://blog.headius.com/2010/03/jruby-startup-time-tips.html"&gt;JRuby startup tips&lt;/a&gt;, we're on the road to a much more pleasant JRuby experience.&lt;br /&gt;&lt;br /&gt;Happy Hacking!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-6034650160414346690?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/6034650160414346690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=6034650160414346690' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/6034650160414346690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/6034650160414346690'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/12/improved-jruby-startup-by-deferring-gem.html' title='Improved JRuby Startup by Deferring Gem Plugins'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-6178590998598716183</id><published>2010-12-23T15:31:00.002-06:00</published><updated>2010-12-23T15:37:42.479-06:00</updated><title type='text'>JRuby Finally Installs ruby-debug Gem</title><content type='html'>This should be a great Christmas present for many of you.&lt;br /&gt;&lt;br /&gt;After over three years, the "ruby-debug" gem finally installs properly on JRuby.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ gem install ruby-debug&lt;br /&gt;Successfully installed ruby-debug-base-0.10.4-java&lt;br /&gt;Successfully installed ruby-debug-0.10.4&lt;br /&gt;2 gems installed&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Back in 2007, folks working on NetBeans, Eclipse, and IntelliJ support for Ruby came together to build a new version of the ruby-debug backend that would work on JRuby. They shared the effort, we JRuby guys added features they needed to do a clean port of the ruby-debug C code, and the ultimate result was a ruby-debug-base gem that isolated the platform-specific bits.&lt;br /&gt;&lt;br /&gt;For whatever reason, the JRuby version of ruby-debug-base never got pushed as a real, live "-java" gem. This meant that you had to download ruby-debug-base-VERSION-java.gem yourself to get ruby-debug to install. To make this process easier, we even shipped ruby-debug and ruby-debug-base preinstalled in JRuby 1.5.&lt;br /&gt;&lt;br /&gt;Unfortunately, this was only a partial answer. Many libraries and applications want to install all their dependencies clean. If one of those dependencies was ruby-debug, it would fail to install. Rails even includes special JRuby-specific lines in its default Bundler Gemfile to exclude ruby-debug when bundling on JRuby.&lt;br /&gt;&lt;br /&gt;All that nonsense ends today. Rocky Bernstein, one of the maintainers of the ruby-debug gem, agreed to push our ruby-debug-base to the canonical rubygems.org repository. As a result, ruby-debug now installs properly on JRuby. It only took three years to get that gem pushed (by nobody's fault...I think everyone expected everyone else to follow through on it).&lt;br /&gt;&lt;br /&gt;Merry Christmas, Happy Chanukah, Joyous Kwanza, and enjoy your holiday season!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-6178590998598716183?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/6178590998598716183/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=6178590998598716183' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/6178590998598716183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/6178590998598716183'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/12/jruby-finally-installs-ruby-debug-gem.html' title='JRuby Finally Installs ruby-debug Gem'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-2050507808853794066</id><published>2010-12-23T13:43:00.003-06:00</published><updated>2010-12-23T14:49:26.922-06:00</updated><title type='text'>Quick Thoughts on Oracle/Apache and the Java TCK</title><content type='html'>This was going to be a reply to a friend on Twitter, when I realized it would be several tweets and I might as well put them in one place.&lt;br /&gt;&lt;br /&gt;Grant Michaels (@grantmichaels) sent me this link to the &lt;a href="http://jcp.org/aboutJava/communityprocess/summaries/2010/October2010-public-minutes.html"&gt;October JCP (Java Community Process) EC (Expert Committee) meeting notes&lt;/a&gt;. The Apache/&lt;a href="http://en.wikipedia.org/wiki/Technology_Compatibility_Kit"&gt;TCK (Technology Compatibility Kit)&lt;/a&gt; issue was discussed at length.&lt;br /&gt;&lt;br /&gt;For those of you in the dark, Apache recently resigned from the JCP because of the ongoing dispute over their "&lt;a href="http://harmony.apache.org/"&gt;Harmony&lt;/a&gt;" OSS (Open-Source Software) Java implementation's inability to get an unencumbered license to the Java TCK. Passing the TCK is a requirement for an implementation to officially be accepted as "Java".&lt;br /&gt;&lt;br /&gt;I had heard about this problem from a distance, but only recently started to understand its complexity. The TCK includes FOU (Field of Use) clauses preventing TCK-tested implementations other than OpenJDK from being released as open-source. Only implementations "largely" based on OpenJDK (Open Java Development Kit, Sun's GPLed "Hotspot" VM and class libraries) are allowed to get around this requirement. Apache's Harmony, being entirely independent and &lt;a href="http://www.apache.org/licenses/LICENSE-2.0.html"&gt;Apache-licensed&lt;/a&gt;, does not qualify.&lt;br /&gt;&lt;br /&gt;If that were all there is to it, Apache would not have any real grounds for complaining. But the &lt;a href="http://jcp.org/aboutJava/communityprocess/JSPA2.pdf"&gt;JSPA (Java Specification Participation Agreement, PDF)&lt;/a&gt; requires only unencumbered specifications, reference implementations, and test kits be submitted to the JCP. This sets the stage for an ugly licensing battle that has stymied Java's progress for over three years.&lt;br /&gt;&lt;br /&gt;I'm not going to do a tl;dr post on this like I did with &lt;a href="http://blog.headius.com/2010/08/my-thoughts-on-oracle-v-google.html"&gt;Oracle/Google&lt;/a&gt;. Instead, just a few quick thoughts as I read through the notes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Overview&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first thing you will notice is that this isn't a simple cut-and-dried issue. The meeting notes express Oracle's position as outwardly fearful of Harmony leading to many downstream forks, with no recourse for asserting they fulfill the requirements of the Java specification. There seems to be an implied stab at Android here, which uses Harmony's class libraries atop the Dalvik VM to implement a substantial portion (but not all) of what looks like Java SE 5. Oracle states this decision is final; Apache will not be granted an unencumbered TCK license. Oracle is not known for changing their minds.&lt;br /&gt;&lt;br /&gt;Several EC members, including Doug Lea and Josh Bloch, point out that it's fairly clear the encumbered TCK violates the JSPA's openness clauses. Oracle refuses to comment on this "legal" matter. Doug suggests that EC members might be able to vote to move Java forward with a clearer conscience if the JSPA were amended to make the encumbered TCK "legal".&lt;br /&gt;&lt;br /&gt;Another point brought up by several members is the frustration that they have to deal with licensing at all. They recall a golden age of the JCP where it actually voted on technical matters rather than arguing over licensing.&lt;br /&gt;&lt;br /&gt;IBM declares they are unhappy with this decision, but even more unhappy that the Java platform has stagnated because of it for so long. IBM would eventually go on to &lt;a href="http://www.jcp.org/en/jsr/results?id=5111"&gt;vote "yes" to the disputed Java 7 JSR&lt;/a&gt;, even in the presence of the apparent JSPA violation.&lt;br /&gt;&lt;br /&gt;Apache representative and longtime Harmony advocate Geir Magnusson also weighed in. He argued that the health of the platform would only be bolstered by allowing for many independent open-source implementations, and damaged by disallowing them. When asking for a clarification of why OpenJDK gets a free pass, Adam Messinger (Oracle) stated that he didn't want to answer a legal question, but that OpenJDK's GPL (Gnu Public License) requires reciprocity from downstream forks, reducing the damage and confusion they might cause if released publicly without full spec compliance (I'm paraphrasing based on the notes here).&lt;br /&gt;&lt;br /&gt;Toward the end of the licensing discussion, Adam again called for all memory organizations to participate in OpenJDK. It's fairly clear from these notes and from previous announcements and discussions that Oracle intends for OpenJDK to be the "one true OSS Java", and for all comers to contribute to it. They even managed to get Apple and IBM, longtime GPL foes, to join the family. Apache doesn't do GPL, and so Apache will not contribute to or base projects off OpenJDK.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;No Right Answer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now we enter entirely into the realm of my own opinions.&lt;br /&gt;&lt;br /&gt;At a glance, I hate Oracle for disallowing free use of the TCK. Nobody should be disallowed from implementing their own OSS Java. Harmony is a promising project that would have a promising future if the cloud of licensing, patent protection, and "compliance" could be lifted. It seems that's nearly impossible now.&lt;br /&gt;&lt;br /&gt;I also hate to see a good project like Harmony "die" or be stuck in legal limbo. I'm sure dozens of developers have poured their hearts into Harmony, and they deserve to see it thrive.&lt;br /&gt;&lt;br /&gt;On the other hand, I applaud Oracle for so vigorously promoting OpenJDK. OpenJDK is certainly a more mature JVM and class library than Harmony, having been Sun's official Java implementation for years and years. Bringing IBM and Apple into OpenJDK will help ensure it moves forward on all platforms of note. If you look only at OpenJDK, OSS Java is stronger now than it ever has been.&lt;br /&gt;&lt;br /&gt;Oracle may have a point with the forking concerns. Because Apache's license is so open that anyone can create and release binary-only forks, it would in theory be possible to speckle the Java landscape with Harmony derivatives that are incompatible in subtle ways. Possible, but perhaps unlikely.&lt;br /&gt;&lt;br /&gt;Ultimately, I feel sad about the direction Oracle has taken, but I'm bolstered by hopes that OpenJDK is going to really thrive and grow, and as a result "Java" will continue to see widespread use and adoption across a variety of platforms.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Other Ways Out&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now I go into pure speculation-mode.&lt;br /&gt;&lt;br /&gt;A key problem with the TCK restriction is the fact that the Java specification provides patent grants only to compliant implementations. In other words, if you don't want an Oracle/Google-esque lawsuit once you have billions in the bank, you need to be compliant with the one true TCK. In order to be compliant with the TCK, you can't release your implementation as open source. The patent grant is obviously intended to ensure that third-party implementations are "really" Java.&lt;br /&gt;&lt;br /&gt;There's a bit of a chicken-and-egg thing here. What if Harmony could pass the TCK? In theory, they may be at that point right now. Does the ability to pass the TCK but the inability to run it without tainting mean they're Java or not? If an unrelated third-party forked Harmony into "Barmony", acquired a TCK license, and proved that it passed...would that mean Harmony could be considered compliant without ever having run the TCK?&lt;br /&gt;&lt;br /&gt;What if, as in Android, Harmony simply moved forward without claiming they were compliant? Oracle could eventually club them to death with patent bats. Perhaps such a legal battle would force the legal remifications of the JSPA violation to be addressed in court? Could Oracle survive a legal test of their violation in attempting to back up a patent suit?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What It Means For You&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The ultimate question is how this affects Java developers today and going forward.&lt;br /&gt;&lt;br /&gt;By most estimates, 99% of the worlds Java developers run on one of the standard Java implementations from Oracle, IBM, and other licensees. A massive number of them run atop Hotspot, either in an old closed-source Java 5/6 form or in an OpenJDK 6/7 form. "Nobody" runs Harmony, and so few if any day-to-day Java developers will be affected. That doesn't excuse the situation, but it does soften the actual damage caused.&lt;br /&gt;&lt;br /&gt;Android is another peculiar case. It would be difficult for it to be tested compliant, even if there weren't FOU restrictions on doing so. It uses Harmony libraries but Dalvik VM. It is also a massive force in mobile development now, and killing it would likely put the final nail in mobile Java's coffin. Oracle has to know this. Oracle also has to know that killing Android would hand the mobile keys over to Apple and Microsoft forever. Could Android switch to using OpenJDK-based class libraries? Would that qualify it as being "largely" based on OpenJDK (noting that the class libraries are the vast majority of the code in OpenJDK)? Oracle/Google is likely to be stuck in court for a long time, while Android continues to expand into televisions and tablets along with telephones.&lt;br /&gt;&lt;br /&gt;How about projects that build atop Java, like JRuby? Perhaps even higher a percentage of JRuby users are already running atop OpenJDK or an OpenJDK derivative like IcedTea or SoyLatte. Oracle pushing OpenJDK will only benefit those users.&lt;a href="http://ruboto.org/"&gt; Ruboto (JRuby on Android)&lt;/a&gt; will follow whatever path Android itself ends up following, and nobody can see that future yet...but it seems unlikely Ruboto will ever die since it's unlikely Android will ever die.&lt;br /&gt;&lt;br /&gt;In closing...I encourage everyone to read the EC notes and gather as much information as they can before claiming this is now the final "death" of Java. I also encourage everyone to contribute thoughts, clarifications, and speculation in the comments here.&lt;br /&gt;&lt;br /&gt;Have a happy holiday!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-2050507808853794066?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/2050507808853794066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=2050507808853794066' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2050507808853794066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2050507808853794066'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/12/quick-thoughts-on-oracleapache-and-java.html' title='Quick Thoughts on Oracle/Apache and the Java TCK'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-3346641558815744460</id><published>2010-09-23T03:39:00.002-05:00</published><updated>2010-09-23T03:48:38.225-05:00</updated><title type='text'>Predator and Prey</title><content type='html'>(This is a repost of an article I wrote in 2004, which I stumbled upon this evening and thought worthy of a reprint. Feel free to rip it up and offer your own commentary. I think it is still 100% valid.)&lt;br /&gt;&lt;br /&gt;I came up with the most compelling idea for a Disney-style film the other day. (Ok, perhaps not the most compelling idea, but certainly a fair shot at one)&lt;br /&gt;&lt;br /&gt;Over the years I've heard a number of biologists (ecologists, environmentalists, what have you) comment on (as in expound endlessly upon) something called the "Bambi Syndrome." Simply put, the "Bambi Syndrome" is brought about by cutesy, utopian images of nature, where only unexpected, amorphous entities (usually accompanied by menacing percussion or something equally non-musical) can embody "evil"; it is a view that, in all its splendor and glory, "nature" is "good," while "man" is "bad." The parallel between this viewpoint and several (all?) nature-based Disney films is apparent (although it should be said that Disney is far from being the only perpetrator of "Bambiism").&lt;br /&gt;&lt;br /&gt;So then, you ask, if nature isn't "good", then what is it? Evil and good are purely human constructions. Truth be told, nothing that exists is innately "good" or "evil". These concepts exist only in the eye of the beholder: to the prey, the successful predator is evil; to the predator, the successful prey is evil.&lt;br /&gt;&lt;br /&gt;It could then be considered a great disservice to continue teaching these false ideals to our children, no? This has been my opinion, and I have tried to take an approach with my own son of presenting these facts of nature in as unbiased a way as possible--whence springs the compelling idea.&lt;br /&gt;&lt;br /&gt;Take a typical Disney movie; its clear definition of "good" and "evil" and its even clearer illustration of which roles fall into which category. This movie would begin the same. Also typically, it would be based in nature, perhaps at a very low stratus of the animal kingdom. Predator and prey would be represented by species A (the "good" prey) and B (the "evil" predator). A typical scene ensues, a contest between good and evil, predator and prey. The predator's evil nature is clearly illustrated here, but atypically, the predator wins.&lt;br /&gt;&lt;br /&gt;Just as people in the audience are questioning their faith in Hollywood, we move up one stratum. The evil predator, returning home with the spoils of war, becomes a gentle, caring mother. She was not simply an "evil" aggressor, bent on death and destruction, but a doting, protective mother, expending her own effort, at risk of her life, to care for her childen. In this way, stratum after stratum, "evil" becomes "good", and the elaborate network that makes up our natural system becomes more recognizable for the purity, neutrality, simplicity of its form.&lt;br /&gt;&lt;br /&gt;Finally, as you would expect in such a movie, we would arrive at the most prolific of the Great Apes: man. Illustrating that all kingdoms on earth are becoming man's prey, with as much tree-hugging, granola-chomping tripe as possible to make sure we, the lords of creation, masters of destiny, killers of all, Shiva to nature's Brahma , are shown--incontrovertably--as the only pure "evil" on earth, the movie careens ever faster toward some measure of certainty: "Ahh, now I understand the film's message."&lt;br /&gt;&lt;br /&gt;But man is just another spoke in the wheel. We can easily flip the coin, showing mothers feeding, defending children, innocents preyed upon by murderers, hunters taking prey not for food, but for the feeding of other hungers. We do what we do not out of pure evil, but because it is our capacity to do so to further our own species, further our goals, perpetuate. But we also have a capacity no other species possesses: the ability to create our own destinies. The only true evil we encounter in a world where we nearly reign supreme is ourselves. We daily pit our most animal desires--acqusition of resources and destruction of usurpers--against our knowledge that such desires run rampant will complicate our path through history, perhaps even terminating it. Can such a machine be affected by the changing opinions of a few small components? That is the question we leave for the viewers.&lt;br /&gt;&lt;br /&gt;The challenge in such a film would almost certainly be not overplaying the hand. No evil must ever appear to be of any different motivation than its antithesis; and man must, in the end, appear as the most schizophrenic creature on Earth. Our "evil" predatory instincts must be tempered by the "good" effects of our fear of intimate and ultimate mortality for us to continue indefinitely. In this, man has another trait not found among the animals: Our system balances on our own decisions alone. With the capacity we will soon possess to control nature completely, without fear of predators, we can only undo ourselves. The balance comes from within.&lt;br /&gt;&lt;br /&gt;Where will the viewer lie?&lt;br /&gt;&lt;br /&gt;I'd hope every kid was as confused as possible by then; and eventually a bit more suspicious of being told what is "good" or "evil".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-3346641558815744460?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/3346641558815744460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=3346641558815744460' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/3346641558815744460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/3346641558815744460'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/09/predator-and-prey.html' title='Predator and Prey'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-5342643660224394169</id><published>2010-08-15T20:53:00.022-05:00</published><updated>2010-08-18T15:52:58.207-05:00</updated><title type='text'>My Thoughts on Oracle v Google</title><content type='html'>As you've probably heard by now, Oracle has decided to file suit against Google, claiming multiple counts of infringement against Java or JVM patents and copyrights they acquired when they assimilated Sun Microsystems this past year. Since I'm unlikely to keep my mouth shut about even trivial matters, something this big obviously requires at least a couple thousand words.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;Who Am I?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Any post of this nature really requires an author to identify where they stand, so their unavoidable biases can be taken with the appropriate dosage of salt. Rather than having you dig through my past and learn who and what I am, I'll just lay it out here.&lt;br /&gt;&lt;br /&gt;I am a Java developer. I've been a Java developer since 1996 or so, when I got my first University job writing stupid little applets in this new-fangled web language. That job expanded into a web development position, also using Java, and culminated with me joining a few senior developers for a 6-month shared development gig with IBM's then-nascent Pacific Development Center in Vancouver, BC. Since then I've had a string of Java-related jobs...some as a trenches developer, some as a lead, some as "architect", but all of them heavily wrapped up in this thing called Java. And I can't say that I've ever been particularly annoyed with Java as a language or a platform. Perhaps I haven't spent enough time on other runtimes, or perhaps I've got tunnel-vision after being a Java developer for so many years. But I'd like to think that I've become "seasoned" enough as a developer to realize no platform is perfect, and the manifold benefits of the JVM and the Java platform vastly outweigh the troublesome aspects.&lt;br /&gt;&lt;br /&gt;I am an open-source developer. In the late 90s, I worked in earnest on my first open-source project: the LiteStep desktop replacement for Windows. At the time, the LiteStep project was a loosely-confederated glob of C code and amateur C hackers. Being a Windows user at the time, I was looking to improve my situation...specifically, I had worked for years on a small application called Hack-It that exposed aspects of the win32 API normally unavailable through standard Windows UI elements, and I was interested in taking that further. LiteStep was not my creation. It had many developers before me and many after, but my small contribution to the project was an almost complete rewrite in amateur-friendly C++ and a decoupling of the core LiteStep "kernel" from the various plugin mechanisms. I was also interviewed for a Wired article on the then-new domain of "skinning" computers, desktops, applications, and so on, though none of my quotes made it into the article. After LiteStep, I fell back into mostly anonymous corporate software development, all still using Java and many open-source technologies, but not much of a visible presence in the OSS world. Then, in 2004 while working as the lead "Java EE Architect" for a multi-million-dollar US government contract, I found JRuby.&lt;br /&gt;&lt;br /&gt;I am a JRuby developer. Since 2004 (or really since late 2005, when I started helping out in earnest) I've been partially responsible for turning JRuby from an interesting novelty project into one of the top Ruby implementations. We've become well known as one of the best-performing – if not the best-performing – Ruby implementations, even faced with increasing competition from the young upstarts. We're also increasingly popular (and perhaps the easiest path) for bringing Ruby and its many paradigm-shifting libraries and frameworks (like Rails) to Java and JVM users around the world – without them having to change platforms or leave any of their legacy code behind. Part of my interest in JRuby has been to bring Ruby to the JVM, plain and simple. I like Ruby, I like the Ruby community, and on most days I like the cockiness and enthusiasm of those community members toward trying crazy new things. But another large part of my interest in JRuby is more sinister: I want to prove to naysayers what a great platform the JVM actually is, and perhaps make them think twice about knee-jerk biases they've carried and cultivated for so many years.&lt;br /&gt;&lt;br /&gt;You'll notice I refer to JRuby not as "it" or "she" or "he", but as "we". "We've become well known...We're also increasingly popular..." That's not an accident. There's now over five years of my efforts in JRuby, and I consider it to be as much a part of me as I am a part of it. And so because of that, I have a much deeper, emotional investment in the platform upon which JRuby rests.&lt;br /&gt;&lt;br /&gt;I am a Java developer. I am an open-source developer. I am a JRuby developer and a Ruby fan.&lt;br /&gt;&lt;br /&gt;I am not a lawyer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;The Facts, According to Me&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;These are the facts as I see them. You're free to disagree with my interpretation of the world, and I encourage you to do so in the comments, on other forums, over email, or to my face (but buy me a beer first).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;On Java&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Java platform is big. Really big. You just won't believe how vastly hugely mindbogglingly big it is. And by big, I mean it's everywhere.&lt;br /&gt;&lt;br /&gt;There are three mainstream JVMs people know about: JRockit (WebLogic's first and then Oracle's after it acquired them), Hotspot (Which came to Sun through an acquisition and eventually became OpenJDK), and J9 (IBM's own JVM, fully-licensed and with all its shots). Upon those three JVMs lives a gigantic world. If you want the details, there's numerous studies and reports about the use of Java in all manner of business, from the hippest new startups (Twitter recently switched much of their stack to the JVM) to the oldest of the old financial concerns. It's the favored choice for government server applications, the strongest not-quite-completely-Free managed runtime for open-source libraries and applications, and now with Android it's rapidly becoming one of the strongest (if not the strongest) mobile OS platform (even though Android isn't *really* Java, as I'll get into later). You may love or hate Java, but I guarantee it's part of your life in some way or another.&lt;br /&gt;&lt;br /&gt;There are a few open-source implementations of Java. The most well-known is OpenJDK, the Hotspot JVM that Sun relicensed under the GPL and set Free into the world. There's also Apache Harmony, whose class libraries form part of Dalvik's (Android's VM) Java-compatibility layer. There's GNU Classpath, a GPL-based implementation of the Java class libraries used for the ahead-of-time Java compiler GCJ. There's JamVM, which leverages Classpath to provide a very light, very minimal, (and very simple) JVM implementation. And there's others of varying qualities and relevance like IKVM (Java for .NET), VMKit (a Java compiler atop LLVM), and so on. OpenJDK is certainly the big daddy, though, and its release as GPL guarantees we'll at least have a solid Java 6 implementation forever.&lt;br /&gt;&lt;br /&gt;Java is not an entirely open platform, what with the now-obvious encumbrances of patents and copyrights (not to mention draconian policies toward Java's various specifications, which are often very slow to evolve due to the JCP quagmire). That's not a great state of affairs, and if nothing else you have to recognize that folks at Sun at least tried to release the platform from its shackles by chasing OpenJDK. But the process of "freeing" Java has been pretty rocky; OpenJDK itself took years to gain acceptance from OSS purists, and the choice of the GPL has meant that folks afeared of the GPL's "viral" side still had to look for other options (which is a large part of why Apache Harmony was used as part of the basis for Android).  Perhaps the biggest nail in the coffin is that Sun's Java test kit, the gold standard of whether an implementation is "compliant" or not, has never been released in open-source form, ultimately binding the hands of developers who wished to build a fully-compatible open-source Java.&lt;br /&gt;&lt;br /&gt;Java is not an entirely closed platform, either. OpenJDK was a huge step in the direction of Freeing Java, and the Java community in general has a very strong OSS ethos. There's no piece of Java software that isn't at least partially based on open-source componenents, and most Java library, framework, or application developers either initially or eventually open-source some or all of their works. Open-source development and the Java platform go hand-in-hand, and without that relationship the platform would not be where it is today. Contrast that to other popular environments like Microsoft's .NET – which has been admirably Freed through open standards, but which has not yet become synonymous with or popular for OSS development – or Apple's various platforms – which aren't based on open-standards *or* open-source, but which have managed to become many OSS developers' environment of choice...for writing or consuming non-Apple open-source software. Among the corporation-controlled runtimes, the Java platform has more OSS in its blood than all others combined...many times more.&lt;br /&gt;&lt;br /&gt;Java is not perfect, but it's pretty darn good. Every platform has its warts. The Java platform represents a decade and a half of tradeoffs, and it's impossible in that amount of time to make everyone happy all the time. One of the big contentious items is the addition in Java 5 of parametric polymorphism as a compile-time trick without also adding VM-level support for reifying per-type specializations as .NET can do. But ask most Java developers if they'd rather have nothing at all, and you'll get mixed responses. The sad, crippled version of generics in Java 5 doesn't do everything static-typing purists want, nor does it really extend to runtime at all (making reflective introspection almost impossible), but they do provide some nice surface-level sugar for Java developers. The same can be said of many Java "features" and tradeoffs. JavaEE became an abortively complicated jumble of mistakes (tradeoffs that went bad), but even upstarts that arguably made better decisions initially have themselves graduated into chaos (I believe the Spring framework has now grown even larger than the largest Java EE conglomerate, and Microsoft's periodically reboots their blessed-framework-of-the-week, resulting in an even more disruptive environment than a slow-moving, bulky standard like JavaEE). Designing good software is hard. Designing good *big* software is exponentially harder. Designing good *big* software that pleases everyone is impossible.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Why People Hate Java&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Java is second only to Microsoft's platforms for being both wildly successful and almost universally hated by the self-sure software elite. The reasons for this are manifold and complex.&lt;br /&gt;&lt;br /&gt;First of all, back in the 90s Java started getting shoved down everyone's throat. Developers were increasingly told to investigate this new platform, since their managers and long-disconnected tech leads kept hearing how great it was from Sun Microsystems, then a big deal in server applications and hardware. So developers that were happily using other environments (many of which exist to this day) often found themselves forced to suck it up and become Java developers. Making matters worse, Java itself was designed to be a fairly limited language...or at least limited in how easily a developer could paint themselves into a corner. Many features those reluctant developers had become used to in other environments were explicitly rejected for Java on the grounds that they added too much complexity, too much confusion, and too little value to trenches developers. So people that were happily doing Perl or C++ or Smalltalk or what have you were suddenly forced into a little J-shaped box and forced to write all those same applications upon Java and the JVM at a time when both were still poorly-suited to those domains. Those folks have had a white-hot hate for anything relating to Java ever since, and many will stop at nothing to see the entire platform ejected into space.&lt;br /&gt;&lt;br /&gt;Second, as mentioned quickly above, Java in the 90s was simply not that great a platform. It had most of the current warts (classpath issues, VM limitations, poor system-level integration, a very limited language) on top of the fact that it was slow (optimizing JVMs didn't come around until the 2000s), marketed for highly-visible, highly-fickle application domains like desktop and browser-based applications (everyone's cursed a Java app or applet at some point in their life), and still largely driven and controlled by a single company (at a time when many developers were trying to get out from under Microsoft's thumb). It wasn't until Java 1.2 that we started to get a large and diverse update to Java's core libraries. Java 1.3 was the first release to ship Hotspot, which started to get the performance monkey off our backs. Java 1.5 brought the first major changes to the Java language, all designed to aid developers in expressing what they meant in standard ways (like using type-safe enums instead of static final ints, or generics for compiler-level assurances of collection homogeneity). And Java 6, the last major version, made great strides in improving startup time, overall performance, and manageability of JVM processes. Java 7, should it ever ship, will bring new changes to the Java language like support for closures and other syntactic sugar, better system-level integration features as found in NIO.2, and the feather in the cap: VM-level support for function objects and non-standard invocation sequences via Method Handles and InvokeDynamic. But unless you've been a Java developer for the past decade, all you remember is the roaring 90s and the pain Java caused you as a developer or a user.&lt;br /&gt;&lt;br /&gt;Third, the Java language and environment has stagnated. Given years of declining fortunes at Sun Microsystems, disagreement among JCP members about the direction the platform should go, and a year of uncertainty triggered by Sun's collapse and rescue at the hands of Oracle, it's surprising anything's managed to get done at all. Java 7 is now many years overdue; they were talking about it when I joined Sun in 2006, and hoped to have preview releases within a year. For both technical and political reasons, it's taken a long time to bring the platform to the next level, and as a result many of the truly excellent improvements have remained on the shelf (much to my dismay...we really could use them in JRuby). For fast-moving technology hipsters, that's as good as dying on the vine; you need to shift paradigms on a regular schedule or you're yesterday's news.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Update:&lt;/span&gt;&lt;/span&gt; At least one commenter also pointed out that it took a long time for Java to be "everywhere", and even today most users still need to download and install it at least once on any newly-installed OS. Notable exceptions include Mac OS X, which ships a cracker-jack Java 6 based on Hotspot, and some flavors of Linux that come with some sort of Java installed out of the box. But this was definitely a very real problem; developers were being pushed to write apps and applets in Java, and users were forced to download a multi-megabyte installer just to run them...at a time when downloading multi-megabyte software was often a very painful ordeal. That would put a bad taste in anyone's mouth.&lt;br /&gt;&lt;br /&gt;It's because of these and similar reasons that folks like Google finally said "enough is enough," and opted to start doing their own things. On the JRuby project, we've routinely hacked around the limitations of the JVM, be they related to its piss-poor process management APIs, its cumbersome support for binding native libraries, or its stubborn reluctance to become the world's greatest dynamic language VM. I've thought on numerous occasions how awesome it would be to spin off a company that took OpenJDK and made it "right" for the kinds of development people want to do today (and I'd love to be a part of that company), but such ventures are both expensive and light on profitability. Nobody pays for platforms or runtimes...they pay for services around those platforms or runtimes, services which are often anathema to the developers of those platforms and runtimes. So it required someone "bigger" to make that happen...someone who could write off the costs of the platform by funding it in creative new ways. Someone with a massive existing investment in Java. Someone with deep pockets and an army of the best developers in the business who love nothing more than a challenge. Someone like Google.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Why Android?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(Note that a lot of this is based on what information I've managed to glean from various conversations. Clarifications or corrections are welcome.)&lt;br /&gt;&lt;br /&gt;There's an incredibly successful mobile Java platform out there. One that boasts millions of devices from almost all the major manufacturers, in form factors ranging from crappy mid-00s clamshells to high-end smartphones. A platform with hundreds or thousands of games and applications and freely-available development tools. That platform is Java ME.&lt;br /&gt;&lt;br /&gt;Java ME started out as an effort to bring Java back to its original roots: as a language and environment for writing embedded applications. The baseline ME profiles are pretty bare; I did some CLDC development years ago and had to implement my own buffered streams and various data structures just to get by. Even the biggest profiles are still fairly restricted, and I don't believe any of them have ever graduated beyond Java 1.3-level featuresets. So Sun did a great job of getting Java ME on devices, back when people cared about Sun...and then they let mobile Java stagnate to a terrible degree while they spent all resources trying to get people to use Java EE and trying to get Java EE to suck less. So while resources were getting poured into EE, people started to form the same opinions of mobile Java they had formed about desktop and server Java years earlier.&lt;br /&gt;&lt;br /&gt;At the same time, Java ME was one of the few Java-related technologies that brought in money. You see, in order for handset manufacturers to ship (and boast about) Java ME support, they had to license the technology from Sun. It wasn't a huge cash cow, but it was a cow nonetheless. Java ME actually made money for Sun. So in true Sun form, they loused it up terribly.&lt;br /&gt;&lt;br /&gt;Fast forward to a few years ago. Google, recognizing that mobile devices finally were becoming the next great technology market, decided that leaving the mobile world in the hands of proprietary platforms was a bad idea. Java ME seemed like it could be an answer, but Sun was starting to get desperate for both revenue and relevance...and they'd started to back a completely new horse-that-would-be-cow called JavaFX, which they hoped to pimp as the next great development environment for in-browser and on-device apps alike. They weren't interested in making Java ME be what Google wanted it to be.&lt;br /&gt;&lt;br /&gt;Google decided to take the hard route: they'd fund development of a new platform, building it entirely from open-source components, and leveraging two of the best platform technologies available: Linux, for the kernel, and Java, for the runtime environment. However there was a problem with Java: it was encumbered by all sorts of patents and copyrights and specifications and restrictions. Hell, even OpenJDK itself, the most complete and competitive OSS implementation of Java, could not be customized and shipped in binary-only form by hardware manufacturers and service providers due to it being GPL. So the answer was to build a new VM, use unencumbered versions of the core Java class libraries, and basically remake the world in a new, copyright and patent-free image. Android was born.&lt;br /&gt;&lt;br /&gt;There's many parts to Android, several of which I'm not really qualified to talk about. But the application environment that runs atop the Dalvik VM needs some explanation.&lt;br /&gt;&lt;br /&gt;First, there's the VM. Dalvik is *not* a JVM. It doesn't run JVM bytecode, and you can't ship JVM bytecode expecting it to work on Dalvik. You must recompile it to Dalvik's own bytecode using one of the provided translation tools. This is similar to how IKVM gets Java code to run on .NET: you're not actually running a JVM, you're transforming your code into a different form so it will run on someone else's VM. So it bears repeating, lest anyone get confused: Dalvik is not a JVM...it just plays one on TV.&lt;br /&gt;&lt;br /&gt;Second, there's the core Java class libraries. Android supports a rough (but large) subset of the Java 1.5 class libraries. That subset is large enough that projects as complicated as JRuby can basically run unmodified on Android, with very few restrictions (a notable one is the fact that since we can't generate JVM bytecode, we can't reoptimize Ruby code at runtime right now). In order to do this without licensing Sun's class libraries (as most other mainstream Java runtimes like JRockit and J9 do), Google opted to go with the not-quite-complete-but-pretty-close Apache Harmony class libraries, which had for years been developed independent of Sun or OpenJDK but never really tested against the Java compatibility kits (and there's a long and storied history behind this situation).&lt;br /&gt;&lt;br /&gt;So by building their own non-JVM VM and using translated versions of non-Sun, non-encumbered class libraries, Google hoped to avoid (or at least blunt) the possibility that their "unofficial", "unlicensed" mobile Java platform might face a legal test. In short, they hoped to build the open mobile Java platform developers wanted without the legal and financial encumbrances of Java ME.&lt;br /&gt;&lt;br /&gt;At first, they seemed to be on a gravy train with biscuit wheels.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Splitting Up the Pie&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Sun Microsystems was not amused. A little over a year ago, when several Sun developers started to take an eager interest in Android, we were all told to back off. It wasn't yet clear whether Android stood on solid legal ground, and Sun execs didn't want egg on their face if a bunch of their own employees turned out to be supporting a platform they'd eventually have to attack. Furthermore, it was an embarrassment to see Android drawing in the same developers Sun really, really wanted to look at JavaFX or PersonalJava or whatever the latest attempt to bring developers back might be. Android actually *was* a great platform that supported existing Java developers and libraries incredibly well (without actually being a Java environment), and for the first time there was a serious contender to "standard" Java that Sun had absolutely no control over.&lt;br /&gt;&lt;br /&gt;To make matters worse, handset manufacturers started to sign on in droves to this new non-Java ME platform, which meant all that technology licensing revenue was reaching a dead end. Nobody (including me) wanted to do Java ME development anymore. Everyone wanted to do Android development.&lt;br /&gt;&lt;br /&gt;Now we must say one thing to Sun's credit: they didn't do what Oracle is now attempting to do. As James Gosling blogged recently, patent litigation just wasn't in Sun's blood...even if there might have been legal ground to file suit. So while we Sun employees were still quietly discouraged from looking at or talking about Android, the rest of the world took Sun's silence as carte blanche to stuff Android into everything from phones to TVs, and mobile app developers started to think there might be hope for a real competitor to Apple's iPhone. Things might have proceeded in this way indefinitely, with Android continuing to grab market share (it recently passed iPhone in raw numbers with no slowing in sight) and mindshare (Android is far more approachable than almost any other mobile development environment, especially if you're one of the millions of developers who know Java.)&lt;br /&gt;&lt;br /&gt;And then it all started to go wrong.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;The Mantle of Java Passes to Oracle&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If for nothing else, Jonathan Schwartz will be remembered as the man who broke open the Sun piñata, simultaneously releasing more open-source software than any company in history and killing Sun in the process. Either Jonathan had no "step 2" or the inertia of a company built on closed-source products was too great to overcome. In either case, by spring of 2009 Sun was hemorrhaging. Many reports claim that Jonathan had started shopping Sun around to possible buyers as early as 2008, but it wasn't until 2009 that the first candidates started lining up. Initially, it was IBM, hoping to gobble up its former competitor along with the IP, patents, and copyrights they carried. That deal ultimately went south when Sun refused to consider any deal that IBM wouldn't promise to carry to completion, even in the face of regulatory roadblocks sure to come up. Many of us breathed a sigh of relief; if there's any Java company even more firmly stuck in the old world than Sun, it's IBM...and we weren't looking forward to dealing with that.&lt;br /&gt;&lt;br /&gt;Once that deal fell through, folks like me became resigned to the fact that Sun was nearing the end of its independent life. Years of platform negligence, management incompetence, and resting on laurels had dug a hole far too deep for anyone to climb out of. Would it be Cisco, who had recently started building up an interesting new portfolio of application server hardware and virtualization software? What about VMWare, who had recently gobbled up Springsource and seemed to be making all the right moves toward a large-scale virtualized "everything cloud." Or perhaps Oracle, a long-time partner to Sun, whose software was either Java-based or widely deployed on Sun hardware and operating systems. Dear god, please don't let it be Oracle.&lt;br /&gt;&lt;br /&gt;Don't get me wrong...Oracle's a highly successful company. They've managed to turn almost every acquisition into gold while coaxing profitability out of just about every one of their divisions. But Oracle's not a developer-oriented company (like Sun)...it's a profit-oriented company (unlike Sun, sadly), and you need to either feed the bottom line or feed others in the company that do. So when it turned out that Oracle would gobble up Sun, many of us OSS folks started to get a little nervous.&lt;br /&gt;&lt;br /&gt;You see, many of us at Sun had been actively trying to change the perception of the platform from that of a corporate, enterprisey, closed world to that of a great VM with a great OSS ecosystem and an open-source reference implementation. Folks like Jonathan believed that by freeing Java we'd free the platform, and both the platform and the developer community would be better for it. We were half right...the OpenJDK genie is out of the bottle, and there's basically no way to put it back now (and for that, the world owes Sun a great debt). But only part of the platform was Freed...the patents and copyrights surrounding Hotspot and Java itself remained in place, carefully tucked away in the vault of a company that just didn't mount patent or copyright-driven legal attacks.&lt;br /&gt;&lt;br /&gt;Oracle, now in control of those patents and copyrights, obviously has different plans.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;The Suit&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So now, after spending 4000 words of your time, we come to the meat of the article: the actual Oracle v Google suit. The full text is provided various places online, though the &lt;a href="http://en.swpat.org/wiki/Oracle_v._Google_(2010,_USA)"&gt;Software Patents Wiki&lt;/a&gt; has probably the best collection of related facts (though the wiki-driven discussions of the actual patents are woefully inaccurate).&lt;br /&gt;&lt;br /&gt;The suit largely comes down to a patent-infringement battle. Oracle claims that by developing and distributing Android, Google is in violation of seven patents. There's also an amorphous copyright claim without much backing information ("Google probably stole something copyrighted so we'll list a bunch of stuff commonly stolen in that way"), so we'll skip that one today.&lt;br /&gt;&lt;br /&gt;Before looking at the actual patents involved, I want to make one thing absolutely clear: Oracle has not already won this suit. Even after a couple days of analysis, nobody has any idea whether they *can* win such a suit, given that Google seems to have taken great pains to avoid legal entanglements when designing Android. So everybody needs to take a deep breath and let things progress as they should, and either trust that things will go the right direction or start doing your damndest to make sure they go the right direction.&lt;br /&gt;&lt;br /&gt;With that said, let's take a peek at the patents, one by one. And as always, the "facts" here are based on my reading of the patents and my understanding of the related systems.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;a href="http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&amp;amp;Sect2=HITOFF&amp;amp;p=1&amp;amp;u=/netahtml/PTO/search-bool.html&amp;amp;r=1&amp;amp;f=G&amp;amp;l=50&amp;amp;co1=AND&amp;amp;d=PTXT&amp;amp;s1=6,125,447.PN.&amp;amp;OS=PN/6,125,447&amp;amp;RS=PN/6,125,447"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Protection Domains To Provide Security In A Computer System (6,125,447)&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt; and &lt;/span&gt;&lt;a href="http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&amp;amp;Sect2=HITOFF&amp;amp;p=1&amp;amp;u=/netahtml/PTO/search-bool.html&amp;amp;r=1&amp;amp;f=G&amp;amp;l=50&amp;amp;co1=AND&amp;amp;d=PTXT&amp;amp;s1=6,192,476.PN.&amp;amp;OS=PN/6,192,476&amp;amp;RS=PN/6,192,476"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Controlling Access To A Resource (6,192,476)&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first two patents describe the Java Security Policy system, for controlling access to resources. One of the least-interesting but most-important aspects of the Java platform is its approach to security. Code under a specific classloader or thread can be forced to comply with a specific security policy by installing a security manager. These permissions control just about every aspect of the code's interaction with the JVM and with the host operating system: loading new code, reflectively accessing existing classes, accessing system-level resources like devices and filesystems, and so on. It's even easy for you to build up security policies of your own by checking for custom-named permissions and only granting them when appropriate. It's a pretty good system, and one of the reasons Java has a much stronger security track record than other runtimes that don't have pervasive security in mind from the beginning.&lt;br /&gt;&lt;br /&gt;In order to host applications written for the Java platform, and to sandbox them in a compatible way, Android necessarily had to support the same security mechanisms. The problem here is the same problem that plagues many patents: what boils down to a fairly simple and obvious way to solve a problem (associate pieces of code with sets of permissions, don't let that code do anything outside those permissions) becomes so far-reaching that almost any reasonable *implementation* of that idea would violate these patents. In this case the '447 and '476 patents do describe mechanisms for implementing Java security policies, but even that simple implementation is very vague and would be hard to avoid with even a clean-room implementation.&lt;br /&gt;&lt;br /&gt;Now I do not know exactly how Android implements security policies, but it's probably pretty close to what's described in these patents...since just about every implementation of security policies would be pretty close to what's described.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;a href="http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&amp;amp;Sect2=HITOFF&amp;amp;p=1&amp;amp;u=/netahtml/PTO/search-bool.html&amp;amp;r=1&amp;amp;f=G&amp;amp;l=50&amp;amp;co1=AND&amp;amp;d=PTXT&amp;amp;s1=5,966,702.PN.&amp;amp;OS=PN/5,966,702&amp;amp;RS=PN/5,966,702"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Method And Apparatus For Preprocessing And Packaging Class Files (5,966,702)&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is basically the patent governing the "Pack200" compression format provided as part of the JDK and used to better-compress class file archives.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Update:&lt;/span&gt;&lt;/span&gt; Alex Blewitt has posted a &lt;a href="http://alblue.bandlem.com/2010/08/more-details-on-5966702-and-pack200.html"&gt;discussion of the Pack200 specification&lt;/a&gt;. He says this patent isn't nearly as comprehensive, but that it may touch upon how Pack200 works. His post is a more complete treatment of the details of the class file format and how Pack200 improves compression ratios for class archives. It also occurs to me now that this patent could be related to mobile/embedded Java too, where better compression would obviously have an enormous savings.&lt;br /&gt;&lt;br /&gt;Java class files are filled with redundant data. For example, every class that contains code that calls PrintStream.println (as in System.out.println) contains the same "constant pool" entry identifying that method by name, a la "java/io/PrintStream.println:(Ljava/lang/String;)V". Every field lookup, class reference, literal string, or method invocation will have some sort of entry in the constant pool. Pack200 takes advantage of this fact by compressing all class files as a single unit, batching duplicate data into one place so that the actual unique class data boils down to just the unique class, method, and code structure.&lt;br /&gt;&lt;br /&gt;The reason for having a separate compression format is because "zip" files, which includes Java's "jar" files, are notoriously bad at compressing many small files with redundant data. Because one of the features of the "zip" format is that you can easily pull a single file out, compressing all files together as a single unit prevents introducing any interdependencies between those files or a global table. This is a large part of why compression formats like "tar.gz" do a better job of compressing many small files: tar turns many files into one file, and gzip or bzip2 compress that one large file as a single unit (conversely, this is why you can't easily get a single file out of a tarball).&lt;br /&gt;&lt;br /&gt;On Android, this is accomplished in a similar way by the "dex" tool, which in the process of translating JVM bytecode into Dalvik bytecode also localizes all duplicate class data in a single place. The general technique is standard data compression theory, so presumably the novelty lies in applying decades-old compression theory specifically to Java classfile structure.&lt;br /&gt;&lt;br /&gt;If I've lost you at this point, we can summarize it this way: part of Oracle's suit lies in a patent for a better compression mechanism for archives containing many class files that takes advantage of redundant data in those files.&lt;br /&gt;&lt;br /&gt;Are you laughing yet?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;a href="http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&amp;amp;Sect2=HITOFF&amp;amp;p=1&amp;amp;u=/netahtml/PTO/search-bool.html&amp;amp;r=1&amp;amp;f=G&amp;amp;l=50&amp;amp;co1=AND&amp;amp;d=PTXT&amp;amp;s1=7,426,720.PN.&amp;amp;OS=PN/7,426,720&amp;amp;RS=PN/7,426,720"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;System And Method For Dynamic Preloading Of Classes Through Memory Space Cloning Of A Master Runtime System Process (7,426,720)&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm not sure this patent ever saw the light of day in a mainstream JVM implementation. It describes a mechanism by which a master parent process could pre-load and pre-initialize code for a managed system, and then new processes that need to boot quickly would basically be memory-copied (plus copy-on-write friendly) "forks" of that master process, with the master maintaining overall control of those child processes through some sort of IPC.&lt;br /&gt;&lt;br /&gt;Ignore for the moment the obvious prior art of "fork" itself as applied to pre-initializing application state for many children. Anyone who's ever used fork to initialize a heavy process or runtime to avoid the cost of reinitializing children has either violated this patent (if done since 2003) or has a compelling case for prior art (if done before 2003).&lt;br /&gt;&lt;br /&gt;It's likely that this patent was formulated as an answer to the poor semantics of running many applications under the same JVM. Java servlets and later Java EE made it possible to consider deploying all of your company's applications in a single process, isolated by classloaders and security policies. What they never really addressed was the fact that code isn't the only thing you're sharing in this model; you're also sharing memory space, CPU time, and process resources like file descriptors. No amount of Java classloader or security trickery could make this a seamless multiapp environment, and so work like this patent hoped to find a lightweight way for all those child applications to actually live as their own processes.&lt;br /&gt;&lt;br /&gt;On Android, this manifests in the fact that each application runs independently, and they (like most operating systems) fork off from either the kernel process or some master process.&lt;br /&gt;&lt;br /&gt;In this case, Oracle's banking on being able to litigate with a patent for a very common application of "fork".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;a href="http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&amp;amp;Sect2=HITOFF&amp;amp;p=1&amp;amp;u=/netahtml/PTO/search-bool.html&amp;amp;r=1&amp;amp;f=G&amp;amp;l=50&amp;amp;co1=AND&amp;amp;d=PTXT&amp;amp;s1=RE38,104.PN.&amp;amp;OS=PN/RE38,104&amp;amp;RS=PN/RE38,104"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Method And Apparatus For Resolving Data References In Generated Code (RE38,104)&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This patent, invented by James Gosling himself, basically describes a mechanism by which symbolic data references in code (e.g. Java field references) can be resolved dynamically at runtime into actual direct memory accesses, eliminating the symbolic lookup overhead. It's part of standard JIT optimization techniques, and there's a lot of references in this patent many great JIT patents and papers of the past.&lt;br /&gt;&lt;br /&gt;Here there may actually be merit, or as much merit as can be found in a software patent to begin with. The patent itself is tiny, as most of these patents are. The techniques seem obvious to me, but perhaps they're obvious because this patent helped make them standard. I'm not qualified to judge. What I can say is that I can't imagine a VM in existence that doesn't violate the spirit – if not the letter – of this patent as well. All systems with symbolic references will seek to eliminate the symbolic references in favor of direct access. The novelty of this patent may be in doing that translation on the fly...not even at a decidedly coarse-grained per-method level, but by rewriting code while the method is actually executing.&lt;br /&gt;&lt;br /&gt;I would guess that this is a patent filed during the development of Java's earlier JIT technologies, before systems like Hotspot came along to do a much better large-scale, cross-method job of optimization. It doesn't seem like it would be hard to debunk the novelty of the patent, or at least show prior art that makes it irrelevant.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Update:&lt;/span&gt;&lt;/span&gt; I actually found a reference in the article &lt;a href="http://www.netmite.com/android/mydroid/dalvik/docs/dexopt.html"&gt;Dalvik Optimization and Verification with dexopt&lt;/a&gt; to the technique described here (about 3/4 down the page, under "Optimization"):&lt;br /&gt;&lt;br /&gt;"The Dalvik optimizer does the following: ... &lt;span style="font-weight:bold;"&gt;For instance field get/put, replace the field index with a byte offset.&lt;/span&gt; ..."&lt;br /&gt;&lt;br /&gt;But Dalvik still does this only once, before running the code (actually, at install time); not *while* running the code as described in the patent.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;a href="http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&amp;amp;Sect2=HITOFF&amp;amp;p=1&amp;amp;u=/netahtml/PTO/search-bool.html&amp;amp;r=1&amp;amp;f=G&amp;amp;l=50&amp;amp;co1=AND&amp;amp;d=PTXT&amp;amp;s1=6,910,205.PN.&amp;amp;OS=PN/6,910,205&amp;amp;RS=PN/6,910,205"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Interpreting Functions Utilizing A Hybrid Of Virtual And Native Machine Instructions (6,910,205)&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This patent, invented by Lars Bak of V8 fame, describes a mechanism for building a "mixed mode" VM that can execute interpreted code and compiled (presumably optimized) code in the same VM process, and flip between the two over time to produce better-optimized compiled code. This describes the basic underpinnings of VMs like Hotspot, which alternate between interpreting virtual machine code and executing real machine code even within the same thread of execution (and sometimes, even branching from virtual code to real code and back within the same method body). Any other VMs that are mixed mode would probably violate this patent, so its impact could reach much farther than Android. (In a sense, even JRuby might violate this patent, though our two mixed modes are both virtual instruction sets.)&lt;br /&gt;&lt;br /&gt;Now you might think the other mainstream JVMs would violate this patent, but they don't. Neither JRockit nor J9 have interpreters; they both go immediately to native code with various tiers of instrumentation to do the runtime profile data gathering. They iterative regenerate native code with successively more and better optimizations. Lars most recent VM, the V8 Javascript VM at the heart of Chrome, also goes straight to native code.&lt;br /&gt;&lt;br /&gt;Now here's where it gets weird: Up until Froyo (Android 2.2) Dalvik did a once-only compilation to native code before anything started executing, which means by definition that it was not mixed-mode. And even in Froyo, I believe it still does its initial execution in native code form with instrumentation to allow subsequent compiles to do a better job. Dalvik does not have an interpreter, Dalvik does not interpret Dalvik bytecode.&lt;br /&gt;&lt;br /&gt;Perhaps someone can explain how this patent even applies to Dalvik or Android?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; "&gt;&lt;span style="font-style: italic; "&gt;Update:&lt;/span&gt;&lt;/span&gt; A couple commenters correct me here: Dalvik actually was 100% interpreted before Froyo, and is now a standard mixed-mode environment post-Froyo. So if this suit had been filed a year ago this patent might not have been applicable, but it probably is now.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;a href="http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&amp;amp;Sect2=HITOFF&amp;amp;p=1&amp;amp;u=/netahtml/PTO/search-bool.html&amp;amp;r=1&amp;amp;f=G&amp;amp;l=50&amp;amp;co1=AND&amp;amp;d=PTXT&amp;amp;s1=6,061,520.PN.&amp;amp;OS=PN/6,061,520&amp;amp;RS=PN/6,061,520"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Method And System for Performing Static Initialization (6,061,520)&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Sigh. This patent appears to revolve completely around a mechanism by which the static initialization of arrays could be "play executed" in a preloader and then rewritten to do static initialization in one shot, or at least more efficiently than running dozens of class initializers that just construct arrays and populate them. Of all the patents, this is probably the narrowest, and the mechanism described are again not very unusual, but there's probably a good chance that the "dex" tool does something along these lines to tidy up static initializers in Android applications.&lt;br /&gt;&lt;br /&gt;Given the "preloader" aspect of this patent, I'd surmise that it was formulated in part to simplify static initialization of code on embedded devices or in applet environments (because on servers...the boot time of static initialization is probably of little concern). Because of the much more limited nature of embedded environments (especially in 1998, when this patent was filed) it would be very beneficial to turn programmatic data initialization into a simple copy operation or a specialized virtual machine instruction. And this may be why it could apply to Android; it's another sort of embedded Java, with a preloader (either dex or the dexopt tool that jit-compiles your app on the device) and resource limitations that would warrant optimizing static initialization.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;So, Does the Suit Have Merit?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'll again reiterate that I'm not a lawyer. I'm just a Java developer with a logical mind and a penchant for debunking myths about the Java platform.&lt;br /&gt;&lt;br /&gt;The collection of patents specified by the suit seems pretty laughable to me. If I were Google, I wouldn't be particularly worried about showing prior art for the patents in question or demonstrating how Android/Dalvik don't actually violate them. Some, like the "mixed mode" patent, don't actually seem to apply at all. It feels very much like a bunch of Sun engineers got together in a room with a bunch of lawyers and started digging for patents that Google might have violated without actually knowing much about Android or Dalvik to begin with.&lt;br /&gt;&lt;br /&gt;But does the suit have merit? It depends if you consider baseless or over-general patents to have merit. The most substantial patent listed here is the "mixed mode" patent, and unless I'm wrong that one doesn't  apply. The others are all variations on prior art, usually specialized for a Java runtime environment (and therefore with some question as to whether they can apply to a non-Java runtime environment that happens to have a translator from Java code). Having read through the suit and scanned the patents, I have to say I'm not particularly worried. But then again, I don't know what sort of magic David Boies and company might be able to pull off.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;What Might Happen?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the unlikely event of a total victory by Oracle, there's probably a lot of possible outcomes. I don't see the "death of Java" among them. There's also the possibility that Google could win a convincing victory. What might happen in each case?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;The Nuclear Option&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The worst case scenario would be that Android is completely destroyed, all Android handsets are confiscated by the Oracle mafia and burned in the city square, and all hope for a Free and Open Java are forever laid to rest. Long live Mono.&lt;br /&gt;&lt;br /&gt;To understand why this won't happen we need to explore Oracle's possible motives.&lt;br /&gt;&lt;br /&gt;As I mentioned above, Java ME actually did bring licensing revenue to Sun. There's a lot of handset manufacturers, millions of handsets, and every one put a couple cents (or a couple bucks?) in Sun's pocket. In the heady high times of Java ME, it was the only managed mobile runtime in town, with sound and graphics and standard UI elements. It wasn't always pretty, but it worked well and it was really easy to write for.&lt;br /&gt;&lt;br /&gt;Now with Android rapidly becoming the preferred mobile and embedded Java, it's become apparent that there's no future for Java ME - or at least no future in the expanding "smart" consumer electronics business. Java ME lives on in Blackberries, some other low-end phones, in most Blu-Ray devices (BD-J is a standard for writing Java apps that run on Blu-Ray systems, utilizing one of the richer class libraries available for Java ME), and in some sub-micro devices like Ajile's AJ-200 Java-based multimedia CPU. If you want Java on a phone or in your TV, Android is taking that world by storm. That means Java ME licensing revenue is rapidly drying up.&lt;br /&gt;&lt;br /&gt;So why wouldn't Oracle want to take a bite of the rapidly-growing Android pie? Would they turn down a portion of that revenue and instead completely destroy a very popular and successful mobile Java, or would they just strongarm a few bucks out of Google and Android handset manufacturers? Remember we're talking about a profit-driven company here. Java ME is never going to come back to smartphones, that much is certain and I don't think even Oracle could argue it. There's no profit in filing this suit just to kill Android, since it would just mean competing mobile platforms like Windows Phone, RIM, Symbian, or iOS would just canibalize their younger brother. Instead of getting a slice of the fastest-growing segment of Java developers, you'd kill off the entire segment and force those developers to non-Java, non-Oracle-friendly platforms.&lt;br /&gt;&lt;br /&gt;Oracle may be big and evil, but they're not stupid.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Google Licensing Deal&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A more likely outcome might be that Google would be forced to license the patents or pay royalties on Android revenue. I honestly believe this is the goal of this lawsuit; Oracle wants to get their foot into the door of the smartphone world, and they know they can't innovate enough to make up for the collapse of Java ME. So they're hoping that by sabre-rattling a few patents, Google will be forced (or scared) into sharing the harvest.&lt;br /&gt;&lt;br /&gt;Given the contents of the suit and the patents, I think this one is pretty unlikely too. Much of Android and Dalvik's designs are specifically crafted to avoid Java entanglements, and I think it's unlikely if this suit goes to trial that Oracle's lawyers would be able to make a convincing argument that the patents were both novel and that they were violated by Google. But let's not put anything past either the lawyers or the US federal court system, eh?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Nothing At All&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There's a good chance that either Oracle or the court will realize quickly that the case has no merit, and drop all charges. I'm obviously hoping for this one, but it's likely to take the longest of all. First, the court would need to gather all facts in the case, which could take months (especially given the highly technical nature of some of the compaints). Then there's the rebuttals of those facts, sorting out the wheat from the chaff, deciding there's not enough there to proceed, and either Oracle backs out or the court tosses the case. In the latter case, there's the possibility of appeals, and things could start to get very expensive.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Total Collapse of Software Patents&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is probably the one of the highest-profile cases involving software patents in recent years. The other would be Apple's recent suit against HTC for design elements of the iPhone. Several other bloggers and analysts have called out the possibility that this could lead to the death of software patents in general. I think that's a bit optimistic, but both Google *and* Oracle have come down officially against patents in the past (though perhaps Oracle's had a change of heart since acquiring Sun's portfolio).&lt;br /&gt;&lt;br /&gt;As much as I'd like to see it happen, software patents probably won't be dead in the next year or two. But this might be a nail in the coffin.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;What Does This Mean for Java?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now we come to the biggest question of all: how does this suit affect the Java world, regardless of outcome?&lt;br /&gt;&lt;br /&gt;Well it's obviously not great to have two Java heavyweights bickering like schoolchildren, and it would be positively devastating if Android were obliterated because of this. But I think the real damage will be in how the developer community perceives Java, rather than in any lasting impact on the platform itself.&lt;br /&gt;&lt;br /&gt;Let's return to some of our facts. First off, nothing in this suit would apply to any of the three mainstream JVMs that 99% of the world's Java runs on. Hotspot and JRockit are both owned by Oracle, and J9 is subject to the Java specification's patent grant for compliant implementations. The lesson here is that Android is the first Java-like environment since Microsoft's J++ to attempt to unilaterally subset or superset the platform (with the difference in Android's case being that it doesn't claim to be a Java environment, and it may not actually need the patent grant). Other Java implementations that "follow the Rules" are in the clear, and so 99% of the world's use of Java is in the clear. Sorry, Java haters...this isn't your moment.&lt;br /&gt;&lt;br /&gt;This certainly does some damage to the notion of open-source Java implementations, but only those that are not (or can not be) compliant with the specification. As the Apache Harmony folks know all too well, it's really hard to build a clean-room implementation of Java and expect to get the "spec compliance patent grant" if you don't actually have the tools necessary to show spec compliance. Tossing the code over to Sun to run compliance testing is a nonstarter; the actual test kit is enormous and requires a huge time investment to set up and run (and Sun/Oracle have better things to do with their time than help out a competing OSS Java implementation). If the test kit had been open-sourced before Sun foundered, there would be no problem; everyone that wanted to make an open-source java would just aim for 100% compliance with the spec and all would be well. As it stands, independently implemented (i.e. non-OpenJDK) open-source Java is a really hard thing to create, especially if you have to clean-room implement all the class libraries yourself. Android has neatly dodged this issue by letting Android just be what it is: a subset of a Java-like platform that doesn't actually run Java bytecode and doesn't use any code from OpenJDK.&lt;br /&gt;&lt;br /&gt;How will it affect Android if this case drags on? It could certainly hurt Android's adoption by hardware manufacturers, but they're already getting such an oustanding deal on the platform that they might not even care. Android is the first platform that has the potential to unify all hardware profiles, freeing manufacturers from the drudgery of building their own OSes or licensing OSes from someone else. Hell, HTC rose from zero to Hero largely because of their backing of Android and shipping of Android devices. Are they going to back off from that platform now just because Oracle's throwing lawyerbombs at Google? Probably not.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;What Does This Mean For You?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you're a non-Android Java developer...don't lose sleep over this. The details are going to take months to play out, and regardless of the outcome you're probably not going to be affected. Be happy, do great things, and keep making the Java platform a better place.&lt;br /&gt;&lt;br /&gt;If you're an Android developer...don't lose sleep over this. Even if things go the way of the "Nuclear Option", you've still got a lot of time to build and sell apps and improve yourself as a developer. For a bit of novelty, start considering what a migration path might look like and turn that into a nice Android-agnostic application layer, something that's largely lacking in the current Android APIs. Or explore Android development in languages like JRuby, which are based on off-platform ecosystems that will survive regardless of Android's fate. Whatever you do, don't panic and run for the hills, and don't tell your friends to panic.&lt;br /&gt;&lt;br /&gt;If you're mad as hell about this...I sympathize. I'm personally going to do whatever I can to keep people informed and keep pushing Android, including but not limited to writing 8000-word essays with my moderately-educated analysis of the "facts". I welcome your help in that fight, and I think it's a damn good time for people that want an open Java and an open mobile platform to show their quality by standing up and letting the world know we're here.&lt;br /&gt;&lt;br /&gt;"All that is necessary for the triumph of evil is for good men to do nothing."&lt;br /&gt;&lt;br /&gt;Do something, and we'll get through this together.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;Footnote: Java Copyrights&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'd love for someone versed in copyright law to provide a brief analysis of how the Java copyrights described (vaguely) in the lawsuit might play out in Android. Java is certainly not ignored as a concept in Android docs, tools, and libraries, but it's unclear to me whether those copyrights amount to something enforceable when it comes to Android or Dalvik.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Update:&lt;/span&gt;&lt;/span&gt; "Crazy" Bob Lee emailed me to clear up a few facts. First off, Android and OpenJDK first came out around roughly the same time, so there was never really time to consider using OpenJDK's GPL'ed class libraries in Android. Bob also claims that Dalvik's design decisions were all technical and not made to circumvent IP, but it seems impossible to me that IP, patent, and licensing issues didn't have *some* influence on those decisions. He goes on to say that Android relies on process separation to sandbox applications, rather than leveraging Java security policies (or similar mechanisms (which Bob insists are badly designed anyway, and I might agree). Finally, he believes that in the worst case scenario, Dalvik would probably only require minor modifications to address the complaints in this suit. The "nuclear option" is, according to Bob, out of the realm of possibility.&lt;br /&gt;&lt;br /&gt;Thanks for the clarifications, Bob!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-5342643660224394169?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/5342643660224394169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=5342643660224394169' title='111 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5342643660224394169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5342643660224394169'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/08/my-thoughts-on-oracle-v-google.html' title='My Thoughts on Oracle v Google'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>111</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-1051683049008424286</id><published>2010-07-19T16:16:00.004-05:00</published><updated>2010-07-19T19:08:13.227-05:00</updated><title type='text'>What JRuby C Extension Support Means to You</title><content type='html'>As part of the Ruby Summer of Code, &lt;a href="http://twitter.com/timfelgentreff"&gt;Tim Felgentreff&lt;/a&gt; has been building out C extension support for JRuby. He's already made great progress, with simple libraries like Thin and Mongrel working now and larger libraries like RMagick and Yajl starting to function. And we haven't even reached the mid-term evaluation yet. I'd say he gets an "A" so far.&lt;br /&gt;&lt;br /&gt;I figured it was time I talked a bit about C extensions, what they mean (or don't mean) for JRuby, and how you can help.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Promise of C Extensions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One of the "last mile" features keeping people from migrating to JRuby has been their dependence on C extensions that only work on regular Ruby. In some cases, these extensions have been written to improve performance, like the various json libraries. Some of that performance could be less of a concern under Ruby 1.9, but it's hard to claim that any implementation will be able to run Ruby as fast as C for general-purpose libraries any time soon.&lt;br /&gt;&lt;br /&gt;However, a large number of extensions – perhaps a majority of extensions – exist only to wrap a well-known and well-trusted C library. Nokogiri, for example, wraps the excellent libxml. RMagick wraps ImageMagick. For these cases, there's no alternative on regular Ruby...it's the C library or nothing (or in the case of Nokogiri, your alternatives are only slow and buggy pure-Ruby XML libraries).&lt;br /&gt;&lt;br /&gt;For the performance case, C extensions on JRuby don't mean a whole lot. In most cases, it would be easier and just as performant to write that code in Java, and many pure-Ruby libraries perform well enough to reduce the need for native code. In addition, there are often libraries that already do what the perf-driven extensions were written for, and it's trivial to just call those libraries directly from Ruby code.&lt;br /&gt;&lt;br /&gt;But the library case is a bit stickier. Nokogiri does have an FFI version, but it's a maintenance headache for them and a bug report headache for us, due to the lack of a C compiler tying the two halves together. There's a pure-Java Nokogiri in progress, but building both the Ruby bindings and emulating libxml behavior takes a long time to get right. For libraries like RMagick or the native MySQL and SQLite drivers, there are basically no options on the JVM. The Google Summer of Code project RMagick4J, by Sergio Arbeo, was a monumental effort that still has a lot of work left to be done. JDBC libraries work for databases, but they provide a very different interface from the native drivers and don't support things like UNIX domain sockets.&lt;br /&gt;&lt;br /&gt;There's a very good chance that JRuby C extension support won't perform as well as C extensions on C Ruby, but in many cases that won't matter. Where there's no equivalent library now, having something that's only 5-10x slower to call – but still runs fast and matches API – may be just fine. Think about the coarse-grained operations you feed to a MySQL or SQLite and you get the picture.&lt;br /&gt;&lt;br /&gt;So ultimately, I think C extensions will be a good thing for JRuby, even if they only serve as a stopgap measure to help people migrate small applications over to native Java equivalents. Why should the end goal be native Java equivalents, you ask?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Peril of C Extensions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now that we're done with the happy, glowing discussion of how great C extension support will be, I can make a confession: I hate C extensions. No feature of C Ruby has done more to hold it back than the desire for backward compatibility with C extensions. Because they have direct pointer access, there's no easy way to build a better garbage collector or easily support multiple runtimes in the same VM, even though various research efforts have tried. I've talked with Koichi Sasada, the creator of Ruby 1.9's "YARV" VM, and there's many things he would have liked to do with YARV that he couldn't because of C extension backward compatibility.&lt;br /&gt;&lt;br /&gt;For JRuby, supporting C extensions will limit many features that make JRuby compelling in the first place. For example, because C extensions often use a lot of global variables, you can't use them from multiple JRuby runtimes in the same process. Because they expect a Ruby-like threading model, we need to restrict concurrency when calling out from Java to C. And all the great memory tooling I've blogged about recently won't see C extensions or the libraries they call, so it introduces an unknown.&lt;br /&gt;&lt;br /&gt;All that said, I think it's a good milestone to show that we can support C extensions, and it may make for a "better JNI" for people who really just want to write C or who simply need to wrap a native library.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;How You Can Help&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There's a few things I think users like you can help with.&lt;br /&gt;&lt;br /&gt;First off, we'd love to know what extensions you are using today, so we can explore what it would take to run them under JRuby (and so we can start exploring pure-Java alternatives, too.) Post your list in the comments, and we'll see what we can come up with.&lt;br /&gt;&lt;br /&gt;Second, anyone that knows C and the Ruby C API (like folks who work on extensions) could help us fill out bits and pieces that are missing. Set up the JRuby cext branch (I'll show you how in a moment), and try to get your extensions to build and load. Tim has already done the heavy lifting of making "gem install xyz" attempt to build the extension and "require 'xyz'" try to load the resulting native library, so you can follow the usual processes (including extconf.rb/mkmf.rb for non-gem building and testing.) If it doesn't build ok, help us figure out what's missing or incorrect. If it builds but doesn't run, help us figure out what it's doing incorrectly.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Building JRuby with C Extension Support&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Like building JRuby proper, building the cext work is probably the easiest thing you'll do all day (assuming the C compiler/build/toolchain doesn't bite you.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Check out (or fork and check out) the JRuby repository from &lt;a href="http://github.com/jruby/jruby"&gt;http://github.com/jruby/jruby&lt;/a&gt;:&lt;br /&gt;&lt;pre&gt;git clone git://github.com/jruby/jruby.git&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Switch to the "cext" branch:&lt;br /&gt;&lt;pre&gt;git checkout -b cext origin/cext&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Do a clean build of JRuby plus the cext subsystem:&lt;br /&gt;&lt;pre&gt;ant clean build-jruby-cext-native&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;At this point you should have a JRuby build (run with bin/jruby) that can gem install and load native extensions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-1051683049008424286?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/1051683049008424286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=1051683049008424286' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1051683049008424286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1051683049008424286'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/07/what-jruby-c-extension-support-means-to.html' title='What JRuby C Extension Support Means to You'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-7166962243491443290</id><published>2010-07-17T16:58:00.005-05:00</published><updated>2010-07-19T03:01:54.501-05:00</updated><title type='text'>Browsing Memory with Ruby and Java Debug Interface</title><content type='html'>This is the third post in a series. The first two were on &lt;a href="http://blog.headius.com/2010/07/browsing-memory-jruby-way.html"&gt;Browsing Memory the JRuby Way&lt;/a&gt; and &lt;a href="http://blog.headius.com/2010/07/finding-leaks-in-ruby-apps-with-eclipse.html"&gt;Finding Leaks in Ruby Apps with Eclipse Memory Analyzer&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Hello again, friends! I'm back with more exciting memory analysis tips and tricks! Ready? Here we go!&lt;br /&gt;&lt;br /&gt;After my previous two posts, several folks asked if it's possible to do all this stuff from Ruby, rather than using Java or C-based apps shipped with the JVM. The answer is yes! Because of the maturity of the Java platform, there are standard Java APIs you can use to access all the same information the previous tools consumed. And since we're talking about JRuby, that means you have Ruby APIs you can use to access that information.&lt;br /&gt;&lt;br /&gt;That's what I'm going to show you today.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Introducing JDI&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The APIs we'll be using are part of the &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/jdk/api/jpda/jdi/index.html"&gt;Java Debug Interface (JDI)&lt;/a&gt;, a set of Java APIs for remotely inspecting a running application. It's part of the &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/technotes/guides/jpda/"&gt;Java Platform Debugger Architecture&lt;/a&gt;, which also includes a &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/technotes/guides/jvmti/index.html"&gt;C/++ API&lt;/a&gt;, a &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/technotes/guides/jpda/jdwp-spec.html"&gt;wire protocol&lt;/a&gt;, and a raw &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/technotes/guides/jpda/jdwpTransport.html"&gt;wire protocol API&lt;/a&gt;. Exploring those is left as an exercise for the reader...but they're also pretty cool.&lt;br /&gt;&lt;br /&gt;We'll use the Rails app from before, inspecting it immediately after boot. JDI provides a number of ways to connect up to a running VM, using &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/jdk/api/jpda/jdi/com/sun/jdi/VirtualMachineManager.html"&gt;VirtualMachineManager&lt;/a&gt;; you can either have the debugger make the connection or the target VM make the connection, and optionally have the target VM launch the debugger or the debugger launch the target VM. For our example, we'll have the debugger attach to a target VM listening for connections.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Preparing the Target VM&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first step is to start up the application with the appropriate debugger endpoint installed. This new flag is a bit of a mouthful (and we should make a standard flag for JRuby users), but we're simply setting up a socket-based listener on port 12345, running as a server, and we don't want to suspend the JVM when the debugger connects.&lt;br /&gt;&lt;pre&gt;jruby -J-agentlib:jdwp=transport=dt_socket,server=y,address=12345,suspend=n -J-Djruby.reify.classes=true script/server -e production&lt;/pre&gt;&lt;br /&gt;The -J-Djruby.reify.classes bit I talked about in my first post. It makes Ruby classes show up as Java classes for purposes of heap inspection.&lt;br /&gt;&lt;br /&gt;The rest is just running the server in production mode.&lt;br /&gt;&lt;br /&gt;As you can see, remote debugging is already baked into the JVM, which means we didn't have to write it or debug it. And that's pretty awesome.&lt;br /&gt;&lt;br /&gt;Let's connect to our Rails process and see what we can do.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Connecting to the target VM&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In order to connect to the target VM, you need to do the Java factory dance. We start with the &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/jdk/api/jpda/jdi/com/sun/jdi/Bootstrap.html"&gt;com.sun.jdi.Bootstrap class&lt;/a&gt;, get a &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/jdk/api/jpda/jdi/com/sun/jdi/VirtualMachineManager.html"&gt;com.sun.jdi.VirtualMachineManager&lt;/a&gt;, and then connect to a target VM to get a &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/jdk/api/jpda/jdi/com/sun/jdi/VirtualMachine.html"&gt;com.sun.jdi.VirtualMachine&lt;/a&gt; object.&lt;br /&gt;&lt;pre&gt;vmm = Bootstrap.virtual_machine_manager&lt;br /&gt;sock_conn = vmm.attaching_connectors[0] # not guaranteed to be Socket&lt;br /&gt;args = sock_conn.default_arguments&lt;br /&gt;args['hostname].value = "localhost"&lt;br /&gt;args['port'].value = "12345"&lt;br /&gt;vm = sock_conn.attach(args)&lt;/pre&gt;&lt;br /&gt;Notice that I didn't dig out the socket connector explicitly here, because on my system, the first connector always appears to be the socket connector. Here's the full list for me on OS X:&lt;br /&gt;&lt;pre&gt;➔ jruby -rjava -e "puts com.sun.jdi.Bootstrap.virtual_machine_manager.attaching_connectors&lt;br /&gt;&gt; "&lt;br /&gt;[com.sun.jdi.SocketAttach (defaults: timeout=, hostname=charles-nutters-macbook-pro.local, port=),&lt;br /&gt;com.sun.jdi.ProcessAttach (defaults: pid=, timeout=)]&lt;/pre&gt;&lt;br /&gt;The ProcessAttach connector there isn't as magical as it looks; all it does is query the target process to find out what transport it's using (dt_socket in our case) and then calls the right connector (e.g. SocketAttach in the case of dt_socket or SharedMemoryAttach if you use dt_shmem on Windows). In our case, we know it's listening on a socket, so we're using the SocketAttach connector directly.&lt;br /&gt;&lt;br /&gt;The rest is pretty simple: we get the default arguments from the connector, twiddle them to have the right hostname and port number, and attach to the VM. Now we have a VirtualMachine object we can query and twiddle; we're inside the matrix.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;With Great Power...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, what can we do with this VirtualMachine object? We can:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;walk all classes and objects on the heap&lt;/li&gt;&lt;li&gt;install breakpoints and step-debug any running code&lt;/li&gt;&lt;li&gt;inspect and modify the current state of any running thread, even manipulating in-flight arguments and variables&lt;/li&gt;&lt;li&gt;replace already-loaded classes with new definitions (such as to install custom instrumentation)&lt;/li&gt;&lt;/ul&gt;Here's the output from JRuby's ri command when we ask about VirtualMachine:&lt;br /&gt;&lt;pre&gt;➔ ri --java com.sun.jdi.VirtualMachine&lt;br /&gt;-------------------------------------- Class: com.sun.jdi.VirtualMachine&lt;br /&gt;     (no description...)&lt;br /&gt;------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Instance methods:&lt;br /&gt;-----------------&lt;br /&gt;     allClasses, allThreads, canAddMethod, canBeModified,&lt;br /&gt;     canForceEarlyReturn, canGetBytecodes, canGetClassFileVersion,&lt;br /&gt;     canGetConstantPool, canGetCurrentContendedMonitor,&lt;br /&gt;     canGetInstanceInfo, canGetMethodReturnValues,&lt;br /&gt;     canGetMonitorFrameInfo, canGetMonitorInfo, canGetOwnedMonitorInfo,&lt;br /&gt;     canGetSourceDebugExtension, canGetSyntheticAttribute, canPopFrames,&lt;br /&gt;     canRedefineClasses, canRequestMonitorEvents,&lt;br /&gt;     canRequestVMDeathEvent, canUnrestrictedlyRedefineClasses,&lt;br /&gt;     canUseInstanceFilters, canUseSourceNameFilters,&lt;br /&gt;     canWatchFieldAccess, canWatchFieldModification, classesByName,&lt;br /&gt;     description, dispose, eventQueue, eventRequestManager, exit,&lt;br /&gt;     getDefaultStratum, instanceCounts, mirrorOf, mirrorOfVoid, name,&lt;br /&gt;     process, redefineClasses, resume, setDebugTraceMode,&lt;br /&gt;     setDefaultStratum, suspend, toString, topLevelThreadGroups,&lt;br /&gt;     version, virtualMachine&lt;/pre&gt;&lt;br /&gt;We can basically make the target VM dance any way we want, even going so far as to write our own debugger entirely in Ruby code. But that's a topic for another day. Right now, we're going to do some memory inspection.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Creating a Histogram of the Heap&lt;/b&gt;&lt;br /&gt;The simplest heap inspection we might do is to produce a histogram of all objects on the heap. And as you might expect, this is one of the easiest things to do, because it's the first thing everyone looks for when debugging a memory issue.&lt;br /&gt;&lt;pre&gt;classes = VM.all_classes&lt;br /&gt;counts = VM.instance_counts(classes)&lt;br /&gt;classes.zip(counts)&lt;/pre&gt;&lt;br /&gt;VirtualMachine.all_classes gives you a list (a java.util.List, but we make those behave mostly like a Ruby Array) of every class the JVM has loaded, including Ruby classes, JRuby core and runtime classes, and other Java classes that JRuby and the JVM use. VirtualMachine.instance_counts takes that list of classes and returns another list of instance counts. Zip the two together, and we have an array of classes and instance counts. So easy!&lt;br /&gt;&lt;br /&gt;Let's take these two pieces and put them together in an easy-to-use class&lt;br /&gt;&lt;pre&gt;require 'java'&lt;br /&gt;&lt;br /&gt;module JRuby&lt;br /&gt;  class Debugger&lt;br /&gt;    VMM = com.sun.jdi.Bootstrap.virtual_machine_manager&lt;br /&gt;    &lt;br /&gt;    attr_accessor :vm&lt;br /&gt;    &lt;br /&gt;    def initialize(options = {})&lt;br /&gt;      connectors = VMM.attaching_connectors&lt;br /&gt;      if options[:port]&lt;br /&gt;        connector = connectors.find {|ac| ac.name =~ /Socket/}&lt;br /&gt;      elsif options[:pid]&lt;br /&gt;        connector = connectors.find {|ac| ac.name =~ /Process/}&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      args = connector.default_arguments&lt;br /&gt;      for k, v in options&lt;br /&gt;        args[k.to_s].value = v.to_s&lt;br /&gt;      end&lt;br /&gt;      &lt;br /&gt;      @vm = connector.attach(args)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Generate a histogram of all classes in the system&lt;br /&gt;    def histogram&lt;br /&gt;      classes = @vm.all_classes&lt;br /&gt;      counts = @vm.instance_counts(classes)&lt;br /&gt;      classes.zip(counts)&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;I've taken the liberty of expanding the connection process to handle pids and other arguments passed in. So to get a histogram from a VM listening on localhost port 12345, we can simply do:&lt;br /&gt;&lt;pre&gt;JRuby::Debugger.new(:hostname =&gt; 'localhost', :port =&gt; 12345).histogram&lt;/pre&gt;&lt;br /&gt;Now of course this list is going to have a lot of JRuby and Java objects that we might not be interested in, so we'll want to filter it to just the Ruby classes. On JRuby master, all the generated Ruby classes start with a package name "ruby". Unfortunately, jitted Ruby methods start with a package of "ruby.jit" right now, so we'll want to filter those out too (unless you're interested in them, of course...JRuby is an open book!)&lt;br /&gt;&lt;pre&gt;require 'jruby_debugger'&lt;br /&gt;&lt;br /&gt;# connect to the VM&lt;br /&gt;debugr = JRuby::Debugger.new(:hostname =&gt; 'localhost', :port =&gt; 12345)&lt;br /&gt;histo = debugr.histogram&lt;br /&gt;# sort by count&lt;br /&gt;histo.sort! {|a,b| b[1] &lt;=&gt; a[1]}&lt;br /&gt;# filter to only user-created Ruby classes with &gt;0 instances&lt;br /&gt;histo.each do |cls,num|&lt;br /&gt;  next if num == 0 || cls.name[0..4] != 'ruby.' || cls.name[5..7] == 'jit'&lt;br /&gt;  puts "#{num} instances of #{cls.name[5..-1].gsub('.', '::')}"&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;If we run this short script against our Rails application, we see similar results to the previous posts (but it's cooler, because we're doing it all from Ruby!)&lt;br /&gt;&lt;pre&gt;➔ jruby ruby_histogram.rb | head -10&lt;br /&gt;11685 instances of TZInfo::TimezoneTransitionInfo&lt;br /&gt;1071 instances of Gem::Version&lt;br /&gt;1012 instances of Gem::Requirement&lt;br /&gt;592 instances of TZInfo::TimezoneOffsetInfo&lt;br /&gt;432 instances of Gem::Dependency&lt;br /&gt;289 instances of Gem::Specification&lt;br /&gt;142 instances of ActiveSupport::TimeZone&lt;br /&gt;118 instances of TZInfo::DataTimezoneInfo&lt;br /&gt;118 instances of TZInfo::DataTimezone&lt;br /&gt;45 instances of Gem::Platform&lt;/pre&gt;&lt;br /&gt;Just so we're all on the same page, it's important to know what we're actually dealing with here. VirtualMachine.all_classes returns a list of &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/jdk/api/jpda/jdi/com/sun/jdi/ReferenceType.html"&gt;com.sun.jdi.ReferenceType&lt;/a&gt; objects. Let's ri that.&lt;br /&gt;&lt;pre&gt;➔ ri --java com.sun.jdi.ReferenceType&lt;br /&gt;--------------------------------------- Class: com.sun.jdi.ReferenceType&lt;br /&gt;     (no description...)&lt;br /&gt;------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Instance methods:&lt;br /&gt;-----------------&lt;br /&gt;     allFields, allLineLocations, allMethods, availableStrata,&lt;br /&gt;     classLoader, classObject, compareTo, constantPool,&lt;br /&gt;     constantPoolCount, defaultStratum, equals, failedToInitialize,&lt;br /&gt;     fieldByName, fields, genericSignature, getValue, getValues,&lt;br /&gt;     hashCode, instances, isAbstract, isFinal, isInitialized,&lt;br /&gt;     isPackagePrivate, isPrepared, isPrivate, isProtected, isPublic,&lt;br /&gt;     isStatic, isVerified, locationsOfLine, majorVersion, methods,&lt;br /&gt;     methodsByName, minorVersion, modifiers, name, nestedTypes,&lt;br /&gt;     signature, sourceDebugExtension, sourceName, sourceNames,&lt;br /&gt;     sourcePaths, toString, virtualMachine, visibleFields,&lt;br /&gt;     visibleMethods&lt;/pre&gt;&lt;br /&gt;You can see there's quite a bit more you can do with a ReferenceType. Let's try something.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Digging Deeper Into TimezoneTransitionInfo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let's actually take some time to explore our old friend TimezoneTransitionInfo (hereafter referred to as TTI). Instead of walking all classes in the system, we'll want to just grab TTI directly. For that we use VirtualMachine.classes_by_name, which returns a list of classes on the target VM of that name. There should be only one, since we only have a single JRuby instance in our server, so we'll grab that class and request exactly one instance of it...any old instance.&lt;br /&gt;&lt;pre&gt;tti_class = debugr.vm.classes_by_name('ruby.TZInfo.TimezoneTransitionInfo')[0]&lt;br /&gt;tti_obj = tti_class.instances(1)[0]&lt;br /&gt;puts tti_obj&lt;/pre&gt;&lt;br /&gt;Running this we can see we've got the reference we're looking for.&lt;br /&gt;&lt;pre&gt;➔ jruby tti_digger.rb&lt;br /&gt;instance of ruby.TZInfo.TimezoneTransitionInfo(id=2)&lt;/pre&gt;&lt;br /&gt;ReferenceType.instances returns a list (no larger than the specified size, or all instances if you specify 0) of &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/jdk/api/jpda/jdi/com/sun/jdi/ObjectReference.html"&gt;com.sun.jdi.ObjectReference&lt;/a&gt; objects.&lt;br /&gt;&lt;pre&gt;➔ ri --java com.sun.jdi.ObjectReference&lt;br /&gt;------------------------------------- Class: com.sun.jdi.ObjectReference&lt;br /&gt;     (no description...)&lt;br /&gt;------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Instance methods:&lt;br /&gt;-----------------&lt;br /&gt;     disableCollection, enableCollection, entryCount, equals, getValue,&lt;br /&gt;     getValues, hashCode, invokeMethod, isCollected, owningThread,&lt;br /&gt;     referenceType, referringObjects, setValue, toString, type,&lt;br /&gt;     uniqueID, virtualMachine, waitingThreads&lt;/pre&gt;&lt;br /&gt;Among the weirder things like disabling garbage collection for this object or listing all threads waiting on this object's monitor (a la 'synchronize' in Java), we can access the object's fields through getValue and setValue.&lt;br /&gt;&lt;br /&gt;Let's examine the instance variables TTI contains. You may recall from previous posts that all Ruby objects in JRuby store their instance variables in an array, to avoid the large memory and cpu cost of storing them in a map. We can grab a reference to that array and display its contents.&lt;br /&gt;&lt;pre&gt;var_table_field = tti_class.field_by_name('varTable')&lt;br /&gt;tti_vars = tti_obj.get_value(var_table_field)&lt;br /&gt;puts "varTable: #{tti_vars}"&lt;br /&gt;puts tti_vars.values.map(&amp;:to_s)&lt;/pre&gt;&lt;br /&gt;And the new output:&lt;br /&gt;&lt;pre&gt;➔ jruby tti_digger.rb&lt;br /&gt;varTable: instance of java.lang.Object[7] (id=13)&lt;br /&gt;instance of ruby.TZInfo.TimezoneOffsetInfo(id=15)&lt;br /&gt;instance of ruby.TZInfo.TimezoneOffsetInfo(id=16)&lt;br /&gt;instance of org.jruby.RubyFixnum(id=17)&lt;br /&gt;instance of org.jruby.RubyFixnum(id=18)&lt;br /&gt;instance of org.jruby.RubyNil(id=19)&lt;br /&gt;instance of org.jruby.RubyNil(id=19)&lt;br /&gt;instance of org.jruby.RubyNil(id=19)&lt;/pre&gt;&lt;br /&gt;Since the varTable field is a simple Object[] in Java, the reference we get to it is of type &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/jdk/api/jpda/jdi/com/sun/jdi/ArrayReference.html"&gt;com.sun.jdi.ArrayReference&lt;/a&gt;.&lt;br /&gt;&lt;pre&gt;➔ ri --java com.sun.jdi.ArrayReference&lt;br /&gt;-------------------------------------- Class: com.sun.jdi.ArrayReference&lt;br /&gt;     (no description...)&lt;br /&gt;------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Instance methods:&lt;br /&gt;-----------------&lt;br /&gt;     disableCollection, enableCollection, entryCount, equals, getValue,&lt;br /&gt;     getValues, hashCode, invokeMethod, isCollected, length,&lt;br /&gt;     owningThread, referenceType, referringObjects, setValue, setValues,&lt;br /&gt;     toString, type, uniqueID, virtualMachine, waitingThreads&lt;/pre&gt;&lt;br /&gt;Of course each of these references can be further explored, but already we can see that this TTI instance has seven instance variables: two TimezoneOffsetInfo objects, two Fixnums, and three nils. But we don't have instance variable names!&lt;br /&gt;&lt;br /&gt;Instance variable names are only stored on the object's class. There, a table of names to offsets is kept up-to-date as new instance variable names are discovered. We can access this from the TTI class reference and combine it with the variable table to get the output we want to see.&lt;br /&gt;&lt;pre&gt;# get the metaclass object and class reference&lt;br /&gt;metaclass_field = tti_class.field_by_name('metaClass')&lt;br /&gt;tti_class_obj = tti_obj.get_value(metaclass_field)&lt;br /&gt;tti_class_class = tti_class_obj.reference_type&lt;br /&gt;&lt;br /&gt;# get the variable names from the metaclass object&lt;br /&gt;var_names_field = tti_class_class.field_by_name('variableNames')&lt;br /&gt;var_names = tti_class_obj.get_value(var_names_field)&lt;br /&gt;&lt;br /&gt;# splice the names and values together&lt;br /&gt;table = var_names.values.zip(tti_vars.values)&lt;br /&gt;puts table&lt;/pre&gt;&lt;br /&gt;This looks a bit complicated, but there's actually a lot of boilerplate here we could put into a utility class. For example, the metaClass and variableNames fields are standard on all (J)Ruby objects and classes, respectively. But considering that we're actually walking a remote VM's *live* heap...this is pretty simple code.&lt;br /&gt;&lt;br /&gt;Here's what our script outputs now:&lt;br /&gt;&lt;pre&gt;➔ jruby tti_digger.rb&lt;br /&gt;"@offset"&lt;br /&gt;instance of ruby.TZInfo.TimezoneOffsetInfo(id=25)&lt;br /&gt;"@previous_offset"&lt;br /&gt;instance of ruby.TZInfo.TimezoneOffsetInfo(id=26)&lt;br /&gt;"@numerator_or_time"&lt;br /&gt;instance of org.jruby.RubyFixnum(id=27)&lt;br /&gt;"@denominator"&lt;br /&gt;instance of org.jruby.RubyFixnum(id=28)&lt;br /&gt;"@at"&lt;br /&gt;instance of org.jruby.RubyNil(id=29)&lt;br /&gt;"@local_end"&lt;br /&gt;instance of org.jruby.RubyNil(id=29)&lt;br /&gt;"@local_start"&lt;br /&gt;instance of org.jruby.RubyNil(id=29)&lt;/pre&gt;&lt;br /&gt;We could go even deeper, but I think you get the idea.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Your Turn&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's a &lt;a href="http://gist.github.com/481102"&gt;gist of the three scripts we've created&lt;/a&gt;, so you can refer to and build off of them. And of course the javadocs and ri docs will help you as well, plus everything we've done here you can do in a jirb session.&lt;br /&gt;&lt;br /&gt;There's a lot to the JDI API, but once you've got the VirtualMachine object in hand it's pretty easy to follow. As you'd expect from any debugger API, you need to know a bit about how things work on the inside, but through the magic of JRuby it's actually possible to write most of those fancy memory and debugging tools entirely in Ruby. Perhaps this article has peaked your interest in exploring JRuby internals using JDI and you might start to write debugging tools. Perhaps we can ship a few utilities to make some of the boilerplate go away. In any case, I hope this series of articles shows that JRuby users have an amazing library of tools available to them, and you don't even have to leave your comfort zone if you don't want to.&lt;br /&gt;&lt;br /&gt;Note: The variableNames field is a recent addition to JRuby master, so if you'd like to play with that you'll probably want to build JRuby yourself or wait for a nightly build that picks it up. But you can certainly do a lot of exploring even without that patch.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-7166962243491443290?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/7166962243491443290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=7166962243491443290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/7166962243491443290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/7166962243491443290'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/07/browsing-memory-with-ruby-and-jdi.html' title='Browsing Memory with Ruby and Java Debug Interface'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-4601412798314916097</id><published>2010-07-12T11:35:00.028-05:00</published><updated>2010-07-12T20:12:02.985-05:00</updated><title type='text'>Finding Leaks in Ruby Apps with Eclipse Memory Analyzer</title><content type='html'>After my post on &lt;a href="http://blog.headius.com/2010/07/browsing-memory-jruby-way.html"&gt;Browsing Memory the JRuby Way&lt;/a&gt;, one commenter and several other folks suggested I actually show using Eclipse MAT with JRuby. So without further ado...&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.eclipse.org/mat/"&gt;Eclipse Memory Analyzer&lt;/a&gt;, like many Eclipse-based applications, starts up with a "for dummies" page linking to various actions.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDtFCmrPcmI/AAAAAAAAAFw/5IUkJUka6Eo/s1600/Screen+shot+2010-07-12+at+11.34.47+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 301px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDtFCmrPcmI/AAAAAAAAAFw/5IUkJUka6Eo/s400/Screen+shot+2010-07-12+at+11.34.47+AM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5493060081552421474" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The most interesting use of MAT is to analyze a heap dump in a bit more interactive way than with the "jhat" tool. The analysis supports the "jmap" dump format, so we'll proceed to get a jmap dump of a "leaky" Rails application.&lt;br /&gt;&lt;br /&gt;I've added this controller to a simple application:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class LeakyController &amp;lt; ApplicationController&lt;br /&gt;  class MyData&lt;br /&gt;    def initialize(params)&lt;br /&gt;      @params = params&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  LEAKING_ARRAY = {}&lt;br /&gt;  def index&lt;br /&gt;    LEAKING_ARRAY[Time.now] = MyData.new(params)&lt;br /&gt;    render :text =&amp;gt; "There are #{LEAKING_ARRAY.size} elements now!"&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Some genius has decided to save all recent request parameters into a constant on the LeakyController, keyed by time, wrapped in a custom type, and never cleaned out. Perhaps this was done temporarily for debugging, or perhaps we have a moron on staff. Either way, we need to find this problem and fix it.&lt;br /&gt;&lt;br /&gt;We'll run this application and crank 10000 requests through the /leaky index, so the final request should output "There are 10000 elements now!"&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~ ➔ ab -n 10000 http://localhost:3000/leaky&lt;br /&gt;This is ApacheBench, Version 2.3 &amp;lt;$Revision: 655654 $&amp;gt;&lt;br /&gt;Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/&lt;br /&gt;Licensed to The Apache Software Foundation, http://www.apache.org/&lt;br /&gt;&lt;br /&gt;Benchmarking localhost (be patient)&lt;br /&gt;Completed 1000 requests&lt;br /&gt;Completed 2000 requests&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After 10000 requests have completed, we notice this application seems to grow and grow until it maxes out the heap (JRuby, being on the JVM, automatically limits heap sizes for you). Let's start by using jmap to investigate the problem.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~ ➔ jps -l&lt;br /&gt;61976 org/jruby/Main&lt;br /&gt;61999 sun.tools.jps.Jps&lt;br /&gt;61837&lt;br /&gt;&lt;br /&gt;~ ➔ jmap -histo 61976 | grep " ruby\." | head -5&lt;br /&gt; 37:         11685         280440  ruby.TZInfo.TimezoneTransitionInfo&lt;br /&gt; 40:         10000         240000  ruby.LeakyController.MyData&lt;br /&gt;133:           970          23280  ruby.Gem.Version&lt;br /&gt;137:           914          21936  ruby.Gem.Requirement&lt;br /&gt;170:           592          14208  ruby.TZInfo.TimezoneOffsetInfo&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can see our old friend TimezoneTransitionInfo in there, but of course we've learned to accept that one. But what's this LeakyController::MyData object we've apparently got 10000 instances of? Where are they coming from? Who's holding on to them?&lt;br /&gt;&lt;br /&gt;At this point, we can proceed to get a memory dump and move over to MAT, or have MAT acquire and open the dump in one shot, similar to VisualVM. Let's have MAT do it for us.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Getting Our Heap Into MAT&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(Caveat: While preparing this post, I discovered that the jmap tool for the current OS X Java 6 (build 1.6.0_20-b02-279-10M3065) is not properly dumping all information. As a result, many fields and objects don't show up in dump analysis tools like MAT. Fortunately, there's a way out; on OS X, you can grab Soylatte or OpenJDK builds from various sources that work properly. In my case, I'm using a local build of OpenJDK 7.)&lt;br /&gt;&lt;br /&gt;From the File menu, we select Acquire Heap Dump.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HWobMsJuRHc/TDtK89bP55I/AAAAAAAAAF4/p83BuCe9SYc/s1600/Screen+shot+2010-07-12+at+12.03.03+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 214px; height: 108px;" src="http://4.bp.blogspot.com/_HWobMsJuRHc/TDtK89bP55I/AAAAAAAAAF4/p83BuCe9SYc/s400/Screen+shot+2010-07-12+at+12.03.03+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5493066581649909650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The resulting dialog should be familiar, since it lists the same JVM processes the "jps" command listed above. (If you had to specify a specific JDK home, like me, you'll need to click the "Configure" button and set the "jdkhome" flag" for "HPROF jmap dump provider".)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDtLNsHLDkI/AAAAAAAAAGA/01GRelhWa6Q/s1600/Screen+shot+2010-07-12+at+12.04.08+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 305px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDtLNsHLDkI/AAAAAAAAAGA/01GRelhWa6Q/s400/Screen+shot+2010-07-12+at+12.04.08+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5493066869060079170" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We'll pick our Rails instance (pid 61976) and proceed.&lt;br /&gt;&lt;br /&gt;MAT connects to the process, pulls a heap dump to disk, and immediately proceeds to parse and open it.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HWobMsJuRHc/TDtLm7ZwVWI/AAAAAAAAAGI/OumtSe-wDso/s1600/Screen+shot+2010-07-12+at+12.05.49+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 162px;" src="http://1.bp.blogspot.com/_HWobMsJuRHc/TDtLm7ZwVWI/AAAAAAAAAGI/OumtSe-wDso/s400/Screen+shot+2010-07-12+at+12.05.49+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5493067302661281122" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Once it has completed parsing, we're presented with a few different paths to follow.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HWobMsJuRHc/TDtL0xLEGgI/AAAAAAAAAGQ/FGfWfCbxaCY/s1600/Screen+shot+2010-07-12+at+12.07.12+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 321px;" src="http://1.bp.blogspot.com/_HWobMsJuRHc/TDtL0xLEGgI/AAAAAAAAAGQ/FGfWfCbxaCY/s400/Screen+shot+2010-07-12+at+12.07.12+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5493067540433476098" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;On other days, we might be interested in doing some component-by-component browsing to look for fat objects or minor leaks, or we might want to revisit the results of previous analyses against this heap. But today, we really need to figure out this MyData leak, so we'll run the Leak Suspects Report.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Leak Suspects?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HWobMsJuRHc/TDtMXrPI-NI/AAAAAAAAAGY/-NmvIZKNbQo/s1600/Screen+shot+2010-07-12+at+12.09.31+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 162px;" src="http://4.bp.blogspot.com/_HWobMsJuRHc/TDtMXrPI-NI/AAAAAAAAAGY/-NmvIZKNbQo/s400/Screen+shot+2010-07-12+at+12.09.31+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5493068140135381202" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Are you kidding? A tool that can search out and report possible leaks in a running system? Yes, Virginia, there is a Santa Claus!&lt;br /&gt;&lt;br /&gt;This is the good side of the "plague of choices" we have on the JVM. Because there's so many tools for almost every basic purpose (like the dozen – at least – memory inspection tools), tool developers have moved on to more specific needs like leak analysis. MAT is my favorite tool for leak-hunting (and it uses less memory than jhat for heap-browsing, which is great for larger dumps).&lt;br /&gt;&lt;br /&gt;Once MAT has finished chewing on our heap, it presents a pie chart of possible leak suspects. The logic used essentially seeks out data structures whose accumulated size is large in comparison to the rest of the heap. In this case, MAT has identified three suspects that in total comprise over half of the live heap data.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HWobMsJuRHc/TDtOJW0lylI/AAAAAAAAAGo/H6s9-Rjt0gU/s1600/Screen+shot+2010-07-12+at+12.15.12+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 275px;" src="http://4.bp.blogspot.com/_HWobMsJuRHc/TDtOJW0lylI/AAAAAAAAAGo/H6s9-Rjt0gU/s400/Screen+shot+2010-07-12+at+12.15.12+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5493070093160401490" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Scrolling down we start to get details about these leak candidates.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDtOnTP8PVI/AAAAAAAAAGw/hmmT_-41h8I/s1600/Screen+shot+2010-07-12+at+12.18.37+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 352px; height: 400px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDtOnTP8PVI/AAAAAAAAAGw/hmmT_-41h8I/s400/Screen+shot+2010-07-12+at+12.18.37+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5493070607597452626" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So there's a Hash, a Module, and 711 Class objects in our list of suspects. The Class objects are probably just loaded classes, since the JRuby core classes and additional classes loaded from Rails and its dependent libraries will easily number in the hundreds. We'll ignore that one for now. There's also an unusually large Module taking up almost 4MB of memory. We'll come back to that.&lt;br /&gt;&lt;br /&gt;The Hash seems like the most likely candidate. Let's expand that.&lt;br /&gt;&lt;br /&gt;The first new block of information gives us a list of "shortest paths" to the "accumulation point", or the point at which all this potentially-leaking data is gathering. There's more to this in the actual application, but I'm showing the top of the "path" here.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HWobMsJuRHc/TDtP2ptyTsI/AAAAAAAAAG4/ePbY9kMrYos/s1600/Screen+shot+2010-07-12+at+12.22.36+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 314px;" src="http://2.bp.blogspot.com/_HWobMsJuRHc/TDtP2ptyTsI/AAAAAAAAAG4/ePbY9kMrYos/s400/Screen+shot+2010-07-12+at+12.22.36+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5493071970837876418" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;At the top of this list, we see the RubyHash object originally reported as a suspect, and a tree of objects that lead to it. In this case, we go from the Hash itself into a ConcurrentHashMap (note that we're hiding nothing here; you can literally browse anything in memory) which in turn is referenced by the "constants" field of a Class. So already we know that this hash is being referenced in some class's constant table. Pretty cool, eh?&lt;br /&gt;&lt;br /&gt;Let's make sure we've got the right Hash and not some harmless data structure inside Rails. If we scroll down a bit more, we see a listing of all the objects this Hash has accumulated. Let's see what's in there.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HWobMsJuRHc/TDtQx_pMw6I/AAAAAAAAAHA/XuiaB_f65f8/s1600/Screen+shot+2010-07-12+at+12.27.55+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 150px;" src="http://1.bp.blogspot.com/_HWobMsJuRHc/TDtQx_pMw6I/AAAAAAAAAHA/XuiaB_f65f8/s400/Screen+shot+2010-07-12+at+12.27.55+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5493072990336500642" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ok, so it's a hashtable structure with a table of entries. Can we get more out of this?&lt;br /&gt;&lt;br /&gt;Of course like most of these tools, just about everything is clickable. We can dive into one of the hash entries and see what's in there. Clicking on an entry gives us several new ways to display the downstream objects we've managed to aggregate. In this case, we'll just do "List Objects", and the suboption "With Outgoing References" for downstream data.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDtSjlWP7wI/AAAAAAAAAHQ/3PKVakLYux8/s1600/Screen+shot+2010-07-12+at+12.35.15+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 192px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDtSjlWP7wI/AAAAAAAAAHQ/3PKVakLYux8/s400/Screen+shot+2010-07-12+at+12.35.15+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493074941782781698" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now finally in the resulting view of this particular RubyHashEntry, we can see that our MyData object is happily tucked away inside.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HWobMsJuRHc/TDtTmzCEicI/AAAAAAAAAHY/css1X69o8CQ/s1600/Screen+shot+2010-07-12+at+12.40.23+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 162px;" src="http://1.bp.blogspot.com/_HWobMsJuRHc/TDtTmzCEicI/AAAAAAAAAHY/css1X69o8CQ/s400/Screen+shot+2010-07-12+at+12.40.23+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493076096507480514" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ok, so we definitely have the right data structure. Not only that, but we can see that the entry's "key" is a Time object (org.jruby.RubyTime). Let's go back to the "Shortest Paths" view and examine the ConcurrentHashMap entry that's holding this Hash object. Each entry in this hash maps a constant name to a value, so we should be able to see which constant is holding the leaking references.&lt;br /&gt;&lt;br /&gt;(At this point you'll see the side effects of my switch to OpenJDK 7; the memory addresses have changed, but the structure is the same.)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HWobMsJuRHc/TDtkD1XjmYI/AAAAAAAAAHo/BwpelWVULt8/s1600/Screen+shot+2010-07-12+at+1.50.21+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 69px;" src="http://4.bp.blogspot.com/_HWobMsJuRHc/TDtkD1XjmYI/AAAAAAAAAHo/BwpelWVULt8/s400/Screen+shot+2010-07-12+at+1.50.21+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493094187536718210" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We'll do another "List Objects" "with outgoing references" against the the HashEntry object immediately referencing our RubyHash.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDtkjEPNbyI/AAAAAAAAAHw/2VrgnFtTjmA/s1600/Screen+shot+2010-07-12+at+1.52.24+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 88px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDtkjEPNbyI/AAAAAAAAAHw/2VrgnFtTjmA/s400/Screen+shot+2010-07-12+at+1.52.24+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493094724104187682" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And there it is! In the "key" field of the HashEntry, we see our constant name "LEAKING_ARRAY".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What About That Module?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Oh yeah, what about that Module that showed up in the leak suspects? It was responsible for almost 4MB of the heap. Let's go back and check it out.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HWobMsJuRHc/TDtonR3TZJI/AAAAAAAAAH4/nBWwgFRGrb8/s1600/Screen+shot+2010-07-12+at+2.09.56+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 182px;" src="http://2.bp.blogspot.com/_HWobMsJuRHc/TDtonR3TZJI/AAAAAAAAAH4/nBWwgFRGrb8/s400/Screen+shot+2010-07-12+at+2.09.56+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493099194527999122" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A-ha! Eclipse MAT has flagged the Gem module as being a potential leak suspect. But why? Let's go back to the suspect report and look at the Accumulated Objects by Class table, toward the bottom.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HWobMsJuRHc/TDtrQmAy46I/AAAAAAAAAII/GMwqC_my1MA/s1600/Screen+shot+2010-07-12+at+2.21.12+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 110px;" src="http://2.bp.blogspot.com/_HWobMsJuRHc/TDtrQmAy46I/AAAAAAAAAII/GMwqC_my1MA/s400/Screen+shot+2010-07-12+at+2.21.12+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493102103334413218" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ok, so the Gem module eventually references nearly &lt;strike&gt;6000&lt;/strike&gt; Gem::Specification objects, which makes up the bulk of our 3.8MB. &lt;strike&gt;I guarantee I don't have 6000 gem versions installed.&lt;/strike&gt; Perhaps that's something that RubyGems should endeavor to fix? Perhaps we've just used JRuby and Eclipse MAT to discover either a leak or wasteful memory use in RubyGems?&lt;br /&gt;&lt;br /&gt;Evan Phoenix pointed out that I misread the columns. It's actually 249 Specification objects, their "self" size is almost 6000 bytes, and their "retained" size is 3.8MB. But that gives me an opportunity to show off another feature of MAT: Customized Retained Set calculation.&lt;br /&gt;&lt;br /&gt;In this case, the retained size seems a bit suspect. Could there really be 3.8MB of data kept alive by Gem::Specification objects? It seems like a bit much, to be sure, but digging through the tree of references from the Gem module down shows there's several references to classes and modules, which in turn reference constant tables, method tables, and so on. How can we filter out that extra noise?&lt;br /&gt;&lt;br /&gt;First we'll return to the view of the Gem module (two screenshots up) by going back to leak suspect #2, expanding "Shortest Paths". The topmost RubyModule in that list is the Gem module, so we're all set to calculate a Customized Retained Set.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HWobMsJuRHc/TDuxnysBvPI/AAAAAAAAAIQ/zCm-yA_omcE/s1600/Screen+shot+2010-07-12+at+7.21.11+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 147px;" src="http://2.bp.blogspot.com/_HWobMsJuRHc/TDuxnysBvPI/AAAAAAAAAIQ/zCm-yA_omcE/s400/Screen+shot+2010-07-12+at+7.21.11+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493179467687902450" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The resulting dialog provides a list of options through which you can specify classes or fields to ignore when calculating the retained set from a given starting point. In this case, it's simple enough to filter out org.jruby.RubyClass and org.jruby.RubyModule, so that references from Gem::Specification back into the class/module hierarchy don't get included in calculations.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDuydqIbWlI/AAAAAAAAAIY/Sa1Bz5PcsYo/s1600/Screen+shot+2010-07-12+at+7.24.50+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 315px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDuydqIbWlI/AAAAAAAAAIY/Sa1Bz5PcsYo/s400/Screen+shot+2010-07-12+at+7.24.50+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493180393104038482" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Which results in a similar view to those we've seen, but with objects sorted by retained heap.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HWobMsJuRHc/TDu1msssTYI/AAAAAAAAAIg/bJGMmqBEi3A/s1600/Screen+shot+2010-07-12+at+7.27.48+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 171px;" src="http://4.bp.blogspot.com/_HWobMsJuRHc/TDu1msssTYI/AAAAAAAAAIg/bJGMmqBEi3A/s400/Screen+shot+2010-07-12+at+7.27.48+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493183846946721154" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Well what the heck? It looks like it's all String data?&lt;br /&gt;&lt;br /&gt;JRuby's String implementation is an org.jruby.RubyString object, aggregating an org.jruby.util.ByteList object, aggregating a byte array, so the top three entries there in total are essentially all String memory. The best way to investigate where they're coming from is to do "List Objects" on RubyString, but instead of "with outgoing references" we'll use "with incoming references" to show where all those Strings are coming from.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HWobMsJuRHc/TDu3PL9iEqI/AAAAAAAAAIw/AohfdQ-indA/s1600/Screen+shot+2010-07-12+at+7.44.44+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 321px;" src="http://4.bp.blogspot.com/_HWobMsJuRHc/TDu3PL9iEqI/AAAAAAAAAIw/AohfdQ-indA/s400/Screen+shot+2010-07-12+at+7.44.44+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493185642045248162" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Finally we have a view that lets us hunt through all these strings and see where they're coming from. Poking at the first few shows they're stored in constant tables of the Gem module (that last RubyModule I haven't expanded in). That's probably not a big deal. But if we sort the the list of RubyString objects by their retained sizes, we get a different picture of the system.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HWobMsJuRHc/TDu8gRTVaOI/AAAAAAAAAI4/k8kwxSTyr3g/s1600/Screen+shot+2010-07-12+at+8.07.09+PM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 272px;" src="http://4.bp.blogspot.com/_HWobMsJuRHc/TDu8gRTVaOI/AAAAAAAAAI4/k8kwxSTyr3g/s400/Screen+shot+2010-07-12+at+8.07.09+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493191433094785250" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If we dig into the *largest* String objects, they appear to be referenced by Gem::Specification instance variables! So there's probably something worth investigating here.&lt;br /&gt;&lt;br /&gt;It's also worth noting that any Ruby application is going to have a lot of Strings in it, so this isn't all that unusual to see. But it's nice to have a tool that lets you investigate potential inefficiencies (even down to the raw bytes!), and it's nice to know that at least some of that retained data for the Gem module is "real" and not just references back into the class hierarchy.&lt;br /&gt;&lt;br /&gt;(And I'm not convinced all those Strings really *need* to be alive...but you're welcome to take it from here!)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Your Turn&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Eclipse MAT is probably one of the nicest of the free tools. In addition to object browsing, leak detection, GC root analysis, and object query language support, there's a ton of other features, both in the main distribution and available from third parties. If you're hunting for memory leaks, or just want to investigate the memory usage of your (J)Ruby application, MAT is a tool worth playing with (and as always, I hope you will blog and report your experiences!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-4601412798314916097?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/4601412798314916097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=4601412798314916097' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/4601412798314916097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/4601412798314916097'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/07/finding-leaks-in-ruby-apps-with-eclipse.html' title='Finding Leaks in Ruby Apps with Eclipse Memory Analyzer'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_HWobMsJuRHc/TDtFCmrPcmI/AAAAAAAAAFw/5IUkJUka6Eo/s72-c/Screen+shot+2010-07-12+at+11.34.47+AM.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-1965835751183434626</id><published>2010-07-09T01:23:00.023-05:00</published><updated>2010-07-09T06:27:08.624-05:00</updated><title type='text'>Browsing Memory the JRuby Way</title><content type='html'>There's been a lot of fuss made lately over memory inspection and profiling tools for Ruby implementations. And it's not without reason; inspecting a Ruby application's memory profile, much less diagnosing problems, has traditionally been very difficult. At least, difficult if you don't use JRuby.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Because JRuby runs on the JVM, we benefit from the dozens of tools that have been written for the JVM. Among these tools are numerous memory inspection, profiling, and reporting tools, some built into the JDK itself. Want a heap dump? Check out the jmap (Java memory map) and jhat (Java heap analysis tool) shipped with Hotspot-based JVMs (Sun, OpenJDK). Looking for a bit more? There's the Memory Analysis Tool based on Eclipse, the YourKit memory and CPU profiling app, VisualVM, now also shipped with Hotspot JVMs...and many more. There's literally dozens of these tools, and they provide just about everything you can imagine for investigating memory.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In this post, I'll show how you can use two of these tools: VisualVM, a simple, graphical tool for exploring a &lt;b&gt;running&lt;/b&gt; JVM; and the jmap/jhat combination, which allows you to dump the memory heap to disk for inspection offline.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;b&gt;Getting JRuby Prepared&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;All these tools work with any version of JRuby, but as part of JRuby 1.6 development I've been adding some enhancements. Specifically, I've made some modifications that allow Ruby objects to show up side-by-side with Java objects in memory profiles. A little explanation is in order.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In JRuby, all the core classes are represented by "native" Java classes. Object is represented by org.jruby.RubyObject, String is org.jruby.RubyString, and so on. Normally, if you extend one of the core classes, we don't actually create a new "native" class to represent it; instead, all user-created classes that extend Object simply show up as RubyObject in memory. This is still incredibly useful; you can look into RubyObject and see the metaClass field, which indicates the actual Ruby type.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let's see what that looks like, so we know where we're starting from. We'll run a simple script that creates a custom class, instantiates and saves 10000 instances of it, and then sleeps.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ cat foo_heap_example.rb &lt;br /&gt;class Foo&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;ary = []&lt;br /&gt;10000.times { ary &amp;lt;&amp;lt; Foo.new }&lt;br /&gt;&lt;br /&gt;puts "ready for analysis!"&lt;br /&gt;sleep&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ jruby foo_heap_example.rb &lt;br /&gt;ready for analysis!&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So we have our test subject ready to go. To use the jmap tool, we need the pid of this process. Of course we can use the usual shell tricks to get it, but the JDK comes with a nice tool for finding all JVM pids active on the system: jps&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jps -l&lt;br /&gt;52862 sun.tools.jps.Jps&lt;br /&gt;52857 org/jruby/Main&lt;br /&gt;48716 com.sun.enterprise.glassfish.bootstrap.ASMain&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;From this, you can see I have three JVMs running on my system right now: jps itself; our JRuby instance; and a GlassFish server I used for testing earlier today. We're interested in the JRuby instance, pid 52857. Let's see what jmap can do with that.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jmap&lt;br /&gt;Usage:&lt;br /&gt;    jmap [option] &amp;lt;pid&amp;gt;&lt;br /&gt;        (to connect to running process)&lt;br /&gt;    jmap [option] &amp;lt;executable &amp;lt;core&amp;gt;&lt;br /&gt;        (to connect to a core file)&lt;br /&gt;    jmap [option] [server_id@]&amp;lt;remote server IP or hostname&amp;gt;&lt;br /&gt;        (to connect to remote debug server)&lt;br /&gt;&lt;br /&gt;where &amp;lt;option&amp;gt; is one of:&lt;br /&gt;    &amp;lt;none&amp;gt;               to print same info as Solaris pmap&lt;br /&gt;    -heap                to print java heap summary&lt;br /&gt;    -histo[:live]        to print histogram of java object heap; if the "live"&lt;br /&gt;                         suboption is specified, only count live objects&lt;br /&gt;    -permstat            to print permanent generation statistics&lt;br /&gt;    -finalizerinfo       to print information on objects awaiting finalization&lt;br /&gt;    -dump:&amp;lt;dump-options&amp;gt; to dump java heap in hprof binary format&lt;br /&gt;                         dump-options:&lt;br /&gt;                           live         dump only live objects; if not specified,&lt;br /&gt;                                        all objects in the heap are dumped.&lt;br /&gt;                           format=b     binary format&lt;br /&gt;                           file=&amp;lt;file&amp;gt;  dump heap to &amp;lt;file&amp;gt;&lt;br /&gt;                         Example: jmap -dump:live,format=b,file=heap.bin &amp;lt;pid&amp;gt;&lt;br /&gt;    -F                   force. Use with -dump:&amp;lt;dump-options&amp;gt; &amp;lt;pid&amp;gt; or -histo&lt;br /&gt;                         to force a heap dump or histogram when &amp;lt;pid&amp;gt; does not&lt;br /&gt;                         respond. The "live" suboption is not supported&lt;br /&gt;                         in this mode.&lt;br /&gt;    -h | -help           to print this help message&lt;br /&gt;    -J&amp;lt;flag&amp;gt;             to pass &amp;lt;flag&amp;gt; directly to the runtime system&lt;br /&gt;&lt;br /&gt;&amp;lt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The simplest option here is -histo, to print out a histogram of the objects on the heap. Let's run that against our JRuby instance.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jmap -histo:live 52857&lt;br /&gt;&lt;br /&gt; num     #instances         #bytes  class name&lt;br /&gt;----------------------------------------------&lt;br /&gt;   1:         22677        3192816  &amp;lt;constMethodKlass&amp;gt;&lt;br /&gt;   2:         22677        1816952  &amp;lt;methodKlass&amp;gt;&lt;br /&gt;   3:         35089        1492992  &amp;lt;symbolKlass&amp;gt;&lt;br /&gt;   4:          2860        1389352  &amp;lt;instanceKlassKlass&amp;gt;&lt;br /&gt;   5:          2860        1193536  &amp;lt;constantPoolKlass&amp;gt;&lt;br /&gt;   6:          2798         739264  &amp;lt;constantPoolCacheKlass&amp;gt;&lt;br /&gt;   7:          5861         465408  [B&lt;br /&gt;   8:          5399         298120  [C&lt;br /&gt;   9:          3042         292032  java.lang.Class&lt;br /&gt;  10:          4037         261712  [S&lt;br /&gt;  11:         10002         240048  org.jruby.RubyObject&lt;br /&gt;  12:          3994         179928  [[I&lt;br /&gt;  13:          5474         131376  java.lang.String&lt;br /&gt;  14:          1661          95912  [I&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The resulting output is a listing of literally &lt;span style="font-weight:bold;"&gt;every&lt;/span&gt; object in the system...not just Ruby objects even! The value of this should be apparent; not only can you start to investigate the memory overhead of code you've written, you'll also be able to investigate the memory overhead of every library and every piece of code running in the same process, right down to byte arrays (the "[B" above) and "native" Java strings ("java.lang.String" above). And so far we haven't had to do anything special to JRuby. Nice, eh?&lt;br /&gt;&lt;br /&gt;So, back to the matter at hand: the Foo class from our example. Where is it?&lt;br /&gt;&lt;br /&gt;Well, the answer is that it's right there; 10000 of those 10002 org.jruby.RubyObject instances are our Foo objects; the other two are probably objects constructed for JRuby runtime purposes. But obviously, there's nothing in this output that tells us how to find our Foo instances. This is what I'm remedying in JRuby 1.6.&lt;br /&gt;&lt;br /&gt;On JRuby master, there's now a flag you can pass that will stand up a JVM class for every user-created Ruby class. Among the many benefits of doing this, we also get a more useful profile. Let's see how to use the flag (which will either be default or very easy to access by the time we release JRuby 1.6).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jruby -J-Djruby.reify.classes=true foo_heap_example.rb &lt;br /&gt;ready for analysis!&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If we run jmap against this new instance, we see a more interesting result.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; num     #instances         #bytes  class name&lt;br /&gt;----------------------------------------------&lt;br /&gt;   1:         22677        3192816  &amp;lt;constMethodKlass&amp;gt;&lt;br /&gt;   2:         22677        1816952  &amp;lt;methodKlass&amp;gt;&lt;br /&gt;   3:         35089        1492992  &amp;lt;symbolKlass&amp;gt;&lt;br /&gt;   4:          2860        1389352  &amp;lt;instanceKlassKlass&amp;gt;&lt;br /&gt;   5:          2860        1193536  &amp;lt;constantPoolKlass&amp;gt;&lt;br /&gt;   6:          2798         739264  &amp;lt;constantPoolCacheKlass&amp;gt;&lt;br /&gt;   7:          5863         465456  [B&lt;br /&gt;   8:          5401         298208  [C&lt;br /&gt;   9:          3042         292032  java.lang.Class&lt;br /&gt;  10:          4037         261712  [S&lt;br /&gt;&lt;b&gt;  11:         10000         240000  ruby.Foo&lt;/b&gt;&lt;br /&gt;  12:          3994         179928  [[I&lt;br /&gt;  13:          5476         131424  java.lang.String&lt;br /&gt;  14:          1661          95912  [I&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A-ha! There's our Foo instances! The "reify classes" option generates a JVM class of the same name as the Ruby class, prefixed by "ruby." to separate it from other JVM classes. Now we can start to see the real power of the tools, and we're just at the beginning. Let's see what a simple Rails application looks like.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jmap -histo:live 52926 | grep " ruby."&lt;br /&gt;  29:         11685         280440  ruby.TZInfo.TimezoneTransitionInfo&lt;br /&gt;  97:           970          23280  ruby.Gem.Version&lt;br /&gt;  98:           914          21936  ruby.Gem.Requirement&lt;br /&gt; 122:           592          14208  ruby.TZInfo.TimezoneOffsetInfo&lt;br /&gt; 138:           382           9168  ruby.Gem.Dependency&lt;br /&gt; 159:           265           6360  ruby.Gem.Specification&lt;br /&gt; 201:           142           3408  ruby.ActiveSupport.TimeZone&lt;br /&gt; 205:           118           2832  ruby.TZInfo.DataTimezoneInfo&lt;br /&gt; 206:           118           2832  ruby.TZInfo.DataTimezone&lt;br /&gt; 273:            41            984  ruby.Gem.Platform&lt;br /&gt; 383:            14            336  ruby.Mime.Type&lt;br /&gt; 403:            13            312  ruby.Set&lt;br /&gt; 467:             8            192  ruby.ActionController.MiddlewareStack.Middleware&lt;br /&gt; 476:             8            192  ruby.ActionView.Template&lt;br /&gt; 487:             7            168  ruby.ActionController.Routing.DividerSegment&lt;br /&gt; 508:             6            144  ruby.TZInfo.LinkedTimezoneInfo&lt;br /&gt; 523:             6            144  ruby.TZInfo.LinkedTimezone&lt;br /&gt; 810:             4             96  ruby.ActionController.Routing.DynamicSegment&lt;br /&gt;2291:             2             48  ruby.ActionController.Routing.Route&lt;br /&gt;2292:             2             48  ruby.I18n.Config&lt;br /&gt;2293:             2             48  ruby.ActiveSupport.Deprecation.DeprecatedConstantProxy&lt;br /&gt;2298:             2             48  ruby.ActionController.Routing.ControllerSegment&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This time I've opted to grep out just the "ruby." items in the histogram, and the results are pretty impressive! We can see the baffling fact that there's 970 instance of Gem::Version, using at least 23280 bytes of memory. We can see the even more depressing fact that there's 11685 &lt;span style="font-weight:bold;"&gt;live&lt;/span&gt; instances of TZInfo::TimezoneTransitionInfo, using at least 280440 bytes.&lt;br /&gt;&lt;br /&gt;Now that we're getting useful data, let's look at the first of our tools in more detail: jmap and jhat.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;jmap and jhat&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As you might guess, I do a lot of profiling in the process of developing JRuby. I've used probably a dozen different tools at different times. But the first tool I always reach for is the jmap/jhat combination.&lt;br /&gt;&lt;br /&gt;You've seen the simple case of using jmap above, generating a histogram of the live heap. Let's take a look at an offline heap dump.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jmap -dump:live,format=b,file=heap.bin 52926&lt;br /&gt;Dumping heap to /Users/headius/projects/jruby/heap.bin ...&lt;br /&gt;Heap dump file created&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's how easy it is! The binary dump in heap.bin is supported by several tools: jhat (obviously), VisualVM, the Eclipse Memory Analysis Tool, and others. It's not officially a "standard" format, but it hasn't changed in a long time. Let's have a look at jhat options.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jhat&lt;br /&gt;ERROR: No arguments supplied&lt;br /&gt;Usage:  jhat [-stack &amp;lt;bool&amp;gt;] [-refs &amp;lt;bool&amp;gt;] [-port &amp;lt;port&amp;gt;] [-baseline &amp;lt;file&amp;gt;] [-debug &amp;lt;int&amp;gt;] [-version] [-h|-help] &amp;lt;file&amp;gt;&lt;br /&gt;&lt;br /&gt; -J&amp;lt;flag&amp;gt;          Pass &amp;lt;flag&amp;gt; directly to the runtime system. For&lt;br /&gt;     example, -J-mx512m to use a maximum heap size of 512MB&lt;br /&gt; -stack false:     Turn off tracking object allocation call stack.&lt;br /&gt; -refs false:      Turn off tracking of references to objects&lt;br /&gt; -port &amp;lt;port&amp;gt;:     Set the port for the HTTP server.  Defaults to 7000&lt;br /&gt; -exclude &amp;lt;file&amp;gt;:  Specify a file that lists data members that should&lt;br /&gt;     be excluded from the reachableFrom query.&lt;br /&gt; -baseline &amp;lt;file&amp;gt;: Specify a baseline object dump.  Objects in&lt;br /&gt;     both heap dumps with the same ID and same class will&lt;br /&gt;     be marked as not being "new".&lt;br /&gt; -debug &amp;lt;int&amp;gt;:     Set debug level.&lt;br /&gt;       0:  No debug output&lt;br /&gt;       1:  Debug hprof file parsing&lt;br /&gt;       2:  Debug hprof file parsing, no server&lt;br /&gt; -version          Report version number&lt;br /&gt; -h|-help          Print this help and exit&lt;br /&gt; &amp;lt;file&amp;gt;            The file to read&lt;br /&gt;&lt;br /&gt;For a dump file that contains multiple heap dumps,&lt;br /&gt;you may specify which dump in the file&lt;br /&gt;by appending "#&amp;lt;number&amp;gt;" to the file name, i.e. "foo.hprof#3".&lt;br /&gt;&lt;br /&gt;All boolean options default to "true"&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Generally you can just point jhat at a heap dump and away it goes. Occasionally if the heap is large, you may need to use the -J option to increase the maximum heap size of the JVM jhat runs in. Since we're running a Rails app, we'll bump the heap up a little bit.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jhat -J-Xmx200M heap.bin&lt;br /&gt;Reading from heap.bin...&lt;br /&gt;Dump file created Fri Jul 09 02:07:46 CDT 2010&lt;br /&gt;Snapshot read, resolving...&lt;br /&gt;Resolving 604115 objects...&lt;br /&gt;[much verbose logging elided for brevity]&lt;br /&gt;&lt;br /&gt;Chasing references, expect 120 dots........................................................................................................................&lt;br /&gt;Eliminating duplicate references........................................................................................................................&lt;br /&gt;Snapshot resolved.&lt;br /&gt;Started HTTP server on port 7000&lt;br /&gt;Server is ready.&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;"Server is ready"? Damn you Java people! Does everything have to be a server with you?&lt;br /&gt;&lt;br /&gt;In this case, it's actually an incredibly useful tool. jhat starts up a small web application on port 7000 that allows you to click through the dump file. Let's see what that looks like.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HWobMsJuRHc/TDbM3T7q-lI/AAAAAAAAADg/RZpaIJpL86k/s1600/Screen+shot+2010-07-09+at+2.15.35+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 335px;" src="http://4.bp.blogspot.com/_HWobMsJuRHc/TDbM3T7q-lI/AAAAAAAAADg/RZpaIJpL86k/s400/Screen+shot+2010-07-09+at+2.15.35+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491802046240324178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here's the front page of the tool. We see a listing of all JVM classes in the system. If you scroll to the bottom, there's a few more general functions.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HWobMsJuRHc/TDbNTB2gDTI/AAAAAAAAADo/LLJAmpUJiIM/s1600/Screen+shot+2010-07-09+at+2.18.13+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 177px;" src="http://1.bp.blogspot.com/_HWobMsJuRHc/TDbNTB2gDTI/AAAAAAAAADo/LLJAmpUJiIM/s400/Screen+shot+2010-07-09+at+2.18.13+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491802522423135538" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Let's go with what we know and view the heap histogram again.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HWobMsJuRHc/TDbNz_OCMFI/AAAAAAAAADw/hqej4bZxrzA/s1600/Screen+shot+2010-07-09+at+2.20.09+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 269px;" src="http://2.bp.blogspot.com/_HWobMsJuRHc/TDbNz_OCMFI/AAAAAAAAADw/hqej4bZxrzA/s400/Screen+shot+2010-07-09+at+2.20.09+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491803088652218450" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here we can see that there's lots of objects taking up memory, and they're a mix of JVM-native types, JRuby implementation classes, and actual Ruby classes. In fact, here we can see our friend TZInfo::TimezoneTransitionInfo again. Let's click through.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HWobMsJuRHc/TDbOgzZ653I/AAAAAAAAAD4/DUpJF2xtB3Q/s1600/Screen+shot+2010-07-09+at+2.23.16+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 328px; height: 400px;" src="http://2.bp.blogspot.com/_HWobMsJuRHc/TDbOgzZ653I/AAAAAAAAAD4/DUpJF2xtB3Q/s400/Screen+shot+2010-07-09+at+2.23.16+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491803858574960498" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Pretty mundane stuff so far; basically just information about the class itself. But you see at the bottom of this screenshot that we can go from here to viewing all instances of TimezoneTransitionInfo. Let's try that.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbO_ofMtbI/AAAAAAAAAEA/D0lMZsk1EgQ/s1600/Screen+shot+2010-07-09+at+2.25.20+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 380px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbO_ofMtbI/AAAAAAAAAEA/D0lMZsk1EgQ/s400/Screen+shot+2010-07-09+at+2.25.20+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491804388220253618" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ahh, that's more like it! Now we can see that there's a heck of a lot of these things floating around. Let's investigate a bit more and click through the first instance.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HWobMsJuRHc/TDbPW_EcOlI/AAAAAAAAAEI/MujaHdUTDrI/s1600/Screen+shot+2010-07-09+at+2.26.53+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 380px;" src="http://4.bp.blogspot.com/_HWobMsJuRHc/TDbPW_EcOlI/AAAAAAAAAEI/MujaHdUTDrI/s400/Screen+shot+2010-07-09+at+2.26.53+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491804789419031122" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now this is some cool stuff!&lt;br /&gt;&lt;br /&gt;We can see that the JVM class generated for TimezoneTransitionInfo has three fields: metaClass, which points at the Ruby Class object; varTable, which is an array of Object references used for instance variables and other "internal" variables; and a flags field containing runtime flags for the object, like whether it's frozen, tainted, and so on. We can see that this object has no special flags set, and we can dig deeper into those fields if we like. We'll skip that today.&lt;br /&gt;&lt;br /&gt;Moving further down, we see a few more amazing links. First, there's a list of all references to this object. Ahh, now we can start to investigate why they're staying in memory, even though we're not using them. We can even have jhat show us the full chains of references keeping these objects alive; a series of objects leading all the way back to one "rooted" by a thread or by global JVM state. And we can explore the other direction as well, walking all objects reachable from this one.&lt;br /&gt;&lt;br /&gt;This is only a small part of what you can do with jmap and jhat, and they're so simple to use it feels almost criminal. But what if we want to inspect an application while it's running? Dumping heaps and analyzing them offline can tell you much of the story, but sometimes you just want to see the objects coming and going yourself. Let's move on to VisualVM.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;VisualVM&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;VisualVM spawned out of the NetBeans profiling tools. One of the biggest complaints about the JVMs of old were that all the built-in tooling seemed to be designed for JVM engineers alone. Because Sun had the foresight to build and own their own IDE and related modules, it eventually became a natural fit to pull out the profiling tools for use by everyone. And so VisualVM was born.&lt;br /&gt;&lt;br /&gt;On most systems with Java 6 installed, you should have a "jvisualvm" command. Let's run it now.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbRjfKhrtI/AAAAAAAAAEQ/_vOOoMds6ec/s1600/Screen+shot+2010-07-09+at+2.36.21+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 263px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbRjfKhrtI/AAAAAAAAAEQ/_vOOoMds6ec/s400/Screen+shot+2010-07-09+at+2.36.21+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491807203216174802" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;When you start up VisualVM, you're presented with a list of running JVMs, similar to using the 'jps' command. You can also connect to remote machines, browse offline heap and core dump files, and look through memory and CPU profiling snapshots from previous runs. Today, we'll just open up our running Rails app and see what we can see.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HWobMsJuRHc/TDbSJZbUp9I/AAAAAAAAAEY/mGwMpr2mMrA/s1600/Screen+shot+2010-07-09+at+2.38.59+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 229px;" src="http://2.bp.blogspot.com/_HWobMsJuRHc/TDbSJZbUp9I/AAAAAAAAAEY/mGwMpr2mMrA/s400/Screen+shot+2010-07-09+at+2.38.59+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491807854511040466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;VisualVM connects to the running process and brings up a basic information pane with process information, JVM information, and so on. We're interested in monitoring heap usage, so let's move to the "Monitor" tab.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbSmuGkczI/AAAAAAAAAEg/jQ6lizETlk4/s1600/Screen+shot+2010-07-09+at+2.40.55+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 227px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbSmuGkczI/AAAAAAAAAEg/jQ6lizETlk4/s400/Screen+shot+2010-07-09+at+2.40.55+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491808358277346098" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Already we're getting some useful information. This view shows CPU usage (currently zero, since it's an idle Rails app), Heap usage over time, and the number of JVM classes and threads that are active. We can trigger a full GC, if we'd like to tidy things up before we start poking around. But most importantly, we can do the jmap/jhat dance in one step, by clicking the Heap Dump button. Tantalizing, isn't it?&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbTPcZVqoI/AAAAAAAAAEo/w4Bt_TiP7-U/s1600/Screen+shot+2010-07-09+at+2.43.36+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 228px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbTPcZVqoI/AAAAAAAAAEo/w4Bt_TiP7-U/s400/Screen+shot+2010-07-09+at+2.43.36+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491809057898867330" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Initially, we see a basic summary of the heap: total size, number of classes and GC roots, and so on. We're looking for our friend TimezoneTransitionInfo, so let's look for it in the "Classes" pane.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HWobMsJuRHc/TDbUOd8sliI/AAAAAAAAAE4/peOO8-U1SVw/s1600/Screen+shot+2010-07-09+at+2.47.52+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 196px;" src="http://2.bp.blogspot.com/_HWobMsJuRHc/TDbUOd8sliI/AAAAAAAAAE4/peOO8-U1SVw/s400/Screen+shot+2010-07-09+at+2.47.52+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491810140647364130" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ahh, there it is, just a little ways down the list. The counts are as we expect, so let's double-click and dig a bit deeper.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HWobMsJuRHc/TDbUcM5s1vI/AAAAAAAAAFA/HMDT88mRIBs/s1600/Screen+shot+2010-07-09+at+2.48.41+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 176px;" src="http://1.bp.blogspot.com/_HWobMsJuRHc/TDbUcM5s1vI/AAAAAAAAAFA/HMDT88mRIBs/s400/Screen+shot+2010-07-09+at+2.48.41+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491810376589563634" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here we have a lot of the same information about object instances that we did with jhat, but presented in a much richer format. Almost everything is active; you can jump around the heap and do analysis that would take a lot of manual work very easily. Let's try another tool: the Retained Size calculator.&lt;br /&gt;&lt;br /&gt;Because our JVM tools see all objects equally, the reported size for a Ruby object on the heap is only part of the story. There's also the variable table, the object's instance variables, and objects they reference to consider. Let's jump to a different object now, Gem::Version.&lt;br /&gt;&lt;br /&gt;We don't want to have to scroll through the list of classes to find ruby.Gem.Version, so let's make use of the Object Query Language console. With the OQL console, you can write SQL-like queries to retrieve listings of objects in the heap. We'll search for all instances of ruby.Gem.Version.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbVuq380RI/AAAAAAAAAFI/aXCwt3BRsWU/s1600/Screen+shot+2010-07-09+at+2.53.44+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 261px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbVuq380RI/AAAAAAAAAFI/aXCwt3BRsWU/s400/Screen+shot+2010-07-09+at+2.53.44+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491811793384558866" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The query runs and we get a listing of Gem::Version objects. Let's dig deeper and see how much retained memory each Version object is keeping alive.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbWHvnwVEI/AAAAAAAAAFQ/q4X3F07ZvTc/s1600/Screen+shot+2010-07-09+at+2.55.53+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 162px;" src="http://3.bp.blogspot.com/_HWobMsJuRHc/TDbWHvnwVEI/AAAAAAAAAFQ/q4X3F07ZvTc/s400/Screen+shot+2010-07-09+at+2.55.53+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491812224155538498" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Clicking on the "Compute Retained Sizes" link in the "Instances" pane prompts us with this dialog. We're tough...we can take it.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HWobMsJuRHc/TDbWaK5bGOI/AAAAAAAAAFY/AnidY4PVb9M/s1600/Screen+shot+2010-07-09+at+2.57.08+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 348px; height: 106px;" src="http://4.bp.blogspot.com/_HWobMsJuRHc/TDbWaK5bGOI/AAAAAAAAAFY/AnidY4PVb9M/s400/Screen+shot+2010-07-09+at+2.57.08+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491812540715047138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Reticulating splines...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HWobMsJuRHc/TDcBUC7ML_I/AAAAAAAAAFo/MYGEKCqzU2U/s1600/Screen+shot+2010-07-09+at+2.59.20+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 190px;" src="http://2.bp.blogspot.com/_HWobMsJuRHc/TDcBUC7ML_I/AAAAAAAAAFo/MYGEKCqzU2U/s400/Screen+shot+2010-07-09+at+2.59.20+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491859714495754226" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So it looks like each of the Version objects take from 125 to 190 bytes for a total of 19400 bytes, most of which is from the variable table. What's in there?&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HWobMsJuRHc/TDbXNQMb4nI/AAAAAAAAAFg/yWfkrni0snI/s1600/Screen+shot+2010-07-09+at+3.00.31+AM.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 77px;" src="http://1.bp.blogspot.com/_HWobMsJuRHc/TDbXNQMb4nI/AAAAAAAAAFg/yWfkrni0snI/s400/Screen+shot+2010-07-09+at+3.00.31+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491813418310296178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ahh...looks like there's a String and an Array. And of course we can poke around the heap ad infinatum, into and out of "native" JRuby and JVM classes, and truly get a complete picture of what our running applications look like. Now you're playing with power.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Your Turn&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is obviously only the tip of the iceberg. Tools like Eclipse Memory Analysis Tool include features for detecting leaks; VisualVM and NetBeans both allow you to turn on allocation tracing, to show &lt;span style="font-weight:bold;"&gt;where&lt;/span&gt; in your code all those objects are being created. There's tools for monitoring live GC behavior, and many of these tools even allow you to dig into a running heap and &lt;span style="font-weight:bold;"&gt;modify live objects&lt;/span&gt;. If you can dream it, there's a tool that can do it. And you get all that for free by using JRuby.&lt;br /&gt;&lt;br /&gt;If you'd like to play with this, it all works with JRuby 1.5.1 but you won't get the nice JVM classes for Ruby classes. For that, you can pull and build JRuby master, download a 1.6.0.dev snapshot, or just wait for JRuby 1.6. And if you do play with these or other tools, I hope you'll let us know and blog about your experience!&lt;br /&gt;&lt;br /&gt;In the future, I'll try to show some of the other tools plus some of the CPU profiling capabilities they bring to the table. For now, rest assured that if you're using JRuby, you really do have the best tools available to you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-1965835751183434626?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/1965835751183434626/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=1965835751183434626' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1965835751183434626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1965835751183434626'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/07/browsing-memory-jruby-way.html' title='Browsing Memory the JRuby Way'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_HWobMsJuRHc/TDbM3T7q-lI/AAAAAAAAADg/RZpaIJpL86k/s72-c/Screen+shot+2010-07-09+at+2.15.35+AM.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-2699943310069285113</id><published>2010-06-16T17:44:00.002-05:00</published><updated>2010-06-16T21:25:09.149-05:00</updated><title type='text'>My Short List of Key Missing JVM Features</title><content type='html'>I mused today on Twitter that there's just a few small things that the JVM/JDK need to become a truly awesome platform for all sorts of development. Since so many people asked for more details, I'm posting a quick list here. There's obviously other things, but these are the ones on my mind today.&lt;div&gt;&lt;br /&gt;&lt;div&gt;&lt;b&gt;Cold Performance&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;Current JVMs start up pretty fast, and there's changes coming in Hotspot in Java 7 that will make them even better. Usually this comes from combinations of pre-verifying bytecode (or providing verification hints), sharing class data across processes, and run-of-the-mill tweaks to make the loading and linking processes more efficient. But for many apps, this doesn't do anything to solve the biggest startup hit of all: cold execution performance. Because the JVM doesn't save off the jitted products of each run, it must start "cold" every time, running everything in the bytecode interpreter until it gets hot enough to compile. Even on JVMs that don't have an interpreter, the initial cost of compiling everything to not-particularly-optimized assembly also causes a major startup hit (try running command-line stuff on JRockit or J9).&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's a few things people have suggested, and they're all hard:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Tiered compilation - compile earlier using the fastest-possible, least-optimizing compiler, but decorate the compiled code with appropriate profiling logic to do a better job later. Hotspot in Java 7 may ship a tiered compiler, but there have been some resource setbacks that delayed its development.&lt;/li&gt;&lt;li&gt;Save off compilation or optimization artifacts - this is theoretically possible, but the deeper you go the harder it is to save it. Usually the in-memory results of optimization and compilation depend on the layout of things...in memory. Saving them to disk means you need to scrub out anything that might be different in a new process like memory addresses and class identities. But .NET can do this, though it largely *just* does static compilation. Happy medium?&lt;/li&gt;&lt;li&gt;Keep a JVM process running and toss it new work. We do this in JRuby with the Nailgun library, but it has some problems. First off, it can leave various aspects of the JVM in a dirty state, like system properties and memory footprint. Second, it can't kill off rogue threads that don't terminate, so they can collect over time. And third...it's not actually running at the console, so a lot of console things you'd do normally don't work.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;This is probably the biggest unsolvable problem for JRuby right now, and the one we most often have to apologize for. JRuby is fast...at times, very fast...and getting faster every day. But not during the first 5 seconds, and so everyone gets the same bad impression.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Better Console/Terminal Support&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;There's endless blogs out there complaining about how the standard IO streams you get from the JVM are crippled in various ways. You can't select on them, for example, which is the source of a few unfixable bugs in JRuby. You can't pass them along to subprocesses, which is perhaps more a failing of the process-launching APIs in the JDK than standard IO itself. There's no direct terminal support in any of Java's APIs, so people end up yanking in libraries like jline just to support line editing. If the JDK shipped with some nice terminal and process APIs, a lot of the hassles developers have writing command-line tools in Java would melt away.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's some light at the end of the tunnel. NIO2, scheduled to be part of Java 7, will bring better process launching APIs (with inherited standard IO streams, if you desire), a broader range of selectable channels, and much more. Hopefully it will be enough.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Fix the Busted APIs&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;JDBC is broken. Why? Because you have to register your driver in a global hard-referencing hash, and have to unregister it from the same classloader or it will leak. That means that if you're loading JDBC drivers from within a webapp or EE application, *your entire application remains in memory* because the driver references it and that map references the driver. This is the primary reason why most Java web application servers leak memory on undeploy, and it's another "unfixable" from JRuby's perspective.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Object serialization is broken. Why? Because it plays all sorts of tricks to get your classloader, reflectively access fields (if you're going to reflectively access them anyway, why not just break encapsulation if security allows it), and construct object instances without allowing you the opportunity to initialize them appropriately yourself. You have to provide no-arg constructors, have to un-final fields so they can be set up outside of construction, and heaven forbid you use default serialization: it's dead slow.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Reflection is too slow and there's no way around it. Not only do you end up calling through many extra levels of logic for reflective invocation, you have to box your argument lists, box your numerics, and wrap everything in exception-handling. And it doesn't have to be this way. The invokedynamic work brings along with it method handles, which are fast, direct pointers to methods. This should have been added long ago, but thankfully it's on the way in Java 7. Until then, projects like JRuby will have to continue eating the cost of reflection...or generate method handles by hand. We do both.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Regular expressions are broken. Why? Because simple alternations can blow the Java stack when fed especially large input. The current Sun-created regex implementation recurses for things like alternation, making it easy for it to fail to match on large input. The problem is so bad that we've actually switched regular expression engines in JRuby *four times*, including two implementations we wrote ourselves. Nobody can say we haven't bled for our users.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And there's numerous other examples. Some are relics of Java 1.0 that never got corrected (because old APIs don't die, they just get deprecated...or ignored). Some are relics of the idea that gigantic monolithic servers hosting dozens of apps (and leaking memory when they undeploy, or else contending for basic resources that separate processes would not) are a good idea, when in actuality running multiple JVMs that each only host one or a few apps works far better. Making a real effort to smooth these bad APIs would go a long way.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Better Support for Native Libraries and POSIX Features&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;As of Java 6, there's still no support for working with symlinks and only limited support for setting file permissions. Process launching is absolutely terrible. You can't select on all channels...only on sockets. If you want to use a native library, you have to write JNI code to do it, even though there are libraries like JNA and JFFI in the wild that do an outstanding job of dynamically loading and binding those libraries.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Missing the POSIXy features is basically inexcusable today. Most of the system-level APIs in the JDK are still based on a lowest common denominator somewhere near Windows 95, even though all modern operating systems provide at least a substantial subset of those APIs. NIO2 will bring many improvements, but it's almost certain that some parts of POSIX won't be exposed, either because there's not enough resources to spec out the Java APIs for them or because they end up being too system-specific.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As for loading native libraries...this is again something that should have been rolled into the JDK a long time ago. Many people will cry foul..."pure Java!" they'll shout...and I agree. But there are times when some functionality simply doesn't exist in a Java library, or doesn't scale well as an out-of-process call. For these times, you just have to use the native library...and the barrier to entry for doing that on the Java platform is just too high. Rolle JNA or JFFI or something similar into the JDK, so we grown-ups can choose when we want to use native code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;The Punchline&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;The punchline is that for most of these things, we've solved or worked around them in JRuby...at *great expense*. I'd go so far as to say we've done more to work around the JVM and the JDK's lackings than any other project. We've gone out of our way to improve startup by any means possible. We ship beautiful, solidly-performing libraries for binding native libs without writing a line of C code. We generate a large amount of code at compile and runtime to avoid using reflection as much. We maintain and ship native POSIX layers for a dozen platforms. We've (i.e. one of our champions, Marcin Mielzynski) implemented our own regular expression engine (i.e. a port of Oniguruma). We've pulled every trick in the book to get process launching to work nicely and behave like Ruby users expect. And so on and so forth.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But it's not sustainable. We can't continue to patch around the JVM and JDK forever, even if we've done a great job so far. Hopefully this will serve as a wake-up call for JVM and JDK implementers around the world: If you don't want the Java platform to be a server-only, large-app-only, long-running-only, headless-only world...it's time to fix these things. I'm standing by to help coordinate those efforts :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-2699943310069285113?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/2699943310069285113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=2699943310069285113' title='28 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2699943310069285113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2699943310069285113'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/06/my-short-list-of-key-missing-jvm.html' title='My Short List of Key Missing JVM Features'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>28</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-9111349159893231512</id><published>2010-06-01T18:09:00.003-05:00</published><updated>2010-06-01T18:45:25.116-05:00</updated><title type='text'>Restful Services in Ruby using JRuby and Jersey</title><content type='html'>There's lots of ways to present RESTful web services these days, and REST has obviously become the new "it's IPC no it's not" hotness. And of course Rubyists have been helping to lead the way, building restfulness into just about everything they write. Rails itself is built around REST, with most controllers doubling as RESTful interfaces, and it even provides extra tools to help you transparently make RESTful calls from your application. If you're doing RESTful services for a typical Ruby application, Rails is the way to go (and even if you're not using Ruby in general...you should be considering JRuby + Rails).&lt;br /&gt;&lt;br /&gt;In the Java world the options aren't quite as clear, but one API has at least attempted to standardize the idea of doing RESTful services on the Java platform: JSR-311, otherwise known as JAX-RS.&lt;br /&gt;&lt;br /&gt;JAX-RS in theory makes it easy for you to simply mark up a piece of Java code with annotations and have it automatically be presented as a RESTful service. Of the available options, it may be the simplest, quickest way to get a Java-based service published and running.&lt;br /&gt;&lt;br /&gt;So I figured I'd try to use it from JRuby, and when doing it in Ruby it's actually surprisingly clean, even compared to Ruby options.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Service&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I followed the Jersey &lt;a href="https://jersey.dev.java.net/source/browse/*checkout*/jersey/tags/jersey-1.0.3/jersey/getting-started.html"&gt;Getting Started&lt;/a&gt; tutorial using Ruby for everything (and not using Maven in this case).&lt;br /&gt;&lt;br /&gt;My version of their HelloWorldResource looks like this in Ruby:&lt;br /&gt;&lt;pre&gt;require 'java'java_import 'javax.ws.rs.Path'&lt;br /&gt;java_import 'javax.ws.rs.GET'&lt;br /&gt;java_import 'javax.ws.rs.Produces'&lt;br /&gt;&lt;br /&gt;java_package 'com.headius.demo.jersey'&lt;br /&gt;java_annotation 'Path("/helloworld")'&lt;br /&gt;class HelloWorld&lt;br /&gt;java_annotation 'GET'&lt;br /&gt;java_annotation 'Produces("text/plain")'&lt;br /&gt;def cliched_message&lt;br /&gt; "Hello World"&lt;br /&gt;end&lt;br /&gt;end&lt;/pre&gt;Notice that we're using the new features in JRuby 1.5 for producing "real" Java classes: java_package to specify a target package for the Java class, java_annotation to specify class and method annotations.&lt;br /&gt;&lt;br /&gt;We compile it using jrubyc from JRuby 1.5 like this:&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jrubyc -c ../jersey-archive-1.2/lib/jsr311-api-1.1.1.jar --javac restful_service.rb&lt;br /&gt;Generating Java class HelloWorld to /Users/headius/projects/jruby/com/headius/demo/jersey/HelloWorld.java&lt;br /&gt;javac  -d /Users/headius/projects/jruby -cp /Users/headius/projects/jruby/lib/jruby.jar:../jersey-archive-1.2/lib/jsr311-api-1.1.1.jar /Users/headius/projects/jruby/com/headius/demo/jersey/HelloWorld.java&lt;/pre&gt;The new --java(c) flags in jrubyc examine your source for any classes, spitting out .java source for each one in turn. Along the way, if you have marked it up with signatures, annotations, imports, and so on, it will emit those into the Java source as well. If you specify --javac (as opposed to --java), it will also compile the resulting sources for you with jruby and your user-specified jars in the classpath, as I've done here.&lt;br /&gt;&lt;br /&gt;The result looks like this to Java:&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ javap com.headius.demo.jersey.HelloWorld&lt;br /&gt;Compiled from "HelloWorld.java"&lt;br /&gt;public class com.headius.demo.jersey.HelloWorld extends org.jruby.RubyObject{&lt;br /&gt; public static org.jruby.runtime.builtin.IRubyObject __allocate__(org.jruby.Ruby, org.jruby.RubyClass);&lt;br /&gt; public com.headius.demo.jersey.HelloWorld();&lt;br /&gt; public java.lang.Object cliched_message();&lt;br /&gt; static {};&lt;br /&gt;}&lt;/pre&gt;Under the covers, this class will load in the source of our restful_service.rb file and wire up all the Ruby and Java pieces so that both sides see HelloWorld as the in-memory representation of the Ruby HelloWorld class. Method calls are dispatched to the Ruby code, constructors dispatch to initialize, and so on. It's truly living in both worlds.&lt;br /&gt;&lt;br /&gt;With the service in hand, we now need a server script to start it up.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Server Script&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Continuing with the tutorial, I've taken their simple Java-based server script and ported it directly to Ruby:&lt;br /&gt;&lt;pre&gt;require 'java'&lt;br /&gt;java_import com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory&lt;br /&gt;&lt;br /&gt;base_uri = "http://localhost:9998/"&lt;br /&gt;init_params = {&lt;br /&gt;"com.sun.jersey.config.property.packages" =&gt; "com.headius.demo.jersey"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;puts "Starting grizzly"&lt;br /&gt;thread_selector = GrizzlyWebContainerFactory.create(&lt;br /&gt; base_uri, init_params.to_java)&lt;br /&gt;&lt;br /&gt;puts &amp;lt;&amp;lt;EOS&lt;br /&gt;Jersey app started with WADL available at #{base_uri}application.wadl&lt;br /&gt;Try out #{base_uri}helloworld&lt;br /&gt;Hit enter to stop it...&lt;br /&gt;EOS&lt;br /&gt;&lt;br /&gt;gets&lt;br /&gt;&lt;br /&gt;thread_selector.stop_endpoint&lt;br /&gt;&lt;br /&gt;exit(0)&lt;/pre&gt;It's somewhat cleaner and shorter, but it wasn't particularly large to begin with. At any rate, it shows how simple it is to launch a Grizzly server and how nice annotation-based APIs can be for auto-configuring our JAX-RS service.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The CLASSPATH&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ahh CLASSPATH. You are so maligned when all you hope to do is make it explicit where libraries are coming from. The world should learn from your successes and your failures.&lt;br /&gt;&lt;br /&gt;There's five jars required for this Jersey example to run. I've tossed them into my CLASSPATH env var, but you're free to do it however you like&lt;br /&gt;&lt;pre&gt;jersey-core-1.2.jar&lt;br /&gt;jersey-server-1.2.jar&lt;br /&gt;jsr311-api-1.1.1.jar&lt;br /&gt;asm-3.1.jar&lt;br /&gt;grizzly-servlet-webserver-1.9.9.jar&lt;/pre&gt;The first four are available in the &lt;a href="http://download.java.net/maven/2/com/sun/jersey/jersey-archive/1.2/jersey-archive-1.2.zip"&gt;jersey-archive download&lt;/a&gt;, and you can fetch the &lt;a href="http://download.java.net/maven/2/com/sun/grizzly/grizzly-servlet-webserver/1.9.9/"&gt;Grizzly jar from Maven&lt;/a&gt; or other places.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Testing It Out&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The lovely bit about this is that it's essentially a four-step process to do the entire thing: write and compile the service, write the server script, set up CLASSPATH, and run the server. Here's the server output, finding my HelloWorld service right where it should:&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jruby main.rb&lt;br /&gt;Starting grizzly&lt;br /&gt;Jersey app started with WADL available at http://localhost:9998/application.wadl&lt;br /&gt;Try out http://localhost:9998/helloworld&lt;br /&gt;Hit enter to stop it...&lt;br /&gt;Jun 1, 2010 6:36:55 PM com.sun.jersey.api.core.PackagesResourceConfig init&lt;br /&gt;INFO: Scanning for root resource and provider classes in the packages:&lt;br /&gt;com.headius.demo.jersey&lt;br /&gt;Jun 1, 2010 6:36:55 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses&lt;br /&gt;INFO: Root resource classes found:&lt;br /&gt;class com.headius.demo.jersey.HelloWorld&lt;br /&gt;Jun 1, 2010 6:36:55 PM com.sun.jersey.api.core.ScanningResourceConfig init&lt;br /&gt;INFO: No provider classes found.&lt;br /&gt;Jun 1, 2010 6:36:55 PM com.sun.jersey.server.impl.application.WebApplicationImpl initiate&lt;br /&gt;INFO: Initiating Jersey application, version 'Jersey: 1.2 05/07/2010 02:04 PM'&lt;/pre&gt;And perhaps the most anti-climactic climax ever, curling our newly-deployed service:&lt;br /&gt;&lt;pre&gt;~ ➔ curl http://localhost:9998/helloworld&lt;br /&gt;Hello World&lt;/pre&gt;It works!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What We've Learned&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This was a simple example, but we demonstrated several things:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;JRuby's new jrubyc --java(c) support for generating "real" Java classes&lt;/li&gt;&lt;li&gt;Tagging a Ruby class with Java annotations, so it can be seen by a Java framework&lt;/li&gt;&lt;li&gt;Booting a Grizzly server from Ruby code&lt;/li&gt;&lt;li&gt;Implementing a JAX-RS service with Jersey in Ruby code&lt;/li&gt;&lt;/ul&gt;Do you have any examples of other nice annotation-based APIs we could test out with JRuby?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-9111349159893231512?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/9111349159893231512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=9111349159893231512' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/9111349159893231512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/9111349159893231512'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/06/restful-services-in-ruby-using-jruby.html' title='Restful Services in Ruby using JRuby and Jersey'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-301015234022701224</id><published>2010-05-31T01:15:00.004-05:00</published><updated>2010-05-31T03:29:56.106-05:00</updated><title type='text'>Kicking JRuby Performance Up a Notch</title><content type='html'>We've often talked about the benefit of running on the JVM, and while our performance numbers have been *good*, they've never been as incredibly awesome as a lot of people expected. After all, regardless of how well we performed when compared to other Ruby implementations, we weren't as fast as statically-typed JVM languages.&lt;br /&gt;&lt;br /&gt;It's time for that to change.&lt;br /&gt;&lt;br /&gt;I've started playing with performing more optimizations based on runtime information in JRuby. You may know that JRuby has always had a JIT (just-in-time compiler), which lazily compiled Ruby AST into JVM bytecode. What you may not know is that unlike most other JIT-based systems, we did not gather any information at runtime that might help the eventual compilation produces a better result. All we applied were the same static optimizations we could safely do for AOT compilation (ahead-of-time, like jrubyc), and ultimately the JIT mode just deferred compilation to reduce the startup cost of compiling everything before it runs.&lt;br /&gt;&lt;br /&gt;This was a pragmatic decision; the JVM itself does a lot to boost performance, even with our very naïve compiler and our limited static optimizations. Because of that, our performance has been perfectly fine for most users; we haven't even made a concentrated effort to improve execution speed for almost 18 months, since the JRuby 1.1.6 release. We've spent a lot more time handling the issues users actually wanted us to work on: better Java integration, specific Ruby incompatibilities, memory reduction (and occasional leaks), peripheral libraries like jruby-rack and activerecord-jdbc, and general system stability. When we asked users what we should focus on, performance always came up as a "nice to have" but rarely as something people had a problem with. We performed very nicely.&lt;br /&gt;&lt;br /&gt;These days, however, we're recognizing a few immutable truths:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You can never be fast enough, and if your performance doesn't steadily improve people will feel like you're moving backward.&lt;/li&gt;&lt;li&gt;People eventually *do* want Ruby code to run as fast as C or Java, and if we can make it happen we should.&lt;/li&gt;&lt;li&gt;JRuby users like to write in Ruby, obviously, so we should make an effort to allow writing more of JRuby in Ruby, which requires that we suffer no performance penalty in the process.&lt;/li&gt;&lt;li&gt;Working on performance can be a dreadful time sink, but succeeding in improving it can be a tremendous (albeit shallow) ego boost.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;So along with other work for JRuby 1.6, I'm back in the compiler.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm just starting to play with this stuff, so take all my results as highly preliminary.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;A JRuby Call Site Primer&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At each location in Ruby code where a dynamic call happens, JRuby installs what's called a &lt;i&gt;call site&lt;/i&gt;. Other VMs may simply refer to the location of the call as the "call site", but in JRuby, each call site has an implementation of &lt;a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/runtime/CallSite.java"&gt;org.jruby.runtime.CallSite&lt;/a&gt; associated with it. So given the following code:&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;def fib(a)&lt;br /&gt;  if a &amp;lt; 2&lt;br /&gt;    a&lt;br /&gt;  else&lt;br /&gt;    fib(a - 1) + fib(a - 2)&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;There are six call sites: the "&lt;" call for "a &lt; 2", the two "-" calls for "a - 1" and "a - 2", the two "fib" calls, and the "+" call for "fib(a - 1) + fib(a - 2)". The naïve approach to doing a dynamic call would be to query the object for the named method every time and then invoke it, like the dumbest possible reflection code might do. In JRuby (like most dynamic language VMs) we instead have a &lt;span style="font-style:italic;"&gt;call site cache&lt;/span&gt; at each call site to blunt that lookup cost. And in implementation terms, that means each caching CallSite is an instance of &lt;a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/runtime/callsite/CachingCallSite.java"&gt;org.jruby.runtime.callsite.CachingCallSite&lt;/a&gt;. Easy, right?&lt;br /&gt;&lt;br /&gt;The simplest way to take advantage of runtime information is to use these caching call sites as hints for what method we've been calling at a given call site. Let's take the example of "+". The "+" method here is being called against a Fixnum object every time it's encountered, since our particular run of "fib" never overflows into Bignum and never works with Float objects. In JRuby, Fixnum is implemented with &lt;a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/RubyFixnum.java"&gt;org.jruby.RubyFixnum&lt;/a&gt;, and the "+" method is bound to &lt;a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/RubyFixnum.java#L326"&gt;RubyFixnum.op_plus&lt;/a&gt;. Here's the implementation of op_plus in JRuby:&lt;br /&gt;&lt;pre&gt;    @JRubyMethod(name = "+")&lt;br /&gt;    public IRubyObject op_plus(ThreadContext context, IRubyObject other) {&lt;br /&gt;        if (other instanceof RubyFixnum) {&lt;br /&gt;            return addFixnum(context, (RubyFixnum)other);&lt;br /&gt;        }&lt;br /&gt;        return addOther(context, other);&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;The details of the actual addition in addFixnum are left as an exercise for the reader.&lt;br /&gt;&lt;br /&gt;Notice that we have an annotation on the method: @JRubyMethod(name = "+"). All the Ruby core classes implemented in JRuby are tagged with a similar annotation, where we can specify the minimum and maximum numbers of arguments, the Ruby-visible method name (e.g. "+" here, which is not a valid Java method name), and other details of how the method should be called. Notice also that the method takes two arguments: the current ThreadContext (thread-local Ruby-specific runtime structures), and the "other" argument being added.&lt;br /&gt;&lt;br /&gt;When we build JRuby, we scan the JRuby codebase for JRubyMethod annotations and generate what we call &lt;span style="font-style:italic;"&gt;invokers&lt;/span&gt;, one for every unique class+name combination in the core classes. These invokers are all instance of &lt;a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/internal/runtime/methods/DynamicMethod.java"&gt;org.jruby.internal.runtime.methods.DynamicMethod&lt;/a&gt;, and they carry various informational details about the method as well as implementing various "call" signatures. The reason we generate an invoker class per method is simple: most JVMs will not inline through code used for many different code paths, so if we only had a single invoker for all methods in the system...nothing would ever inline.&lt;br /&gt;&lt;br /&gt;So, putting it all together. At runtime, we have a &lt;a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/runtime/callsite/CachingCallSite.java"&gt;CachingCallSite&lt;/a&gt; instance for every method call in the code. The first time we call "+" for example, we go out and fetch the method object and cache it in place for future calls. That cached method object is a subclass of &lt;a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/internal/runtime/methods/DynamicMethod.java"&gt;DynamicMethod&lt;/a&gt;, which knows how to do the eventual invocation of &lt;a href="http://github.com/jruby/jruby/blob/master/src/org/jruby/RubyFixnum.java#L326"&gt;RubyFixnum.op_plus&lt;/a&gt; and return the desired result. Simple!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;First Steps Toward Runtime Optimization&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The changes I'm working on locally will finally take advantage of the fact that after running for a while, we have a darn good idea what methods are being called. And if we know what methods are being called, those invocations no longer have to be dynamic, provided our assumptions hold (assumptions being things like "we're always calling against Fixnums" or "it's always the core implementation of "+"). Put differently: because JRuby defers its eventual compilation to JVM bytecode, we can potentially &lt;span style="font-style:italic;"&gt;turn dynamic calls into static calls&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The process is actually very simple, and since I just started playing with it two days ago, I'll describe the steps I took.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step One: Turn Dynamic Into Static&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First, I needed the generated methods to bring along enough information for me to do a direct call. Specifically, I needed to know what target Java class they pointed at (RubyFixnum in our "+" example), what the Java name of the method was (op_plus), what arguments the method signature expected to receive (returning IRubyObject and receiving ThreadContext, IRubyObject), and whether the implementation was static (as are most module-based methods...but our "op_plus" is not). So I bundled this information into what I called a "NativeCall" data structure, populated on any invokers for which a native call might be possible.&lt;br /&gt;&lt;pre&gt;    public static class NativeCall {&lt;br /&gt;        private final Class nativeTarget;&lt;br /&gt;        private final String nativeName;&lt;br /&gt;        private final Class nativeReturn;&lt;br /&gt;        private final Class[] nativeSignature;&lt;br /&gt;        private final boolean statik;&lt;br /&gt;        ...&lt;/pre&gt;&lt;br /&gt;In the compiler, I added a similar bit of logic. When compiling a dynamic call, it now will look to see whether the call site has already cached some method. If so, it checks whether that method has a corresponding NativeCall data structure associated with it. If it does, then instead of emitting the dynamic call logic it would normally emit, it compiles a normal, direct JVM invocation. So where we used to have a call like this:&lt;br /&gt;&lt;pre&gt;INVOKEVIRTUAL org/jruby/runtime/CallSite.call&lt;/pre&gt;&lt;br /&gt;We now have a call like this:&lt;br /&gt;&lt;pre&gt;INVOKEVIRTUAL org/jruby/RubyFixnum.op_plus&lt;/pre&gt;&lt;br /&gt;This call to "+" is now essentially equivalent to writing the same code in Java against our RubyFixnum class.&lt;br /&gt;&lt;br /&gt;This comprises the first step: get the compiler to recognize and "make static" dynamic calls we've seen before. My experimental code is able to do this for most core class methods right now, and it will not be difficult to extend it to any call.&lt;br /&gt;&lt;br /&gt;(The astute VM implementer will notice I made no mention of inserting a guard or test before the direct call, in case we later need to actually call a different method. This is, for the moment, intentional. I'll come back to it).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step Two: Reduce Some Fixnum Use&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The second step I took was to allow some call paths to use primitive values rather than boxed RubyFixnum objects. RubyFixnum in JRuby always represents a 64-bit long value, but since our call path only supports invocation with IRubyObject, we generally have to construct a new RubyFixnum for all dynamic calls. These objects are very small and usually very short-lived, so they don't impact GC times much. But they do impact allocation rates; we still have to grab the memory space for every RubyFixnum, and so we're constantly chewing up memory bandwidth to do so.&lt;br /&gt;&lt;br /&gt;There are various ways in which VMs can eliminate or reduce object allocations like this: stack allocation, value types, true fixnums, escape analysis, and more. But of these, only escape analysis is available on current JVMs, and it's a very fragile optimization: all paths that would consume an object must be completely inlined, or else the object can't be elided.&lt;br /&gt;&lt;br /&gt;So to help reduce the burden on the JVM, we have a couple call paths that can receive a single long or double argument where it's possible for us to prove that we're passing a boxed long or double value (i.e. a RubyFixnum or RubyFloat). The second step I took was to make the compiler aware of several of these methods on RubyFixnum, such as the long version of op_plus:&lt;br /&gt;&lt;pre&gt;    public IRubyObject op_plus(ThreadContext context, long other) {&lt;br /&gt;        return addFixnum(context, other);&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;Since we have not yet implemented more advanced means of proving a given object is always a Fixnum (like doing local type propagation or per-variable type profiling at runtime), the compiler currently can only see that we're making a call with a literal value like "100" or "12.5". As luck would have it, there's three such cases in the "fib" implementation above: one for the "&lt;" call and two for the "-" calls. By combining the compiler's knowledge of &lt;span style="font-style:italic;"&gt;which&lt;/span&gt; actual method is being called in each case and &lt;span style="font-style:italic;"&gt;how&lt;/span&gt; to make a call without standing up a RubyFixnum object, our actual call in the bytecode gets simplified further:&lt;br /&gt;&lt;pre&gt;INVOKEVIRTUAL org/jruby/RubyFixnum.op_minus (Lorg/jruby/runtime/ThreadContext;J)&lt;/pre&gt;&lt;br /&gt;(For the uninitiated, that "J" at the end of the signature means this call is passing a primitive long for the second argument to op_minus.)&lt;br /&gt;&lt;br /&gt;We now have the potential to insert additional compiler smarts about how to make a call more efficiently. This is a simple case, of course, but consider the potential for another case: calling from Ruby to arbitrary Java code. Instead of encumbering that call with all our own multi-method dispatch logic *plus* the multiple layers of Java's reflection API, we can instead make the call *directly*, going straight from Ruby code to Java code with no intervening code. And with no intervening code, the JVM will be able to inline arbitrary Java code straight into Ruby code, optimize it as a whole. Are we getting excited yet?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step Three: Steal a Micro-optimization&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There's two pesky calls remaining in "fib": the recursive invocations of "fib" itself. Now the smart thing to do would be to proceed with adding logic to the compiler to be aware of calls from currently-jitting Ruby code to not-yet jitted Ruby code and handle that accordingly. For example, we might also force those methods to compile, and the methods they call to compile, and so on, allowing us to optimize from a "hot" method outward to potentially "colder" methods within some threshold distance. And of course, that's probably what we'll do; it's trivial to trigger any Ruby method in JRuby to JIT at any time, so adding this to the compiler will be a few minutes work. But since I've only been playing with this since Thursday, I figured I'd do an even smarter thing: cheat.&lt;br /&gt;&lt;br /&gt;Instead of adding the additional compiler smarts, I instead threw in a dirt-simple single-optimization subset of those smarts: detect self-recursion and optimize that case alone. In JRuby terms, this meant simply seeing that the "fib" CachingCallSite objects pointed back to the same "fib" method we were currently compiling. Instead of plumbing them through the dynamic pipeline, we make them be direct recursive calls, similar to the core method calls to "&lt;" and "-" and "+". So our fib calls turn into the following bytecode-level invocation:&lt;br /&gt;&lt;pre&gt;INVOKESTATIC ruby/jit/fib_ruby_B52DB2843EB6D56226F26C559F5510210E9E330D.__file__&lt;/pre&gt;&lt;br /&gt;Where "B52DB28..." is the SHA1 hash of the "fib" method, and __file__ is the default entry point for jitted calls.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Everything Else I'm Not Telling You&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As with any experiment, I'm bending compatibility a bit here to show how far we can move JRuby's "upper bound" on performance. So these optimizations currently include some caveats.&lt;br /&gt;&lt;br /&gt;They currently damage Ruby backtraces, since by skipping the invokers we're no longer tracking Ruby-specific backtrace information (current method, file, line, etc) in a heap-based structure. This is one area where JRuby loses some performance, since the JVM is actually double-tracking both the Java backtrace information and the Ruby backtrace information. We will need to do a bit more work toward making the Java backtrace actually show the relevant Ruby information, or else generate our Ruby backtraces by mining the Java backtrace (and the existing "--fast" flag actually does this already, matching normal Ruby traces pretty well).&lt;br /&gt;&lt;br /&gt;The changes also don't track the data necessary for managing "backref" and "lastline" data (the $~ and $_ pseudo-globals), which means that regular expression matches or line reads might have reduced functionality in the presence of these optimizations (though you might never notice; those variables are usually discouraged). This behavior can be restored by clever use of thread-local stacks (only pushing down the stack when in the presence of a method that might use those pseudo-globals), or by simply easing back the optimizations if those variables are likely to be used. Ideally we'll be able to use runtime profiling to make a smart decision, since we'll know whether a given call site has ever encountered a method that reads or writes $~ or $_.&lt;br /&gt;&lt;br /&gt;Finally, I have not inserted the necessary guards before these direct invocations that would branch to doing a normal dynamic call. This was again a pragmatic decision to speed the progress of my experiment...but it also raises an interesting question. What if we knew, without a doubt, that our code had seen all the types and methods it would ever see. Wouldn't it be nice to say "optimize yourself to death" and know it's doing so? While I doubt we'll see a JRuby ship without some guard in place (ideally a simple "method ID" comparison, which I wouldn't expect to impact performance much), I think it's almost assured that we'll allow users to "opt in" to completely "statickifying" specific of code. And it's likely that if we started moving more of JRuby's implementation into Ruby code, we would take advantage of "fully" optimizing as well.&lt;br /&gt;&lt;br /&gt;With all these caveats in mind, let's take a look at some numbers.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;And Now, Numbers Meaningless to Anyone Not Using JRuby To Calculate Fibonacci Numbers&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The "fib" method is dreadfully abused in benchmarking. It's largely a method call benchmark, since most calls spawn at least two more recursive calls and potentially several others if numeric operations are calls as well. In JRuby, it doubles as an allocation-rate or memory-bandwidth benchmark, since the bulk of our time is spent constructing Fixnum objects or updating per-call runtime data structures.&lt;br /&gt;&lt;br /&gt;But since it's a simple result to show, I'm going to abuse it again. Please keep in mind these numbers are meaningless except in comparison to each other; JRuby is still cranking through a lot more objects than implementations with true Fixnums or value types, and the JVM is almost certainly over-optimizing portions of this benchmark. But of course, that's part of the point; we're making it possible for the JVM to accelerate and potentially eliminate unnecessary computation, and it's all becoming possible because we're using runtime data to improve runtime compilation.&lt;br /&gt;&lt;br /&gt;I'll be using JRuby 1.6.dev (master plus my hacks) on OS X Java 6 (1.6.0_20) 64-bit Server VM on a MacBook Pro Core 2 Duo at 2.66GHz.&lt;br /&gt;&lt;br /&gt;First, the basic JRuby "&lt;a href="http://github.com/jruby/jruby/blob/master/bench/bench_fib_recursive.rb"&gt;fib&lt;/a&gt;" numbers with full Ruby backtraces and dynamic calls:&lt;br /&gt;&lt;pre&gt;  0.357000   0.000000   0.357000 (  0.290000)&lt;br /&gt;  0.176000   0.000000   0.176000 (  0.176000)&lt;br /&gt;  0.174000   0.000000   0.174000 (  0.174000)&lt;br /&gt;  0.175000   0.000000   0.175000 (  0.175000)&lt;br /&gt;  0.174000   0.000000   0.174000 (  0.174000)&lt;/pre&gt;&lt;br /&gt;Now, with backtraces calculated from Java backtraces, dynamic calls restructured slightly to be more inlinable (but still dynamic and via invokers), and limited use of primitive call paths. Essentially the fastest we can get in JRuby 1.5 without totally breaking compatibility (and with some minor breakages, in fact):&lt;br /&gt;&lt;pre&gt;  0.383000   0.000000   0.383000 (  0.330000)&lt;br /&gt;  0.109000   0.000000   0.109000 (  0.108000)&lt;br /&gt;  0.111000   0.000000   0.111000 (  0.112000)&lt;br /&gt;  0.101000   0.000000   0.101000 (  0.101000)&lt;br /&gt;  0.101000   0.000000   0.101000 (  0.101000)&lt;/pre&gt;&lt;br /&gt;Now, using all the runtime optimizations described above. Keep in mind these numbers will probably drop a bit with guards in place (but they're still pretty fantastic):&lt;br /&gt;&lt;pre&gt;  0.443000   0.000000   0.443000 (  0.376000)&lt;br /&gt;  0.035000   0.000000   0.035000 (  0.035000)&lt;br /&gt;  0.036000   0.000000   0.036000 (  0.036000)&lt;br /&gt;  0.036000   0.000000   0.036000 (  0.036000)&lt;br /&gt;  0.036000   0.000000   0.036000 (  0.036000)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And a couple comparisons of another mostly-recursive, largely-abused benchmark target: the &lt;a href="http://github.com/jruby/jruby/blob/master/bench/bench_tak.rb"&gt;tak&lt;/a&gt; function...&lt;br /&gt;&lt;br /&gt;Static optimizations only, as fast as we can make it:&lt;br /&gt;&lt;pre&gt;  1.750000   0.000000   1.750000 (  1.695000)&lt;br /&gt;  0.779000   0.000000   0.779000 (  0.779000)&lt;br /&gt;  0.764000   0.000000   0.764000 (  0.764000)&lt;br /&gt;  0.775000   0.000000   0.775000 (  0.775000)&lt;br /&gt;  0.763000   0.000000   0.763000 (  0.763000)&lt;/pre&gt;&lt;br /&gt;And with runtime optimizations:&lt;br /&gt;&lt;pre&gt;  0.899000   0.000000   0.899000 (  0.832000)&lt;br /&gt;  0.331000   0.000000   0.331000 (  0.331000)&lt;br /&gt;  0.332000   0.000000   0.332000 (  0.332000)&lt;br /&gt;  0.329000   0.000000   0.329000 (  0.329000)&lt;br /&gt;  0.331000   0.000000   0.331000 (  0.332000)&lt;/pre&gt;&lt;br /&gt;So for these trivial benchmarks, a couple hours hacking in JRuby's compiler has produced numbers 2-3x faster than the fastest JRuby performance we've achieved thusfar. Understanding why requires one last section.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Hooray for the JVM&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There's a missing trick here I haven't explained: the JVM is still doing most of the work for us.&lt;br /&gt;&lt;br /&gt;In the plain old dynamic-calling, static-optimized case, the JVM is dutifully optimizing everything we throw at it. It's taking our Ruby calls, inlining the invokers and their eventual calls, inlining core class methods (yes, this means we've always been able to inline Ruby into Ruby or Java into Ruby or Ruby into Java, given the appropriate tweaks), and optimizing things very well. But here's the problem: the JVM's default settings are tuned for optimizing *Java*, not for optimizing Ruby. In Java, a call from one method to another has exactly one hop. In JRuby's dynamic calls, it may take three or four hops, bouncing through CallSites and DynamicMethods to eventually get to the target. Since Hotspot only inlines up to 9 levels of calls by default, you can see we're eating up that budget very quickly. Add to that the fact that Java to Java calls have no intervening code to eat up bytecode size thresholds, and we're essentially only getting a fraction of the optimization potential out of Hotspot that a "simpler" language like Java does.&lt;br /&gt;&lt;br /&gt;Now consider the dynamically-optimized case. We've eliminated both the CallSite and the DynamicMethod from most calls, even if we have to insert a bit of guard code to do it. That means nine levels of Ruby calls can inline, or nine levels of logic from Ruby to core methods or Ruby to Java. We've now given Hotspot a much better picture of the system to optimize. We've also eliminated some of the background noise of doing a Ruby call, like updating rarely-used data structures. We'll need to ensure backtraces come out in some usable form, but at least we're not double-tracking them.&lt;br /&gt;&lt;br /&gt;The bottom line here is that instead of doing all the much harder work of adding inlining to our own compiler, all we need to do is &lt;span style="font-style:italic;"&gt;let the JVM do it&lt;/span&gt;, and we benefit from the years of work that have gone into current JVMs' optimizing compilers. The best way to solve a hard problem is to get someone else to solve it for you, and the JVM does an excellent job of solving this particular hard problem. Instead of giving the JVM a fish *or* teaching it how to fish, we're just giving it a map of the lake; it's already an expert fisherman.&lt;br /&gt;&lt;br /&gt;There's also another side to these optimizations: our continued maintenance of an interpreter is starting to pay off. Other JVM languages that don't have an interpreted mode have a much more difficult time doing any runtime optimization; simply put, it's really hard to swap out bytecode you've already loaded unless you're explicitly abstracting how that bytecode gets generated in the first place. In JRuby, where methods have always had to switch from interpreted to jitted at runtime, we're can can hop back and forth much more freely, optimizing along the way.&lt;br /&gt;&lt;br /&gt;That's all for now. Don't expect to download JRuby 1.6 in a few months and see everything be three times (or ten times! or 100 times!) faster. There's a lot of details we need to work out about when these optimizations will be safe, how users might be able to opt-in to "full" optimization if necessary, and whether we'll get things fast enough to start replacing core code with Ruby. But early results are very promising, and it's assured we'll ship some of this very soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-301015234022701224?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/301015234022701224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=301015234022701224' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/301015234022701224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/301015234022701224'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/05/kicking-jruby-performance-up-notch.html' title='Kicking JRuby Performance Up a Notch'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-2124306056621469065</id><published>2010-04-30T01:12:00.002-05:00</published><updated>2010-04-30T02:08:39.181-05:00</updated><title type='text'>Building Ruboto: Precompiling Ruby for Android</title><content type='html'>I originally started to send this to the JRuby dev list and to the Ruboto list, but realized quickly that it might make a good blog post. Since I don't blog enough lately, here it is.&lt;br /&gt;&lt;br /&gt;I've been looking into better ways to precompile Ruby code to classes for deploy on Android devices. Normally, JRuby users can just jar up their .rb files and load and require them as though they were on the filesystem; JRuby finds, loads, and runs them just fine. This works well enough on Android, but since there's no way to generate bytecode at runtime, JRuby code that isn't precompiled must run interpreted forever...and run a bit slower than we'd like because of it. In order for Ruby to be a first-class language for Android development, we must make it possible to precompile Ruby code *completely* and bundle it up with the application. So this evening I spent some time making that possible.&lt;br /&gt;&lt;br /&gt;I have some good news, some bad news, and some good news. First, a bit of background into JRuby's compiler.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What JRuby's Compiler Produces&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;JRuby's ahead-of-time compiler produces a single .class file per .rb file, to ease deployment and lookup of those files (and because I think it's ugly to always vomit out an unidentifiable class for every method body). This produces a nice 1:1 mapping between .rb and .class, but it comes at a cost: since those .class files are just "bags of methods" we need to bind those methods somehow. This usually happens at runtime, with JRuby generating a small "handle" class for every method as it is bound. So for a script like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;# foo.rb&lt;br /&gt;class Foo&lt;br /&gt;  def bar; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def hello; end&lt;/pre&gt;&lt;br /&gt;You will get one top-level class file when you AOT compile, and then two more class files are generated at runtime for the "handles" for methods "bar" and "hello". This provides the best possible performance for invocation, plus a nice 1:1 on-disk format...but it means we're still generating a lot of code at runtime.&lt;br /&gt;&lt;br /&gt;The other complication is that jrubyc normally outputs a .class file of the same name as the .rb file, to ease lookup of that .class file at runtime. So the main .class for the above script would be called "foo.class". The problem with this is that "foo.rb" may not always be loaded as "foo.rb". A user might load '../yum/../foo.rb' or some other peculiar path. As a result, the base name of the file is not enough to determine what class name to load. To solve this, I've introduced an alternate naming scheme that uses the SHA1 hash of the *actual* content of the file as the class name. So, for the above script, the resulting class would be named:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;ruby.jit.FILE_351347C9126659D4479558A2706DBC35E45D16D2&lt;/pre&gt;&lt;br /&gt;While this isn't a pretty name, it does provide a way to locate the compiled version of a script universally, regardless of what path is used to load it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Good News&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I've modified jrubyc (on master only...we need to talk about whether this should be a late addition to 1.5) to have a new --sha1 flag. As you might guess, this flag alters the compile process to generate the sha1-named class for each compiled file.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jrubyc foo.rb &lt;br /&gt;Compiling foo.rb to class foo&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ jrubyc --sha1 foo.rb &lt;br /&gt;Compiling foo.rb to class ruby.jit.FILE_351347C9126659D4479558A2706DBC35E45D16D2&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ jruby -X+C -J-Djruby.jit.debug=true -e "require 'foo'"&lt;br /&gt;...&lt;br /&gt;found jitted code for ./foo.rb at class: ruby.jit.FILE_351347C9126659D4479558A2706DBC35E45D16D2&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;This is actually finding the foo.rb file, calculating its SHA1 hash, and then loading the .class file instead. So if you had a bunch of .rb code for an Android application and wanted to precompile it, you'd run this command to get the sha1 classes, and then include &lt;span style="font-style:italic;"&gt;&lt;span style="font-weight:bold;"&gt;both&lt;/span&gt;&lt;/span&gt; the .rb file and the .class file in your application (the .rb file must be there because...you guessed it...we need to calculate the sha1 hash from its contents).&lt;br /&gt;&lt;br /&gt;To test this out, I actually ran jrubyc against the Ruby stdlib to produce a sha1 class for every .rb file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jrubyc -t /tmp --sha1 lib/ruby/1.8/&lt;br /&gt;Compiling all in '/Users/headius/projects/jruby/lib/ruby/1.8'...&lt;br /&gt;Compiling lib/ruby/1.8//abbrev.rb to class ruby.jit.FILE_4F30363F88066CC74555ABA5BE4B73FDE323BE1A&lt;br /&gt;Compiling lib/ruby/1.8//base64.rb to class ruby.jit.FILE_DD42170B797E34D082C952B92A19474E3FDF3FA2&lt;br /&gt;Compiling lib/ruby/1.8//benchmark.rb to class ruby.jit.FILE_0C42EBD7F248AF396DE7A70C0FBC31E9E8D233DE&lt;br /&gt;...&lt;br /&gt;Compiling lib/ruby/1.8//xsd/xmlparser/rexmlparser.rb to class ruby.jit.FILE_8B106B9E9F2F1768470A7A4E6BD1A36FC0859862&lt;br /&gt;Compiling lib/ruby/1.8//xsd/xmlparser/xmlparser.rb to class ruby.jit.FILE_AF51477EA5467822D8ADED37EEB5AB5D841E07D9&lt;br /&gt;Compiling lib/ruby/1.8//xsd/xmlparser/xmlscanner.rb to class ruby.jit.FILE_3203482AEE794F4B9D5448BF51935879B026092C&lt;/pre&gt;&lt;br /&gt;This produces 524 class files for 524 .rb files, just as it should, and running with forced compilation (-X+C) and jruby.jit.debug=true shows that it finds each class when loading anything from stdlib. That's a good start!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What About the Handles?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I mentioned above that we also generate, at runtime, a small handle class for every bound method in a given script. And again, since we can't generate bytecode on-device, we need a way to pregenerate all those handles.&lt;br /&gt;&lt;br /&gt;An hour's worth of work later, and jrubyc has a --handles flag that will additionally spit out all method handles for each script compiled. Here's our foo script compiled with --sha1 and --handles, along with the resulting .class files:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ jrubyc --sha1 --handles foo.rb&lt;br /&gt;Compiling foo.rb to class ruby.jit.FILE_351347C9126659D4479558A2706DBC35E45D16D2&lt;br /&gt;Generating direct handles for foo.rb&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ ls ruby/jit/*351347*&lt;br /&gt;ruby/jit/FILE_351347C9126659D4479558A2706DBC35E45D16D2.class&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ ls *351347*&lt;br /&gt;ruby_jit_FILE_351347C9126659D4479558A2706DBC35E45D16D2Invokermethod__1$RUBY$barFixed0.class&lt;br /&gt;ruby_jit_FILE_351347C9126659D4479558A2706DBC35E45D16D2Invokermethod__2$RUBY$helloFixed0.class&lt;/pre&gt;&lt;br /&gt;And sure enough, we can also see that these handles are being loaded instead of generated at runtime. So it's possible with these two options to *completely* precompile JRuby sources into .class files. Hooray!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Bad News&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My next step was obviously to try to precompile and dex the entire Ruby standard library. That's 524 files, but how many method bodies? We'd need to generate a handle for each one of them.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ mkdir stdlib-compiled&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ jrubyc --sha1 --handles -t stdlib-compiled/ lib/ruby/1.8/&lt;br /&gt;Compiling all in '/Users/headius/projects/jruby/lib/ruby/1.8'...&lt;br /&gt;Compiling lib/ruby/1.8//abbrev.rb to class ruby.jit.FILE_4F30363F88066CC74555ABA5BE4B73FDE323BE1A&lt;br /&gt;Generating direct handles for lib/ruby/1.8//abbrev.rb&lt;br /&gt;Compiling lib/ruby/1.8//base64.rb to class ruby.jit.FILE_DD42170B797E34D082C952B92A19474E3FDF3FA2&lt;br /&gt;Generating direct handles for lib/ruby/1.8//base64.rb&lt;br /&gt;...&lt;br /&gt;Compiling lib/ruby/1.8//xsd/xmlparser/xmlparser.rb to class ruby.jit.FILE_AF51477EA5467822D8ADED37EEB5AB5D841E07D9&lt;br /&gt;Generating direct handles for lib/ruby/1.8//xsd/xmlparser/xmlparser.rb&lt;br /&gt;Compiling lib/ruby/1.8//xsd/xmlparser/xmlscanner.rb to class ruby.jit.FILE_3203482AEE794F4B9D5448BF51935879B026092C&lt;br /&gt;Generating direct handles for lib/ruby/1.8//xsd/xmlparser/xmlscanner.rb&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ find stdlib-compiled/ -name \*.class | wc -l&lt;br /&gt;    8212&lt;/pre&gt;&lt;br /&gt;Wowsers, that's a lot of method bodies..over 7500 of them. But of course this is the entire Ruby standard library, with code for network protocols, templating, xml parsing, soap, and so on. Now for the more frightening numbers: keeping in mind that .class is a pretty verbose file format, how big are all these class files?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ du -ks stdlib-compiled/ruby&lt;br /&gt;14008 stdlib-compiled/ruby&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ du -ks stdlib-compiled/&lt;br /&gt;44784 stdlib-compiled/&lt;/pre&gt;&lt;br /&gt;Yeeow! The standard library alone (without handles) produces 14MB of .class files, and with handles it goes up to a whopping 44MB of .class files! That seems a bit high, doesn't it? Especially considering that the .rb files add up to around 4.5MB?&lt;br /&gt;&lt;br /&gt;Well there's a few explanations for this. First off, the generated handles are rather small, around 2k each, but they each are probably 50% the exact same code. They're generated as separate handles primarily because the JVM will not inline the same loaded body of code through two different call paths, so we have to duplicate that logic repeatedly. Java 7 fixes some of this, but for now we're stuck. The handle classes also share almost identical &lt;span style="font-style:italic;"&gt;constant pools&lt;/span&gt;, or in-file tables of strings. Many of the same characteristics apply to the compiled Ruby scripts, so the 44MB number is a bit larger than it needs to be.&lt;br /&gt;&lt;br /&gt;We can show a more realistic estimate of on-disk size by compressing the lot, first with normal "jar", and then with the "pack200" utility, which takes greater advantage of the .class format's intra-file redundancy:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ cd stdlib-compiled/&lt;br /&gt;&lt;br /&gt;~/projects/jruby/stdlib-compiled ➔ jar cf stdlib-compiled.jar .&lt;br /&gt;&lt;br /&gt;~/projects/jruby/stdlib-compiled ➔ pack200 stdlib-compiled.pack.gz stdlib-compiled.jar&lt;br /&gt;&lt;br /&gt;~/projects/jruby/stdlib-compiled ➔ ls -l stdlib-compiled.*&lt;br /&gt;-rw-r--r--  1 headius  staff  13424221 Apr 30 01:43 stdlib-compiled.jar&lt;br /&gt;-rw-r--r--  1 headius  staff   4051355 Apr 30 01:44 stdlib-compiled.pack.gz&lt;/pre&gt;&lt;br /&gt;Now we're seeing more reasonable numbers. A 13MB jar file is still pretty large, but it's not bad considering we started with 44MB of .class files. The packed size is even better: only 4MB for a completely-compiled Ruby standard library, and ultimately *smaller* than the original sources.&lt;br /&gt;&lt;br /&gt;So what's the bad news? It obviously wasn't the size, since I just showed that was a red herring. The bad news is when we try to dex this jar.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The "dx" Tool&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Android SDK ships with a tool called "dx" which gets used at build time to translate Java bytecode (in .class files, .jar files, etc) to Dalvik bytecode (resulting in a .dex file. Along the way it optimizes the code, tidies up redundancies, and basically makes it as clean and compact as possible for distribution to an Android device. Once on the device, the Dalvik bytecode gets immediately compiled into whatever the native processor runs, so the dex data needs to be as clean and optimized as possible.&lt;br /&gt;&lt;br /&gt;Every Java application shipped for Android must pass through dx in some way, so my next step was to try to "dex" the compiled standard library:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby/out ➔ ../../android-sdk-mac_86/platforms/android-7/tools/dx --dex --verbose --positions=none --no-locals --output=stdlib-compiled.dex stdlib-compiled.jar &lt;br /&gt;processing archive stdlib-compiled.jar...&lt;br /&gt;ignored resource META-INF/MANIFEST.MF&lt;br /&gt;processing ruby/jit/FILE_003796EE1C0C24540DF7239B8197C183BC7017BB.class...&lt;br /&gt;processing ruby/jit/FILE_00499F5FE29ED8EDB63965B0F65B19CFE994D120.class...&lt;br /&gt;...&lt;br /&gt;processing ruby_jit_FILE_FEF23DE8CDA5B9BD9D880CBC08D3249158379E58Invokermethod__5$RUBY$run_suiteFixed0.class...&lt;br /&gt;processing ruby_jit_FILE_FEF23DE8CDA5B9BD9D880CBC08D3249158379E58Invokermethod__6$RUBY$create_resultFixed0.class...&lt;br /&gt;&lt;br /&gt;trouble writing output: format == null&lt;/pre&gt;&lt;br /&gt;Uh-oh, that doesn't look good. What happened?&lt;br /&gt;&lt;br /&gt;Well it turns out that the Ruby standard library *plus* all the handles needed to bind it is &lt;a href="http://code.google.com/p/android/issues/detail?id=7147"&gt;too much for the current dex file format&lt;/a&gt; It's a known issue that similarly bit Maciek Makowski (reported of the linked bug) when he tried to dex both the Scala compiler and the Scala base set of libraries in one go. And similar to his case, I was able to successfully dex *either* the precompiled stdlib *or* the generated handles...but not both at the same time.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What Can We Do?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It appears that for the moment, it's not going to be possible to completely precompile the entire Ruby standard library. But there's ways around that.&lt;br /&gt;&lt;br /&gt;First off, probably no application on the planet needs the entire standard library, so we can easily just include the files needed for a given app. That may be enough to cut the size down tremendously. It's also perfectly possible to build a very complicated Ruby application for Android that will easily fit into the current dex format; I doubt most mobile applications would result in 4.5MB of uncompressed .rb source. So the added --sha1 and --handle features will be immediately useful for Android development.&lt;br /&gt;&lt;br /&gt;Secondly, I've been planning on adding a different way to bind methods that doesn't require a class file per method. I would probably generate a large switch for each .rb file and then bind the methods numerically, so only a single additional class (and only a few methods in that class) would be needed to bind an entire compiled .rb script. This issue with dex will force me to finally do that.&lt;br /&gt;&lt;br /&gt;And lastly, there's a bit more good news. Remember that the packed size of the entire standard library plus handles was around 4MB? Here's the sizes of the dex'ed standard library and handles:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ ls -l *.dex&lt;br /&gt;-rw-r--r--  1 headius  staff  3718340 Apr 30 00:57 stdlib-compiled-solo.dex&lt;br /&gt;-rw-r--r--  1 headius  staff  8656300 Apr 30 00:52 stdlib-compiled-handles.dex&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ jar cf blah.apk *.dex&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ ls -l blah.apk &lt;br /&gt;-rw-r--r--  1 headius  staff  3179625 Apr 30 02:01 blah.apk&lt;/pre&gt;&lt;br /&gt;Once dex has worked its magic against our sources, we're now down to 3.1MB of compressed code...a pretty good size for the entire Ruby standard library plus 7500+ noisy, repetitive handles. We're definitely within reach of making full Ruby development for Android a reality.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-2124306056621469065?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/2124306056621469065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=2124306056621469065' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2124306056621469065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2124306056621469065'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/04/building-ruboto-precompiling-ruby-for.html' title='Building Ruboto: Precompiling Ruby for Android'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-9060780715845049643</id><published>2010-04-11T12:27:00.005-05:00</published><updated>2010-04-11T16:13:36.815-05:00</updated><title type='text'>Nokogiri Java Port: Help Us Finish It!</title><content type='html'>One of the most commonly used native extensions for Ruby is the &lt;a href="http://github.com/tenderlove/nokogiri"&gt;Nokogiri&lt;/a&gt; XML API. Nokogiri wraps libxml and has a fair amount of C code that links directly against the Ruby C extension API...an API we don't support in JRuby (and won't, without a lot of community help).&lt;br /&gt;&lt;br /&gt;A bit over a year ago, the Nokogiri folks did us a big favor by creating an &lt;a href="http://github.com/tenderlove/nokogiri/tree/master/lib/nokogiri/ffi/"&gt;FFI version of Nokogiri&lt;/a&gt; that works surprisingly well; it's probably the most widely-used FFI-based Ruby library around. But the endgame for Nokogiri on JRuby has always been to get a &lt;a href="http://github.com/tenderlove/nokogiri/tree/java"&gt;pure-Java version&lt;/a&gt;. Not everyone is allowed to link native libraries on their Java platform of choice, and those that are often have trouble getting the right libxml versions installed. The Java version needs to happen.&lt;br /&gt;&lt;br /&gt;That day is very close.&lt;br /&gt;&lt;br /&gt;I spent a bit of time this weekend getting the Nokogiri "java" port running on my system, and the folks working on it have brought it almost to 100% passing. It's time to push it over the edge.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Building and Testing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's my process for getting it building. Let me know if this needs to be edited.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Update:&lt;/span&gt;&lt;/span&gt; Added rake-compiler and hoe to gems you need to install and modified the git command-line for versions that don't automatically create a local tracking branch.&lt;br /&gt;&lt;br /&gt;1. Clone the Nokogiri repository and switch to the "java" branch&lt;br /&gt;&lt;pre&gt;~/projects ➔ git clone git://github.com/tenderlove/nokogiri.git&lt;br /&gt;Initialized empty Git repository in /Users/headius/projects/nokogiri/.git/&lt;br /&gt;remote: Counting objects: 14767, done.&lt;br /&gt;remote: Compressing objects: 100% (3882/3882), done.&lt;br /&gt;remote: Total 14767 (delta 10482), reused 13969 (delta 9945)&lt;br /&gt;Receiving objects: 100% (14767/14767), 3.73 MiB | 742 KiB/s, done.&lt;br /&gt;Resolving deltas: 100% (10482/10482), done.&lt;br /&gt;&lt;br /&gt;~/projects ➔ cd nokogiri/&lt;br /&gt;&lt;br /&gt;~/projects/nokogiri ➔ git checkout -b java origin/java&lt;br /&gt;Branch java set up to track remote branch java from origin.&lt;br /&gt;Switched to a new branch 'java'&lt;/pre&gt;&lt;br /&gt;2. Install racc, rexical, rake-compiler, and hoe into Ruby (C Ruby, that is, since they also have extensions)&lt;br /&gt;&lt;pre&gt;~/projects/nokogiri ➔ sudo gem install racc rexical rake-compiler hoe&lt;br /&gt;Building native extensions.  This could take a while...&lt;br /&gt;Successfully installed racc-1.4.6&lt;br /&gt;Successfully installed rexical-1.0.4&lt;br /&gt;Successfully installed rake-compiler-0.7.0&lt;br /&gt;Successfully installed hoe-2.6.0&lt;br /&gt;4 gems installed&lt;/pre&gt;&lt;br /&gt;3. Build the lexer and parser using C Ruby&lt;br /&gt;&lt;pre&gt;~/projects/nokogiri ➔ rake gem:dev:spec&lt;br /&gt;(in /Users/headius/projects/nokogiri)&lt;br /&gt;warning: couldn't activate the debugging plugin, skipping&lt;br /&gt;rake-compiler must be configured first to enable cross-compilation&lt;br /&gt;/usr/bin/racc -l -o lib/nokogiri/css/generated_parser.rb lib/nokogiri/css/parser.y&lt;br /&gt;rex --independent -o lib/nokogiri/css/generated_tokenizer.rb lib/nokogiri/css/tokenizer.rex&lt;/pre&gt;&lt;br /&gt;4. Build the Java bits (using rake in JRuby)&lt;br /&gt;&lt;pre&gt;~/projects/nokogiri ➔ jruby -S rake java:build&lt;br /&gt;(in /Users/headius/projects/nokogiri)&lt;br /&gt;warning: couldn't activate the debugging plugin, skipping&lt;br /&gt;javac -g -cp /Users/headius/projects/jruby/lib/jruby.jar:../../lib/nekohtml.jar:../../lib/nekodtd.jar:../../lib/xercesImpl.jar:../../lib/isorelax.jar:../../lib/jing.jar nokogiri/*.java nokogiri/internals/*.java&lt;br /&gt;jar cf ../../lib/nokogiri/nokogiri.jar nokogiri/*.class nokogiri/internals/*.class&lt;/pre&gt;&lt;br /&gt;5. Run the tests (again with rake on JRuby)&lt;br /&gt;&lt;pre&gt;~/projects/nokogiri ➔ jruby -S rake test&lt;br /&gt;(in /Users/headius/projects/nokogiri)&lt;br /&gt;...&lt;a href="http://gist.github.com/362908"&gt;full output&lt;/a&gt;...&lt;/pre&gt;&lt;br /&gt;On my system, I get about 8 failures and 19 errors, out of 785 tests and 1657 assertions. We're very close!&lt;br /&gt;&lt;br /&gt;A few other useful tasks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;jruby -S rake java:clean_all wipes out the build Java stuff&lt;/li&gt;&lt;li&gt;jruby -S rake java:gem builds the Java gem, if you want to try installing it&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-style: italic;"&gt;Helping Out&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you'd like to help fix these bugs, there's a few ways to approach it.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Join the &lt;a href="http://groups.google.com/group/nokogiri-talk?pli=1"&gt;nokogiri-talk Google Group&lt;/a&gt; so you can communicate with others working on the port. The key folks right now are &lt;a href="http://yokolet.blogspot.com/"&gt;Yoko Harada&lt;/a&gt; and &lt;a href="http://www.serabe.com/"&gt;Sergio Arbeo&lt;/a&gt; (who did the original bulk of the work for GSoC 2009). I'm also poking at it a bit in my spare time.&lt;/li&gt;&lt;li&gt;Post to the group to let folks know you want to help. This will help avoid duplicated effort.&lt;/li&gt;&lt;li&gt;Pick tests that appear to be missing or incorrect Ruby logic, like "not implemented", nil results ("method blah not found for nil") or arity errors ("3 arguments for 2" kinds of things). These are often the simplest ones to fix.&lt;/li&gt;&lt;li&gt;Don't give up! We're almost there!&lt;/li&gt;&lt;/ul&gt;It would be great if we could have a 100% working Nokogiri Java port for JRuby 1.5 final this month. I hope to see you on the nokogiri-talk list! Feel free to comment here if you have questions about getting bootstrapped.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-9060780715845049643?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/9060780715845049643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=9060780715845049643' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/9060780715845049643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/9060780715845049643'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/04/nokogiri-java-port-help-us-finish-it.html' title='Nokogiri Java Port: Help Us Finish It!'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-196436260531271984</id><published>2010-04-03T19:05:00.005-05:00</published><updated>2010-04-04T02:46:19.315-05:00</updated><title type='text'>Getting Started with Duby</title><content type='html'>Hello again!&lt;br /&gt;&lt;br /&gt;As you may know, I've been working part-time on a new language called &lt;a href="http://github.com/headius/duby/"&gt;Duby&lt;/a&gt;. Duby looks like Ruby, since it co-opts the JRuby parser, and includes some of the features of the Ruby language like optional arguments and closures. But Duby is not Ruby; it's statically typed, compiles to "native" code (JVM bytecode, for example) before running, and does not have any built-in library of its own (preferring to just use what's available on a given runtime). Here's a quick sample of Duby code:&lt;br /&gt;&lt;pre&gt;class Foo&lt;br /&gt;  def initialize(hello:String)&lt;br /&gt;    puts 'constructor'&lt;br /&gt;    @hello = hello&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def hello(name:String)&lt;br /&gt;    puts "#{@hello}, #{name}"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Foo.new('Hiya').hello('Duby')&lt;/pre&gt;&lt;br /&gt;This post is not going to be an overview of the Duby language; I'll get that together soon, once I take stock of where the language stands as far as features go. Instead, this "getting started" post will show how you can grab the Duby repository and start playing with it right now.&lt;br /&gt;&lt;br /&gt;First you need to pull down three resources: Duby itself, BiteScript (the Ruby DSL I use to generate JVM bytecode), and a JRuby 1.5 snapshot:&lt;br /&gt;&lt;pre&gt;~/projects/tmp ➔ git clone git://github.com/headius/duby.git&lt;br /&gt;Initialized empty Git repository in /Users/headius/projects/tmp/duby/.git/&lt;br /&gt;remote: Counting objects: 2810, done.&lt;br /&gt;remote: Compressing objects: 100% (1291/1291), done.&lt;br /&gt;remote: Total 2810 (delta 1690), reused 2509 (delta 1447)&lt;br /&gt;Receiving objects: 100% (2810/2810), 10.64 MiB | 722 KiB/s, done.&lt;br /&gt;Resolving deltas: 100% (1690/1690), done.&lt;br /&gt;&lt;br /&gt;~/projects/tmp ➔ git clone git://github.com/headius/bitescript.git&lt;br /&gt;Initialized empty Git repository in /Users/headius/projects/tmp/bitescript/.git/&lt;br /&gt;remote: Counting objects: 470, done.&lt;br /&gt;remote: Compressing objects: 100% (404/404), done.&lt;br /&gt;remote: Total 470 (delta 166), reused 313 (delta 57)&lt;br /&gt;Receiving objects: 100% (470/470), 93.56 KiB, done.&lt;br /&gt;Resolving deltas: 100% (166/166), done.&lt;br /&gt;&lt;br /&gt;~/projects/tmp ➔ curl http://ci.jruby.org/snapshots/jruby-bin-1.5.0.dev.tar.gz | tar xz&lt;br /&gt;  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current&lt;br /&gt;                                 Dload  Upload   Total   Spent    Left  Speed&lt;br /&gt;100 11.3M  100 11.3M    0     0   353k      0  0:00:32  0:00:32 --:--:--  262k&lt;br /&gt;&lt;br /&gt;~/projects/tmp ➔ ls&lt;br /&gt;bitescript duby  jruby-1.5.0.dev&lt;br /&gt;&lt;br /&gt;~/projects/tmp ➔ mv jruby-1.5.0.dev/ jruby&lt;/pre&gt;&lt;br /&gt;Once you have these three pieces in place, Duby can now be run. It's easiest to put the JRuby snapshot in PATH, but you can just run it directly too:&lt;br /&gt;&lt;pre&gt;~/projects/tmp ➔ cd duby&lt;br /&gt;&lt;br /&gt;~/projects/tmp/duby ➔ ../jruby/bin/jruby bin/duby -e "puts 'hello'"&lt;br /&gt;hello&lt;br /&gt;&lt;br /&gt;~/projects/tmp/duby ➔ ../jruby/bin/jruby bin/dubyc -e "puts 'hello'"&lt;br /&gt;&lt;br /&gt;~/projects/tmp/duby ➔ java DashE&lt;br /&gt;hello&lt;/pre&gt;&lt;br /&gt;Finally, you may want to create a "complete" Duby jar that includes Duby, BiteScript, JRuby, and Java classes for command-line or Ant task usage. Using JRuby 1.5's Ant integration, the Duby Rakefile can produce that for you:&lt;br /&gt;&lt;pre&gt;~/projects/tmp/duby ➔ ../jruby/bin/jruby -S rake jar:complete&lt;br /&gt;(in /Users/headius/projects/tmp/duby)&lt;br /&gt;mkdir -p build&lt;br /&gt;Compiling Ruby sources&lt;br /&gt;Generating Java class DubyCommand to DubyCommand.java&lt;br /&gt;javac -d build -cp ../jruby/lib/jruby.jar:. DubyCommand.java&lt;br /&gt;Compiling Duby sources&lt;br /&gt;mkdir -p dist&lt;br /&gt;Building jar: /Users/headius/projects/tmp/duby/dist/duby.jar&lt;br /&gt;mkdir -p dist&lt;br /&gt;Building jar: /Users/headius/projects/tmp/duby/dist/duby-complete.jar&lt;br /&gt;&lt;br /&gt;~/projects/tmp/duby ➔ java -jar dist/duby-complete.jar run -e 'puts "Duby is Awesome!"'&lt;br /&gt;Duby is Awesome!&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Hopefully we'll soon have duby.jar, duby-complete.jar, and a new Duby gem released, but this is a quick way to get involved.&lt;br /&gt;&lt;br /&gt;I'll get back to you with a post on the Duby language itself Real Soon Now!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Update:&lt;/span&gt;&lt;/span&gt; I have also uploaded a snapshot duby-complete.jar (which includes both the Main-Class for jar execution and the simple Ant task org.jruby.duby.ant.Compiler) on the &lt;a href="http://github.com/headius/duby/downloads"&gt;Duby Github downloads page&lt;/a&gt;. Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-196436260531271984?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/196436260531271984/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=196436260531271984' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/196436260531271984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/196436260531271984'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/04/getting-started-with-duby.html' title='Getting Started with Duby'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-1577067705355325147</id><published>2010-04-03T17:18:00.003-05:00</published><updated>2010-04-03T17:43:18.883-05:00</updated><title type='text'>Using Ivy with JRuby 1.5's Ant Integration</title><content type='html'>JRuby 1.5 will be released soon, and one of the coolest new features is the integration of Ant support into Rake, the Ruby build tool. Tom Enebo wrote an article on the &lt;a href="http://www.engineyard.com/blog/2010/rake-and-ant-together-a-pick-it-n-stick-it-approach/"&gt;Rake/Ant integration&lt;/a&gt; for the Engine Yard blog, which has lots of examples of how to start migrating to Rake without leaving Ant behind. I'm not going to cover all that here.&lt;br /&gt;&lt;br /&gt;I've been using the Rake/Ant stuff for a few weeks now, first for my &lt;a href="http://github.com/headius/weakling"&gt;"weakling" RubyGem&lt;/a&gt; which adds a queue-supporting WeakRef to JRuby, and now for cleaning up &lt;a href="http://github.com/headius/duby"&gt;Duby&lt;/a&gt;'s build process. Along the way, I've realized I really never want to write Ant scripts again; they're so much nicer in Rake, and I have all of Ruby and Ant available to me.&lt;br /&gt;&lt;br /&gt;One thing Ant still needs help with is dependency resolution. Many people make the leap to &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt;, and let it handle all the nuts and bolts. But that only works if you really buy into the Maven way of life...a problem if you're like me and you live in a lot of hybrid worlds where the Maven way doesn't necessarily fit. So many folks are turning to &lt;a href="http://ant.apache.org/ivy/"&gt;Apache Ivy&lt;/a&gt; to get dependency management in their builds without using Maven.&lt;br /&gt;&lt;br /&gt;Today I thought I'd translate the simple &lt;a href="http://ant.apache.org/ivy/history/latest-milestone/samples/build.xml"&gt;"no-install" Ivy example build&lt;/a&gt; (warning, XML) to Rake, to see how easy it would be. The results are pretty slick.&lt;br /&gt;&lt;br /&gt;First we need to construct the equivalent to the "download-ivy" and "install-ivy" ant tasks. I chose to put that in a Rake namespace, like this:&lt;br /&gt;&lt;pre&gt;namespace :ivy do&lt;br /&gt;  ivy_install_version = '2.0.0-beta1'&lt;br /&gt;  ivy_jar_dir = './ivy'&lt;br /&gt;  ivy_jar_file = "#{ivy_jar_dir}/ivy.jar"&lt;br /&gt;&lt;br /&gt;  task :download do&lt;br /&gt;    mkdir_p ivy_jar_dir&lt;br /&gt;    ant.get :src =&amp;gt; "http://repo1.maven.org/maven2/org/apache/ivy/ivy/#{ivy_install_version}/ivy-#{ivy_install_version}.jar",&lt;br /&gt;      :dest =&amp;gt; ivy_jar_file,&lt;br /&gt;      :usetimestamp =&amp;gt; true&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  task :install =&amp;gt; :download do&lt;br /&gt;    ant.path :id =&amp;gt; 'ivy.lib.path' do&lt;br /&gt;      fileset :dir =&amp;gt; ivy_jar_dir, :includes =&amp;gt; '*.jar'&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    ant.taskdef :resource =&amp;gt; "org/apache/ivy/ant/antlib.xml",&lt;br /&gt;      #:uri =&amp;gt; "antlib:org.apache.ivy.ant",&lt;br /&gt;      :classpathref =&amp;gt; "ivy.lib.path"&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Notice that instead of using Ant properties, I've just used Ruby variables for the Ivy install version, dir, and file. I've also removed the "uri" element to ant.taskdef because I'm not sure if we have an equivalent for that in Rake yet (note to self: figure out if we have an equivalent for that).&lt;br /&gt;&lt;br /&gt;With these two tasks, we can now fetch ivy and install it for the remainder of the build. Here's running the download task from the command line:&lt;br /&gt;&lt;pre&gt;~/projects/duby ➔ rake ivy:download&lt;br /&gt;(in /Users/headius/projects/duby)&lt;br /&gt;mkdir -p ./ivy&lt;br /&gt;Getting: http://repo1.maven.org/maven2/org/apache/ivy/ivy/2.0.0-beta1/ivy-2.0.0-beta1.jar&lt;br /&gt;To: /Users/headius/projects/duby/ivy/ivy.jar&lt;/pre&gt;&lt;br /&gt;Now we want a simple task that uses ivy:install to fetch resources and make them available for the build. Here's the example from Apache, using the cachepath task, written in Rake:&lt;br /&gt;&lt;pre&gt;task :go =&amp;gt; "ivy:install" do&lt;br /&gt;  ant.cachepath :organisation =&amp;gt; "commons-lang",&lt;br /&gt;    :module =&amp;gt; "commons-lang",&lt;br /&gt;    :revision =&amp;gt; "2.1",&lt;br /&gt;    :pathid =&amp;gt; "lib.path.id",&lt;br /&gt;    :inline =&amp;gt; "true"&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Pretty clean and simple, and it fits nicely into the flow of the Rakefile. I can also switch this to using the "retrieve" task, which just pulls the jars down and puts them where I want them:&lt;br /&gt;&lt;pre&gt;task :go =&amp;gt; "ivy:install" do&lt;br /&gt;  ant.retrieve :organisation =&amp;gt; 'commons-lang',&lt;br /&gt;    :module =&amp;gt; 'commons-lang',&lt;br /&gt;    :revision =&amp;gt; '2.1',&lt;br /&gt;    :pattern =&amp;gt; 'javalib/[conf]/[artifact].[ext]',&lt;br /&gt;    :inline =&amp;gt; true&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;This fetches the Apache Commons Lang package along with all dependencies into javalib, separated by what build configuration they are associated with (runtime, test, etc). Here it is in action:&lt;br /&gt;&lt;pre&gt;~/projects/duby ➔ rake go&lt;br /&gt;(in /Users/headius/projects/duby)&lt;br /&gt;mkdir -p ./ivy&lt;br /&gt;Getting: http://repo1.maven.org/maven2/org/apache/ivy/ivy/2.0.0-beta1/ivy-2.0.0-beta1.jar&lt;br /&gt;To: /Users/headius/projects/duby/ivy/ivy.jar&lt;br /&gt;Not modified - so not downloaded&lt;br /&gt;Trying to override old definition of task buildnumber&lt;br /&gt;:: Ivy 2.1.0 - 20090925235825 :: http://ant.apache.org/ivy/ ::&lt;br /&gt;:: loading settings :: url = jar:file:/Users/headius/.ant/lib/ivy.jar!/org/apache/ivy/core/settings/ivysettings.xml&lt;br /&gt;:: resolving dependencies :: commons-lang#commons-lang-caller;working&lt;br /&gt; confs: [default, master, compile, provided, runtime, system, sources, javadoc, optional]&lt;br /&gt; found commons-lang#commons-lang;2.1 in public&lt;br /&gt;:: resolution report :: resolve 64ms :: artifacts dl 3ms&lt;br /&gt; ---------------------------------------------------------------------&lt;br /&gt; |                  |            modules            ||   artifacts   |&lt;br /&gt; |       conf       | number| search|dwnlded|evicted|| number|dwnlded|&lt;br /&gt; ---------------------------------------------------------------------&lt;br /&gt; |      default     |   1   |   0   |   0   |   0   ||   1   |   0   |&lt;br /&gt; |      master      |   1   |   0   |   0   |   0   ||   1   |   0   |&lt;br /&gt; |      compile     |   1   |   0   |   0   |   0   ||   0   |   0   |&lt;br /&gt; |     provided     |   1   |   0   |   0   |   0   ||   0   |   0   |&lt;br /&gt; |      runtime     |   1   |   0   |   0   |   0   ||   0   |   0   |&lt;br /&gt; |      system      |   1   |   0   |   0   |   0   ||   0   |   0   |&lt;br /&gt; |      sources     |   1   |   0   |   0   |   0   ||   1   |   0   |&lt;br /&gt; |      javadoc     |   1   |   0   |   0   |   0   ||   1   |   0   |&lt;br /&gt; |     optional     |   1   |   0   |   0   |   0   ||   0   |   0   |&lt;br /&gt; ---------------------------------------------------------------------&lt;br /&gt;:: retrieving :: commons-lang#commons-lang-caller&lt;br /&gt; confs: [default, master, compile, provided, runtime, system, sources, javadoc, optional]&lt;br /&gt; 4 artifacts copied, 0 already retrieved (1180kB/30ms)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But if I have multiple artifacts, this could be pretty cumbersome. Since this is Ruby, I can just put this in a method and call it repeatedly:&lt;br /&gt;&lt;pre&gt;def ivy_retrieve(org, mod, rev)&lt;br /&gt;  ant.retrieve :organisation =&amp;gt; org,&lt;br /&gt;    :module =&amp;gt; mod,&lt;br /&gt;    :revision =&amp;gt; rev,&lt;br /&gt;    :pattern =&amp;gt; 'javalib/[conf]/[artifact].[ext]',&lt;br /&gt;    :inline =&amp;gt; true&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;artifacts = %w[&lt;br /&gt;  commons-lang commons-lang 2.1&lt;br /&gt;  org.jruby jruby 1.4.0&lt;br /&gt;]&lt;br /&gt;&lt;br /&gt;task :go =&amp;gt; "ivy:install" do&lt;br /&gt;  artifacts.each_slice(3) do |*artifact|&lt;br /&gt;    ivy_retrieve(*artifact)&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Look for JRuby 1.5 release candidates soon, and let us know what you think of the new Ant integration!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-1577067705355325147?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/1577067705355325147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=1577067705355325147' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1577067705355325147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1577067705355325147'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/04/using-ivy-with-jruby-15s-ant.html' title='Using Ivy with JRuby 1.5&apos;s Ant Integration'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-3648554808161524197</id><published>2010-03-28T13:24:00.002-05:00</published><updated>2010-03-28T13:37:31.528-05:00</updated><title type='text'>Ruby Summer of Code 2010</title><content type='html'>This year, no major Ruby organization got accepted to Google's Summer of Code (even though a half dozen Python projects got accepted, but I won't rant here). What do we as Rubyists do? Take it sitting down? NO! We make our own Summer of Code!&lt;br /&gt;&lt;br /&gt;Thanks to Engine Yard, Ruby Central, and the Rails team, Ruby Summer of Code has raised $100k in just three days, allowing us to run 20 student projects! Hooray!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://rubysoc.org/"&gt;Ruby Summer of Code&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now of course we really would love to have some JRuby projects involved. There's so much exciting stuff going on with JRuby, and I believe it's the most promising platform for really growing the Ruby community. So we've set up a page for &lt;a href="http://kenai.com/projects/jruby/pages/RubySummerOfCode2010"&gt;JRuby Ruby Summer of Code 2010&lt;/a&gt; ideas. Here's a few to get you started:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;JRuby on Android work, including command-line tooling, performance work, and all the little bits and pieces needed to make Ruby a first-class Android language.&lt;/li&gt;&lt;li&gt;Porting key C extensions to JRuby, so there's an alternative for people migrating.&lt;/li&gt;&lt;li&gt;A super-fast lightweight server similar to the GlassFish gem.&lt;/li&gt;&lt;li&gt;A full Hibernate and/or JPA backend for DataMapper or DataObjects, so that all databases Hibernate supports "just work" with JRuby.&lt;/li&gt;&lt;li&gt;Work on JRuby's nascent suport for Ruby C extensions by building the API out&lt;/li&gt;&lt;li&gt;Help get JRuby's early optimizing compiler wired up, to take JRuby's perf to the next level&lt;/li&gt;&lt;li&gt;Duby-related projects, like IDE support, better tooling, codebase cleanup, features, documentation.&lt;/li&gt;&lt;/ul&gt;And there's dozens of other projects out there just waiting for you! Add yourself as a student on the &lt;a href="http://rubysoc.org/"&gt;RubySOC page&lt;/a&gt;, add some ideas to the &lt;a href="http://kenai.com/projects/jruby/pages/RubySummerOfCode2010"&gt;JRuby ideas page&lt;/a&gt;, and let's get hacking!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-3648554808161524197?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/3648554808161524197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=3648554808161524197' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/3648554808161524197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/3648554808161524197'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/03/ruby-summer-of-code-2010.html' title='Ruby Summer of Code 2010'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-2863999783593463066</id><published>2010-03-01T15:52:00.005-06:00</published><updated>2010-03-01T17:09:54.001-06:00</updated><title type='text'>JRuby Startup Time Tips</title><content type='html'>JRuby has become notorious among Ruby implementations for having a slow startup time. Some of this is the JVM's fault, since it doesn't save JIT products and often just takes a long time to boot and get going. Some of this is JRuby's fault, though we work very hard to eliminate startup bottlenecks once they're reported and diagnosed. But a large number of startup time problems stem from simple configuration issues. Here's a few tips to help you improve JRuby's startup time.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(Note: JRuby actually does pretty well on base startup time compared to other JVM languages; but MRI, while generally not the fastest Ruby impl, starts up incredibly fast.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Make sure you're running the client JVM&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is by far the easiest way to improve startup. On HotSpot, the JVM behind OpenJDK and Sun's JDK, there are two different JIT-compiling backends: "client" and "server". The "client" backend does only superficial optimizations to JVM code as it compiles, but compiles things earlier and more quickly. The "server" backend performs larger-scale, more-global optimizations as it compiles, but takes a lot longer to get there and uses more resources when it compiles.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Up until recently, most JVM installs preferred the "client" backend, which meant JVM startup was about as fast as it could get. Unfortunately, many newer JVM releases on many operating systems are either defaulting to "server" or defaulting to a 64-bit JVM (which only has "server"). This means that without you or JRuby doing anything wrong, startup time takes a major hit.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's an example session showing a typical jruby -v line for a "server" JVM and the speed of doing some RubyGems requires (which is where most time is spent booting a RubyGems-heavy application):&lt;/div&gt;&lt;pre&gt;~/projects/jruby ➔ jruby -v&lt;br /&gt;jruby 1.5.0.dev (ruby 1.8.7 patchlevel 174) (2010-03-01 6857a4e) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_17) [x86_64-java]&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ time jruby -e "require 'rubygems'; require 'active_support'"&lt;br /&gt;&lt;br /&gt;real 0m5.174s&lt;br /&gt;user 0m7.643s&lt;br /&gt;sys 0m0.422s&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ time jruby -e "require 'rubygems'; require 'active_support'"&lt;br /&gt;&lt;br /&gt;real 0m5.068s&lt;br /&gt;user 0m7.662s&lt;br /&gt;sys 0m0.449s&lt;/pre&gt;&lt;div&gt;Ouch, over 5 seconds just to boot RubyGems and load ActiveSupport. You can see in this case that the JVM is preferring the "64-Bit Server VM", which will give you great runtime performance but pretty dismal startup time. If you see this sort of -v output, you can usually force the JVM to run in 32-bit "client" mode by specifying "-d32" as a JVM option. Here's an example using an environment variable:&lt;/div&gt;&lt;pre&gt;~/projects/jruby ➔ export JAVA_OPTS="-d32"&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ time jruby -e "require 'rubygems'; require 'active_support'"&lt;br /&gt;&lt;br /&gt;real 0m2.320s&lt;br /&gt;user 0m2.583s&lt;br /&gt;sys 0m0.207s&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ time jruby -e "require 'rubygems'; require 'active_support'"&lt;br /&gt;&lt;br /&gt;real 0m2.275s&lt;br /&gt;user 0m2.580s&lt;br /&gt;sys 0m0.207s&lt;/pre&gt;&lt;div&gt;On my system, a MacBook Pro running OS X 10.6, switching to the "client" VM improves this scenario by well over 50%. You may also want to try the "-client" option alone or in combination with -d32, since some 32-bit systems will still default to "server". Play around with it and see what works for you, and then let us know your platform, -v string, and how much improvement you see.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Regenerate the JVM's shared archive&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Starting with Java 5, the HotSpot JVM has included a feature known as &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/vm/class-data-sharing.html"&gt;Class Data Sharing (CDS)&lt;/a&gt;. Originally created by Apple for their OS X version of HotSpot, this feature loads all the common JDK classes as a single archive into a shared memory location. Subsequent JVM startups then simply reuse this read-only shared memory rather than reloading the same data again. It's a large reason why startup times on Windows and OS X have been so much better in recent years, and users of those systems may be able to ignore this tip.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On Linux, however, the shared archive is often *never* generated, since installers mostly just unpack the JVM into its final location and never run it. In order to force your system to generate the shared archive, run some equivalent of this command line:&lt;/div&gt;&lt;pre&gt;headius@headius-desktop:~/jruby$ sudo java -Xshare:dump&lt;br /&gt;Loading classes to share ... done.&lt;br /&gt;Rewriting and unlinking classes ... done.&lt;br /&gt;Calculating hash values for String objects .. done.&lt;br /&gt;Calculating fingerprints ... done.&lt;br /&gt;Removing unshareable information ... done.&lt;br /&gt;Moving pre-ordered read-only objects to shared space at 0x94030000 ... done.&lt;br /&gt;Moving read-only objects to shared space at 0x9444bef8 ... done.&lt;br /&gt;Moving common symbols to shared space at 0x9444d870 ... done.&lt;br /&gt;Moving remaining symbols to shared space at 0x945154e0 ... done.&lt;br /&gt;Moving string char arrays to shared space at 0x94516118 ... done.&lt;br /&gt;Moving additional symbols to shared space at 0x945ac5b0 ... done.&lt;br /&gt;Read-only space ends at 0x94612560, 6169952 bytes.&lt;br /&gt;Moving pre-ordered read-write objects to shared space at 0x94830000 ... done.&lt;br /&gt;Moving read-write objects to shared space at 0x94ea64a0 ... done.&lt;br /&gt;Moving String objects to shared space at 0x94ee3708 ... done.&lt;br /&gt;Read-write space ends at 0x94f27448, 7304264 bytes.&lt;br /&gt;Updating references to shared objects ... done. &lt;/pre&gt;&lt;div&gt;For many users, this can make a tremendous difference in startup time, since all that extra class data remains available in memory. You may need to specify the -d32 or -client options along with the -Xshare option. Play with those and the other -Xshare modes to see if it helps your situation.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Delay or disable JRuby's JIT&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;An interesting side effect of JRuby's JIT is that it sometimes actually &lt;i&gt;slows&lt;/i&gt; execution for really short runs. The compiler isn't free, obviously, nor is the cost of loading, verifying, and linking the resulting JVM bytecode. If you have a very short command that touches a lot of code, you might want to try disabling or delaying the JIT.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Disabling is easy: pass the -X-C flag or set the jruby.compile.mode property to "OFF":&lt;/div&gt;&lt;pre&gt;~/projects/jruby ➔ time jruby -S gem install rake&lt;br /&gt;Successfully installed rake-0.8.7&lt;br /&gt;1 gem installed&lt;br /&gt;Installing ri documentation for rake-0.8.7...&lt;br /&gt;Installing RDoc documentation for rake-0.8.7...&lt;br /&gt;&lt;br /&gt;real 0m13.188s&lt;br /&gt;user 0m12.342s&lt;br /&gt;sys 0m0.685s&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ time jruby -X-C -S gem install rake&lt;br /&gt;Successfully installed rake-0.8.7&lt;br /&gt;1 gem installed&lt;br /&gt;Installing ri documentation for rake-0.8.7...&lt;br /&gt;Installing RDoc documentation for rake-0.8.7...&lt;br /&gt;&lt;br /&gt;real 0m12.590s&lt;br /&gt;user 0m12.342s&lt;br /&gt;sys 0m0.583s&lt;/pre&gt;&lt;div&gt;This doesn't generally give you a huge boost, but it can be enough to keep you from going mad.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Avoid spawning "sub-rubies"&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's a fairly common idiom for Rubyists to spawn a Ruby subprocess using Kernel#system, Kernel#exec, or backquotes. For example, you may want to prepare a clean environment for a test run. That sort of scenario is perfectly understandable, but spawning many sub-rubies can take a tremendous toll on overall runtime.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When JRuby sees a #system, #exec, or backquote starting with "ruby", we will attempt to run it in the same JVM using a new JRuby instance. Because we have always supported "multi-VM" execution (where multiple isolated Ruby environments share a single process), this can make spawning sub-Rubies considerably faster. This is, in fact, how JRuby's Nailgun support (more on that later) keeps a single JVM "clean" for multiple JRuby command executions. But even though this can improve performance, there's still a cost for starting up those JRuby instances, since they need to have fresh, clean core classes and a clean runtime.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The worst-case scenario is when we detect that we can't spin up a JRuby instance in the same process, such as if you have shell redirection characters in the command line (e.g. system 'ruby -e blah &gt; /dev/null'). In those cases, we have no choice but to launch an entirely new JRuby process, complete with a new JVM, and you'll be paying the full zero-to-running cost.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you're able, try to limit how often you spawn "sub-rubies" or use tools like Nailgun or spec-server to reuse a given process for multiple hits.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Do less at startup&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is a difficult tip to follow, since often it's not your code doing so much at startup (and usually it's RubyGems itself). One of the sad truths of JRuby is that because we're based on the JVM, and the JVM takes a while to warm up, code executed early in a process runs a lot slower than code executed later. Add to this the fact that JRuby doesn't JIT Ruby code into JVM bytecode until it's been executed a few times, and you can see why cold performance is not one of JRuby's strong areas.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It may seem like delaying the inevitable, but doing less at startup can have surprisingly good results for your application. If you are able to eliminate most of the heavy processing until an application window starts up or a server starts listening, you may avoid (or spread out) the cold performance hit. Smart use of on-disk caches and better boot-time algorithms can help a lot, like saving a cache of mostly-read-only data rather than reloading and reprocessing it on every boot.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Try using Nailgun&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In JRuby 1.3, we officially shipped support for Nailgun. Nailgun is a small library and client-side tool that reuses a single JVM for multiple invocations. With Nailgun, small JRuby command-line invocations can be orders of magnitude faster. Have a look at my article on &lt;a href="http://blog.headius.com/2009/05/jruby-nailgun-support-in-130.html"&gt;Nailgun in JRuby 1.3.0&lt;/a&gt; for details.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Nailgun seems like a magic bullet, but unfortunately it does little to help certain common cases like booting RubyGems or starting up Rails (such as when running tests). It also can't help cases where you are causing lots of sub-rubies to be launched. Your best bet is to give it a try and let us know if it helps.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Play around with JVM flags&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's scads of JVM flags that can improve (or degrade) startup time. For a good list of flags you can play with, see my article on &lt;a href="http://blog.headius.com/2009/01/my-favorite-hotspot-jvm-flags.html"&gt;my favorite JVM flags&lt;/a&gt;, paying special attention to the heap-sizing and GC flags. If you find combinations that really help your application start up faster, let us know!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Help us find bottlenecks&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The biggest advances in startup-time performance have come from users like you investigating the load process to see where all that time is going. If you do a little poking around and find that particular libraries take unreasonably long to start (or just do too much at startup) or if you find that startup time seems to be limited by something other than CPU (like if your hard drive starts thrashing madly or your memory bus is being saturated) there may be improvements possible in JRuby or in the libraries and code you're loading. Dig a little...you may be surprised what you find.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a few JRuby flags that might help you investigate:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;--sample turns on the JVM's sampling profiler. It's not super accurate, but if there's some egregious bottleneck it should rise to the top.&lt;/li&gt;&lt;li&gt;-J-Xrunhprof:cpu=times turns on the JVM's instrumented profiler, saving profile results to java.hprof.txt. This slows down execution tremendously, but can give you more accurate low-level timings for JRuby and JDK code.&lt;/li&gt;&lt;li&gt;-J-Djruby.debug.loadService.timing=true turns on timing of all requires, showing fairly accurately where boot-time load costs are heaviest.&lt;/li&gt;&lt;li&gt;On Windows, where you may not have a "time" command, pass -b to JRuby (as in 'jruby -b ...') to print out a timing of your command's runtime execution (excluding JVM boot time).&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Let us help you!&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sometimes, there's an obvious misconfiguration or bug in JRuby that causes an application to start up unreasonably slowly. If startup time seems drastically different than what you've seen here, there's a good chance something's wrong with your setup. Post your situation to the JRuby mailing list or find us on IRC, and we (along with other JRuby users) will do our best to help you.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-2863999783593463066?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/2863999783593463066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=2863999783593463066' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2863999783593463066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2863999783593463066'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/03/jruby-startup-time-tips.html' title='JRuby Startup Time Tips'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-4361804608832616645</id><published>2010-01-28T01:49:00.003-06:00</published><updated>2010-01-28T03:05:18.991-06:00</updated><title type='text'>Five Reasons to Wait on the iPad</title><content type='html'>Like most geeks, I watched with great anticipation as the iPad was unveiled yesterday. In my case, it was from liveblogs monitored on spotty 3G and WiFi access at the Jfokus after-conference event. I'm reasonably impressed with the device, especially the $500 price point on the low end. But after giving it some thought, I have a few good reasons to wait on purchasing one. Here's five I came up with:&lt;br /&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Wait for the next generation.&lt;/b&gt; Never, ever buy the first generation of a device this new and this complex. Doubly so for anything the Apple hype machine is pimping. First-gen devices are always at least a little bit tweaky, and Apple has proven repeatedly that their first-gen devices are overpriced, underpowered, and replaced by something better in 4-6 months.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Wait for competitors to answer.&lt;/b&gt; Sure, there have been other tablets and "slates" announced over the past year, but the iPad has moved the bar. Given the number of competing vendors, the availability of viable tablet options like Windows 7 and Android (or Chrome OS), and the ever-present iControl and iLock-in associated with all things Apple, you can bet there's going to be a bunch of competitive options during 2010.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Wait for everyone else to buy it.&lt;/b&gt; Yeah, this one is painful, but think about all the suckers that bought the iPhone right when it came out. You'll spend a couple months as a temporary luddite, ridiculed by your peers. And then you'll get a better device for cheaper and have the last laugh. I mean, isn't half the joy of the iPad in having the bigger iPenis? You can hold off for a while.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Wait for crackers to bust it wide open.&lt;/b&gt; Nobody's happy that the iPhone is a closed platform, nor are they happy that the App Store is so sketchy at approving applications. So why not wait and see what the busy iPhone hackers can do with an iPad before diving it? Chances are it will be a far better laptop replacement once they get ahold of it.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Wait because you don't actually need it.&lt;/b&gt; It can't replace your phone. It can't replace your laptop. It can't replace your 50" LCD TV. Seriously now...what do you need it for?&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Me, I'm on the fence. I can afford it, but then I probably wouldn't be able to afford something else. And I'm a programmer...I want to be able to put my own apps on the device (or give apps to friends) without dealing with the App Store gatekeeper. In my ideal world, it would be Apple's hardware and design sensibility combined with Android's open platform and familiar runtime. Anything even close to that would outshine the iPad for me.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;Update:&lt;/i&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt; One last bit of anecdotal evidence. Before the iPhone, I had held off buying anything other than the crappiest, cheapest phones, the lowest-end music devices (yep, I had the "pack of gum" Shuffle), the most basic digital cameras, and no PDA. I was waiting for something that would allow me to get rid of all devices at once. iPhone obviously did that, as a music/media player, internet device, PDA, phone, and camera all in one. iPad takes two of those features away (phone and camera) and only adds a larger screen with the potential for large-form apps.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-4361804608832616645?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/4361804608832616645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=4361804608832616645' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/4361804608832616645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/4361804608832616645'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/01/five-reasons-to-wait-on-ipad.html' title='Five Reasons to Wait on the iPad'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-6101950269326188393</id><published>2010-01-08T14:20:00.003-06:00</published><updated>2010-01-08T17:15:49.674-06:00</updated><title type='text'>Busy Week: JRuby with Android, Maven, Rake, C exts, and More!</title><content type='html'>(How long has it been since I last blogged? Answer: a long time. I'll try to blog more frequently now that the (TOTALLY INSANE) fall conference season is over. Remind me to never have three conferences in a month ever again.)&lt;br /&gt;&lt;br /&gt;Hello friends! It's been a busy week! I thought I'd show some of what's happening with JRuby, so you know we're still here plugging away.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Android Update&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Earlier this week I helped Jan Berkel get the Ruboto IRB application working on a more recent JRuby build. There were a few minor tweaks needed, and Jan was interested in helping out, so I made the tweaks and added him as a committer.&lt;br /&gt;&lt;br /&gt;The Ruboto IRB project repository is here: &lt;a href="http://github.com/headius/ruboto-irb"&gt;http://github.com/headius/ruboto-irb&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Lately my interest in JRuby on Android has increased. I realized very recently that JRuby is just about the only mainstream JVM languge that can create *new* code while running on the device, which opens up a whole host of possibilities. It is not possible to implement an interactive shell in Groovy or Scala or Clojure, for example, since they all must first compile code to JVM bytecode, and JVM bytecode can't run on the Dalvik VM directly.&lt;br /&gt;&lt;br /&gt;As I played with Ruboto IRB this week, I discovered something even more exciting: almost all the bugs that prevented JRuby from working well in early Android releases have been solved! Specifically, the inability to reflect any android.* classes seems to be fixed in both Android 1.6 and Android 2.0.x. Why is this so cool? It's cool because with Ruboto IRB you can interactively play with almost any Android API:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.skitch.com/20100108-1nr5rj4y7dpw4spfr9sf5w3ui3.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 342px; height: 501px;" src="http://img.skitch.com/20100108-1nr5rj4y7dpw4spfr9sf5w3ui3.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This example accesses the Activity (the IRB class in Ruboto IRB), constructs a new WebView, loads some HTML into it, and (not shown) replaces the content WebView. Interactively. On the device. Awesome.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.skitch.com/20100108-dagfkf1thqktftghpnaigxhus5.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 343px; height: 501px;" src="http://img.skitch.com/20100108-dagfkf1thqktftghpnaigxhus5.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I am trusting you to not go mad with power, and to use Ruboto only for good.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;RubyGems/Maven Integration&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;JRuby has always been a Ruby implementation first, and as a result we've often neglected Java platform integration. But with Ruby 1.8.7 compatibility very solid and Ruby 1.9 work under way, we've started to turn our attentions toward Java again.&lt;br /&gt;&lt;br /&gt;One of the key areas for language integration is tool support. And for Java developers, tool support invariably involves Maven.&lt;br /&gt;&lt;br /&gt;About a year ago, I started a little project to turn Maven artifacts into RubyGems. The mapping was straightforward: both have dependencies, a name, a description, a unique identifier, version numbers, and a standard file format for describing a given package. The maven_gem project was my proof-of-concept that it's possible to merge the two worlds.&lt;br /&gt;&lt;br /&gt;The maven_gem repository is here: &lt;a href="http://github.com/jruby/maven_gem"&gt;http://github.com/jruby/maven_gem&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The project sat mostly dormant until I circled back to it this fall. But once I got the guys from Sonatype involved (purveyors of the Nexus Maven server) things really got interesting.&lt;br /&gt;&lt;br /&gt;Thanks to Tamas Cservenak from Sonatype, we now have something once thought impossible: full RubyGems integration of all the Maven artifacts in the world!&lt;br /&gt;&lt;br /&gt;The Nexus RubyGems support repository is here: &lt;a href="http://github.com/cstamas/nexus-ruby-support/"&gt;http://github.com/cstamas/nexus-ruby-support/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ gem install com.lowagie.itext-rtf&lt;br /&gt;Successfully installed bouncycastle.bcmail-jdk14-138-java&lt;br /&gt;Successfully installed bouncycastle.bcprov-jdk14-138-java&lt;br /&gt;Successfully installed bouncycastle.bctsp-jdk14-138-java&lt;br /&gt;Successfully installed com.lowagie.itext-rtf-2.1.7-java&lt;br /&gt;4 gems installed&lt;br /&gt;Installing ri documentation for bouncycastle.bcmail-jdk14-138-java...&lt;br /&gt;Installing ri documentation for bouncycastle.bcprov-jdk14-138-java...&lt;br /&gt;Installing ri documentation for bouncycastle.bctsp-jdk14-138-java...&lt;br /&gt;Installing ri documentation for com.lowagie.itext-rtf-2.1.7-java...&lt;br /&gt;Installing RDoc documentation for bouncycastle.bcmail-jdk14-138-java...&lt;br /&gt;Installing RDoc documentation for bouncycastle.bcprov-jdk14-138-java...&lt;br /&gt;Installing RDoc documentation for bouncycastle.bctsp-jdk14-138-java...&lt;br /&gt;Installing RDoc documentation for com.lowagie.itext-rtf-2.1.7-java...&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here's a an example of a full session, where I additionally install Rhino and then use it from IRB: &lt;a href="http://gist.github.com/271764"&gt;http://gist.github.com/271764&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I should reiterate what this means for JRuby users: as of JRuby 1.5, you'll be able to install or use in dependencies any Java library ever published to the public Maven repository. In short, you now have an additional 60000-some libraries at your fingertips. Awesome, no?&lt;br /&gt;&lt;br /&gt;There are some remaining issues to work through, like the fact that RubyGems itself chokes on that many gems when generating indexes, but there's a test server up and working. We'll get all the issues resolved by the time we release JRuby 1.5 RC1. Jump on the JRuby mailing list if you're like to discuss this new capability.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Rake? Ant? Why not Both?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another item on the integration front is Tom Enebo's work on providing seamless two-way integration of Rake (Ruby's build tool) and Ant. There's three aspects to Rake/Ant integration:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Using Rake tasks from Ant and Ant tasks from Rake&lt;/li&gt;&lt;li&gt;Calling Rake targets from Ant and Ant targets from Rake&lt;/li&gt;&lt;li&gt;Mixed build systems with part in Rake and part in Ant&lt;/li&gt;&lt;/ul&gt;Tom's work so far has focused on the first bullet, but the other two will come along as well. You'll be able to translate your Ant script to Rake and have it work without modification, call out to Rake from Ant, include a Rakefile in Ant and use its targets, and so on.&lt;br /&gt;&lt;br /&gt;Here's an example of pulling in a build.xml file, depending on its targets, and calling Ant tasks from Rake:&lt;br /&gt;&lt;pre&gt;require 'ant'&lt;br /&gt;&lt;br /&gt;ant.load 'build.xml' # defines tasks :mkdir + :setup in ant!&lt;br /&gt;&lt;br /&gt;task :compile =&gt; [:mkdir, :setup] do&lt;br /&gt;  ant.javac(:srcdir =&gt; src_dir, :destdir =&gt; "./build/classes") do&lt;br /&gt;    classpath :refid =&gt; "project.class.path" &lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Ideally we'll cover all possible integration scenarios, and finally blur the lines between Rake and Ant. And we'll be able to move JRuby's build into Rake, which will make all of us very happy. Look forward to this in JRuby 1.5 as well.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The C Extension Question&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One aspect of Ruby itself that we've punted on is support for Ruby's C extension API. We haven't done that to spite C extension users or developers--far from it...we'd love to flip a switch and have C extensions magically work. The problem is that Ruby's C API provides too-invasive access to the internals of objects, and there's just no way we can support that sort of access without incurring a massive overhead (because we'd have to copy stuff back and forth for every operation).&lt;br /&gt;&lt;br /&gt;But there's another possibility we've started to explore: supporting only a "safe" subset of the Ruby C API, and providing a few additional functions to replace the "unsafe" invasive bits. To that end, we (as in Wayne Meissner, creator of the FFI implementations for JRuby and Ruby) have cleaned up and published a C extension API shim library to Github.&lt;br /&gt;&lt;br /&gt;The JRuby C extension shim library repository is here: &lt;a href="http://github.com/wmeissner/jruby-cext"&gt;http://github.com/wmeissner/jruby-cext&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Last night I spent some time getting this building and working on OS X, and to my surprise I was able to get a (very) trivial C extension to work!&lt;br /&gt;&lt;br /&gt;Here's the part in C. Note that this is identical to what you'd write if you were implementing the extension for Ruby:&lt;br /&gt;&lt;pre&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;ruby.h&amp;gt;&lt;br /&gt; &lt;br /&gt;VALUE HelloModule = Qnil;&lt;br /&gt;VALUE HelloClass = Qnil;&lt;br /&gt; &lt;br /&gt;VALUE say_hello(VALUE self, VALUE hello);&lt;br /&gt;VALUE get_hello(VALUE self);&lt;br /&gt; &lt;br /&gt;void&lt;br /&gt;Init_defineclass()&lt;br /&gt;{&lt;br /&gt;    HelloClass = rb_define_class("Hello", rb_cObject);&lt;br /&gt;    rb_define_method(HelloClass, "get_hello", get_hello, 0);&lt;br /&gt;    rb_define_method(HelloClass, "say_hello", say_hello, 1);&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;VALUE&lt;br /&gt;say_hello(VALUE self, VALUE hello)&lt;br /&gt;{&lt;br /&gt;    return Qnil;&lt;br /&gt;}&lt;br /&gt;VALUE&lt;br /&gt;get_hello(VALUE self)&lt;br /&gt;{&lt;br /&gt;    return rb_str_new2("Hello, World");&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Here's the little snippit of Ruby code that loads and calls it. Note that the ModuleLoader logic would be hidden behind require/load in a final version of the C extension support.&lt;br /&gt;&lt;pre&gt;require 'java'&lt;br /&gt; &lt;br /&gt;m = org.jruby.cext.ModuleLoader.new&lt;br /&gt;m.load(self, "defineclass")&lt;br /&gt; &lt;br /&gt;h = Hello.new&lt;br /&gt;puts "Hello.new returned #{h.inspect}"&lt;br /&gt;puts "h.get_hello returns #{h.get_hello}"&lt;/pre&gt;&lt;br /&gt;Among the C API pieces we probably won't ever support are things like RSTRING, RARRAY, RHASH that give direct access to string, array, and hash internals, anything dealing with Ruby's threads or runtime, and so on. Basically the pieces that don't fit well into JNI (the Java VM C API) would not be supported.&lt;br /&gt;&lt;br /&gt;It's also worth mentioning that this is really a user-driven venture. If you are interested in a C extension API for JRuby, then you'll need to help us get there. Not only are we plenty busy with Java and Ruby support, we are also not extension authors ourselves. Have a look at the repository, hop on the JRuby dev list, and we'll start collaborating.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;JRuby in 2010&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There's a lot more coming for JRuby in 2010. We're going to finally let you create "real" Java classes from Ruby code that you can compile against, serialize, annotate, and specify in configuration files. We're going to offer JRuby development support to help prioritize and accelerate bug fixes for commercial users that really need them. We're going to have a beautiful, simple deployment option in Engine Yard Cloud, with fire-and-forget for your JRuby-based applications (including any non-Ruby libraries and code you might use like Java, Scala or Clojure). And we're going to finally publish a JRuby book, with all the walkthroughs, reference material, and troubleshooting tips you'll need to adopt JRuby today.&lt;br /&gt;&lt;br /&gt;It's going to be a great year...and a lot of fun.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-6101950269326188393?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/6101950269326188393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=6101950269326188393' title='27 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/6101950269326188393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/6101950269326188393'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2010/01/busy-week-jruby-with-android-maven-rake.html' title='Busy Week: JRuby with Android, Maven, Rake, C exts, and More!'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>27</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-2414424309867359514</id><published>2009-10-31T12:48:00.005-05:00</published><updated>2009-11-01T01:44:57.467-05:00</updated><title type='text'>Missed RubyConf? Attend Qcon's Ruby Track!</title><content type='html'>This year, RubyConf reportedly reduced their attendee cap to 250 people (&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Update:&lt;/span&gt;&lt;/span&gt; actually 450 people), after hosting a 500 to 600-person conference last year. As you can imagine, this meant a lot of people that wanted to attend were not able to get tickets. To complicate matters, the RubyConf registration site happened to go live during the middle of the night EU time, and by the time most Europeans woke up it was already sold out. &lt;span style="font-weight:bold;"&gt;What's a Rubyist to do?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Well there's another option. Working with Ryan Slobojan of InfoQ and the organizers of Qcon San Francisco,&lt;span style="font-weight:bold;"&gt; I'll be hosting a one-day Ruby track the day before RubyConf!&lt;/span&gt; Qcon's main conference runs Wednesday through Friday, with my track on &lt;span style="font-weight:bold;"&gt;Wednesday, November 18th&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;And now the REALLY good news! Because we wanted this to be a fallback for folks that could not attend RubyConf, we realized that the full conference fee was simply too high (ranging from $1500 up). So to make it possible for people to attend just the one day Ruby track, you can register with the code "rubywednesday" to get a drastically reduced &lt;span style="font-weight:bold;"&gt;$350 one-day conference pass&lt;/span&gt;. And to sweeten the deal even more, you can pop over to other tracks and attend the keynotes that day. Yes Virginia, there is a Santa Claus!&lt;br /&gt;&lt;br /&gt;Those of you attending RubyConf are also welcome to attend this one-day track as well; most of the presentations won't overlap. &lt;span style="font-weight:bold;"&gt;&lt;a href="http://qconsf.com/sf2009/tracks/show_track.jsp?trackOID=318"&gt;Here's the lineup&lt;/a&gt;&lt;/span&gt;, including a special opening presentation by Yukihiro Matsumoto himself!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;10:20 - "The Many Facets of Ruby" track opening by me&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;Ruby has seen a dramatic growth in popularity over the last few years, and there are now many facets to the Ruby story - multiple implementations, game-changing web frameworks, and large-scale use in enterprise solutions. Join us as we explore many aspects of Ruby in today's world.&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;10:30 - "Why we love Ruby?" by Yukihiro Matsumoto&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;Why we love Ruby? I have asked myself this question repeatedly. In this presentation, I will disclose my answer as of 2009. The keyword is QWAN.&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;11:45 - "Basking in the Limelight" by Paul Pagel&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;Limelight is Ruby on the desktop.  Build applications with multiple windows, or just one window.  Take control of the desktop, or play nicely with the desktop.  Create fun animated games, or productive business apps.  Develop rich internet applications, or unwired apps to make you rich.  Publish your apps on the internet, or keep them for you and your friends.   Do all this, writing nothing but Ruby code, in Limelight.&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;13:45 - "You've Got Java in my Ruby" by Thomas Enebo&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;JRuby is now well-established as a popular alternative implementation of Ruby.But why would you want to use it? How can it help you? This talk will detail some of the more interesting differences and advantages of using JRuby. Expect to get a better understanding of how Java makes a faster and more stable Ruby as well as how you can leverage Java features as an extra set of tools for your project.&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;15:00 - "Rails 3" by Yehuda Katz&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;I don't have a full abstract for this, but it's what you might expect...an overview of why Rails 3 is really "growing up" the framework, making it more clearly componentized and easier to adapt to more complicated (dare I say "enterprise") applications in the future. In working with Yehuda I know he's also paid special attention to performance.. Rails 3 is going to be excellent.&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;16:30 - "Rails in the Large: How Agility Allows Us to Build One of the World's Biggest Rails Apps" by Neal Ford&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;While others have been debating whether Rails can scale to enterprise levels, we've been demonstrating it. ThoughtWorks is running one of the largest Rails projects in the world, for an Enterprise. This session discusses tactics, techniques, best practices, and other things we've learned from scaling rails development. I discuss infrastructure, testing, messaging, optimization, performance, and the results of lots of lessons learned, including killer rock-scissors-paper tricks to help you avoid babysitting the view tests!&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I think it's going to an outstanding track, and I'd probably pay the $350 just to see Matz speak if I knew I wouldn't get another chance for a long time. &lt;span style="font-weight:bold;"&gt;Limelight&lt;/span&gt; looks like an outstanding way to build&lt;span style="font-weight:bold;"&gt; rich client apps&lt;/span&gt; using JRuby, and of course you know I like JRuby. Tom will show some of the latest advancements we've done in JRuby, including the ability to produce &lt;span style="font-weight:bold;"&gt;"real" Java classes&lt;/span&gt; at runtime for integrating with Java frameworks better. &lt;span style="font-weight:bold;"&gt;Rails 3&lt;/span&gt; I've described above, but you really have to see Yehuda present it himself. And of course everyone would like to know how to &lt;span style="font-weight:bold;"&gt;scale Rails to the moon&lt;/span&gt;...Neal knows his stuff.&lt;br /&gt;&lt;br /&gt;Here's the track page: &lt;a href="http://qconsf.com/sf2009/tracks/show_track.jsp?trackOID=318"&gt;The Many Facets of Ruby&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And the &lt;a href="http://qconsf.com/sf2009/schedule/wednesday.jsp"&gt;full conference schedule for Wednesday&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;And finally, the &lt;a href="http://qconsf.com/sf2009/registration/"&gt;registration page&lt;/a&gt; (don't forget to use code "rubywednesday").&lt;br /&gt;&lt;br /&gt;I really hope to see you all there, so you can get your Ruby conference fix this fall. &lt;span style="font-weight:bold;"&gt;Tell your friends&lt;/span&gt; and let me know if you have any questions!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-2414424309867359514?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/2414424309867359514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=2414424309867359514' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2414424309867359514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2414424309867359514'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/10/missed-rubyconf-attend-qcons-ruby-track.html' title='Missed RubyConf? Attend Qcon&apos;s Ruby Track!'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-4227112972393354416</id><published>2009-09-11T11:58:00.004-05:00</published><updated>2009-09-11T14:54:09.971-05:00</updated><title type='text'>Announcing JRubyConf 2009</title><content type='html'>Good news everybody! We're finally going to have JRubyConf!&lt;br /&gt;&lt;br /&gt;After over 3 years of heavy development, dozens of deployments and hundreds of users, it's time for a conference for JRuby users. We've talked about it on the JRuby mailing lists, polled users, and seen other JRubyists do the same. And the chorus slowly grew: you all wanted JRubyConf more and more.&lt;br /&gt;&lt;br /&gt;Now, thanks to &lt;a href="http://www.engineyard.com"&gt;Engine Yard&lt;/a&gt;, who's producing the conference, and to sponsors &lt;a href="http://edgecase.com/home"&gt;EdgeCase&lt;/a&gt; and &lt;a href="http://www.thoughtworks.com/"&gt;ThoughtWorks&lt;/a&gt;, we'll host the first ever JRubyConf the day after RubyConf, on Sunday November 22nd. This should allow folks attending RubyConf to also attend JRubyConf and not have to schedule a separate trip.&lt;br /&gt;&lt;br /&gt;So here's the details:&lt;br /&gt;&lt;blockquote&gt;What: JRubyConf 2009 (the first ever!)&lt;br /&gt;When: Sunday, November 22nd; the day after RubyConf 2009&lt;br /&gt;Where: Same hotel as RubyConf, the Embassy Suites at San Francisco Airport. You don't even have to switch locations!&lt;br /&gt;Why: Because we love you!&lt;br /&gt;Price: &lt;b&gt;FREE!!!&lt;/b&gt;&lt;br /&gt;&lt;/blockquote&gt;We've been putting together a wide range of talks and speakers, from the JRuby core team members to real-world users; from the latest on deploying Rails to gaming and desktop development. It's going to be a fast-paced event with something for everyone, and best of all, it's &lt;span style="font-weight: bold;"&gt;FREE!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Space is limited for the event, and you will have to register separately from RubyConf to secure your seat (but you don't have to go to RubyConf to attend JRubyConf!). Check out &lt;a href="http://www.jrubyconf.com/"&gt;www.jrubyconf.com&lt;/a&gt; for information, registration, and so on, and be quick about it!&lt;br /&gt;&lt;br /&gt;See you at JRubyConf 2009!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-4227112972393354416?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/4227112972393354416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=4227112972393354416' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/4227112972393354416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/4227112972393354416'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/09/announcing-jrubyconf-2009.html' title='Announcing JRubyConf 2009'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-5872747522426190002</id><published>2009-08-26T03:52:00.003-05:00</published><updated>2009-08-26T04:30:15.353-05:00</updated><title type='text'>Introducing Surinx</title><content type='html'>In June of this year, I spent a few hours formulating a dynamic cousin to &lt;a href="http://blog.headius.com/2008/08/duby-update.html"&gt;Duby&lt;/a&gt;. Duby, if you don't remember, is a static-typed language with Ruby's syntax and Java's type system. Duby supports all Ruby's literals, uses local type inference (only argument types *must* be declared), and runs as fast as Java (because it produces nearly identical bytecode). But with the advent of invokedynamic, Duby needed a playmate.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Enter "Juby". Juby is intended to be basically like Duby, in that it uses Java's types and Ruby's syntax. But it takes advantage of the new invokedynamic opcode to be 100% dynamic. Juby is a dynamic Duby, or perhaps a dynamic Java with Ruby syntax. It's not hard to comprehend.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But the name was a problem. Juby sounds like "Jewbie", a pejorative term for a Jewish person. So I sent out a call for names to the Twitterverse, ultimately ending up with far more names than I could choose from.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The name I have chosen, &lt;a href="http://github.com/headius/surinx/tree/master"&gt;Surinx&lt;/a&gt;, has a simple story attached. You see, when James Gosling created Java, he originally named it "Oak", after the tree outside his window. So I followed his lead; the tree (a bush, really) outside my window is a lilac, &lt;i&gt;Syringa vulgaris&lt;/i&gt;. The genus "Syringa" is derived from New Latin, based on a Greek word "surinx" meaning "shepherd's pipe" from the use of the &lt;i&gt;Syringa&lt;/i&gt; plant's hollow stems to make pipes. Perhaps Surinx is building on the "hollow stem" of the JVM to produce something you can smoke (other dynamic languages) with. Combined with its cousin "Duby", we have quite a pair.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And in other news, the simple Surinx implementation of "fib" below (identical to Ruby) manages to run fib(40) in only 7 seconds on current MLVM (OpenJDK7 + invokedynamic and other tidbits), a five-fold improvement over JRuby's fastest mode (jruby --fast).&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;def fib(a)&lt;br /&gt;  if a &lt; 2&lt;br /&gt;    a&lt;br /&gt;  else&lt;br /&gt;    fib(a - 1) + fib(a - 2)&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Given that JRuby has started to support invokedynamic, the solid performance of Surinx bodes very well for JRuby's future.&lt;br /&gt;&lt;br /&gt;Please welcome &lt;a href="http://github.com/headius/surinx/tree/master"&gt;Surinx&lt;/a&gt; to your language repertoire!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-5872747522426190002?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/5872747522426190002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=5872747522426190002' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5872747522426190002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5872747522426190002'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/08/introducing-surinx.html' title='Introducing Surinx'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-1228106860484681296</id><published>2009-08-02T23:35:00.004-05:00</published><updated>2009-08-03T08:11:12.779-05:00</updated><title type='text'>Which Deployment for JRuby on Rails?</title><content type='html'>We often get the question "which deployment option is the best for JRuby on Rails?" The truth is that it depends on what you need out of deployment.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you have a fairly straightforward Rails app without a lot of service dependencies and a greenfield deployment target, your best bet is probably the GlassFish gem right now. It performs really well, can handle high loads and high concurrency, and automatically detects Rails' threadsafe mode, scaling better when it's turned on. I'm no longer a Sun employee, and I still think the GF gem is an outstanding piece of work. Here's my howto on &lt;a href="http://blog.headius.com/2009/04/apache-jruby-rails-glassfish-easy.html"&gt;GF gem + JRuby on Rails + Apache&lt;/a&gt;. &lt;b&gt;&lt;i&gt;Update&lt;/i&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;: Here's information on &lt;a href="http://blogs.sun.com/Jacobkessler/entry/capistrano_and_glassfish_now_with"&gt;using Capistrano with the GlassFish gem&lt;/a&gt;.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you have an existing Java EE or web container like Tomcat, JBoss, GlassFish, WebLogic, or WebSphere, you want to look into Warbler. Warbler packages your application as a .war file, suitable for deployment on any of these standard servers. The &lt;a href="http://kenai.com/projects/warbler/pages/Home"&gt;Warbler wiki&lt;/a&gt; is the best place to learn about deploying with Warbler.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you're looking for something that's somewhat greenfield but also needs more advanced services like scheduled asynchronous jobs, web services, and some level of EE integration, you should look at &lt;a href="http://torquebox.org/"&gt;JBoss's TorqueBox&lt;/a&gt;, a customized JBoss specially tailored for deployment of Rack-based apps (like Rails) on JRuby.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you're looking for a hosting provider that can take your app and make it "just work", then you should look into &lt;a href="http://www.engineyard.com/jruby-cloud"&gt;Engine Yard's JRuby cloud offering&lt;/a&gt;. We don't yet have it 100% ready to go, but it won't be long and it will be fantastic. For now you can give us some direction and input on what that hosting/cloud should look like.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All told, there's a lot of great options for JRuby deployment, and no one of them is going to be perfect for everyone. Choose wisely, and join the &lt;a href="http://kenai.com/projects/jruby/pages/MailingLists"&gt;JRuby mailing lists&lt;/a&gt; if you have questions.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-1228106860484681296?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/1228106860484681296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=1228106860484681296' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1228106860484681296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1228106860484681296'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/08/which-deployment-for-jruby-on-rails.html' title='Which Deployment for JRuby on Rails?'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-3512263538148607036</id><published>2009-08-01T23:52:00.004-05:00</published><updated>2009-08-02T14:07:06.391-05:00</updated><title type='text'>Return of Ruboto!</title><content type='html'>It's been a while since I was able to work on JRuby's Android support, but tonight I managed to finally circle back. And I've got something much more impressive working today: a real IRB application!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3568/3780201678_f126a812bb_o_d.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 380px; height: 730px;" src="http://farm4.static.flickr.com/3568/3780201678_f126a812bb_o_d.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(And yes, this works just fine on the phone too)&lt;br /&gt;&lt;br /&gt;It turned out to be incredibly easy to get this working. I'm not using any stinking plugin because they all seemed to just get in my way. So I generated a dummy application using the "android" tool, dropped the jruby jar in "libs", wrote up a quick interactive console, built and signed it, and that's all there was to it.&lt;br /&gt;&lt;br /&gt;JRuby turns out to work very well for this sort of thing because we have an interpreter, so we can parse and execute code dynamically. Hooray for interpreted support!&lt;br /&gt;&lt;br /&gt;I had to tweak a couple things to work around shortcomings in Android:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I had to edit the dx tool to allow up to a 1024M heap, since JRuby's jar has a ton of stuff in it&lt;/li&gt;&lt;li&gt;I had to catch and swallow an ArrayIndexOutOfBounds exception coming out of Dalvik's enum support. Bug!&lt;/li&gt;&lt;/ul&gt;This is of course a proof-of-concept. Writing full applications in Ruby isn't far behind, but we'll need a couple adjustments to JRuby to support it well:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Ability to run 100% precompiled with no runtime code generation&lt;/li&gt;&lt;li&gt;Strip out parser, interpreter, compiler, and bytecode-generation bits to shrink the jar&lt;/li&gt;&lt;li&gt;Tidy up the AOT compiler and wire it into the app build process&lt;/li&gt;&lt;li&gt;Generate some Ruby stub logic for the Android APIs, so they'll work well from Ruby&lt;/li&gt;&lt;li&gt;Strip down the weirder and wilder Ruby features (eval, etc) to allow fastest-possible execution&lt;/li&gt;&lt;/ul&gt;I know how to do all of this.&lt;br /&gt;&lt;br /&gt;I've pushed &lt;a href="http://github.com/headius/ruboto-irb/tree/master"&gt;ruboto-irb&lt;/a&gt; to Github so you can check it out and play with it. I welcome contributors :)&lt;br /&gt;&lt;br /&gt;Ruboto lives!&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;b&gt;Update:&lt;/b&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt; Good news, everyone!&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt;First, the two bugs I've encountered have both been previously reported and are due to be fixed in an upcoming Android release. They are the &lt;a href="http://code.google.com/p/android/issues/detail?id=2497"&gt;enum bug&lt;/a&gt; and the &lt;a href="http://code.google.com/p/android/issues/detail?id=2812"&gt;reflection bug&lt;/a&gt;.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Second, someone going by the handle of "Psycho" reports in the comments that the next version of the Android Scripting Environment (ASE) will include JRuby support! Of course I'm interested in more than just scripting applications with JRuby...I'd like to be able to write applications using only Ruby code, so I'll continue working on this. But JRuby support seems to be coming in from all directions.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-3512263538148607036?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/3512263538148607036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=3512263538148607036' title='29 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/3512263538148607036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/3512263538148607036'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/08/return-of-ruboto.html' title='Return of Ruboto!'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>29</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-3829877680628519858</id><published>2009-07-28T09:08:00.003-05:00</published><updated>2009-07-28T09:19:04.325-05:00</updated><title type='text'>JVM Language Summit Call for Participation</title><content type='html'>I should have blogged this sooner, but things have been a little...crazy...lately.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The JVM Languages Summit is coming up for its second year. The event last year was spectacular; representatives of all the major languages and several minor ones showed up and talked about their plans, their history, and their desires from the JVM. And JVM engineers from the three major vendors (Sun, IBM, Oracle) sat there and dutifully took notes. It was a great meeting of minds, and an incredibly uplifting event for those of us invested in the JVM.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's also not just an event for implementers; if you're keen on the nitty-gritty details of JVM languages and want to help improve them, promote them, or otherwise relate to them in some way, you should be here.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hope to see you at the Summit!&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;=== CALL FOR PARTICIPATION -- JVM LANGUAGE SUMMIT, September 2009 ===&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jvmlangsummit.com/"&gt;http://jvmlangsummit.com/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Dear colleague;&lt;br /&gt;&lt;br /&gt;We are pleased to announce the the 2009 JVM Language Summit to be held at Sun's Santa Clara campus on September 16-18, 2009.  Registration is now open for speaker submissions (presentations and workshops) and general attendance.&lt;br /&gt;&lt;br /&gt;The JVM Language Summit is an open technical collaboration among language designers, compiler writers, tool builders, runtime engineers, and VM architects. We will share our experiences as creators of programming languages for the JVM and of the JVM itself.  We also welcome non-JVM developers on similar technologies to attend or speak on their runtime, VM, or language of choice.&lt;br /&gt;&lt;br /&gt;The format this year will be slightly different from last year.  Attendees told us that the most successful interactions came from small discussion groups rather than prepared lectures, so we've divided the schedule equally between traditional presentations (we're limiting most presentations to 30 minutes this year) and "Workshops".  Workshops are informal, facilitated discussion groups among smaller, self-selected participants, and should enable "deeper dives" into the subject matter.  There will also be impromptu "lightning talks".&lt;br /&gt;&lt;br /&gt;We encourage speakers to submit both a presentation and a workshop; we will arrange to schedule the presentation before the workshop, so that the presentation can spark people's interest and the workshop will allow those who are really interested to go deeper into the subject area.  Workshop facilitators may, but are not expected to, prepare presentation materials, but they should come prepared to guide a deep technical discussion.&lt;br /&gt;&lt;br /&gt;The Summit is being organized by the JVM Engineering team; no managers or marketers involved!  So bring your slide rules and be prepared for some seriously geeky discussions.&lt;br /&gt;&lt;br /&gt;The registration page is now open at:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://registration.jvmlangsummit.com/"&gt;http://registration.jvmlangsummit.com/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you have any questions, send inquiries to &lt;a href="mailto:inquire@jvmlangsummit.com"&gt;inquire@jvmlangsummit.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;We hope to see you in September!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-3829877680628519858?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/3829877680628519858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=3829877680628519858' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/3829877680628519858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/3829877680628519858'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/07/jvm-language-summit-call-for.html' title='JVM Language Summit Call for Participation'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-8442900577419001024</id><published>2009-07-27T11:48:00.004-05:00</published><updated>2009-07-27T12:10:37.823-05:00</updated><title type='text'>JRuby's Importance to Ruby, and eRubyCon 2009</title><content type='html'>I'm going to be speaking about JRuby again this year at &lt;a href="http://erubycon.com/"&gt;eRubyCon&lt;/a&gt;, in Columbus OH. I just got back from &lt;a href="http://rails-underground.com"&gt;Rails Underground&lt;/a&gt;, which reminded me how much I love the smaller regional Ruby conferences. So I'm totally pumped to go to eRubyCon this year.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The idea of "Enterprise Ruby" has become less repellant since Dave Thomas's infamous keynote at RalsConf 2006. There are a lot of large, lumbering organizations out there that have yet to adopt any of the newer agile language/framework combinations, and Rails has most definitely led the way. I personally believe that in order for Ruby to become more than just a nice language with a great community, it needs to gain adoption in those organizations, and it needs to do it damn quickly. JRuby is by far the best way for that to happen.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's another aspect to adoption I think has escaped a lot of Rubyists. In 2006 and 2007, Ruby gained a lot of Java developers who were running away from bloated, over-complicated frameworks and the verbosity and inelegance of Java. When I asked at Ruby conferences in 2005, 2006, and 2007 how many people had done Java development in a former life, almost everyone in the room raised their hands. When I've asked the same question in 2008 and 2009, it's down to less than half the room. Where did they go?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The truth is that the Java platform now has reasonably good answers to Ruby in Groovy, Scala, and Clojure, and reasonably good answers to Rails in Grails and Lift. And yet many Rubyists don't realize how important it is for JRuby to continue doing well, many still seeing it as simply "nice to have" while dismissing the entirety of the Java platform as unimportant to Ruby's future. It's an absurd position, but I blame myself for not making this case sooner.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I believe that JRuby is the most crucial technology for Ruby's future right now. Regardless of how fast or how solid the C or C++ based Ruby implementations get, the vast majority of large organizations are *never* going to run them. That's the truth. If we can leverage JRuby to grab 1-2% of the Java market, we'll *double* the size of the Ruby community. If we completely lose the Java platform to alternatives, Rubyists may not have the luxury of remaining Rubyists in the future. It's that big a deal.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I hope you'll come by &lt;a href="http://erubycon.com/"&gt;eRubyCon&lt;/a&gt; and hear what we've been working on in JRuby and what we have planned for the future, especially our work on making JRuby a stronger JVM citizen. I'm certain to expand on the Hibernate-based prototype code I showed at Rails Underground, and hope to have some additional, never-before-seen demonstrations that will shock and amaze you. And if there's time, I'll demonstrate my two research pets, the "Ruby Mutant" twins Duby and Juby.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;See you there!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-8442900577419001024?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/8442900577419001024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=8442900577419001024' title='32 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/8442900577419001024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/8442900577419001024'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/07/jrubys-importance-to-ruby-and-erubycon.html' title='JRuby&apos;s Importance to Ruby, and eRubyCon 2009'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>32</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-5828492447291772752</id><published>2009-05-31T17:40:00.005-05:00</published><updated>2009-05-31T18:45:24.880-05:00</updated><title type='text'>Your JavaOne 2009 Ruby Guide</title><content type='html'>Here's a list of talks about Ruby or that mention/relate to Ruby at &lt;a href="http://developers.sun.com/events/communityone/2009/west/index.jsp"&gt;CommunityOne&lt;/a&gt; and &lt;a href="http://java.sun.com/javaone/"&gt;JavaOne&lt;/a&gt; 2009. Some of these are about other languages, since I just did a dumb search for any mention of "ruby".&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Add your suggestions in comments to help narrow down which talks people should go see.&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;CommunityOne:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;table width="748.0" cellspacing="0" cellpadding="0" style="width: 748.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="middle" style="width: 65.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;S304128&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 277.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial; color: #5851bc"&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=308513&amp;ilocation_id=230-1&amp;ilanguage=english');"&gt;Developing on the OpenSolaris™Operating System&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle"  style="width: 138.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border- padding: 6.0px 6.0px 6.0px 6.0pxcolor:#808080 #808080 #808080 #808080;"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial"&gt;&lt;span style="color:#5851bc;"&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=308513&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=43393');"&gt;David Miner&lt;/a&gt;&lt;/span&gt;, Sun Microsystems; &lt;a href="javascript:newWnd('speaker_details.jsp?isid=308513&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=54823');"&gt;&lt;span style="color:#5851bc;"&gt;Nicholas Solter&lt;/span&gt;&lt;/a&gt;, Sun Microsystems&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Monday &lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;June 01&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;10:50 AM - 11:40 AM&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Esplanade 305&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td valign="middle" style="width: 65.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;S307894&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 277.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial; color: #5851bc"&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=307894&amp;ilocation_id=230-1&amp;ilanguage=english');"&gt;Sun GlassFish™ Portfolio: Where Sun's Application Platform Is Going&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle"  style="width: 138.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border- padding: 6.0px 6.0px 6.0px 6.0pxcolor:#808080 #808080 #808080 #808080;"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial"&gt;&lt;span style="color:#5851bc;"&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=307894&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=16479');"&gt;Eduardo Pelegri-Llopart&lt;/a&gt;&lt;/span&gt;, Sun Microsystems, Inc.&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Monday &lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;June 01&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;10:50 AM - 11:40 AM&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Hall E 135&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td valign="middle" style="width: 65.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;S304001&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 277.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial; color: #5851bc"&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=307144&amp;ilocation_id=230-1&amp;ilanguage=english');"&gt;Pragmatic Identity 2.0: Invoking Identity Services with a Simplified REST/ROA Architecture&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle"  style="width: 138.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border- padding: 6.0px 6.0px 6.0px 6.0pxcolor:#808080 #808080 #808080 #808080;"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial"&gt;&lt;span style="color:#5851bc;"&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=307144&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=24820');"&gt;Pat Patterson&lt;/a&gt;&lt;/span&gt;, Sun Microsystems, Inc.; &lt;a href="javascript:newWnd('speaker_details.jsp?isid=307144&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=57519');"&gt;&lt;span style="color:#5851bc;"&gt;Daniel Raskin&lt;/span&gt;&lt;/a&gt;, Sun Microsystems, Inc.; &lt;a href="javascript:newWnd('speaker_details.jsp?isid=307144&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=15972');"&gt;&lt;span style="color:#5851bc;"&gt;Ron Ten-Hove&lt;/span&gt;&lt;/a&gt;, Sun Microsystems, Inc.&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Monday &lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;June 01&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;11:50 AM - 12:40 PM&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Gateway 102-103&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td valign="middle" style="width: 65.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;S304141&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 277.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial; color: #5851bc"&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=307153&amp;ilocation_id=230-1&amp;ilanguage=english');"&gt;Programming Languages and the Cloud&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle"  style="width: 138.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border- padding: 6.0px 6.0px 6.0px 6.0pxcolor:#808080 #808080 #808080 #808080;"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial"&gt;&lt;span style="color:#5851bc;"&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=307153&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=58459');"&gt;Ted Leung&lt;/a&gt;&lt;/span&gt;, Sun Microsystems, Inc.&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Monday &lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;June 01&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;11:50 AM - 12:40 PM&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Gateway 104&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td valign="middle" style="width: 65.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;S304267&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 277.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial; color: #5851bc"&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=307162&amp;ilocation_id=230-1&amp;ilanguage=english');"&gt;Beyond Impossible: How JRuby Has Evolved the Java™ Platform&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 138.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border- padding: 6.0px 6.0px 6.0px 6.0pxcolor:#808080 #808080 #808080 #808080;"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial"&gt;Charles Nutter, Sun Microsystems, Inc.&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Monday &lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;June 01&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;1:40 PM - 2:30 PM&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Hall E 134&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td valign="middle" style="width: 65.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;S304040&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 277.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial; color: #5851bc"&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=307148&amp;ilocation_id=230-1&amp;ilanguage=english');"&gt;Social-Enable Your Web Apps with OpenSocial&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 138.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border- padding: 6.0px 6.0px 6.0px 6.0pxcolor:#808080 #808080 #808080 #808080;"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial; color: #5851bc"&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=307148&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=14386');"&gt;Dave Johnson&lt;/a&gt;&lt;span style="color:#000000;"&gt;, IBM&lt;/span&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Monday &lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;June 01&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;4:00 PM - 4:50 PM&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Esplanade 300&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td valign="middle" style="width: 65.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;S311290&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 277.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial; color: #5851bc"&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=311290&amp;ilocation_id=230-1&amp;ilanguage=english');"&gt;JRuby Rails Workshop&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle"  style="width: 138.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border- padding: 6.0px 6.0px 6.0px 6.0pxcolor:#808080 #808080 #808080 #808080;"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial"&gt;&lt;span style="color:#5851bc;"&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=311290&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=10415');"&gt;Arun Gupta&lt;/a&gt;&lt;/span&gt;, Sun Microsystems, Inc.; &lt;a href="javascript:newWnd('speaker_details.jsp?isid=311290&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=83029');"&gt;&lt;span style="color:#5851bc;"&gt;Jacob Kessler&lt;/span&gt;&lt;/a&gt;, Sun Microsystems; &lt;a href="javascript:newWnd('speaker_details.jsp?isid=311290&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=5234');"&gt;&lt;span style="color:#5851bc;"&gt;Vivek Pandey&lt;/span&gt;&lt;/a&gt;, Sun Microsystems, Inc.; &lt;a href="javascript:newWnd('speaker_details.jsp?isid=311290&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=55284');"&gt;&lt;span style="color:#5851bc;"&gt;Nick Sieger&lt;/span&gt;&lt;/a&gt;, Sun Microsystems, Inc&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Tuesday &lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;June 02&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;9:00 AM - 5:00 PM&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Breakout Room 7&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td valign="middle" style="width: 65.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;S311294&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 277.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial; color: #5851bc"&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=311294&amp;ilocation_id=230-1&amp;ilanguage=english');"&gt;Cloud Computing and Storage in Practice&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle"  style="width: 138.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border- padding: 6.0px 6.0px 6.0px 6.0pxcolor:#808080 #808080 #808080 #808080;"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Arial"&gt;&lt;span style="color:#5851bc;"&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=311294&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=14380');"&gt;Tim Bray&lt;/a&gt;&lt;/span&gt;, Sun Microsystems, Inc.; &lt;a href="javascript:newWnd('speaker_details.jsp?isid=311294&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=18602');"&gt;&lt;span style="color:#5851bc;"&gt;Chris Kutler&lt;/span&gt;&lt;/a&gt;, Sun Microsystems, Inc.&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Wednesday &lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;June 03&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;1:30 PM - 5:00 PM&lt;/p&gt; &lt;/td&gt; &lt;td valign="middle" style="width: 114.0px; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #808080 #808080 #808080 #808080; padding: 6.0px 6.0px 6.0px 6.0px"&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Arial"&gt;Breakout Room 2&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;JavaOne:&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="  -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:Arial;font-size:12px;"&gt;&lt;table width="750" border="1" cellspacing="0" cellpadding="3"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;PAN-5348&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=305348&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Script Bowl 2009: A Scripting Languages Shootout&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Panel Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Roberto Chinnici, Sun Microsystems, Inc.; Thomas Enebo, Sun Microsystems, Inc. ; Rich Hickey, Clojure;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=305348&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=25335');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Guillaume Laforge&lt;/a&gt;, SpringSource; Raghavan Srinivas, Self; Dick Wall , Google; Frank Wierzbicki, Sun Microsystems, Inc.&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Tuesday&lt;br /&gt;June 02&lt;br /&gt;10:50 AM - 11:50 AM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-4164&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=304164&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Clojure: Dynamic Functional Programming for the JVM™ Machine&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Rich Hickey, Clojure&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Tuesday&lt;br /&gt;June 02&lt;br /&gt;12:10 PM - 1:10 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Hall E 133&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-4487&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=304487&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;The Feel of Scala&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Bill Venners, Artima, Inc.&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Tuesday&lt;br /&gt;June 02&lt;br /&gt;3:20 PM - 4:20 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-5015&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=305015&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Welcome to Ruby&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Yehuda Katz, Engine Yard&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Tuesday&lt;br /&gt;June 02&lt;br /&gt;4:40 PM - 5:40 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-5216&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=305216&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Toward a Renaissance VM&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=305216&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=14776');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Brian Goetz&lt;/a&gt;, Sun Microsystems, Inc.; &lt;a href="javascript:newWnd('speaker_details.jsp?isid=305216&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=54163');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;John Rose&lt;/a&gt;, Sun Microsystems&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Tuesday&lt;br /&gt;June 02&lt;br /&gt;6:00 PM - 7:00 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Hall E 133&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;BOF-4434&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=304434&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Hacking JRuby&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;BOF&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Ola Bini, ThoughtWorks&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Tuesday&lt;br /&gt;June 02&lt;br /&gt;8:30 PM - 9:20 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;BOF-5058&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=305058&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;JRuby Experiences in the Real World&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;BOF&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Logan Barnett, Happy Camper Studios; David Koontz, JumpBox&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Tuesday&lt;br /&gt;June 02&lt;br /&gt;9:30 PM - 10:20 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-5413&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=305413&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;JRuby on Rails in Production: Lessons Learned from Operating a Live, Real-World Site&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=305413&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=55284');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Nick Sieger&lt;/a&gt;, Sun Microsystems, Inc&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Wednesday&lt;br /&gt;June 03&lt;br /&gt;11:05 AM - 12:05 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-4921&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=304921&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Dynamic Languages Powered by GlassFish™ Application Server v3&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=304921&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=83029');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Jacob Kessler&lt;/a&gt;, Sun Microsystems; &lt;a href="javascript:newWnd('speaker_details.jsp?isid=304921&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=5234');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Vivek Pandey&lt;/a&gt;, Sun Microsystems, Inc.&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Wednesday&lt;br /&gt;June 03&lt;br /&gt;11:05 AM - 12:05 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Hall E 133&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-4955&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=304955&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Comparing Groovy and JRuby&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Neal Ford, ThoughtWorks Inc.&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Wednesday&lt;br /&gt;June 03&lt;br /&gt;2:50 PM - 3:50 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;BOF-4682&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=304682&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Performance Comparisons of Dynamic Languages on the Java™ Virtual Machine&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;BOF&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=304682&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=82160');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Michael Galpin&lt;/a&gt;, eBay&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Wednesday&lt;br /&gt;June 03&lt;br /&gt;6:45 PM - 7:35 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Esplanade 300&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-5385&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=305385&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Alternative Languages on the JVM™ Machine&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Cliff Click, Azul Systems&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Thursday&lt;br /&gt;June 04&lt;br /&gt;9:30 AM - 10:30 AM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-4012&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=304012&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Pragmatic Identity 2.0: Simple, Open, Identity Services Using REST&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('speaker_details.jsp?isid=304012&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=24820');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Pat Patterson&lt;/a&gt;, Sun Microsystems, Inc.; &lt;a href="javascript:newWnd('speaker_details.jsp?isid=304012&amp;ilocation_id=230-1&amp;ilanguage=english&amp;icontact_id=15972');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Ron Ten-Hove&lt;/a&gt;, Sun Microsystems, Inc.&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Thursday&lt;br /&gt;June 04&lt;br /&gt;10:50 AM - 11:50 AM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Esplanade 307-310&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-4961&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=304961&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;"Design Patterns" for Dynamic Languages on the JVM™ Machine&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Neal Ford, ThoughtWorks Inc.&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Thursday&lt;br /&gt;June 04&lt;br /&gt;10:50 AM - 11:50 AM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-5354&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=305354&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Exploiting Concurrency with Dynamic Languages&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Tobias Ivarsson, Neo Technology&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Thursday&lt;br /&gt;June 04&lt;br /&gt;1:30 PM - 2:30 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-5033&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=305033&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Scripting Java™ Technology with JRuby&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Thomas Enebo, Sun Microsystems, Inc. ; Charles Nutter, Sun Microsystems, Inc.&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Thursday&lt;br /&gt;June 04&lt;br /&gt;2:50 PM - 3:50 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Gateway 104&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;center&gt;TS-3955&lt;/center&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;&lt;a href="javascript:newWnd('session_details.jsp?isid=303955&amp;ilocation_id=230-1&amp;ilanguage=english');" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; text-decoration: none; color: rgb(89, 79, 191); "&gt;Monkeybars: Tools-Enabled Swing Development with JRuby&lt;/a&gt;&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Technical Session&lt;/td&gt;&lt;td style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Logan Barnett, Happy Camper Studios; David Koontz, JumpBox&lt;/td&gt;&lt;td nowrap="" align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Friday&lt;br /&gt;June 05&lt;br /&gt;12:10 PM - 1:10 PM&lt;/td&gt;&lt;td align="center" style="font-family: Arial, Geneva, Verdana, Helvetica, sans-serif; font-size: 12px; "&gt;Esplanade 302&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-5828492447291772752?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/5828492447291772752/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=5828492447291772752' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5828492447291772752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5828492447291772752'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/05/your-javaone-2009-ruby-guide.html' title='Your JavaOne 2009 Ruby Guide'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-2476828821001508670</id><published>2009-05-14T23:46:00.002-05:00</published><updated>2009-05-15T00:09:13.742-05:00</updated><title type='text'>BiteScript 0.0.2 Scripting Examples</title><content type='html'>I just released BiteScript 0.0.2, which mainly fixes some issues defining packages and non-public classes.&lt;br /&gt;&lt;br /&gt;BiteScript is basically just a simple DSL for generating JVM bytecode. I use it in &lt;a href="http://kenai.com/projects/duby"&gt;Duby&lt;/a&gt; and now in &lt;a href="http://kenai.com/projects/ruby2java"&gt;the "ruby2java" compiler&lt;/a&gt; we'll be using to turn Ruby classes into Java classes.&lt;br /&gt;&lt;br /&gt;I've &lt;a href="http://blog.headius.com/2009/03/bitescript-001-ruby-dsl-for-jvm.html"&gt;blogged about BiteScript here before&lt;/a&gt;, 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.&lt;br /&gt;&lt;br /&gt;First, the simplest version:&lt;br /&gt;&lt;pre&gt;main do&lt;br /&gt;  ldc "Hello, world!"&lt;br /&gt;  aprintln&lt;br /&gt;  returnvoid&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;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&lt;br /&gt;&lt;pre&gt;import java.lang.System&lt;br /&gt;import java.io.PrintStream&lt;br /&gt;&lt;br /&gt;macro :aprintln do&lt;br /&gt;  getstatic System, :out, PrintStream&lt;br /&gt;  swap&lt;br /&gt;  invokevirtual PrintStream, println, [Object]&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;macro :aprint do&lt;br /&gt;  getstatic System, :out, PrintStream&lt;br /&gt;  swap&lt;br /&gt;  invokevirtual PrintStream, print, [Object]&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;main do&lt;br /&gt;  ldc "Hello, "&lt;br /&gt;  aprint&lt;br /&gt;  aload 0&lt;br /&gt;  aaload 0&lt;br /&gt;  aprintln&lt;br /&gt;  returnvoid&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;And of course this is just Ruby code, so you can just use Ruby to alter the generation of code:&lt;br /&gt;&lt;pre&gt;main do&lt;br /&gt;  5.times do&lt;br /&gt;    ldc "Wow!"&lt;br /&gt;    aprintln&lt;br /&gt;  end&lt;br /&gt;  returnvoid&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;These "BiteScripts" can all be either run with the "bite" command or compiled with the "bitec" command:&lt;br /&gt;&lt;pre&gt;$ bite examples/using_ruby.bs &lt;br /&gt;Wow!&lt;br /&gt;Wow!&lt;br /&gt;Wow!&lt;br /&gt;Wow!&lt;br /&gt;Wow!&lt;br /&gt;&lt;br /&gt;$ bitec examples/using_ruby.bs &lt;br /&gt;&lt;br /&gt;$ javap -c examples/using_ruby&lt;br /&gt;Compiled from "examples.using_ruby.bs"&lt;br /&gt;public class examples.using_ruby extends java.lang.Object{&lt;br /&gt;public static void main(java.lang.String[]);&lt;br /&gt;  Code:&lt;br /&gt;   0: ldc #9; //String Wow!&lt;br /&gt;   2: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream;&lt;br /&gt;   5: swap&lt;br /&gt;   6: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V&lt;br /&gt;   9: ldc #9; //String Wow!&lt;br /&gt;   11: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream;&lt;br /&gt;   14: swap&lt;br /&gt;   15: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V&lt;br /&gt;   18: ldc #9; //String Wow!&lt;br /&gt;   20: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream;&lt;br /&gt;   23: swap&lt;br /&gt;   24: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V&lt;br /&gt;   27: ldc #9; //String Wow!&lt;br /&gt;   29: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream;&lt;br /&gt;   32: swap&lt;br /&gt;   33: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V&lt;br /&gt;   36: ldc #9; //String Wow!&lt;br /&gt;   38: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream;&lt;br /&gt;   41: swap&lt;br /&gt;   42: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V&lt;br /&gt;   45: return&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;This last example shows the resulting JVM bytecode as well.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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&lt;br /&gt;&lt;br /&gt;And if you're not up on the JVM or JVM bytecodes, the &lt;a href="http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html"&gt;JVM Specification&lt;/a&gt; is an easy-to-read complete reference for code targeting the JVM, and here is &lt;a href="http://homepages.inf.ed.ac.uk/kwxm/JVM/home.html"&gt;my favorite JVM opcode quickref&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-2476828821001508670?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/2476828821001508670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=2476828821001508670' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2476828821001508670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2476828821001508670'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/05/bitescript-002-scripting-examples.html' title='BiteScript 0.0.2 Scripting Examples'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-5719693637392665049</id><published>2009-05-14T20:34:00.005-05:00</published><updated>2009-05-14T21:10:44.267-05:00</updated><title type='text'>Help JRuby by Fixing RubySpecs</title><content type='html'>A number of you have asked how you can help JRuby development. Well there's actually an easy way: fix &lt;a href="http://www.rubyspec.org/"&gt;RubySpec&lt;/a&gt; failures.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;1. Get a JRuby working copy and build it&lt;br /&gt;&lt;br /&gt;This is as simple as '&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git clone git://github.com/jruby/jruby.git&lt;/span&gt;', then '&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;cd jruby&lt;/span&gt;' and '&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ant&lt;/span&gt;'. You'll need &lt;a href="http://ant.apache.org/bindownload.cgi"&gt;Apache Ant 1.7&lt;/a&gt; and Java 5/1.5 or higher (grab "Java SE Development Kit" from the &lt;a href="http://java.sun.com/javase/downloads/index.jsp"&gt;Java SE downloads page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;2. Run the CI spec run&lt;br /&gt;&lt;br /&gt;We have a clean spec run that should be clean for you before you start. Just run &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;"ant spec-short&lt;/span&gt;" 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.&lt;br /&gt;&lt;br /&gt;3. Run specific spec files with bugs reported&lt;br /&gt;&lt;br /&gt;You can look in &lt;a href="http://jira.codehaus.org/secure/IssueNavigator.jspa?reset=true&amp;amp;&amp;amp;pid=11295&amp;amp;resolution=-1&amp;amp;component=13420&amp;amp;sorter/field=priority&amp;amp;sorter/order=DESC"&gt;Jira under the "RubySpec" category&lt;/a&gt;, 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 "&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bin/jruby spec/mspec/bin/mspec &amp;lt;path/to/spec/file&amp;gt;&lt;/span&gt;". For example to set the Range#initialize failures I just reported, run "&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bin/jruby spec/mspec/bin/mspec spec/ruby/core/range/initialize_spec.rb&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Now you can proceed to fixing it.&lt;br /&gt;&lt;br /&gt;4. Identify where the problem is.&lt;br /&gt;&lt;br /&gt;Most of the core classes are pretty easy to locate. Any classes in the "core" specs will have a Java class named Ruby&lt;class&gt;, 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.&lt;br /&gt;&lt;br /&gt;5. Create a patch and submit it to the bug&lt;br /&gt;&lt;br /&gt;Once you have a working fix, you can go ahead create a patch, either with "&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git diff &gt; somefile.patch&lt;/span&gt;" or by committing it to your local repository and using "&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git format-patch -1&lt;/span&gt;" to create a formatted patch for the topmost commit. Some git-fu may be necessary, so I usually just use "&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git diff&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;That's all there is to it! You'll be a JRuby contributor in no time!&lt;/class&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-5719693637392665049?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/5719693637392665049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=5719693637392665049' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5719693637392665049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5719693637392665049'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/05/help-jruby-by-fixing-rubyspecs.html' title='Help JRuby by Fixing RubySpecs'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-1215677090195335944</id><published>2009-05-14T01:50:00.003-05:00</published><updated>2010-03-07T08:51:44.108-06:00</updated><title type='text'>fork and exec on the JVM? JRuby to the Rescue!</title><content type='html'>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?"&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;pre&gt;require 'ffi'&lt;br /&gt;&lt;br /&gt;module Exec&lt;br /&gt; extend FFI::Library&lt;br /&gt;&lt;br /&gt; attach_function :my_exec, :execl, [:string, :string, :varargs], :int&lt;br /&gt; attach_function :fork, [], :int&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;vim1 = '/usr/bin/vim'&lt;br /&gt;vim2 = 'vim'&lt;br /&gt;if Exec.fork == 0&lt;br /&gt; Exec.my_exec vim1, vim2, :pointer, nil&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Process.waitall&lt;/pre&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;JRuby rocks.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;Update:&lt;/i&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt; 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.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;However, since this post I've learned of the "&lt;a href="http://www.opengroup.org/onlinepubs/009695399/functions/posix_spawn.html"&gt;posix_spawn&lt;/a&gt;" 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 &lt;a href="http://gist.github.com/321084"&gt;using Spoon to launch JRuby as a daemon&lt;/a&gt;. If you just need fork+exec on the JVM, posix_spawn or the Spoon gem are the best way to do it.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-1215677090195335944?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/1215677090195335944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=1215677090195335944' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1215677090195335944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1215677090195335944'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/05/fork-and-exec-on-jvm-jruby-to-rescue.html' title='fork and exec on the JVM? JRuby to the Rescue!'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-9198915872973128017</id><published>2009-05-13T15:47:00.003-05:00</published><updated>2010-03-01T17:03:05.600-06:00</updated><title type='text'>JRuby Nailgun Support in 1.3.0</title><content type='html'>I've merged changes into master (to be 1.3 soon) that should make &lt;a href="http://sourceforge.net/projects/nailgun/"&gt;Nailgun&lt;/a&gt; easier to use. And 1.3 will be the first release to include all NG stuff in the binary dist.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;jruby --ng-server starts up a server. You can manage it however you like&lt;/li&gt;&lt;li&gt;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).&lt;/li&gt;&lt;/ul&gt;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.&lt;br /&gt;&lt;br /&gt;Heres a sample session:&lt;br /&gt;&lt;pre&gt;~/projects/jruby ➔ cd tool/nailgun/ ; make ; cd -&lt;br /&gt;Building ng client.  To build a Windows binary, type 'make ng.exe'&lt;br /&gt;gcc -Wall -pedantic -s -O3 -o ng src/c/ng.c&lt;br /&gt;ld warning: option -s is obsolete and being ignored&lt;br /&gt;/Users/headius/projects/jruby&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ jruby --ng-server&lt;br /&gt;NGServer started on all interfaces, port 2113.&lt;br /&gt;^Z&lt;br /&gt;[1]+  Stopped                 jruby --ng-server&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ bg&lt;br /&gt;[1]+ jruby --ng-server &amp;amp;&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ jruby --ng -e "puts 1"&lt;br /&gt;1&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ time jruby -e "puts 1"&lt;br /&gt;1&lt;br /&gt;&lt;br /&gt;real    0m0.609s&lt;br /&gt;user    0m0.482s&lt;br /&gt;sys    0m0.119s&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ time jruby --ng -e "puts 1"&lt;br /&gt;1&lt;br /&gt;&lt;br /&gt;real    0m0.073s&lt;br /&gt;user    0m0.010s&lt;br /&gt;sys    0m0.018s&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Update:&lt;/span&gt;&lt;/span&gt; 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."&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;Update 2:&lt;/i&gt;&lt;/b&gt; &lt;span&gt;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:&lt;/span&gt;&lt;/div&gt;&lt;pre&gt;~/projects/jruby ➔ cd tool/nailgun/ ; ./configure ; make ; cd -&lt;/pre&gt;&lt;div&gt;Alternatively, you can run "ant build-ng" in the JRuby root, which will do largely the same thing for you using Ant.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-9198915872973128017?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/9198915872973128017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=9198915872973128017' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/9198915872973128017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/9198915872973128017'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/05/jruby-nailgun-support-in-130.html' title='JRuby Nailgun Support in 1.3.0'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-4794057131247509599</id><published>2009-04-30T01:51:00.002-05:00</published><updated>2009-04-30T03:09:59.421-05:00</updated><title type='text'>Stand and Be Counted</title><content type='html'>In the spirit of &lt;a href="http://blog.nicksieger.com/articles/2009/04/30/stand-and-be-counted"&gt;Nick Sieger's short statement&lt;/a&gt; on the recent uproar over Matt Aimonetti's "pr0n star" talk, I'm posting my one and only blog response to the whole thing.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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."&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;You start to see a pattern here, yes?&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Now, let's move forward and get back to hacking and having fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-4794057131247509599?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/4794057131247509599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=4794057131247509599' title='29 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/4794057131247509599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/4794057131247509599'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/04/stand-and-be-counted.html' title='Stand and Be Counted'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>29</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-8101451855270975405</id><published>2009-04-25T10:53:00.005-05:00</published><updated>2009-04-25T11:14:50.328-05:00</updated><title type='text'>Setting up Typo on JRuby</title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;BTW, is Typo still the preeminent blog package for Rails? I certainly don't want to be out of fashion.&lt;br /&gt;&lt;br /&gt;Prerequisites:&lt;div&gt;&lt;ol&gt;&lt;li&gt;MySQL already set up and working, with TCP sockets enabled (or I guess you can use SQLite too)&lt;/li&gt;&lt;li&gt;Java (sudo apt-get install sun-java6-jdk or whatever's appropriate for your platform)&lt;/li&gt;&lt;li&gt;JRuby (&lt;a href="http://dist.codehaus.org/jruby/1.2.0/jruby-bin-1.2.0.zip"&gt;download&lt;/a&gt;, unpack, put bin/ in PATH)&lt;/li&gt;&lt;li&gt;Appropriate gems installed (rails, activerecord-jdbcmysql-adapter, glassfish or mongrel)&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;The process:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://rubyforge.org/frs/?group_id=555&amp;amp;release_id=32721"&gt;Download Typo&lt;/a&gt;. The gem unfortunately tries to install native extensions like sqlite3 and mysql (I sure wish they wouldn't do that!)&lt;/li&gt;&lt;li&gt;Unpack the Typo zip wherever you want your blog site to live and cd into that directory&lt;/li&gt;&lt;li&gt;Edit config/database.yml.example to your liking, replacing "mysql" with "jdbcmysql" and save it as config/database.yml&lt;/li&gt;&lt;li&gt;Create the database:&lt;br /&gt;&lt;pre&gt;jruby -S rake db:create RAILS_ENV=production&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Migrate the database:&lt;br /&gt;&lt;pre&gt;jruby -S rake db:migrate RAILS_ENV=production&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Run the server:&lt;br /&gt;&lt;pre&gt;glassfish -p &amp;lt;port&amp;gt; -e production [and whatever other options you want]&lt;/pre&gt; or&lt;br /&gt;&lt;pre&gt;jruby script/server -p &amp;lt;port&amp;gt; -e production&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.headius.com/2009/04/apache-jruby-rails-glassfish-easy.html"&gt;Set up Apache to point at your new Typo instance&lt;/a&gt; (optional)&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Perhaps it's time I finally moved my blog off Blogger and on to a JRuby-hosted server, eh?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Suggestions, improvements to this process? Add to comments and I'll update the post.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-8101451855270975405?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/8101451855270975405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=8101451855270975405' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/8101451855270975405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/8101451855270975405'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/04/setting-up-typo-on-jruby.html' title='Setting up Typo on JRuby'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-489282119765169980</id><published>2009-04-25T08:47:00.008-05:00</published><updated>2009-08-02T14:13:28.233-05:00</updated><title type='text'>Apache + JRuby + Rails + GlassFish = Easy Deployment!</title><content type='html'>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.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;Update:&lt;/i&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt; It's worth mentioning that this works fine with JRuby + Mongrel too, though Mongrel doesn't automatically multithread without &lt;a href="http://mongrel.rubyforge.org/ticket/48"&gt;this patch&lt;/a&gt; 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.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Prerequisites:&lt;br /&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Apache with mod_proxy_http enabled (sudo a2enmod proxy_http on Ubuntu)&lt;/li&gt;&lt;li&gt;Java (sudo apt-get install sun-java6-jdk or the openjdk flavors if you like)&lt;/li&gt;&lt;li&gt;JRuby (&lt;a href="http://dist.codehaus.org/jruby/1.2.0/jruby-bin-1.2.0.zip"&gt;download&lt;/a&gt;, unpack, put bin/ in PATH)&lt;/li&gt;&lt;li&gt;gems appropriate to run your app with JRuby (e.g. rails, activerecord-jdbcsqlite3-adapter, etc)&lt;/li&gt;&lt;li&gt;production DB all set to go&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Install the glassfish gem&lt;br /&gt;&lt;pre&gt;gem install glassfish&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;From your application directory, run glassfish with these options:&lt;br /&gt;&lt;pre&gt;glassfish -p &amp;lt;port&amp;gt; -e production -c &amp;lt;context&amp;gt; -d&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Add ProxyPass and ProxyPassReverse lines to Apache (whereever is appropriate on your system) for the GlassFish server instance. For example, if &amp;lt;port&amp;gt; is 9000 and &amp;lt;context&amp;gt; is foo:&lt;br /&gt;&lt;pre&gt;ProxyPass /foo http://localhost:9000/foo&lt;br /&gt;ProxyPassReverse /foo http://localhost:9000/foo&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Reload Apache config, however is appropriate for your system&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;You'll now be able to access your app via http://servername/foo, and requests will all proxy to the GlassFish server instance.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A few caveats:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;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&lt;/li&gt;&lt;li&gt;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).&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;I'll update this post as suggestions come in. Enjoy!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;Update:&lt;/i&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt; Dberg suggests the following improvement:&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;blockquote&gt;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&lt;br /&gt;&lt;br /&gt;ProxyPass /images !&lt;br /&gt;ProxyPass /javascripts !&lt;br /&gt;ProxyPass /stylesheets&lt;br /&gt;&lt;br /&gt;Then make sure DocumentRoot is set to the right place for these files and you will get a slight performance boost !&lt;/blockquote&gt;Thanks for that!&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-489282119765169980?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/489282119765169980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=489282119765169980' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/489282119765169980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/489282119765169980'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/04/apache-jruby-rails-glassfish-easy.html' title='Apache + JRuby + Rails + GlassFish = Easy Deployment!'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-8381808268961829564</id><published>2009-04-22T05:36:00.003-05:00</published><updated>2009-04-22T06:17:50.293-05:00</updated><title type='text'>The Future: Part One</title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Languages&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;In order for the platform to embrace these and many future languages, several things need to happen:&lt;div&gt;&lt;ul&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;More to come.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-8381808268961829564?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/8381808268961829564/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=8381808268961829564' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/8381808268961829564'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/8381808268961829564'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/04/future-part-one.html' title='The Future: Part One'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-8588120877319514181</id><published>2009-04-13T19:30:00.003-05:00</published><updated>2009-04-14T12:14:19.232-05:00</updated><title type='text'>JRuby Moves to Git</title><content type='html'>We have successfully migrated JRuby development to Git!&lt;br /&gt;&lt;br /&gt;The main repository is on the &lt;a href="http://kenai.com/projects/jruby"&gt;JRuby kenai.com project&lt;/a&gt;, 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.&lt;br /&gt;&lt;br /&gt;Kenai: &lt;a href="git://kenai.com/jruby~main"&gt;git://kenai.com/jruby~main&lt;/a&gt;&lt;br /&gt;Github: &lt;a href="git://github.com/jruby/jruby.git"&gt;git://github.com/jruby/jruby.git&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;The Github repository is also attached to the &lt;a href="http://github.com/jruby"&gt;official Github "jruby" user&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jruby.headius.com:8080/hudson/job/jruby-dist/"&gt;http://jruby.headius.com:8080/hudson/job/jruby-dist/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Why Git?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;But a few things changed our minds over the past couple months:&lt;br /&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Kenai added git support&lt;/li&gt;&lt;li&gt;We realized that we'd get more Rubyists contributing if we had a mirror on Github&lt;/li&gt;&lt;li&gt;We became more comfortable with Git&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Enjoy!&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-8588120877319514181?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/8588120877319514181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=8588120877319514181' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/8588120877319514181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/8588120877319514181'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/04/jruby-moves-to-git.html' title='JRuby Moves to Git'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-5425179292824715024</id><published>2009-04-02T10:09:00.012-05:00</published><updated>2009-04-04T22:48:25.482-05:00</updated><title type='text'>How JRuby Makes Ruby Fast</title><content type='html'>&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Performance Optimization, JRuby-style&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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?&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;pre&gt;# Takeuchi function performance, tak(24, 16, 8)&lt;br /&gt;def tak x, y, z&lt;br /&gt; if y &amp;gt;= x&lt;br /&gt;   return z&lt;br /&gt; else&lt;br /&gt;   return tak( tak(x-1, y, z),&lt;br /&gt;               tak(y-1, z, x),&lt;br /&gt;               tak(z-1, x, y))&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;require "benchmark"&lt;br /&gt;&lt;br /&gt;N = (ARGV.shift || 1).to_i&lt;br /&gt;&lt;br /&gt;Benchmark.bm do |make|&lt;br /&gt; N.times do&lt;br /&gt;   make.report do&lt;br /&gt;     i = 0&lt;br /&gt;     while i&amp;lt;10&lt;br /&gt;       tak(24, 16, 8)&lt;br /&gt;       i+=1&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt; end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;And here's our first set of results. I have provided Ruby 1.8.6 and Ruby 1.9.1 numbers for comparison.&lt;/div&gt;&lt;pre&gt;Ruby 1.8.6p114:&lt;br /&gt;➔ ruby bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;17.150000   0.120000  17.270000 ( 17.585128)&lt;br /&gt;17.170000   0.140000  17.310000 ( 17.946869)&lt;br /&gt;17.180000   0.160000  17.340000 ( 18.234570)&lt;br /&gt;17.180000   0.150000  17.330000 ( 17.779536)&lt;br /&gt;18.790000   0.190000  18.980000 ( 19.560232)&lt;br /&gt;&lt;br /&gt;Ruby 1.9.1p0:&lt;br /&gt;➔ ruby191 bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;3.570000   0.030000   3.600000 (  3.614855)&lt;br /&gt;3.570000   0.030000   3.600000 (  3.615341)&lt;br /&gt;3.560000   0.020000   3.580000 (  3.608843)&lt;br /&gt;3.570000   0.020000   3.590000 (  3.591833)&lt;br /&gt;3.570000   0.020000   3.590000 (  3.640205)&lt;br /&gt;&lt;br /&gt;JRuby 1.3.0-dev, interpreted, client VM&lt;br /&gt;➔ jruby -X-C bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;24.981000   0.000000  24.981000 ( 24.903000)&lt;br /&gt;24.632000   0.000000  24.632000 ( 24.633000)&lt;br /&gt;25.459000   0.000000  25.459000 ( 25.459000)&lt;br /&gt;29.122000   0.000000  29.122000 ( 29.122000)&lt;br /&gt;29.935000   0.000000  29.935000 ( 29.935000)&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;pre&gt;JRuby 1.3.0-dev, interpreted, server VM&lt;br /&gt;➔ jruby --server -X-C bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;8.262000   0.000000   8.262000 (  8.192000)&lt;br /&gt;7.789000   0.000000   7.789000 (  7.789000)&lt;br /&gt;8.012000   0.000000   8.012000 (  8.012000)&lt;br /&gt;7.998000   0.000000   7.998000 (  7.998000)&lt;br /&gt;8.000000   0.000000   8.000000 (  8.000000)&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;pre&gt;JRuby 1.3.0-dev, compiled (unoptimized), server VM:&lt;br /&gt;➔ jruby --server -J-Djruby.astInspector.enabled=false bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;5.436000   0.000000   5.436000 (  5.376000)&lt;br /&gt;3.655000   0.000000   3.655000 (  3.655000)&lt;br /&gt;3.662000   0.000000   3.662000 (  3.662000)&lt;br /&gt;3.683000   0.000000   3.683000 (  3.683000)&lt;br /&gt;3.668000   0.000000   3.668000 (  3.668000)&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Next, we'll turn on the simplest and oldest JRuby compiler optimization, "heap scope elimination".&lt;/div&gt;&lt;pre&gt;JRuby 1.3.0-dev, compiled (heap scope optz), server VM:&lt;br /&gt;➔ jruby --server bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;4.014000   0.000000   4.014000 (  3.942000)&lt;br /&gt;2.776000   0.000000   2.776000 (  2.776000)&lt;br /&gt;2.760000   0.000000   2.760000 (  2.760000)&lt;br /&gt;2.769000   0.000000   2.769000 (  2.769000)&lt;br /&gt;2.768000   0.000000   2.768000 (  2.769000)&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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".&lt;/div&gt;&lt;pre&gt;JRuby 1.3.0-dev, compiled (heap scope + bracktrace frame optz), server VM:&lt;br /&gt;➔ jruby --server -J-Djruby.compile.frameless=true bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;3.609000   0.000000   3.609000 (  3.526000)&lt;br /&gt;2.600000   0.000000   2.600000 (  2.600000)&lt;br /&gt;2.602000   0.000000   2.602000 (  2.602000)&lt;br /&gt;2.598000   0.000000   2.598000 (  2.598000)&lt;br /&gt;2.602000   0.000000   2.602000 (  2.602000)&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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":&lt;/div&gt;&lt;pre&gt;JRuby 1.3.0-dev, compiled (heap scope + heap frame optz), server VM:&lt;br /&gt;➔ jruby --server -J-Djruby.compile.frameless=true bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;2.955000   0.000000   2.955000 (  2.890000)&lt;br /&gt;1.904000   0.000000   1.904000 (  1.904000)&lt;br /&gt;1.843000   0.000000   1.843000 (  1.843000)&lt;br /&gt;1.823000   0.000000   1.823000 (  1.823000)&lt;br /&gt;1.813000   0.000000   1.813000 (  1.813000)&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Next up we'll turn on some optimizations for math operators.&lt;/div&gt;&lt;pre&gt;JRuby 1.3.0-dev, compiled (heap scope, heap frame, fastops optz), server VM:&lt;br /&gt;➔ jruby --server -J-Djruby.compile.frameless=true -J-Djruby.compile.fastops=true bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;2.291000   0.000000   2.291000 (  2.225000)&lt;br /&gt;1.335000   0.000000   1.335000 (  1.335000)&lt;br /&gt;1.337000   0.000000   1.337000 (  1.337000)&lt;br /&gt;1.344000   0.000000   1.344000 (  1.344000)&lt;br /&gt;1.346000   0.000000   1.346000 (  1.346000)&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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:&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;JRuby 1.3.0-dev, compiled (heap scope, heap frame, fastops, threadless, positionless optz), server VM:&lt;br /&gt;➔ 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&lt;br /&gt; user     system      total        real&lt;br /&gt;2.256000   0.000000   2.256000 (  2.186000)&lt;br /&gt;1.304000   0.000000   1.304000 (  1.304000)&lt;br /&gt;1.310000   0.000000   1.310000 (  1.310000)&lt;br /&gt;1.307000   0.000000   1.307000 (  1.307000)&lt;br /&gt;1.301000   0.000000   1.301000 (  1.301000)&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;We get a small but measurable performance boost from this change as well.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;pre&gt;JRuby 1.3.0-dev, compiled ("--fast", dyncall optz), server VM:&lt;br /&gt;➔ jruby --server --fast bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;2.206000   0.000000   2.206000 (  2.066000)&lt;br /&gt;1.259000   0.000000   1.259000 (  1.259000)&lt;br /&gt;1.258000   0.000000   1.258000 (  1.258000)&lt;br /&gt;1.269000   0.000000   1.269000 (  1.269000)&lt;br /&gt;1.270000   0.000000   1.270000 (  1.270000)&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Performance Optimization, Duby-style&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;pre&gt;def tak(x =&gt; :fixnum, y =&amp;gt; :fixnum, z =&amp;gt; :fixnum)&lt;br /&gt; unless y &amp;lt; x&lt;br /&gt;   z&lt;br /&gt; else&lt;br /&gt;   tak( tak(x-1, y, z),&lt;br /&gt;        tak(y-1, z, x),&lt;br /&gt;        tak(z-1, x, y))&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;puts "Running tak(24,16,8) 1000 times"&lt;br /&gt;&lt;br /&gt;i = 0&lt;br /&gt;while i&amp;lt;1000&lt;br /&gt; tak(24, 16, 8)&lt;br /&gt; i+=1&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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:&lt;/div&gt;&lt;pre&gt;➔ time jruby -J-server bin/duby examples/tak.duby&lt;br /&gt;Running tak(24,16,8) 1000 times&lt;br /&gt;&lt;br /&gt;real 0m13.657s&lt;br /&gt;user 0m14.529s&lt;br /&gt;sys 0m0.450s&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Be a (Supportive) Critic!&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;Update, April 4:&lt;/i&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt; 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.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;pre&gt;JRuby 1.3.0-dev, compiled ("--fast", dyncall optz, recursion optz), server VM:&lt;br /&gt;➔ jruby --server --fast bench/bench_tak.rb 5&lt;br /&gt; user     system      total        real&lt;br /&gt;0.524000   0.000000   0.524000 (  0.524000)&lt;br /&gt;0.338000   0.000000   0.338000 (  0.338000)&lt;br /&gt;0.325000   0.000000   0.325000 (  0.325000)&lt;br /&gt;0.299000   0.000000   0.299000 (  0.299000)&lt;br /&gt;0.310000   0.000000   0.310000 (  0.310000)&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-5425179292824715024?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/5425179292824715024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=5425179292824715024' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5425179292824715024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5425179292824715024'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/04/how-jruby-makes-ruby-fast.html' title='How JRuby Makes Ruby Fast'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-1704846515987354785</id><published>2009-03-29T01:25:00.004-05:00</published><updated>2009-03-29T02:06:17.351-05:00</updated><title type='text'>On Benchmarking</title><content type='html'>Sigh. It must be that time of year again. Another partially-completed Ruby implementation has started to get overhyped because of early performance numbers.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.macruby.org/"&gt;MacRuby&lt;/a&gt; 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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And I believe it was a great disservice to the MagLev team.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Listen, people: Ruby is &lt;b&gt;hard&lt;/b&gt; 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%.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So let's try to be adults about this and give new implementations time to actually &lt;b&gt;finish&lt;/b&gt; 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.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-1704846515987354785?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/1704846515987354785/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=1704846515987354785' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1704846515987354785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/1704846515987354785'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/03/on-benchmarking.html' title='On Benchmarking'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-5758732834948935397</id><published>2009-03-28T14:21:00.003-05:00</published><updated>2009-03-28T14:52:10.221-05:00</updated><title type='text'>BiteScript 0.0.1 - A Ruby DSL for JVM Bytecode</title><content type='html'>I have finally released the first version of &lt;a href="http://kenai.com/projects/jvmscript"&gt;BiteScript&lt;/a&gt;, my little DSL for generating JVM bytecode. Install it as a gem with "gem install bitescript".&lt;br /&gt;&lt;pre&gt;require 'bitescript'&lt;br /&gt;&lt;br /&gt;include BiteScript&lt;br /&gt;&lt;br /&gt;fb = FileBuilder.build(__FILE__) do&lt;br /&gt;public_class "SimpleLoop" do&lt;br /&gt; public_static_method "main", void, string[] do&lt;br /&gt;   aload 0&lt;br /&gt;   push_int 0&lt;br /&gt;   aaload&lt;br /&gt;   label :top&lt;br /&gt;   dup&lt;br /&gt;   aprintln&lt;br /&gt;   goto :top&lt;br /&gt;   returnvoid&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;fb.generate do |filename, class_builder|&lt;br /&gt;File.open(filename, 'w') do |file|&lt;br /&gt; file.write(class_builder.generate)&lt;br /&gt;end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;BiteScript grew out of my work on &lt;a href="http://kenai.com/projects/duby"&gt;Duby&lt;/a&gt;. 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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;For a longer example, you can look at &lt;a href="http://svn.codehaus.org/jruby/trunk/jruby/tool/compiler2.rb"&gt;tool/compiler2.rb&lt;/a&gt; in JRuby, &lt;a href="https://kenai.com/hg/duby~mercurial/file/d0fc20d338bc/lib/duby/jvm/compiler.rb"&gt;lib/duby/jvm/jvm_compiler.rb&lt;/a&gt; in Duby, or an example implementation of &lt;a href="http://kenai.com/hg/jvmscript~mercurial/file/tip/examples/fib.bs"&gt;Fibonacci in BiteScript&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;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.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For folks interested in using BiteScript, the &lt;a href="http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html"&gt;JVM Specification&lt;/a&gt; is an easy-to-read complete reference for targeting the JVM, and here is &lt;a href="http://homepages.inf.ed.ac.uk/kwxm/JVM/home.html"&gt;my favorite JVM opcode quickref&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-5758732834948935397?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/5758732834948935397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=5758732834948935397' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5758732834948935397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/5758732834948935397'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/03/bitescript-001-ruby-dsl-for-jvm.html' title='BiteScript 0.0.1 - A Ruby DSL for JVM Bytecode'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-8033589621548222311</id><published>2009-03-12T23:20:00.003-05:00</published><updated>2009-03-13T01:01:55.230-05:00</updated><title type='text'>More Compiling Ruby to Java Types</title><content type='html'>I did another pass on &lt;a href="http://blog.headius.com/2009/03/compiling-ruby-to-java-types.html"&gt;compiler2&lt;/a&gt;, and managed to wire in signature support. So let's look at a couple examples:&lt;br /&gt;&lt;pre&gt;class MyRubyClass&lt;br /&gt; def helloWorld&lt;br /&gt;   puts "Hello from Ruby"&lt;br /&gt; end&lt;br /&gt; def goodbyeWorld(a)&lt;br /&gt;   puts a&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt; signature :helloWorld, [] =&amp;gt; Java::void&lt;br /&gt; signature :goodbyeWorld, [java.lang.String] =&amp;gt; Java::void&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;In this case we have our friend MyRubyClass once again, with helloWorld and goodbyeWorld methods. You'll recall from &lt;a href="http://blog.headius.com/2009/03/compiling-ruby-to-java-types.html"&gt;my previous post&lt;/a&gt; that these two methods originally compiled as returning IRubyObject, and goodbyeWorld compiled as receiving a single IRubyObject parameter.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;The compiler takes this new information, and produces a more normal-looking set of Java signatures:&lt;br /&gt;&lt;pre&gt;Compiled from "MyObject.java.rb"&lt;br /&gt;public class MyObject extends org.jruby.RubyObject{&lt;br /&gt;   static {};&lt;br /&gt;   public MyObject();&lt;br /&gt;   public void helloWorld();&lt;br /&gt;   public void goodbyeWorld(java.lang.String);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;pre&gt;public class MyObjectTest {&lt;br /&gt; public static void main(String[] args) {&lt;br /&gt;   MyObject obj = new MyObject();&lt;br /&gt;   obj.helloWorld();&lt;br /&gt;   obj.goodbyeWorld("hello");&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;And that's literally all there is to it. Here's a more advanced example:&lt;br /&gt;&lt;pre&gt;class MyRubyClass&lt;br /&gt; %w[boolean byte short char int long float double].each do |type|&lt;br /&gt;   java_type = Java.send type&lt;br /&gt;   eval "def #{type}Method(a); a; end"&lt;br /&gt;   signature "#{type}Method", [java_type] =&gt; java_type&lt;br /&gt; end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;pre&gt;Compiled from "MyObject2.java.rb"&lt;br /&gt;public class MyObject2 extends org.jruby.RubyObject{&lt;br /&gt;   static {};&lt;br /&gt;   public MyObject2();&lt;br /&gt;   public double doubleMethod(double);&lt;br /&gt;   public int intMethod(int);&lt;br /&gt;   public char charMethod(char);&lt;br /&gt;   public short shortMethod(short);&lt;br /&gt;   public boolean booleanMethod(boolean);&lt;br /&gt;   public float floatMethod(float);&lt;br /&gt;   public long longMethod(long);&lt;br /&gt;   public byte byteMethod(byte);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;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?)&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;There's certainly more work to be done:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;/ul&gt;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.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is just the beginning!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-8033589621548222311?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/8033589621548222311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=8033589621548222311' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/8033589621548222311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/8033589621548222311'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/03/more-compiling-ruby-to-java-types.html' title='More Compiling Ruby to Java Types'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-2990005581464266831</id><published>2009-03-10T17:05:00.004-05:00</published><updated>2009-03-10T17:52:08.629-05:00</updated><title type='text'>Compiling Ruby to Java Types</title><content type='html'>"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.&lt;br /&gt;&lt;br /&gt;I have just landed an early prototype of the compiler on trunk. I made a few decisions about it today:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It will use my bytecode DSL "&lt;a href="http://kenai.com/projects/jvmscript"&gt;BiteScript&lt;/a&gt;", just like &lt;a href="http://kenai.com/projects/duby"&gt;Duby&lt;/a&gt; does&lt;/li&gt;&lt;li&gt;It will use the *runtime* definition of a class to generate the Java version&lt;/li&gt;&lt;/ul&gt;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.&lt;br /&gt;&lt;br /&gt;Here's an example:&lt;div&gt;&lt;br /&gt;&lt;pre&gt;# myruby.rb&lt;br /&gt;require 'rbconfig'&lt;br /&gt;&lt;br /&gt;class MyRubyClass&lt;br /&gt;  def helloWorld&lt;br /&gt;    puts "Hello from Ruby"&lt;br /&gt;  end&lt;br /&gt;  if Config::CONFIG['host_os'] =~ /mswin32/&lt;br /&gt;    def goodbyeWorld(a)&lt;br /&gt;      puts a&lt;br /&gt;    end&lt;br /&gt;  else&lt;br /&gt;    def nevermore(*a)&lt;br /&gt;      puts a&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;The compiler2 prototype can be invoked as follows (assuming bitescript is checked out into ../bitescript):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;jruby -I ../bitescript/lib/ tool/compiler2.rb MyObject MyRubyClass myruby&lt;/pre&gt;&lt;br /&gt;A breakdown of these arguments is as follows:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;-I ../bitescript/lib includes bitescript&lt;/li&gt;&lt;li&gt;tool/compiler2.rb is the compiler itself&lt;/li&gt;&lt;li&gt;MyObject is the name we'd like the Java class to have&lt;/li&gt;&lt;li&gt;MyRubyClass is the name of the Ruby class we want it to front&lt;/li&gt;&lt;li&gt;myruby is the library we want it to require to load that class&lt;/li&gt;&lt;/ul&gt;Running this on OS X and dumping the resulting Java class gives us:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Compiled from "MyObject.java.rb"&lt;br /&gt;public class MyObject extends org.jruby.RubyObject{&lt;br /&gt; static {};&lt;br /&gt; public MyObject();&lt;br /&gt; public org.jruby.runtime.builtin.IRubyObject helloWorld();&lt;br /&gt; public org.jruby.runtime.builtin.IRubyObject nevermore(org.jruby.runtime.builtin.IRubyObject[]);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;So, thoughts? Questions? Have a look at the code under &lt;a href="http://svn.codehaus.org/jruby/trunk/jruby/tool/compiler2.rb"&gt;tool/compiler2.rb&lt;/a&gt; in JRuby's repository. The entire compiler is so far only 78 lines of Ruby code.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-2990005581464266831?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/2990005581464266831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=2990005581464266831' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2990005581464266831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/2990005581464266831'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/03/compiling-ruby-to-java-types.html' title='Compiling Ruby to Java Types'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-7387544165247854282</id><published>2009-02-28T15:42:00.006-06:00</published><updated>2009-02-28T15:51:05.896-06:00</updated><title type='text'>Help Us Set Priorities for JRuby 1.3</title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;Some obvious items will continue to see work:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;1.9 libraries, interp, compiler, parser&lt;/li&gt;&lt;li&gt;1.8.6 bugs&lt;/li&gt;&lt;li&gt;"Pure ruby" application support, like Rails deployment stuff (Warbler, AR-JDBC)&lt;/li&gt;&lt;/ul&gt;But there's other areas that we may want to prioritize:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;1.8.7 support&lt;/li&gt;&lt;li&gt;Ruby execution performance (how fast do you want it?)&lt;/li&gt;&lt;li&gt;Specific library performance (YAML, IO, Java)&lt;/li&gt;&lt;li&gt;More Java integration improvement/refactoring (esp. subclassing)&lt;/li&gt;&lt;li&gt;"Compiler #2" to produce normal Java classes from Ruby&lt;/li&gt;&lt;li&gt;Improvements to AOT compilation (all-at-once, eliminate runtime codegen)&lt;/li&gt;&lt;li&gt;Expand support for embedded/mobile platforms&lt;/li&gt;&lt;/ul&gt;And there's a number of internal chores to work on too:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Start generating most of the call path, to reduce duplicate code&lt;/li&gt;&lt;li&gt;Specific-arity optimizations for block yield (could be big)&lt;/li&gt;&lt;li&gt;Compiler cleanup and refactoring&lt;/li&gt;&lt;li&gt;Modularization of core classes that aren't valid on applet, Android, secured envs, etc; also may allow shipping smaller runtimes&lt;/li&gt;&lt;li&gt;More startup perf work; I have a few ideas&lt;/li&gt;&lt;/ul&gt;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?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20975090-7387544165247854282?l=headius.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://headius.blogspot.com/feeds/7387544165247854282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20975090&amp;postID=7387544165247854282' title='30 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/7387544165247854282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20975090/posts/default/7387544165247854282'/><link rel='alternate' type='text/html' href='http://headius.blogspot.com/2009/02/help-us-set-priorities-for-jruby-13.html' title='Help Us Set Priorities for JRuby 1.3'/><author><name>Charles Oliver Nutter</name><uri>http://www.blogger.com/profile/06400331959739924670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_HWobMsJuRHc/SLsGKrLRkgI/AAAAAAAAACM/7upklVGpbuY/S220/charles.nutter%40sun.com_e5232610.jpg'/></author><thr:total>30</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20975090.post-6182984272396628874</id><published>2009-02-27T04:25:00.007-06:00</published><updated>2009-02-27T04:59:52.409-06:00</updated><title type='text'>JRuby on Java ME</title><content type='html'>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 &lt;a href="http://blog.hea
