Nick Sieger
@nicksieger
(RE-)
INTRO
Ruby on
the JVM
Best of Ruby
 and Java...
 Together!
http://www.flickr.com/photos/texascooking/5864122096/
COMPAT
IBILITY
runs nearly all pure ruby code

runs 92% of rubyspec suite

runs ~30% of 1.9 test suite

(even more with 1.8 mode)
http://jruby.org/download

    rvm install jruby

   INSTALL   gem install jruby-lint




             $ jrlint
drawbacks
startup time

memory footprint

native code

no Kernel#fork
PERFOR
MANCE
GC.pauses =
 “no thanks”
class Simple
  attr_accessor :next
end

top = Simple.new

puts Benchmark.measure {
  outer = 10
  total = 100000
  per = 100

  outer.times do
    total.times do
      per.times { Simple.new }
      s = Simple.new
      top.next = s
      top = s
    end
  end
}
Ruby 1.9.3              JRuby
8000


6000


4000


2000


  0
                    GC count
Ruby 1.9.3              JRuby
10000


 1000


  100


   10


    1
                     GC count
15
     Ruby 1.9.3               JRuby

12


9


6


3


0
                  GC time %
Time per GC versus heap usage

300ms

              Ruby 2.0.0                JRuby
225ms


150ms


75ms


 0ms
 188KB/29MB                27MB/127MB           199MB/238MB

                 Heap usage (MRI/JRuby)
REAL
THREADS
Ruby 1.9     Ruby 1.9
unthreaded   threaded




  JRuby        JRuby
unthreaded   threaded
sidekiq.org
 What if 1 Sidekiq process could
 do the work of 20 Resque or
 DelayedJob processes?
COMPILER
Ruby application code

     JVM bytecode           Key

        Native code




                          Ruby             Ruby
     Ruby code
                          code             code
                                  Ruby             Ruby
        JRuby             JRuby            JRuby
                                  code             code
                                                           Ruby
         JVM              JVM     JRuby    JVM     JRuby
                                                           code


Full interpretation      JRuby compiler   HotSpot compiler

 Time
BENCH
MARKS
Red-Black Tree
5


4
          ruby 1.9.3p286
          jruby 1.7.0 java 1.6.0_29
3
          jruby 1.7.0 java 1.7.0_09
          jruby 1.7.0 java 1.7.0_09-b05 +indy
2


1


0
Times Faster than Ruby 1.9.3
  5
           JRuby/Java 6                   JRuby/Java 7+indy
                                                     4.226           4.32
3.75
                                          3.66
                           3.44
 2.5       2.658

                                  1.914          1.806
1.25               1.538                                     1.565
       1.346


  0
        base64     richards        neural mandelbrot redblack
Java 7
Get JDK 7
   (OSX too!)
java.oracle.com
INVOKE
DYNAMIC
experthuman.com/
programming-with-
      nothing
    Tom Stuart
    @tomstuart
# lambda
-> x {
}
# call
p[x]
FIZZ
BUZZ
(1..100).each do |n|
  if (n % 15).zero?
    puts 'FizzBuzz'
  elsif (n % 3).zero?
    puts 'Fizz'
  elsif (n % 5).zero?
    puts 'Buzz'
  else
    puts n.to_s
  end
