Statically Compiling
Ruby with LLVM
Laurent Sansonetti
HipByte
About me
•

Laurent Sansonetti
•

Programming Language Nerd

•

Founder of HipByte

•

From Belgium (yay!)
MacRuby
MacRuby
•

2007: Project created (as a hobby)
•

Replacement for RubyCocoa

•

Fork of CRuby 1.9

•

2008: Had a beer with...
RubyMotion
RubyMotion
•

Command-line toolchain for iOS / OS X dev

•

Implementation of Ruby dialect

•

Unified Ruby runtime with O...
RubyMotion
•

Command-line toolchain for iOS / OS X dev

•

Implementation of Ruby dialect

•

Unified Ruby runtime with O...
Ruby
Ruby
•

Created in 1995 by Yukihiro Matsumoto (Matz)
•

“human-oriented language”

•

Dynamically typed

•

Object oriente...
hello.rb
class Hello
def initialize(something)
@something = something
end
def say
puts “Hello “ + @something
end
end
!

He...
CRuby
Compilation

Ruby Code

AST
Bytecode

Runtime
Let’s use LLVM!
RubyMotion
Compilation

Ruby Code

AST
LLVM IR
Assembly
Runtime
RubyMotion compiler
•

About 12k C++ LOC

•

Targets LLVM 2.4

•

Supports the entire Ruby language “specifications”
File functions
class Hello
def initialize(something)
…
end
def say
…
end
end
!

class Ohai < Hello
def say
…
end
end
!

He...
Method functions
class Hello
…
def say
puts “Hello “ + @something
end
end

Method
IMP

Ruby Runtime

ObjC
Stub

