cast_off 0.2.0

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 (58) hide show
  1. data/README +578 -0
  2. data/README.en +256 -0
  3. data/bin/CastOff +145 -0
  4. data/cast_off.gemspec +25 -0
  5. data/ext/cast_off/cast_off.c.rb +1386 -0
  6. data/ext/cast_off/cast_off.h +24 -0
  7. data/ext/cast_off/depend +70 -0
  8. data/ext/cast_off/extconf.rb +19 -0
  9. data/ext/cast_off/generated_c_include/inline_api.h +507 -0
  10. data/ext/cast_off/generated_c_include/iter_api.h +595 -0
  11. data/ext/cast_off/generated_c_include/unbox_api.h.rb +76 -0
  12. data/ext/cast_off/generated_c_include/vm_api.h +751 -0
  13. data/ext/cast_off/ruby_source/atomic.h +56 -0
  14. data/ext/cast_off/ruby_source/constant.h +34 -0
  15. data/ext/cast_off/ruby_source/debug.h +41 -0
  16. data/ext/cast_off/ruby_source/eval_intern.h +234 -0
  17. data/ext/cast_off/ruby_source/gc.h +98 -0
  18. data/ext/cast_off/ruby_source/id.h +175 -0
  19. data/ext/cast_off/ruby_source/insns.inc +179 -0
  20. data/ext/cast_off/ruby_source/insns_info.inc +695 -0
  21. data/ext/cast_off/ruby_source/internal.h +227 -0
  22. data/ext/cast_off/ruby_source/iseq.h +125 -0
  23. data/ext/cast_off/ruby_source/manual_update.h +135 -0
  24. data/ext/cast_off/ruby_source/method.h +105 -0
  25. data/ext/cast_off/ruby_source/node.h +503 -0
  26. data/ext/cast_off/ruby_source/thread_pthread.h +51 -0
  27. data/ext/cast_off/ruby_source/thread_win32.h +40 -0
  28. data/ext/cast_off/ruby_source/vm_core.h +756 -0
  29. data/ext/cast_off/ruby_source/vm_exec.h +184 -0
  30. data/ext/cast_off/ruby_source/vm_insnhelper.c +1748 -0
  31. data/ext/cast_off/ruby_source/vm_insnhelper.h +220 -0
  32. data/ext/cast_off/ruby_source/vm_opts.h +51 -0
  33. data/lib/cast_off.rb +15 -0
  34. data/lib/cast_off/compile.rb +629 -0
  35. data/lib/cast_off/compile/basicblock.rb +144 -0
  36. data/lib/cast_off/compile/cfg.rb +391 -0
  37. data/lib/cast_off/compile/code_manager.rb +284 -0
  38. data/lib/cast_off/compile/configuration.rb +2368 -0
  39. data/lib/cast_off/compile/dependency.rb +240 -0
  40. data/lib/cast_off/compile/information.rb +775 -0
  41. data/lib/cast_off/compile/instruction.rb +446 -0
  42. data/lib/cast_off/compile/ir/call_ir.rb +2348 -0
  43. data/lib/cast_off/compile/ir/guard_ir.rb +423 -0
  44. data/lib/cast_off/compile/ir/jump_ir.rb +223 -0
  45. data/lib/cast_off/compile/ir/operand.rb +934 -0
  46. data/lib/cast_off/compile/ir/param_ir.rb +98 -0
  47. data/lib/cast_off/compile/ir/return_ir.rb +92 -0
  48. data/lib/cast_off/compile/ir/simple_ir.rb +808 -0
  49. data/lib/cast_off/compile/ir/sub_ir.rb +212 -0
  50. data/lib/cast_off/compile/iseq.rb +454 -0
  51. data/lib/cast_off/compile/method_information.rb +1384 -0
  52. data/lib/cast_off/compile/namespace/namespace.rb +556 -0
  53. data/lib/cast_off/compile/namespace/uuid.rb +323 -0
  54. data/lib/cast_off/compile/stack.rb +65 -0
  55. data/lib/cast_off/compile/translator.rb +1562 -0
  56. data/lib/cast_off/suggestion.rb +98 -0
  57. data/lib/cast_off/util.rb +58 -0
  58. metadata +107 -0