end
fizzbuzz = -> k { -> f { -> f { -> x { f[-> y { x[x][y] }] }[-> x {
f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p {
p[-> x { -> y { x } } ] }[l]][x][-> y { g[f[-> l { -> p { p[-> x { ->
y { y } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][x][g]][-> l {
-> p { p[-> x { -> y { x } } ] }[-> p { p[-> x { -> y { y } } ] }[l]]
}[l]][y] }] } } } }][k][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y
{ x } }][-> x { -> y { x } }]][-> l { -> x { -> l { -> x { -> x { -> y
{ -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f {
f[x][y] } } }[x][l]] } }[l][f[x]] } }] } }[-> f { -> x { f[-> y {
x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b
{ b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y
{ x } }] }[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h {
h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]] }
}[m][n]][-> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x
{ -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[f[-> n {
-> p { -> x { p[n[p][x]] } } }[m]][n]][m][x] }][-> x { -> y { -> f {
f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]] } } }][-> p {
-> x { p[x] } }][-> p { -> x {p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[
p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[
p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[
p[p[p[p[p[p[p[p[p[p[x]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]} }]][-> n { -> b {
b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f
{ -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f {
-> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y
} } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> f { -> x {
n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] }
METHOD
HANDLES
INVOKEDYNAMIC
           [bootstrapMethod]


bootstrapMethod():
                           Call Site
  CallSite (once)
                                target

                           Method
                           Handle
package java.lang.invoke;

public abstract class MethodHandle {
    public final native Object invoke(Object... args)
        throws Throwable;
}
LAMBDA
  p[x]
methodHandle.invoke(x);
java.lang.invoke.
       MethodHandles
 arrayElementGetter arrayElementSetter
   spreadInvoker exactInvoker invoker
explicitCastArguments permuteArguments
    constant identity insertArguments
       dropArguments dropArguments
    filterArguments filterReturnValue
       foldArguments guardWithTest
      catchException throwException
String literal
 Constant lookup
  Other literals
Instance variables
Method invocation
 Math operations
IT’S A JVM
  WORLD
DRIVE JAVA
FROM RUBY
require 'java'
require 'rubygems'
require 'flying_saucer'

java_import org.xhtmlrenderer.pdf.ITextRenderer

document = <<-HTML
<html><body><h1>Hello Flying Saucer!</h1></body></html>
HTML

File.open("doc.pdf", "wb") do |out|
  renderer = ITextRenderer.new
  renderer.set_document_from_string document
  renderer.layout
  renderer.create_pdf out.to_outputstream
end

system("open doc.pdf")



 jruby -S gem install flying_saucer to try this example.
$ jruby saucer.rb
DECORATE
JAVA OBJECTS
 WITH JRUBY
module java::util::Iterator
  include Enumerable

  def each
    while has_next
      yield self.next
    end
  end
end
DRIVE RUBY
   FROM JAVA
(org.jruby.embed)
import org.jruby.embed.ScriptingContainer;

public class EmbedJRuby {
    public static void main(String[] args) {
        ScriptingContainer container = new ScriptingContainer();
        container.runScriptlet("puts 'Hello from Ruby'");
    }
}



(defn -main
  "Call JRuby!"
  [& args]
  (doto (org.jruby.embed.ScriptingContainer.)
    (.runScriptlet "puts 'Hello from Ruby!'")))
JRuby +
 Clojure
;; examples.clj
(def hmap (hash-map "foo" "FOO"
                    "bar" "BAR"
                    "baz" "BAZ"))

(println hmap)
(println (get hmap "bar"))
(println (contains? hmap "foo"))
# ruby
Java::clojure.main.main(["./examples.clj"])
github.com/
  daveray/
  familiar
Familiar.with do
  # clojure.core functions here
  # ‘-’ replaced with ‘_’
  # e.g. hash-map => hash_map
end
Familiar.with do
  r = ref(nil)

  begin
    ref_set r, 'foo'
  rescue
    puts "no transaction! #{$!}"
  end

  dosync do
    ref_set r, 'foo'
  end
  p deref(r)
end
j.mp/
  clojure-
from-jruby
FUTURE
{,bugs,wiki,ci}
   jruby.org
github.com/
    jruby
Thanks!

JRuby @ Boulder Ruby

  • 1.
  • 3.
  • 4.
  • 5.
    Best of Ruby and Java... Together!
  • 6.
  • 7.
  • 8.
    runs nearly allpure ruby code runs 92% of rubyspec suite runs ~30% of 1.9 test suite (even more with 1.8 mode)
  • 9.
    http://jruby.org/download rvm install jruby INSTALL gem install jruby-lint $ jrlint
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
    class Simple   attr_accessor :next end top= Simple.new puts Benchmark.measure {   outer = 10   total = 100000   per = 100   outer.times do     total.times do       per.times { Simple.new }       s = Simple.new       top.next = s       top = s     end   end }
  • 15.
    Ruby 1.9.3 JRuby 8000 6000 4000 2000 0 GC count
  • 16.
    Ruby 1.9.3 JRuby 10000 1000 100 10 1 GC count
  • 17.
    15 Ruby 1.9.3 JRuby 12 9 6 3 0 GC time %
  • 18.
    Time per GCversus heap usage 300ms Ruby 2.0.0 JRuby 225ms 150ms 75ms 0ms 188KB/29MB 27MB/127MB 199MB/238MB Heap usage (MRI/JRuby)
  • 19.
  • 20.
    Ruby 1.9 Ruby 1.9 unthreaded threaded JRuby JRuby unthreaded threaded
  • 21.
    sidekiq.org What if1 Sidekiq process could do the work of 20 Resque or DelayedJob processes?
  • 22.
  • 23.
    Ruby application code JVM bytecode Key Native code Ruby Ruby Ruby code code code Ruby Ruby JRuby JRuby JRuby code code Ruby JVM JVM JRuby JVM JRuby code Full interpretation JRuby compiler HotSpot compiler Time
  • 24.
  • 25.
    Red-Black Tree 5 4 ruby 1.9.3p286 jruby 1.7.0 java 1.6.0_29 3 jruby 1.7.0 java 1.7.0_09 jruby 1.7.0 java 1.7.0_09-b05 +indy 2 1 0
  • 26.
    Times Faster thanRuby 1.9.3 5 JRuby/Java 6 JRuby/Java 7+indy 4.226 4.32 3.75 3.66 3.44 2.5 2.658 1.914 1.806 1.25 1.538 1.565 1.346 0 base64 richards neural mandelbrot redblack
  • 27.
  • 28.
    Get JDK 7 (OSX too!) java.oracle.com
  • 29.
  • 30.
    experthuman.com/ programming-with- nothing Tom Stuart @tomstuart
  • 31.
  • 32.
  • 33.
  • 34.
    (1..100).each do |n| if (n % 15).zero? puts 'FizzBuzz' elsif (n % 3).zero? puts 'Fizz' elsif (n % 5).zero? puts 'Buzz' else puts n.to_s end end
  • 35.
    fizzbuzz = ->k { -> f { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[-> x { -> y { x } } ] }[l]][x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][y] }] } } } }][k][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> l { -> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[l][f[x]] } }] } }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]] } }[m][n]][-> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[f[-> n { -> p { -> x { p[n[p][x]] } } }[m]][n]][m][x] }][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]] } } }][-> p { -> x { p[x] } }][-> p { -> x {p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[ p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[ p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[ p[p[p[p[p[p[p[p[p[p[x]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]} }]][-> n { -> b { b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] }
  • 36.
  • 37.
    INVOKEDYNAMIC [bootstrapMethod] bootstrapMethod(): Call Site CallSite (once) target Method Handle
  • 38.
    package java.lang.invoke; public abstractclass MethodHandle { public final native Object invoke(Object... args) throws Throwable; }
  • 39.
  • 40.
  • 41.
    java.lang.invoke. MethodHandles arrayElementGetter arrayElementSetter spreadInvoker exactInvoker invoker explicitCastArguments permuteArguments constant identity insertArguments dropArguments dropArguments filterArguments filterReturnValue foldArguments guardWithTest catchException throwException
  • 42.
    String literal Constantlookup Other literals Instance variables Method invocation Math operations
  • 43.
  • 44.
  • 45.
    require 'java' require 'rubygems' require'flying_saucer' java_import org.xhtmlrenderer.pdf.ITextRenderer document = <<-HTML <html><body><h1>Hello Flying Saucer!</h1></body></html> HTML File.open("doc.pdf", "wb") do |out| renderer = ITextRenderer.new renderer.set_document_from_string document renderer.layout renderer.create_pdf out.to_outputstream end system("open doc.pdf") jruby -S gem install flying_saucer to try this example.
  • 46.
  • 47.
  • 48.
    module java::util::Iterator include Enumerable def each while has_next yield self.next end end end
  • 49.
    DRIVE RUBY FROM JAVA (org.jruby.embed)
  • 50.
    import org.jruby.embed.ScriptingContainer; public classEmbedJRuby { public static void main(String[] args) { ScriptingContainer container = new ScriptingContainer(); container.runScriptlet("puts 'Hello from Ruby'"); } } (defn -main "Call JRuby!" [& args] (doto (org.jruby.embed.ScriptingContainer.) (.runScriptlet "puts 'Hello from Ruby!'")))
  • 51.
  • 52.
    ;; examples.clj (def hmap(hash-map "foo" "FOO" "bar" "BAR" "baz" "BAZ")) (println hmap) (println (get hmap "bar")) (println (contains? hmap "foo"))
  • 53.
  • 54.
  • 55.
    Familiar.with do # clojure.core functions here # ‘-’ replaced with ‘_’ # e.g. hash-map => hash_map end
  • 56.
    Familiar.with do r = ref(nil) begin ref_set r, 'foo' rescue puts "no transaction! #{$!}" end dosync do ref_set r, 'foo' end p deref(r) end
  • 57.
  • 58.
  • 60.
  • 61.
  • 62.