ObjC Runti...
Methods
def hello(x, y, z)
…
end
Methods
define internal i32 @"rb_scope__hello:__"(i32 %self,
i8* %sel, i32 %a, i32 %b, i32 %c) {
MainBlock:
…
}
Conditionals
def hello(something)
if something
true
else
false
end
end
Conditionals
define internal i32 @"rb_scope__hello:__"(i32 %self, i8* %sel, i32 %something) {
MainBlock:
call void @llvm.d...
Local variables
•

Allocated on the stack
•

Benefits from the mem2reg pass
Block variables
•

Allocated initially on the stack

•

Re-allocated in heap memory in case the block
leaves the scope of ...
kernel.bc
•

Runtime primitives
•

vm_fast_{plus,minus,…} (arithmetic ops)

•

vm_ivar_{get,set} (instance variables)

•

...
Instance variables
def initialize(foo)
@foo = foo
end
Instance variables
define internal i32 @"rb_scope__initialize:__"(i32 %self, i8* %sel, i32 %foo) {
MainBlock:
%0 = alloca ...
Instance variables
PRIMITIVE void
vm_ivar_set(VALUE obj, ID name, VALUE val, void *cache_p)
{
…
klass = *(VALUE *)obj;
if ...
After passes
Instance variables
define internal i32 @"rb_scope__initialize:__"(i32 %self, i8* %sel, i32 %foo) {
MainBlock:
br label %en...
Arithmetic
def answer
21 + 21
end
Arithmetic
define internal i32 @rb_scope__answer__(i32 %self, i8* %sel) {
MainBlock:
br label %entry_point
!

entry_point:...
Arithmetic
PRIMITIVE VALUE
vm_fast_plus(VALUE left, VALUE right, unsigned char overridden)
{
if (overridden == 0 && NUMERI...
After passes
Arithmetic
define internal i32 @rb_scope__answer__(i32 %self, i8* %sel) {
MainBlock:
br label %entry_point
!

entry_point:...
Exceptions
•

Implemented as C++ exceptions

•

Zero-cost for “normal flow”

•

Handlers are compiled using IR intrinsics
...
DWARF
•

All instructions have proper debug location
metadata

•

Method/block arguments and local variables are
tagged as...
REPL
•

Allows to interpret expressions at runtime
•

Only for development (simulator)

•

App process loads the compiler
...
Demo
LLVM lessons
Pluses
• Great to write static
compilers
• Easy to target new
platforms
• Lots of great
optimization passes

...
LLVM is awesome!
Thank you
lrz@hipbyte.com
Twitter: @lrz
Upcoming SlideShare
Loading in...5
×

Statically Compiling Ruby with LLVM

4,484

Published on

How RubyMotion makes use of LLVM to statically compile Ruby into machine code.

Talk given at the LLVM devroom at FOSDEM 2014.

Published in: Technology, Education
0 Comments
10 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
4,484
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
34
Comments
0
Likes
10
Embeds 0
No embeds

No notes for slide

Statically Compiling Ruby with LLVM

  1. 1. Statically Compiling Ruby with LLVM Laurent Sansonetti HipByte
  2. 2. About me • Laurent Sansonetti • Programming Language Nerd • Founder of HipByte • From Belgium (yay!)
  3. 3. MacRuby
  4. 4. MacRuby • 2007: Project created (as a hobby) • Replacement for RubyCocoa • Fork of CRuby 1.9 • 2008: Had a beer with Chris Lattner • 2009: Replaced bytecode VM by LLVM JIT • 2011: Left Apple
  5. 5. RubyMotion
  6. 6. RubyMotion • Command-line toolchain for iOS / OS X dev • Implementation of Ruby dialect • Unified Ruby runtime with Objective-C • Static compiler for Ruby into Intel/ARM • Platform for wrappers/libraries ecosystem • Commercial product & sustainable business
  7. 7. RubyMotion • Command-line toolchain for iOS / OS X dev • Implementation of Ruby dialect • Unified Ruby runtime with Objective-C • Static compiler for Ruby into Intel/ARM • Platform for wrappers/libraries ecosystem • Commercial product & sustainable business
  8. 8. Ruby
  9. 9. Ruby • Created in 1995 by Yukihiro Matsumoto (Matz) • “human-oriented language” • Dynamically typed • Object oriented • Blocks • Exceptions • Garbage collection • …
  10. 10. hello.rb class Hello def initialize(something) @something = something end def say puts “Hello “ + @something end end ! Hello.new(‘world’).say
  11. 11. CRuby Compilation Ruby Code AST Bytecode Runtime
  12. 12. Let’s use LLVM!
  13. 13. RubyMotion Compilation Ruby Code AST LLVM IR Assembly Runtime
  14. 14. RubyMotion compiler • About 12k C++ LOC • Targets LLVM 2.4 • Supports the entire Ruby language “specifications”
  15. 15. File functions class Hello def initialize(something) … end def say … end end ! class Ohai < Hello def say … end end ! Hello.new(‘world’).say File Scope 1 5 3 Hello Ctor 2 Hello Scope Ohai Ctor 4 Ohai Scope File Code
  16. 16. Method functions class Hello … def say puts “Hello “ + @something end end Method IMP Ruby Runtime ObjC Stub ObjC Runtime
  17. 17. Methods def hello(x, y, z) … end
  18. 18. Methods define internal i32 @"rb_scope__hello:__"(i32 %self, i8* %sel, i32 %a, i32 %b, i32 %c) { MainBlock: … }
  19. 19. Conditionals def hello(something) if something true else false end end
  20. 20. Conditionals define internal i32 @"rb_scope__hello:__"(i32 %self, i8* %sel, i32 %something) { MainBlock: call void @llvm.dbg.declare(metadata !{i32 %self}, metadata !23), !dbg !54 call void @llvm.dbg.value(metadata !{i32 %something}, i64 0, metadata !24), !dbg !54 %0 = alloca i8 store volatile i8 0, i8* %0 switch i32 %something, label %merge [ i32 0, label %else i32 4, label %else ] ! else: br label %merge ! ; preds = %MainBlock, %MainBlock merge: ; preds = %MainBlock, %else %iftmp = phi i32 [ 0, %else ], [ 2, %MainBlock ] ret i32 %iftmp }
  21. 21. Local variables • Allocated on the stack • Benefits from the mem2reg pass
  22. 22. Block variables • Allocated initially on the stack • Re-allocated in heap memory in case the block leaves the scope of the method
  23. 23. kernel.bc • Runtime primitives • vm_fast_{plus,minus,…} (arithmetic ops) • vm_ivar_{get,set} (instance variables) • vm_dispatch (method dispatch) • … • Pre-compiled into LLVM bitcode • Loaded by the compiler • Provides the initial module
  24. 24. Instance variables def initialize(foo) @foo = foo end
  25. 25. Instance variables define internal i32 @"rb_scope__initialize:__"(i32 %self, i8* %sel, i32 %foo) { MainBlock: %0 = alloca i32* %1 = alloca i32 store i32* %1, i32** %0 store i32 %foo, i32* %1 %2 = alloca i8 store volatile i8 0, i8* %2 br label %entry_point ! entry_point: %3 = load i32** %0 %4 = load i32* %3 %5 = load i32* @3 %6 = load i8** @4 call void @vm_ivar_set(i32 %self, i32 %5, i32 %4, i8* %6) ret i32 %4 }
  26. 26. Instance variables PRIMITIVE void vm_ivar_set(VALUE obj, ID name, VALUE val, void *cache_p) { … klass = *(VALUE *)obj; if (klass == cache->klass) { if ((unsigned int)cache->slot < ROBJECT(obj)->num_slots) { rb_object_ivar_slot_t *slot; slot = &ROBJECT(obj)->slots[cache->slot]; if (slot->name == name) { … GC_WB_OBJ(&slot->value, val); return; … // slow path PRIMITIVE VALUE vm_gc_wb(VALUE *slot, VALUE val) { … *slot = val; return val; }
  27. 27. After passes
  28. 28. Instance variables define internal i32 @"rb_scope__initialize:__"(i32 %self, i8* %sel, i32 %foo) { MainBlock: br label %entry_point ! entry_point: … %39 = getelementptr inbounds %struct.rb_object_ivar_slot_t* %28, i32 %26, i32 1 store i32 %4, i32* %39 … ret i32 %4 }
  29. 29. Arithmetic def answer 21 + 21 end
  30. 30. Arithmetic define internal i32 @rb_scope__answer__(i32 %self, i8* %sel) { MainBlock: br label %entry_point ! entry_point: %0 = load i8** @8 %1 = load i8* @9 %2 = call i32 @vm_fast_plus(i32 85, i32 85, i8 %1) ret i32 %2 }
  31. 31. Arithmetic PRIMITIVE VALUE vm_fast_plus(VALUE left, VALUE right, unsigned char overridden) { if (overridden == 0 && NUMERIC_P(left) && NUMERIC_P(right)) { if (FIXNUM_P(left) && FIXNUM_P(right)) { const long res = FIX2LONG(left) + FIX2LONG(right); if (FIXABLE(res)) { return LONG2FIX(res); } } } … // slow path }
  32. 32. After passes
  33. 33. Arithmetic define internal i32 @rb_scope__answer__(i32 %self, i8* %sel) { MainBlock: br label %entry_point ! entry_point: … ret i32 169 }
  34. 34. Exceptions • Implemented as C++ exceptions • Zero-cost for “normal flow” • Handlers are compiled using IR intrinsics • • “catch all” landing pad clause Exception#raise triggers __cxa_raise()
  35. 35. DWARF • All instructions have proper debug location metadata • Method/block arguments and local variables are tagged as DW_TAG_{arg,auto}_variable • Build system generates a .dSYM bundle • Can be loaded by gdb/lldb, atos(1), profilers, etc.
  36. 36. REPL • Allows to interpret expressions at runtime • Only for development (simulator) • App process loads the compiler • Uses JIT execution engine
  37. 37. Demo
  38. 38. LLVM lessons Pluses • Great to write static compilers • Easy to target new platforms • Lots of great optimization passes Minuses • C++ API breakage • Huge code size • IR is not 100% portable • Proprietary backends • Not as great to use as a JIT
  39. 39. LLVM is awesome!
  40. 40. Thank you lrz@hipbyte.com Twitter: @lrz
  1. Gostou de algum slide específico?

    Recortar slides é uma maneira fácil de colecionar informações para acessar mais tarde.

×