@@ -0,0 +1,144 @@
1
+ # coding=utf-8
2
+
3
+ module CastOff::Compiler
4
+ class Translator::CFG
5
+ class BasicBlock
6
+ include CastOff::Util
7
+ include CastOff::Compiler::Instruction
8
+ include CastOff::Compiler::SimpleIR
9
+
10
+ attr_reader :insns, :pre, :next, :labels, :number, :irs, :iseq
11
+
12
+ def initialize(cfg, insns, number)
13
+ @cfg = cfg
14
+ @insns = insns
15
+ bug() if @insns.find{|i| not i.instance_of?(InsnInfo)}
16
+ @number = number
17
+ @pre = nil
18
+ @next = nil
19
+ @labels = []
20
+ @irs = nil
21
+ @entry_point = number == 0
22
+ @iseq = @insns[0].iseq
23
+ bug() if @insns.find{|i| i.iseq != @iseq}
24
+ end
25
+
26
+ def entry_point?
27
+ @entry_point
28
+ end
29
+
30
+ def set_prev_block(blocks)
31
+ @pre = []
32
+ index = blocks.index(self)
33
+ if index != 0
34
+ pre = blocks[index - 1]
35
+ case pre
36
+ when Symbol
37
+ # this block is branch or jump target
38
+ @labels << pre
39
+ i = index - 2
40
+ while i >= 0
41
+ break unless blocks[i].is_a?(Symbol)
42
+ @labels << blocks[i]
43
+ i -= 1
44
+ end
45
+ matchlabels = []
46
+ blocks.each do |basicblock|
47
+ case basicblock when BasicBlock
48
+ last_insn = basicblock.insns.last
49
+ op = last_insn.op
50
+ argv = last_insn.argv
51
+ if BranchInstruction.include?(op)
52
+ case op
53
+ when :jump, :branchunless, :branchif, \
54
+ :cast_off_enter_block, :cast_off_leave_block, :cast_off_continue_loop, \
55
+ :cast_off_break_block
56
+ targets = [argv[0]]
57
+ when :cast_off_handle_optional_args
58
+ targets = argv[0]
59
+ else
60
+ bug("unexpected instruction #{op}")
61
+ end
62
+ targets.each do |t|
63
+ if @labels.include?(t)
64
+ matchlabels << t
65
+ @pre << basicblock unless @pre.include?(basicblock)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ if @pre.empty?
72
+ # join point with exception handler
73
+ # nothing to do
74
+ @labels = []
75
+ else
76
+ @labels = @labels & matchlabels
77
+ bug() if @labels.empty?
78
+ end
79
+ # consider fall-throuth from previous block
80
+ i = index - 2
81
+ while i >= 0
82
+ pre = blocks[i]
83
+ break if pre.is_a?(BasicBlock)
84
+ i -= 1
85
+ end
86
+ if pre.is_a?(BasicBlock)
87
+ last_insn = pre.insns.last
88
+ @pre << pre if !JumpOrReturnInstruction.include?(last_insn.op)
89
+ end
90
+ when BasicBlock
91
+ # fall-throuth from previous block
92
+ last_insn = pre.insns.last
93
+ if JumpOrReturnInstruction.include?(last_insn.op)
94
+ # dead block
95
+ else
96
+ @pre << pre
97
+ end
98
+ else
99
+ bug()
100
+ end
101
+ else
102
+ # entry point
103
+ end
104
+ end
105
+
106
+ def set_next_block(blocks)
107
+ @next = []
108
+ bug() if blocks.find{|b| b.instance_of?(BasicBlock) && !b.pre }
109
+ blocks.each{|b| @next << b if b.instance_of?(BasicBlock) && b.pre.include?(self)}
110
+ end
111
+
112
+ def gen_ir()
113
+ @irs = generate_ir(@cfg, @insns, in_depth())
114
+ end
115
+
116
+ def to_c()
117
+ params = []
118
+ codes = []
119
+ @labels.each{|label| codes << "#{label}:" }
120
+ @irs.each do |ir|
121
+ bug() unless ir.insn.iseq == @iseq
122
+ ir.variables.each{|v| @iseq.declare_local_variable("#{v.declare()} #{v}") if v.declare?}
123
+ case ir
124
+ when SubIR, JumpIR, ReturnIR, GuardIR
125
+ codes << ir.to_c()
126
+ when ParamIR
127
+ params << ir.param_value
128
+ when CallIR
129
+ codes << ir.to_c(params)
130
+ else
131
+ bug("invalid ir #{ir}")
132
+ end
133
+ end
134
+ bug() unless params.empty?
135
+ codes.join("\n")
136
+ end
137
+
138
+ def to_s()
139
+ "(#{@labels.join(", ")})BB#{@number}"
140
+ end
141
+ end
142
+ end
143
+ end
144
+
@@ -0,0 +1,391 @@
1
+ # coding=utf-8
2
+
3
+ module CastOff::Compiler
4
+ class Translator
5
+ class CFG
6
+ include CastOff::Util
7
+ include CastOff::Compiler::Instruction
8
+ include CastOff::Compiler::SimpleIR
9
+
10
+ attr_reader :blocks
11
+
12
+ def to_c()
13
+ @blocks.each{|b| b.iseq.append_c_function_body(b.to_c())}
14
+ end
15
+
16
+ def to_s()
17
+ @blocks.join("\n")
18
+ end
19
+
20
+ def translator
21
+ bug() unless @translator
22
+ @translator
23
+ end
24
+
25
+ def initialize(body)
26
+ @translator = nil
27
+ blocks = []
28
+ basicblock = []
29
+ body.each do |v|
30
+ case v
31
+ when InsnInfo
32
+ basicblock << v
33
+ if BlockSeparator.include?(v.op)
34
+ blocks << basicblock
35
+ basicblock = []
36
+ end
37
+ when Symbol
38
+ if !basicblock.empty?
39
+ blocks << basicblock
40
+ basicblock = []
41
+ end
42
+ blocks << v
43
+ else
44
+ bug("v = #{v}")
45
+ end
46
+ end
47
+ blocks << basicblock unless basicblock.empty?
48
+
49
+ bbnum = -1
50
+ blocks.map!{|b| b.instance_of?(Array) ? BasicBlock.new(self, b, bbnum += 1) : b}
51
+ blocks.each{|b| b.set_prev_block(blocks) if b.instance_of?(BasicBlock)}
52
+ blocks.each{|b| b.set_next_block(blocks) if b.instance_of?(BasicBlock)}
53
+ @blocks = blocks.select{|b| b.instance_of?(BasicBlock)}
54
+ @blocks.each{|b| bug() unless b.next && b.pre}
55
+
56
+ eliminate_unreachable_blocks()
57
+ validate_stack() # stack.rb
58
+ end
59
+
60
+ def gen_ir(t)
61
+ @translator = t
62
+ @blocks.each{|b| b.gen_ir()}
63
+ change = true
64
+ while change
65
+ change = false
66
+ set_information() # information.rb
67
+ type_propergation()
68
+ propergate_exact_class()
69
+ propergate_guard_usage()
70
+ inject_guards()
71
+ reject_redundant_guards()
72
+ if transform_branch_instruction()
73
+ eliminate_unreachable_blocks() # this method generates jump_guards
74
+ change = true
75
+ end
76
+ reject_unused_ir() # should be call after guard generation
77
+ change |= method_inlining()
78
+ if change
79
+ validate_stack() # stack.rb
80
+ reject_guards()
81
+ reset_ir()
82
+ end
83
+ end
84
+ unboxing()
85
+ attach_var_info()
86
+ set_sampling()
87
+ end
88
+
89
+ def find_variable(v0)
90
+ all_variable.find{|v1| v0 == v1}
91
+ end
92
+
93
+ private
94
+
95
+ def all_ir()
96
+ @blocks.inject([]){|a, b| a.concat(b.irs)}.freeze()
97
+ end
98
+
99
+ def all_pointer_definition()
100
+ all_ir().select{|ir| ir.result_variable.is_a?(Pointer)}.freeze()
101
+ end
102
+
103
+ def all_pointer()
104
+ ptrs = all_pointer_definition().map{|ir| ir.result_variable}.uniq()
105
+ bug() if ptrs.find{|p| not p.is_a?(Pointer)}
106
+ ptrs.freeze()
107
+ end
108
+
109
+ def all_variable()
110
+ all_ir().inject([]){|a, ir| a.concat(ir.variables)}.uniq()
111
+ end
112
+
113
+ def reset_ir()
114
+ all_ir().each{|ir| ir.reset()}
115
+ end
116
+
117
+ def eliminate_unreachable_blocks()
118
+ # Breadth first search
119
+ achieved = []
120
+ vertex = nil
121
+ depth = 0
122
+ queue = [@blocks[0]]
123
+ while !queue.empty?
124
+ vertex = queue.shift()
125
+ bug() unless vertex
126
+ achieved << vertex
127
+ queue += vertex.next.select{|b| !queue.include?(b) && !achieved.include?(b)}
128
+ end
129
+ deadblocks = @blocks - achieved
130
+ achieved.each do |aliveblock|
131
+ aliveblock.pre.reject!{|b| deadblocks.include?(b)}
132
+ bug() if aliveblock.next.find{|b| deadblocks.include?(b)}
133
+ end
134
+ @blocks = achieved
135
+ @blocks.sort! {|a, b| a.number <=> b.number}
136
+ bug() if @blocks.find{|b| b.pre.empty? && !b.entry_point?}
137
+ end
138
+
139
+ def reject_unused_ir()
140
+ change = true
141
+ while change
142
+ change = false
143
+ @blocks.each do |b|
144
+ defs = b.information.dup
145
+ b.irs.each do |ir|
146
+ change |= ir.mark(defs)
147
+ defs.step(ir)
148
+ end
149
+ end
150
+ end
151
+ @blocks.each do |b|
152
+ information = b.information.dup
153
+ information.reject!{|ir| not ir.alive?}
154
+ b.information = information
155
+ b.irs.reject!{|ir| not ir.alive?}
156
+ end
157
+ end
158
+
159
+ def transform_branch_instruction()
160
+ change = false
161
+ @blocks.each do |b|
162
+ if b.next.size > 1
163
+ ir = b.irs.last
164
+ bug() unless ir.is_a?(JumpIR)
165
+ unused = ir.unused_target()
166
+ if unused
167
+ change = true
168
+ bug() unless b.next.size == 2
169
+ targets = ir.jump_targets
170
+ bug() unless targets.size() == 1
171
+ target = targets[0]
172
+ fallthrough = unused != :fallthrough
173
+ if fallthrough
174
+ dead_index = b.next[0].labels.include?(target) ? 0 : 1
175
+ else
176
+ dead_index = b.next[0].labels.include?(target) ? 1 : 0
177
+ end
178
+ dead = b.next[dead_index]
179
+ jir = b.irs.pop()
180
+ b.irs.push(JumpGuard.new(jir.cond_value, all_variable, jir.insn, self))
181
+ if !fallthrough
182
+ insn = InsnInfo.new([:jump, target], ir.insn.iseq, -1, -1)
183
+ b.irs.push(JumpIR.new(nil, insn, self))
184
+ end
185
+ b.next.delete(dead)
186
+ dead.pre.delete(b)
187
+ end
188
+ end
189
+ end
190
+ change
191
+ end
192
+
193
+ def method_inlining()
194
+ @blocks.each do |b|
195
+ b.irs.each do |ir|
196
+ if ir.inlining_target?
197
+ todo()
198
+ end
199
+ end
200
+ end
201
+ false
202
+ end
203
+
204
+ def type_propergation()
205
+ change = true
206
+ while change
207
+ change = false
208
+ @blocks.each do |b|
209
+ defs = b.information.dup
210
+ b.irs.each do |ir|
211
+ change |= ir.type_propergation(defs)
212
+ bug() unless change == true || change == false
213
+ defs.step(ir)
214
+ end
215
+ end
216
+ end
217
+ all_ir().each{|ir| ir.variables.each{|v| v.not_initialized() if v.undefined?}}
218
+ bug() if all_ir().find{|ir| ir.variables.find{|v| v.undefined?}}
219
+ end
220
+
221
+ def propergate_exact_class()
222
+ change = true
223
+ while change
224
+ change = false
225
+ @blocks.each do |b|
226
+ defs = b.information.dup
227
+ b.irs.each do |ir|
228
+ change |= ir.propergate_exact_class(defs)
229
+ defs.step(ir)
230
+ end
231
+ end
232
+ end
233
+ end
234
+
235
+ def propergate_guard_usage()
236
+ irs = all_ir()
237
+ irs.each{|ir| ir.propergate_guard_usage()}
238
+ end
239
+
240
+ ### unboxing begin ###
241
+ def unboxing()
242
+ # 1: mark value which can not unbox
243
+ # 1: mark value which can unbox
244
+ irs = all_ir()
245
+ irs.each{|ir| ir.unboxing_prelude()}
246
+ bug() if irs.map{|ir| ir.values }.flatten.find{|v| v.box_unbox_undefined? }
247
+
248
+ # 2: propergate value which can not unbox
249
+ change = true
250
+ while change
251
+ change = false
252
+ @blocks.each do |b|
253
+ defs = b.information.dup
254
+ b.irs.each do |ir|
255
+ change |= ir.propergate_value_which_can_not_unbox(defs)
256
+ defs.step(ir)
257
+ end
258
+ end
259
+ end
260
+ bug() if irs.find{|ir| ir.instance_of?(SubIR) && ir.dst.can_not_unbox? != ir.src.can_not_unbox?}
261
+
262
+ # 3: propergate value which can unbox
263
+ change = true
264
+ while change
265
+ change = false
266
+ @blocks.each do |b|
267
+ defs = b.information.dup
268
+ b.irs.each do |ir|
269
+ change |= ir.propergate_unbox_value(defs)
270
+ defs.step(ir)
271
+ end
272
+ end
273
+ end
274
+
275
+ bug() if irs.map{|ir| ir.values }.flatten.find{|v| v.unboxed? && (v.dynamic? || v.types.size != 1)}
276
+ irs.each do |ir|
277
+ ir.values.each do |v|
278
+ next unless v.unboxed?
279
+ end
280
+ end
281
+
282
+ irs.map{|ir| ir.values}.flatten.each{|v| v.box() unless v.unboxed?}
283
+ irs.map{|ir| ir.values}.flatten.each{|v| bug() if !v.boxed? && !v.unboxed?}
284
+ change = true
285
+ while change
286
+ change = false
287
+ @blocks.each do |b|
288
+ defs = b.information.dup
289
+ b.irs.each do |ir|
290
+ change |= ir.propergate_box_value(defs)
291
+ defs.step(ir)
292
+ end
293
+ end
294
+ end
295
+
296
+ @blocks.each do |b|
297
+ defs = b.information.dup
298
+ b.irs.each do |ir|
299
+ case ir
300
+ when SubIR
301
+ bug() unless ir.src.boxed? == ir.dst.boxed?
302
+ bug() unless ir.src.unboxed? == ir.dst.unboxed?
303
+ end
304
+ ir.variables_without_result.each do |v|
305
+ ds = defs.variable_definition.select {|d| v == d.result_variable }
306
+ if v.unboxed?
307
+ bug() if ds.find{|d| not d.result_variable.unboxed? }
308
+ elsif v.boxed?
309
+ bug() if ds.find{|d| d.result_variable.unboxed? }
310
+ else
311
+ bug(ir)
312
+ end
313
+ end
314
+ defs.step(ir)
315
+ end
316
+ end
317
+ end
318
+ ### unboxing end ###
319
+
320
+ def reject_redundant_guards()
321
+ redundant = []
322
+ ptrs = all_pointer()
323
+ @blocks.each do |b|
324
+ safe = b.in_guards.dup()
325
+ b.irs.each do |ir|
326
+ redundant << ir if safe.redundant?(ir)
327
+ safe.step(ir)
328
+ end
329
+ safe.validate_final()
330
+ b.irs.reject!{|ir| redundant.include?(ir)}
331
+ end
332
+ end
333
+
334
+ def reject_guards()
335
+ @blocks.each{|b| b.irs.reject!{|ir| ir.is_a?(StandardGuard)}}
336
+ end
337
+
338
+ def set_sampling()
339
+ all_ir().each do |ir|
340
+ targets = nil
341
+ case ir
342
+ when CallIR
343
+ case ir
344
+ when InvokeIR
345
+ ir.sampling_return_value()
346
+ else
347
+ # TODO
348
+ end
349
+ targets = ir.param_variables()
350
+ when JumpIR
351
+ targets = [ir.cond_value] if ir.cond_value
352
+ end
353
+ next unless targets
354
+ targets.each do |p|
355
+ next unless p.dynamic?
356
+ ir.get_definition(p).each do |d|
357
+ case d
358
+ when Literal
359
+ bug()
360
+ when Self
361
+ ir.add_sampling_variable(d)
362
+ when SubIR
363
+ d.add_sampling_variable(d.src)
364
+ #ir.add_sampling_variable(d.src)
365
+ when CallIR
366
+ # Nothing to do.
367
+ # Always sampling CallIR's return value.
368
+ else
369
+ bug()
370
+ end
371
+ end
372
+ end
373
+ end
374
+ end
375
+
376
+ def attach_var_info()
377
+ set_information() # information.rb
378
+
379
+ @blocks.each do |b|
380
+ defs = b.information.dup()
381
+ b.irs.each do |ir|
382
+ ir.set_info(defs.dup())
383
+ defs.step(ir)
384
+ end
385
+ defs.validate_final()
386
+ end
387
+ end
388
+ end
389
+ end
390
+ end
391
+