Slide 1

Slide 1 text

Ruby on the Modern JVM

Slide 2

Slide 2 text

Who Am I • Charles Oliver Nutter • @headius(@mastodon.social) • [email protected] • JRuby developer for 20 years

Slide 3

Slide 3 text

Karaoke! • #RubyKaraoke tonight after the conference! • Cash Studio @ Prinsep Street • 8pm-10pm • Let's sing and celebrate Ruby together!

Slide 4

Slide 4 text

Thank You Sponsors! BEESCM https://beescm.com and 30+ individual sponsors

Slide 5

Slide 5 text

JRuby Needs You! Support JRuby! JRuby Support! https://github.com/sponsors/headius https://www.headius.com/jruby-support

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

What is JRuby? • Ruby on the Java Virtual Machine (JVM) • Ruby implementation fi rst, JVM language second • Many bene fi ts from JVM ecosystem • Ruby code should "just work" • Different extension API, no forking, parallel threads • Thousands of production users, 17 years of real-world use

Slide 8

Slide 8 text

Example Users • Kami: homework app for teachers, students • LogStash: you probably have already used it • Datek: point-of-sale, airplane refueling terminals, ad kiosks • Looker: business analytics platform from Google • Kinetic Data: business portal and automation platform • Let us know if you use JRuby!

Slide 9

Slide 9 text

JVM Advantage • World class garbage collectors (many choices) • Native JIT (JRuby was the fi rst JIT for Ruby) • Optimizes your whole application • Monitoring and pro fi ling tools (many choices, most are Free) • Deploy anywhere (single fi le, obfuscated code, sell your app!) • Thousands of JVM developers making it better

Slide 10

Slide 10 text

Enterprises Trust the JVM

Slide 11

Slide 11 text

Enterprises Need Ruby

Slide 12

Slide 12 text

JRuby is Ruby for the Enterprise

Slide 13

Slide 13 text

JRuby Today

Slide 14

Slide 14 text

JRuby 9.4 • Stable release, supported until 2026(?) • Ruby 3.1 compatible • Java 8+ compatible • rvm, ruby-install, ruby-build, OS packages, Windows installer, Docker images, tarballs, zips, whatever • Thousands of users, billions of requests worldwide

Slide 15

Slide 15 text

JRuby Compiler Pipeline Ruby (.rb) JIT Java Instructions (java bytecode) Ruby Instructions (IR) parse interpret interpreter interpret C1 compile native code better native code java bytecode interpreter execute C2 compile Java Virtual Machine JRuby Internals

Slide 16

Slide 16 text

Native/C Ruby Composition of JRuby Ruby parser Compiler and IR Core classes Standard library Java

Slide 17

Slide 17 text

Composition of CRuby Ruby parser Compiler and IR Core classes Standard library Native/C Ruby Rust

Slide 18

Slide 18 text

Better Extension Performance 0M 0.3M 0.6M 0.9M 1.2M small medium large 0.13 0.29 1.1 0.06 0.11 0.72 MRI (oj) JRuby (oj) Millions of loads per second (higher is better)

Slide 19

Slide 19 text

Better Scaling requests per second per MB of memory (16-way concurrency) 0rps/mb 0.45rps/mb 0.9rps/mb 1.35rps/mb 1.8rps/mb 1.72 rps/MB 0.92 rps/MB 0.8 rps/MB CRuby CRuby + YJIT JRuby 300MB heap One JRuby process can run your entire site

Slide 20

Slide 20 text

Graphics GUIs and Games Shoes 4 Glimmer Minecraft

Slide 21

Slide 21 text

JRuby on Android ruboto.org

Slide 22

Slide 22 text

JRuby 10

Slide 23

Slide 23 text

JRuby 10! • Major leap forward! • Ruby 3.4 support, Java 17 (or 21) minimum • New Prism parser with complete language features • Targeted optimization across the board • Our biggest jump since JRuby 9000 (9.0.0.0) • Releasing late this year...now is the time to contribute!

Slide 24

Slide 24 text

