llrb 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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