Ruby & JVM:
A (Jruby) Love Story
Yarden Laifenfeld
@yardenlaif
@[email protected]
Slide 2
Slide 2 text
2
Who Am I?
• Software Engineer at Rookout
• Background in low level C
programming in linux IOT
environments
• Ruby, Java, Go
• C#, Python, JavaScript, C++
Slide 3
Slide 3 text
Non Breaking Breakpoints
3
Slide 4
Slide 4 text
What is JRuby?
4
“ JRuby is a 100% Java implementation of
the Ruby programming language. It is Ruby
for the JVM. ”
- the JRuby wiki
Slide 5
Slide 5 text
Running an app
5
● rails server -p 8080 -e development
Slide 6
Slide 6 text
Running an app
6
rvm install jruby
rvm use jruby
bundle install
Slide 7
Slide 7 text
Running an app
7
Slide 8
Slide 8 text
Running an app
8
3 business days
later…
Slide 9
Slide 9 text
Running an app
9
bundle config unset force_ruby_platform
Slide 10
Slide 10 text
Running an app
10
➜ tutorial-ruby git:(master) ✗ jruby -S rails server -p 8080 -e development
=> Booting Puma
=> Rails 6.0.3.4 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.7 (jruby 9.2.9.0 - ruby 2.5.7), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://[::1]:8080
* Listening on tcp://127.0.0.1:8080
Use Ctrl-C to stop
Slide 11
Slide 11 text
Running an app
11
➜ tutorial-ruby git:(master) ✗ jruby -S rails server -p 8080 -e development
=> Booting Puma
=> Rails 6.0.3.4 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.7 (jruby 9.2.9.0 - ruby 2.5.7), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://[::1]:8080
* Listening on tcp://127.0.0.1:8080
Use Ctrl-C to stop
Slide 12
Slide 12 text
Running an app
12
➜ tutorial-ruby git:(master) ✗ jruby -S rails server -p 8080 -e development
=> Booting Puma
=> Rails 6.0.3.4 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.7 (jruby 9.2.9.0 - ruby 2.5.7), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://[::1]:8080
* Listening on tcp://127.0.0.1:8080
Use Ctrl-C to stop
Slide 13
Slide 13 text
Supporting JRuby in one of
Rookout’s debuggers
13
Slide 14
Slide 14 text
Decision Time
14
Java or Ruby
Slide 15
Slide 15 text
Java
15
● JVM API
● Instrument bytecode
● No debugger
● Ruby API
● Use built in functionality
● Pry already exists
Ruby
Slide 16
Slide 16 text
Decision Time
16
Java or Ruby
Slide 17
Slide 17 text
Supporting JRuby
17
❏ Running an app
❏ Adding a breakpoint
❏ Collecting data
Running an app
19
➜ tutorial-ruby git:(master) ✗ jruby -S rails server -p 8080 -e
development
Slide 20
Slide 20 text
Running an app
20
➜ tutorial-ruby git:(master) ✗ jruby -S rails server -p 8080 -e
development
[Rookout] Successfully connected to controller.
Slide 21
Slide 21 text
Running an app
21
Slide 22
Slide 22 text
TracePoints
22
Slide 23
Slide 23 text
TracePoints
23
tracepoint = Tracepoint.new(:line) do
# Collect locals, stacktrace...
end
Slide 24
Slide 24 text
TracePoints
24
t = TracePoint.new(:line) { |tp| p tp }
t.enable(target: method(:m1))
Slide 25
Slide 25 text
TracePoints
25
Slide 26
Slide 26 text
TracePoints
26
trace_point = TracePoint.new :script_compiled do |tp|
iseq = tp.instruction_sequence
@iseqs << iseq
end
trace_point.enable
Slide 27
Slide 27 text
TracePoints
27
@iseqs.each do |iseq|
if iseq.absolute_path == filename
t = TracePoint.new :line do |tp|
# Collect locals, stacktrace...
end
t.enable target: iseq, target_line: lineno
end
end
Slide 28
Slide 28 text
TracePoints
28
Slide 29
Slide 29 text
TracePoints in JRuby
29
Slide 30
Slide 30 text
Workaround
30
tracepoint.enable
Slide 31
Slide 31 text
Supporting JRuby
31
✗ Running an app
❏ Adding a breakpoint
❏ Collecting data
Slide 32
Slide 32 text
Decision Time
32
Java or Ruby
Slide 33
Slide 33 text
Decision Time
33
Java or Ruby
Slide 34
Slide 34 text
Supporting JRuby
34
❏ Running an app
❏ Adding a breakpoint
❏ Collecting data
Slide 35
Slide 35 text
Running an app - Java Agents
35
● -javaagent flag
● premain entrypoint
● Instrumentation API
App
JavaAgent
Instrumentation API
Slide 36
Slide 36 text
Running an app
36
➜ tutorial-ruby git:(master) ✗ jruby -J-javaagent:rook.jar -S rails
server -p 8080 -e development
Slide 37
Slide 37 text
Running an app
37
➜ tutorial-ruby git:(master) ✗ jruby -J-javaagent:rook.jar -S rails
server -p 8080 -e development
[Rookout] Successfully connected to controller.
Slide 38
Slide 38 text
Running an app
38
➜ tutorial-ruby git:(master) ✗ jruby -J-javaagent:rook.jar -S rails server -p 8080 -e
development
[Rookout] Successfully connected to controller.
=> Booting Puma
=> Rails 6.0.6 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.12 (jruby 9.3.8.0 - ruby 2.6.8), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://[::1]:8080
* Listening on tcp://127.0.0.1:8080
Use Ctrl-C to stop
Slide 39
Slide 39 text
Supporting JRuby
39
✓ Running an app
❏ Adding a breakpoint
❏ Collecting data
Slide 40
Slide 40 text
Adding a breakpoint - Class Loaders
40
JVM
Compiler
Code Bytecode
Slide 41
Slide 41 text
Adding a breakpoint - Class Loaders
41
JVM
32 | …
33 | new Item()
34 | …
Class
Loader
Get Item
class bytecode
Return Item
class bytecode
Slide 42
Slide 42 text
Java Agent - ClassFileTransformer
42
JVM
32 | …
33 | new Item()
34 | … Class Loader
Get Item class
bytecode
Return Item
class bytecode
Class File
Transformer
Return new Item
class bytecode
Item class bytecode
Slide 43
Slide 43 text
43
Slide 44
Slide 44 text
44
Slide 45
Slide 45 text
45
Slide 46
Slide 46 text
46
Slide 47
Slide 47 text
47
Slide 48
Slide 48 text
48
Slide 49
Slide 49 text
49
Slide 50
Slide 50 text
50
A few, spaced out invocations
Many, rapid invocations
Class isn’t loaded
Class is loaded
Slide 51
Slide 51 text
51
A few, spaced out invocations
Many, rapid invocations
Class isn’t loaded
Class is loaded
JIT