Ruby 3.4 Support

Slide 25

Slide 25 text

Ruby 3.4 Compatible • Language specs: 98.6% passing • Core specs: 97% passing • Same default and bundled gems, some with JRuby extensions • Releasing right after CRuby 3.4 • And preview releases maybe?

Slide 26

Slide 26 text

Ruby Parser • Two parsers: Java (port of C version) and Prism (new C-based) • Future is Prism by default • Ship native library for most platforms • Ship WASM build that runs on JVM without native code • Prism already integrated in JRuby 9.4!

Slide 27

Slide 27 text

Optimization

Slide 28

Slide 28 text

Compatibility Before Optimization • Compatibility fi rst • Keep up with Ruby features • Support users and fi x bugs • Now: caught up with CRuby, more compatible than ever • Finally doing long-planned optimizations!

Slide 29

Slide 29 text

Keyword-like Methods • Special methods can see into the method that called them • __method__/__callee__ look at method's name • block_given? needs passed block • JVM does not let us access caller dierectly (security etc) • Copying data to heap is slow and breaks optimization • Optimized: pass caller data to special call sites

Slide 30

Slide 30 text

__callee__ performance 0M iter/s 2.25M iter/s 4.5M iter/s 6.75M iter/s 9M iter/s __callee__ 8.4M 4.4M 2.5M CRuby JRuby 9.4 CRuby YJIT JRuby 10

Slide 31

Slide 31 text

