llrb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.gitmodules +4 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +56 -0
  8. data/README.md +311 -0
  9. data/Rakefile +30 -0
  10. data/bin/bm_app_fib +41 -0
  11. data/bin/bm_empty_method +33 -0
  12. data/bin/bm_loop_while +27 -0
  13. data/bin/bm_plus +33 -0
  14. data/bin/console +14 -0
  15. data/bin/loop_while.rb +5 -0
  16. data/bin/setup +8 -0
  17. data/ext/llrb/cfg.h +124 -0
  18. data/ext/llrb/compiler.c +987 -0
  19. data/ext/llrb/compiler/funcs.h +164 -0
  20. data/ext/llrb/compiler/stack.h +43 -0
  21. data/ext/llrb/cruby.h +42 -0
  22. data/ext/llrb/cruby/ccan/build_assert/build_assert.h +40 -0
  23. data/ext/llrb/cruby/ccan/check_type/check_type.h +63 -0
  24. data/ext/llrb/cruby/ccan/container_of/container_of.h +142 -0
  25. data/ext/llrb/cruby/ccan/list/list.h +773 -0
  26. data/ext/llrb/cruby/ccan/str/str.h +16 -0
  27. data/ext/llrb/cruby/internal.h +1774 -0
  28. data/ext/llrb/cruby/iseq.h +252 -0
  29. data/ext/llrb/cruby/method.h +213 -0
  30. data/ext/llrb/cruby/node.h +520 -0
  31. data/ext/llrb/cruby/probes_helper.h +43 -0
  32. data/ext/llrb/cruby/ruby_assert.h +54 -0
  33. data/ext/llrb/cruby/ruby_atomic.h +233 -0
  34. data/ext/llrb/cruby/thread_pthread.h +54 -0
  35. data/ext/llrb/cruby/vm_core.h +1646 -0
  36. data/ext/llrb/cruby/vm_debug.h +37 -0
  37. data/ext/llrb/cruby/vm_exec.h +182 -0
  38. data/ext/llrb/cruby/vm_opts.h +57 -0
  39. data/ext/llrb/cruby_extra/id.h +220 -0
  40. data/ext/llrb/cruby_extra/insns.inc +113 -0
  41. data/ext/llrb/cruby_extra/insns_info.inc +796 -0
  42. data/ext/llrb/cruby_extra/probes.h +80 -0
  43. data/ext/llrb/extconf.rb +102 -0
  44. data/ext/llrb/llrb.c +148 -0
  45. data/ext/llrb/optimizer.cc +118 -0
  46. data/ext/llrb/parser.c +191 -0
  47. data/ext/llrb/profiler.c +336 -0
  48. data/ext/llrb_insn_checkkeyword.c +20 -0
  49. data/ext/llrb_insn_checkmatch.c +28 -0
  50. data/ext/llrb_insn_concatarray.c +23 -0
  51. data/ext/llrb_insn_concatstrings.c +21 -0
  52. data/ext/llrb_insn_defined.c +9 -0
  53. data/ext/llrb_insn_getclassvariable.c +10 -0
  54. data/ext/llrb_insn_getinstancevariable.c +44 -0
  55. data/ext/llrb_insn_getlocal.c +14 -0
  56. data/ext/llrb_insn_getlocal_level0.c +8 -0
  57. data/ext/llrb_insn_getlocal_level1.c +8 -0
  58. data/ext/llrb_insn_getspecial.c +14 -0
  59. data/ext/llrb_insn_invokeblock.c +39 -0
  60. data/ext/llrb_insn_invokesuper.c +47 -0
  61. data/ext/llrb_insn_opt_aref.c +25 -0
  62. data/ext/llrb_insn_opt_aset.c +28 -0
  63. data/ext/llrb_insn_opt_div.c +32 -0
  64. data/ext/llrb_insn_opt_eq.c +57 -0
  65. data/ext/llrb_insn_opt_ge.c +28 -0
  66. data/ext/llrb_insn_opt_gt.c +38 -0
  67. data/ext/llrb_insn_opt_le.c +29 -0
  68. data/ext/llrb_insn_opt_lt.c +38 -0
  69. data/ext/llrb_insn_opt_ltlt.c +27 -0
  70. data/ext/llrb_insn_opt_minus.c +36 -0
  71. data/ext/llrb_insn_opt_mod.c +32 -0
  72. data/ext/llrb_insn_opt_mult.c +30 -0
  73. data/ext/llrb_insn_opt_neq.c +103 -0
  74. data/ext/llrb_insn_opt_plus.c +48 -0
  75. data/ext/llrb_insn_opt_send_without_block.c +45 -0
  76. data/ext/llrb_insn_opt_str_freeze.c +12 -0
  77. data/ext/llrb_insn_putspecialobject.c +23 -0
  78. data/ext/llrb_insn_send.c +49 -0
  79. data/ext/llrb_insn_setclassvariable.c +19 -0
  80. data/ext/llrb_insn_setconstant.c +23 -0
  81. data/ext/llrb_insn_setinstancevariable.c +48 -0
  82. data/ext/llrb_insn_setlocal.c +16 -0
  83. data/ext/llrb_insn_setlocal_level0.c +9 -0
  84. data/ext/llrb_insn_setlocal_level1.c +10 -0
  85. data/ext/llrb_insn_setspecial.c +15 -0
  86. data/ext/llrb_insn_splatarray.c +13 -0
  87. data/ext/llrb_insn_throw.c +11 -0
  88. data/ext/llrb_insn_trace.c +37 -0
  89. data/ext/llrb_push_result.c +14 -0
  90. data/ext/llrb_self_from_cfp.c +12 -0
  91. data/ext/llrb_set_pc.c +8 -0
  92. data/lib/llrb.rb +2 -0
  93. data/lib/llrb/jit.rb +76 -0
  94. data/lib/llrb/start.rb +2 -0
  95. data/lib/llrb/version.rb +3 -0
  96. data/llrb.gemspec +48 -0
  97. data/wercker.yml +31 -0
  98. metadata +227 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6a0d444c8fb55a7f69c33bd803cd86a39533f73d