ALOAD 0 ALOAD 4 ALOAD 5 ALOAD 2 GETSTATIC org/jruby/runtime/Visibility.PUBLIC : Lorg/jruby/runtime/Visibility; ALOAD 3 INVOKEVIRTUAL org/jruby/runtime/ThreadContext.preMethodFrameOnly (Lorg/jruby/RubyModul ALOAD 0 ALOAD 2 INVOKEDYNAMIC callVariable:__callee__(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runt // handle kind 0x6 : INVOKESTATIC org/jruby/ir/targets/indy/SelfInvokeSite.bootstrap(Ljava/lang/invoke/MethodHandles$L // arguments: 0, 0, "-e", 1 ] Load method name on stack Update frame on heap Normal call to __callee__

Slide 32

Slide 32 text

InvokeDynamic • JVM's special sauce for dynamic languages • De fi ne a new "instruction" • Write code to connect call site to instruction logic • JIT optimizes like static JVM bytecode • Most JRuby optimizations use InvokeDynamic

Slide 33

Slide 33 text

ALOAD 0 ALOAD 2 ALOAD 5 INVOKEDYNAMIC callVariable:__callee__(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runt // handle kind 0x6 : INVOKESTATIC org/jruby/ir/targets/indy/FrameNameSite.frameNameBootstrap(Ljava/lang/invoke/MethodH // arguments: "-e", 1 ] Load method name on stack Special call to name-aware instruction FrameNameSite calls frameless __callee__ with name or makes normal method call

Slide 34

Slide 34 text

__callee__ performance 0M iter/s 2.25M iter/s 4.5M iter/s 6.75M iter/s 9M iter/s __callee__ 8.4M 4.4M 2.5M CRuby JRuby 9.4 CRuby YJIT JRuby 10

Slide 35

Slide 35 text

__callee__ performance 0M iter/s 10M iter/s 20M iter/s 30M iter/s 40M iter/s __callee__ 36.30M 8.40M 4.40M 2.50M CRuby JRuby 9.4 CRuby YJIT JRuby 10

Slide 36

Slide 36 text

block_given? performance 0M iter/s 5M iter/s 10M iter/s 15M iter/s 20M iter/s block_given? 18.9M 6.4M 2.6M CRuby JRuby 9.4 CRuby YJIT JRuby 10

Slide 37

Slide 37 text

block_given? performance 0M iter/s 75M iter/s 150M iter/s 225M iter/s 300M iter/s block_given? 241.5M 18.9M 6.4M 2.6M CRuby JRuby 9.4 CRuby YJIT JRuby 10

Slide 38

Slide 38 text

String Interpolation • Too much bytecode to compile interpolated string • Harder to inline, slower to warm up • Optimized: special call site with static string and pattern • Small bytecode, better optimization

Slide 39

Slide 39 text

"foo#{a}bar#{b}baz#{c}"

Slide 40

Slide 40 text

ALOAD 0 INVOKEDYNAMIC bufferString(Lorg/jruby/runtime/ThreadContext;)Lorg/jruby/RubyStr ALOAD 0 INVOKEDYNAMIC frozen(Lorg/jruby/runtime/ThreadContext;)Lorg/jruby/RubyString; INVOKEVIRTUAL org/jruby/RubyString.cat19 (Lorg/jruby/RubyString;)Lorg/jruby/Rub ALOAD 8 INVOKEVIRTUAL org/jruby/RubyString.appendAsDynamicString (Lorg/jruby/runtime/bu ALOAD 0 INVOKEDYNAMIC frozen(Lorg/jruby/runtime/ThreadContext;)Lorg/jruby/RubyString; INVOKEVIRTUAL org/jruby/RubyString.cat19 (Lorg/jruby/RubyString;)Lorg/jruby/Rub ALOAD 9 INVOKEVIRTUAL org/jruby/RubyString.appendAsDynamicString (Lorg/jruby/runtime/bu ALOAD 0 INVOKEDYNAMIC frozen(Lorg/jruby/runtime/ThreadContext;)Lorg/jruby/RubyString; INVOKEVIRTUAL org/jruby/RubyString.cat19 (Lorg/jruby/RubyString;)Lorg/jruby/Rub ALOAD 10 INVOKEVIRTUAL org/jruby/RubyString.appendAsDynamicString (Lorg/jruby/runtime/bu ASTORE 11

Slide 41

Slide 41 text

0001 putobject "foo" 0003 getlocal_WC_0 a@0 0005 dup 0006 objtostring 0008 anytostring 0009 putobject "bar" 0011 getlocal_WC_0 b@1 0013 dup 0014 objtostring 0016 anytostring 0017 putobject "baz" 0019 getlocal_WC_0 c@2 0021 dup 0022 objtostring 0024 anytostring 0025 concatstrings 6

Slide 42

Slide 42 text

BuildDynamicString • Allocate large enough buffer for all elements • Pro fi le to pick "right size"? • Static strings copy directly into buffer • "Appendable" objects copy directly into buffer • Only non-String objects create temporary strings

Slide 43

Slide 43 text

ALOAD 0 INVOKEDYNAMIC bufferString(Lorg/jruby/runtime/ThreadContext;)Lorg/jruby/RubyStr ALOAD 0 INVOKEDYNAMIC frozen(Lorg/jruby/runtime/ThreadContext;)Lorg/jruby/RubyString; INVOKEVIRTUAL org/jruby/RubyString.cat19 (Lorg/jruby/RubyString;)Lorg/jruby/Rub ALOAD 8 INVOKEVIRTUAL org/jruby/RubyString.appendAsDynamicString (Lorg/jruby/runtime/bu ALOAD 0 INVOKEDYNAMIC frozen(Lorg/jruby/runtime/ThreadContext;)Lorg/jruby/RubyString; INVOKEVIRTUAL org/jruby/RubyString.cat19 (Lorg/jruby/RubyString;)Lorg/jruby/Rub ALOAD 9 INVOKEVIRTUAL org/jruby/RubyString.appendAsDynamicString (Lorg/jruby/runtime/bu ALOAD 0 INVOKEDYNAMIC frozen(Lorg/jruby/runtime/ThreadContext;)Lorg/jruby/RubyString; INVOKEVIRTUAL org/jruby/RubyString.cat19 (Lorg/jruby/RubyString;)Lorg/jruby/Rub ALOAD 10 INVOKEVIRTUAL org/jruby/RubyString.appendAsDynamicString (Lorg/jruby/runtime/bu ASTORE 11

Slide 44

Slide 44 text

ALOAD 0 ALOAD 8 ALOAD 9 ALOAD 10 INVOKEDYNAMIC buildDynamicString(Lorg/jruby/runtime // handle kind 0x6 : INVOKESTATIC org/jruby/ir/targets/indy/BuildDynamicStringSite. // arguments: "foo", "UTF-8",

Slide 45

Slide 45 text

0 7.5 15 22.5 30 "#{n}" "foo#{n}" "#{n}bar" "#{n}#{n}" "foo#{n}bar" "#{n}bar#{n}" "#{n}#{n}bar" "foo#{n}#{n}" "#{n}#{n}#{n}" "foo#{n}bar#{n}baz" "foo#{n}bar#{n}baz#{n}" "#{x}#{x}#{x}#{x}#{x}" "#{x}#{x}#{x}#{x}#{x}#{x}#{x}#{x}#{x}#{x}" CRuby 3.4 YJIT JRuby 10

Slide 46

Slide 46 text

Many Opportunities • Special variables like $~ and $_ • Read-only closure variables passed on stack • Block-receiving methods inlined with block • Smarter object shapes for instance variables, strings, arrays • Inline super calls, re fi nements, metaprogramming, and more • JRuby 10 will be faster and warm up more quickly!

Slide 47

Slide 47 text

Modern JVM

Slide 48

Slide 48 text

Better Fibers

Slide 49

Slide 49 text

Fibers with Project Loom • Thread-based fi bers don't scale • Enumerators use fi bers • Structured concurrency is coming • Loom brings fi bers to JVM • Easily handles thousands of fi bers • Faster context-switching • Working with @ioquatix on async

Slide 50

Slide 50 text

Faster FFI

Slide 51

Slide 51 text

FFI With Project Panama • Foreign function interface (FFI) • With JVM help to make direct calls • Foreign memory API • JVM-assisted access, lifecycle • Make FFI calls as fast as C ext • Time to get rid of C extensions! • Generate Panama FFI, call from Ruby, better than writing C!

Slide 52

Slide 52 text

Faster Startup and Warmup

Slide 53

Slide 53 text

JRuby Compiler Pipeline Ruby (.rb) JIT Java Instructions (java bytecode) Ruby Instructions (IR) parse interpret interpreter interpret C1 compile native code better native code java bytecode interpreter execute C2 compile Java Virtual Machine JRuby Internals

Slide 54

Slide 54 text

Startup Time • Very hard for JRuby, due to JVM design • Project CRaC: checkpoint and restore (Linux-only) • Snapshot a warm JRuby and jump back in • Project Leyden: ahead-of-time optimization for OpenJDK • Early access builds are promising! • JVM JIT server: start with JIT code from previous run

Slide 55

Slide 55 text

ruby -e 1 0s 0.45s 0.9s 1.35s 1.8s -e 1 0.21s 0.635s 1.271s 1.686s 0.053s CRuby 3.2 JRuby 9.4 JRuby 9.4 --dev JRuby 9.4 Leyden JRuby 9.4 CRaC

Slide 56

Slide 56 text

rails new testapp --skip-bundle 0s 1.5s 3s 4.5s 6s rails new testapp --skip-bundle 0.89s 1.35s 2.7s 5.918s 0.314s CRuby JRuby JRuby --dev JRuby Leyden JRuby CRaC

Slide 57

Slide 57 text

Just a Matter of Time!

Slide 58

Slide 58 text

Future of JRuby

Slide 59

Slide 59 text

Big Plans • Maintaining parity with CRuby features • Leveraging all the new JVM features • Optimizing all the things • Tooling for the enterprise • Mobile and embedded enhancements

Slide 60

Slide 60 text

JRuby Needs You! • Sponsor @headius on Github • Help me keep building JRuby • Publicity for you or your company! • Commercial JRuby support now available • Contact [email protected] • Let us know how we can help you!

Slide 61

Slide 61 text

Thank you! Support JRuby! JRuby Support! https://github.com/sponsors/headius https://www.headius.com/jruby-support