4
+ data.tar.gz: 0403e982edb24a764bfee28bf2f7356982c6500b
5
+ SHA512:
6
+ metadata.gz: aa33e4543d3478c82409862252f39a08e63327e51582e6575452d20b0da4df5fe04447e7cf8156ff9eba351c12b1ce4d7c7840b48d97083875a4da9e18464f01
7
+ data.tar.gz: d97bec3202de9f3693f7edf453509052737909a0e3799ccef6dee3ad05802ac9cdb96e715f3ff280b445dca7cb0725aae94b5daa123ee4fa5e0722580cfde50d
@@ -0,0 +1,21 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.ll
16
+ *.bc
17
+ /core*
18
+ /optcarrot
19
+
20
+ # rspec failure tracking
21
+ .rspec_status
@@ -0,0 +1,4 @@
1
+ [submodule "ext/llrb/cruby"]
2
+ path = ext/llrb/cruby
3
+ url = https://github.com/k0kubun/ruby.git
4
+ shallow = true
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.15.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in llrb.gemspec
4
+ gemspec
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the
3
+ 2-clause BSDL (see the file BSDL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a) distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
@@ -0,0 +1,311 @@
1
+ # LLRB [![wercker status](https://app.wercker.com/status/71d808ff9de7f4f411714d40f9e99127/s/master "wercker status")](https://app.wercker.com/project/byKey/71d808ff9de7f4f411714d40f9e99127)
2
+
3
+ LLRB is a LLVM-based JIT compiler for Ruby.
4
+
5
+ ## What's LLRB?
6
+
7
+ This is an experimental project to implement an idea presented by [@evanphx](https://github.com/evanphx) at [RubyKaigi 2015 Keynote](http://rubykaigi.org/2015/presentations/evanphx):<br>
8
+ Method JIT compiler inlining CRuby core functions using LLVM.
9
+
10
+ ### How does it work?
11
+
12
+ On build time, some core functions are compiled to LLVM bitcode (binary form of LLVM IR) files via LLVM IR.
13
+
14
+ ```
15
+ ________ _________ ______________
16
+ | | | | | |
17
+ | CRuby | | CRuby | | CRuby |
18
+ | C code |-->| LLVM IR |-->| LLVM bitcode |
19
+ |________| |_________| |______________|
20
+ ```
21
+
22
+ Those files are separated per function to load only necessary functions.
23
+ You can see how they are separated in [ext directory](./ext).
24
+
25
+ After profiler of LLRB JIT is started, when Ruby is running,
26
+ LLRB compiles Ruby method's YARV Instruction Sequence to native machine code.
27
+
28
+ ```
29
+ ______ ______________ __________ ___________ _________
30
+ | | | | | | | | | |
31
+ | YARV | | ISeq Control | | LLVM IR | | Optimized | | Machine |
32
+ | ISeq |-->| Flow Graph |-*->| for ISeq |-*->| LLVM IR |-*->| code |
33
+ |______| |______________| | |__________| | |___________| | |_________|
34
+ | | |
35
+ | Link | Optimize | JIT compile
36
+ ______|_______ ___|____ __|____
37
+ | | | | | |
38
+ | CRuby | | LLVM | | LLVM |
39
+ | LLVM Bitcode | | Passes | | MCJIT |
40
+ |______________| |________| |_______|
41
+ ```
42
+
43
+ ### Does it improve performance?
44
+
45
+ Now basic instruction inlining is done. Let's see its effect.
46
+
47
+ Consider following Ruby method, which is the same as [ruby/benchmark/bm\_loop\_whileloop.rb](https://github.com/ruby/ruby/blob/v2_4_1/benchmark/bm_loop_whileloop.rb).
48
+
49
+ ```rb
50
+ def while_loop
51
+ i = 0
52
+ while i<30_000_000
53
+ i += 1
54
+ end
55
+ end
56
+ ```
57
+
58
+ The YARV ISeq, compilation target in LLRB, is this:
59
+
60
+ ```
61
+ > puts RubyVM::InstructionSequence.of(method(:while_loop)).disasm
62
+ == disasm: #<ISeq:while_loop@(pry)>=====================================
63
+ == catch table
64
+ | catch type: break st: 0015 ed: 0035 sp: 0000 cont: 0035
65
+ | catch type: next st: 0015 ed: 0035 sp: 0000 cont: 0012
66
+ | catch type: redo st: 0015 ed: 0035 sp: 0000 cont: 0015
67
+ |------------------------------------------------------------------------
68
+ local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
69
+ [ 1] i
70
+ 0000 trace 8 ( 1)
71
+ 0002 trace 1 ( 2)
72
+ 0004 putobject_OP_INT2FIX_O_0_C_
73
+ 0005 setlocal_OP__WC__0 3
74
+ 0007 trace 1 ( 3)
75
+ 0009 jump 25
76
+ 0011 putnil
77
+ 0012 pop
78
+ 0013 jump 25
79
+ 0015 trace 1 ( 4)
80
+ 0017 getlocal_OP__WC__0 3
81
+ 0019 putobject_OP_INT2FIX_O_1_C_
82
+ 0020 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE>, <callcache>
83
+ 0023 setlocal_OP__WC__0 3
84
+ 0025 getlocal_OP__WC__0 3 ( 3)
85
+ 0027 putobject 30000000
86
+ 0029 opt_lt <callinfo!mid:<, argc:1, ARGS_SIMPLE>, <callcache>
87
+ 0032 branchif 15
88
+ 0034 putnil
89
+ 0035 trace 16 ( 6)
90
+ 0037 leave ( 4)
91
+ => nil
92
+ ```
93
+
94
+ By LLRB compiler, such YARV ISeq is compiled to LLVM IR like:
95
+
96
+ ```llvm
97
+ define i64 @llrb_exec(i64, i64) {
98
+ label_0:
99
+ call void @llrb_insn_trace(i64 %0, i64 %1, i32 8, i64 52)
100
+ call void @llrb_insn_trace(i64 %0, i64 %1, i32 1, i64 52)
101
+ call void @llrb_insn_setlocal_level0(i64 %1, i64 3, i64 1)
102
+ call void @llrb_insn_trace(i64 %0, i64 %1, i32 1, i64 52)
103
+ br label %label_25
104
+
105
+ label_15: ; preds = %label_25
106
+ call void @llrb_insn_trace(i64 %0, i64 %1, i32 1, i64 52)
107
+ %2 = call i64 @llrb_insn_getlocal_level0(i64 %1, i64 3)
108
+ call void @llrb_set_pc(i64 %1, i64 94225474387824)
109
+ %opt_plus = call i64 @llrb_insn_opt_plus(i64 %2, i64 3)
110
+ call void @llrb_insn_setlocal_level0(i64 %1, i64 3, i64 %opt_plus)
111
+ br label %label_25
112
+
113
+ label_25: ; preds = %label_15, %label_0
114
+ %3 = call i64 @llrb_insn_getlocal_level0(i64 %1, i64 3)
115
+ call void @llrb_set_pc(i64 %1, i64 94225474387896)
116
+ %opt_lt = call i64 @llrb_insn_opt_lt(i64 %3, i64 60000001)
117
+ %RTEST_mask = and i64 %opt_lt, -9
118
+ %RTEST = icmp ne i64 %RTEST_mask, 0
119
+ br i1 %RTEST, label %label_15, label %label_34
120
+
121
+ label_34: ; preds = %label_25
122
+ call void @llrb_insn_trace(i64 %0, i64 %1, i32 16, i64 8)
123
+ call void @llrb_set_pc(i64 %1, i64 94225474387960)
124
+ call void @llrb_push_result(i64 %1, i64 8)
125
+ ret i64 %1
126
+ }
127
+ ```
128
+
129
+ As LLRB compiler links precompiled LLVM bitcode of CRuby functions,
130
+ using LLVM's FunctionInliningPass ("Pass" is LLVM's optimizer),
131
+ some C functions are inlined and inlined code will be well optimized by Passes like InstCombinePass.
132
+
133
+ ```llvm
134
+ define i64 @llrb_exec(i64, i64) #0 {
135
+ ...
136
+
137
+ land.lhs.true.i: ; preds = %label_25
138
+ %49 = load %struct.rb_vm_struct*, %struct.rb_vm_struct** @ruby_current_vm, align 8, !dbg !3471, !tbaa !3472
139
+ %arrayidx.i = getelementptr inbounds %struct.rb_vm_struct, %struct.rb_vm_struct* %49, i64 0, i32 39, i64 7, !dbg !3471
140
+ %50 = load i16, i16* %arrayidx.i, align 2, !dbg !3471, !tbaa !3473
141
+ %and2.i = and i16 %50, 1, !dbg !3471
142
+ %tobool6.i = icmp eq i16 %and2.i, 0, !dbg !3471
143
+ br i1 %tobool6.i, label %if.then.i, label %if.else11.i, !dbg !3475, !prof !3380
144
+
145
+ if.then.i: ; preds = %land.lhs.true.i
146
+ call void @llvm.dbg.value(metadata i64 %48, i64 0, metadata !2680, metadata !3361) #7, !dbg !3477
147
+ call void @llvm.dbg.value(metadata i64 60000001, i64 0, metadata !2683, metadata !3361) #7, !dbg !3478
148
+ %cmp7.i = icmp slt i64 %48, 60000001, !dbg !3479
149
+ %..i = select i1 %cmp7.i, i64 20, i64 0, !dbg !3481
150
+ br label %llrb_insn_opt_lt.exit
151
+
152
+ if.else11.i: ; preds = %land.lhs.true.i, %label_25
153
+ %call35.i = call i64 (i64, i64, i32, ...) @rb_funcall(i64 %48, i64 60, i32 1, i64 60000001) #7, !dbg !3483
154
+ br label %llrb_insn_opt_lt.exit, !dbg !3486
155
+
156
+ llrb_insn_opt_lt.exit: ; preds = %if.then.i, %if.else11.i
157
+ %retval.1.i = phi i64 [ %..i, %if.then.i ], [ %call35.i, %if.else11.i ]
158
+ %RTEST_mask = and i64 %retval.1.i, -9
159
+ %RTEST = icmp eq i64 %RTEST_mask, 0
160
+
161
+ ...
162
+ }
163
+ ```
164
+
165
+ In this example, you can see many things are inlined.
166
+ LLRB's compiled code fetches RubyVM state and check whether `<` method is redefined or not,
167
+ and if `<` is not redefined, `if.then.i` block is used and in that block `icmp slt` is used instead of calling Ruby method `#<`.
168
+ Note that it's done by just inlining YARV's `opt_lt` instruction directly and it's not hard to implement.
169
+
170
+ Thus, following benchmark shows the performance is improved.
171
+
172
+ ```rb
173
+ ruby = Class.new
174
+ def ruby.script
175
+ i = 0
176
+ while i< 30_000_000
177
+ i += 1
178
+ end
179
+ end
180
+
181
+ llrb = Class.new
182
+ def llrb.script
183
+ i = 0
184
+ while i< 30_000_000
185
+ i += 1
186
+ end
187
+ end
188
+
189
+ LLRB::JIT.compile(llrb, :script)
190
+
191
+ Benchmark.ips do |x|
192
+ x.report('Ruby') { ruby.script }
193
+ x.report('LLRB') { llrb.script }
194
+ x.compare!
195
+ end
196
+ ```
197
+
198
+ ```
199
+ # x86_64 GNU/Linux, Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz
200
+ Calculating -------------------------------------
201
+ Ruby 2.449 (± 0.0%) i/s - 13.000 in 5.308125s
202
+ LLRB 8.533 (± 0.0%) i/s - 43.000 in 5.040016s
203
+
204
+ Comparison:
205
+ LLRB: 8.5 i/s
206
+ Ruby: 2.4 i/s - 3.48x slower
207
+ ```
208
+
209
+ ## How is the design?
210
+ ### Built as C extension
211
+
212
+ Currently LLRB is in an experimental stage. For fast development and to stay up-to-date
213
+ for CRuby core changes, LLRB is built as C extension.
214
+ We can use bundler, benchmark-ips, pry, everything else in normal C extension repository. It's hard in just CRuby fork.
215
+
216
+ For optimization, unfortunately it needs to export some symbols from CRuby,
217
+ so it needs to compile [k0kubun/ruby's llrb branch](https://github.com/k0kubun/ruby/tree/llrb)
218
+ and install llrb.gem from that Ruby.
219
+
220
+ But I had the rule that I don't add modification except exporting symbols.
221
+ And LLRB code refers to such exported functions or variables in CRuby core by including CRuby header as possible.
222
+ I believe it contributes to maintainability of LLRB prototype.
223
+
224
+ ### Conservative design for safety
225
+
226
+ YARV is already proven to be reliable. In LLRB, YARV is not modified at all.
227
+ Then, how is JIT achieved?
228
+
229
+ YARV has `opt_call_c_function` instruction, which is explained to ["call native compiled method"](https://github.com/ruby/ruby/blob/v2_4_1/insns.def#L2136).
230
+ Why not use that?
231
+
232
+ LLRB compiles any ISeq to following ISeq.
233
+
234
+ ```
235
+ 0000 opt_call_c_function
236
+ 0002 leave
237
+ ```
238
+
239
+ So simple. Note that `opt_call_c_function` [can handle YARV's internal exception](https://github.com/ruby/ruby/blob/v2_4_1/insns.def#L2147-L2151).
240
+ In that instruction, we can do everything.
241
+
242
+ One more conservative thing in LLRB is that it fills `leave` instructions to remaining places.
243
+ To let YARV catch table work, it needs to update program counter properly,
244
+ and then it requires an instruction to the place that program counter points to.
245
+
246
+ For safe exit when catch table is used, `leave` instructions are filled to the rest of first `opt_call_c_function`.
247
+
248
+ ### Sampling-based lightweight profiler
249
+
250
+ Sampling profiler is promising approach to reduce the overhead of profiling without spoiling profiling efficiency.
251
+ LLRB's profiler to schedule JIT-ed ISeq is implemented in almost the same way as [stackprof](https://github.com/tmm1/stackprof).
252
+ It is widely-used on production and proven to be a reliable approach.
253
+
254
+ It kicks profiler in some CPU-time interval, and the parameter can be modified if necessary.
255
+ Using [optcarrot](https://github.com/mame/optcarrot) benchmark, I tested profiler overhead
256
+ and LLRB's profiler didn't reduce the fps of optcarrot with current parameter.
257
+
258
+ Also, it uses `rb_postponed_job_register_one` API, which is used by stackprof too, to do JIT compile.
259
+ So the compilation is done in very safe timing.
260
+
261
+ ### Less compilation effort
262
+
263
+ CRuby's C functions to inline are precompiled as LLVM bitcode on LLRB build process.
264
+ LLRB's compiler builds LLVM IR using LLVM IRBuilder, so the bitcode files are directly linked to that.
265
+
266
+ It means that LLRB has no overhead of parsing and compiling C source code on runtime.
267
+ It has less compilation effort, right?
268
+
269
+ Currently the performance bottleneck is not in compiler, unfortunately!
270
+ So it doesn't use extra thread for JIT compilation for now.
271
+
272
+ ## Project status
273
+
274
+ Experimental. Not matured at all.
275
+
276
+ Everything I said above is already implemented, but that's all!
277
+ Core function inlining is achieved but it's not completely applied to all instructions
278
+ and we need MUCH MORE effort to improve performance in real-world application.
279
+
280
+ ## Build dependency
281
+
282
+ - **64bit CPU**
283
+ - This should be fixed later
284
+ - LLVM/clang 3.8+
285
+ - `llvm-config`, `clang` and `llvm-as` commands need to appear in `$PATH`
286
+ - [CRuby fork in k0kubun/ruby's llrb branch](https://github.com/k0kubun/ruby/tree/llrb)
287
+
288
+ ## Usage
289
+
290
+ Once build dependency is met, execute `gem install llrb` and do:
291
+
292
+ ```ruby
293
+ require 'llrb/start'
294
+ ```
295
+
296
+ `llrb/start` file does `LLRB::JIT.start`. Note that you can also do that by `ruby -rllrb/start -e "..."`.
297
+
298
+ If you want to see which method is compiled, compile the gem with `#define LLRB_ENABLE_DEBUG 1`.
299
+ Again, it's in an experimental stage and currently it doesn't improve performance in real-world application.
300
+
301
+ ## TODOs
302
+
303
+ - Improve performance...
304
+ - Implement ISeq method inlining
305
+ - Support all YARV instructions
306
+ - `expandarray`, `reverse`, `reput`, `defineclass`, `once`, `opt_call_c_function` are not supported yet.
307
+ - Care about unexpectedly GCed object made during compilation
308
+
309
+ ## License
310
+
311
+ The same as Ruby.
@@ -0,0 +1,30 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ require 'rake/extensiontask'
7
+
8
+ task :build => :compile
9
+
10
+ Rake::ExtensionTask.new('llrb') do |ext|
11
+ ext.lib_dir = 'lib/llrb'
12
+ end
13
+
14
+ task :default => [:compile, :spec]
15
+
16
+ desc 'Clone optcarrot'
17
+ file :optcarrot do
18
+ sh 'git clone --depth 1 https://github.com/mame/optcarrot'
19
+ Dir.chdir("#{__dir__}/optcarrot") do
20
+ File.write('Gemfile', "#{File.read('Gemfile')}\ngem 'llrb', path: '..'\n")
21
+ end
22
+ end
23
+
24
+ desc 'Run optcarrot benchmark'
25
+ task 'optcarrot:run' => :optcarrot do
26
+ Dir.chdir("#{__dir__}/optcarrot") do
27
+ sh "bundle check || bundle install -j#{`nproc`.rstrip}"
28
+ sh 'bundle exec ruby -I../lib -rllrb/start bin/optcarrot --benchmark examples/Lan_Master.nes'
29
+ end
30
+ end