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,98 @@
1
+ # coding=utf-8
2
+
3
+ module CastOff::Compiler
4
+ module SimpleIR
5
+ class ParamIR < IR
6
+ attr_reader :param_value, :variables_without_result, :variables, :result_variable, :values
7
+ def initialize(val, insn, cfg)
8
+ super(insn, cfg)
9
+ @param_value = val
10
+ @values = [@param_value]
11
+ @variables = []
12
+ @variables_without_result = []
13
+ if @param_value.is_a?(Variable)
14
+ @variables << @param_value
15
+ @variables_without_result << @param_value
16
+ end
17
+ @result_variable = nil
18
+ @need_guard = nil
19
+ end
20
+
21
+ ### unboxing begin ###
22
+ def unboxing_prelude()
23
+ # nothing to do
24
+ end
25
+
26
+ def propergate_value_which_can_not_unbox(defs)
27
+ change = false
28
+
29
+ # forward
30
+ change |= defs.can_not_unbox_variable_resolve_forward(@param_value)
31
+
32
+ # backward
33
+ if @param_value.can_not_unbox?
34
+ change |= defs.can_not_unbox_variable_resolve_backward(@param_value)
35
+ end
36
+
37
+ change
38
+ end
39
+
40
+ def propergate_box_value(defs)
41
+ change = false
42
+
43
+ # forward
44
+ change |= defs.box_value_resolve_forward(@param_value)
45
+
46
+ # backward
47
+ if @param_value.boxed?
48
+ change |= defs.box_value_resolve_backward(@param_value)
49
+ end
50
+
51
+ change
52
+ end
53
+
54
+ def propergate_unbox_value(defs)
55
+ return false if @param_value.can_not_unbox?
56
+ defs.unbox_value_resolve(@param_value)
57
+ end
58
+ ### unboxing end ###
59
+
60
+ def propergate_exact_class(defs)
61
+ defs.exact_class_resolve(@param_value)
62
+ end
63
+
64
+ def to_c()
65
+ bug()
66
+ end
67
+
68
+ def type_propergation(defs)
69
+ defs.type_resolve(@param_value)
70
+ end
71
+
72
+ def need_guard(bool)
73
+ @need_guard = !!bool
74
+ end
75
+
76
+ def reset()
77
+ @need_guard = nil
78
+ super()
79
+ end
80
+
81
+ def standard_guard_target()
82
+ need_guard? ? @param_value : nil
83
+ end
84
+
85
+ def mark(defs)
86
+ alive? && defs.mark(@param_value)
87
+ end
88
+
89
+ private
90
+
91
+ def need_guard?()
92
+ bug() if @need_guard.nil?
93
+ @need_guard
94
+ end
95
+ end
96
+ end
97
+ end
98
+
@@ -0,0 +1,92 @@
1
+ # coding=utf-8
2
+
3
+ module CastOff::Compiler
4
+ module SimpleIR
5
+ class ReturnIR < IR
6
+ attr_reader :return_value, :variables_without_result, :variables, :result_variable, :values
7
+
8
+ class ThrowObj
9
+ attr_reader :type, :raw_state, :state
10
+
11
+ def initialize(type, raw_state, state, flag, level)
12
+ @type = type
13
+ @raw_state = raw_state
14
+ @state = state
15
+ end
16
+ end
17
+
18
+ def initialize(retval, throwobj, insn, cfg)
19
+ super(insn, cfg)
20
+ @throwobj = throwobj
21
+ @return_value = retval
22
+ @values = [@return_value]
23
+ @variables = []
24
+ @variables_without_result = []
25
+ if @return_value.is_a?(Variable)
26
+ @variables << @return_value
27
+ @variables_without_result << @return_value
28
+ end
29
+ @result_variable = nil
30
+ end
31
+
32
+ ### unboxing begin ###
33
+ def unboxing_prelude()
34
+ @return_value.can_not_unbox()
35
+ end
36
+
37
+ def propergate_value_which_can_not_unbox(defs)
38
+ bug() unless @return_value.can_not_unbox?
39
+ defs.can_not_unbox_variable_resolve_backward(@return_value)
40
+ end
41
+
42
+ def propergate_box_value(defs)
43
+ bug() unless @return_value.boxed?
44
+ defs.box_value_resolve_backward(@return_value)
45
+ end
46
+
47
+ def propergate_unbox_value(defs)
48
+ bug() unless @return_value.can_not_unbox?
49
+ false
50
+ end
51
+ ### unboxing end ###
52
+
53
+ def propergate_exact_class(defs)
54
+ false
55
+ end
56
+
57
+ def to_c()
58
+ if @insn.iseq.catch_exception?
59
+ prereturn = " TH_POP_TAG2();\n"
60
+ else
61
+ prereturn = ''
62
+ end
63
+ case @throwobj
64
+ when ThrowObj
65
+ if @translator.inline_block?
66
+ return prereturn + " return_from_execute(#{@throwobj.raw_state}, #{@return_value});"
67
+ else
68
+ return prereturn + " return return_block(#{@throwobj.raw_state}, #{@return_value}, lambda_p);"
69
+ end
70
+ when NilClass
71
+ return prereturn + " return #{@return_value};"
72
+ end
73
+ bug()
74
+ end
75
+
76
+ def type_propergation(defs)
77
+ defs.type_resolve(@return_value)
78
+ end
79
+
80
+ def mark(defs)
81
+ if !alive?
82
+ alive()
83
+ defs.mark(@return_value)
84
+ true
85
+ else
86
+ false
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+
@@ -0,0 +1,808 @@
1
+ # coding=utf-8
2
+
3
+ module CastOff
4
+ module Compiler
5
+ module SimpleIR
6
+ # 3 address code
7
+
8
+ include Instruction
9
+
10
+ class Stack
11
+ include CastOff::Util
12
+
13
+ attr_reader :depth
14
+
15
+ def initialize(depth)
16
+ @depth = depth
17
+ end
18
+
19
+ def pop()
20
+ @depth -= 1
21
+ bug() if @depth < 0
22
+ @depth
23
+ end
24
+
25
+ def push()
26
+ ret = @depth
27
+ @depth += 1
28
+ ret
29
+ end
30
+ end
31
+
32
+ def block_argument_is_unsupported(translator, insn)
33
+ raise UnsupportedError.new(<<-EOS)
34
+
35
+ Currently, CastOff doesn't support method and block invocation with a block argument.
36
+ ------------------------------------------------------------------------------
37
+ Target file is (#{translator.target_name()}).
38
+ Call site is (#{insn}).
39
+ EOS
40
+ end
41
+
42
+ def generate_ir(cfg, insns, depth)
43
+ irs = []
44
+ translator = cfg.translator
45
+ stack = Stack.new(depth)
46
+ insns.each do |insn|
47
+ bug() unless stack.depth == insn.depth
48
+ op = insn.op
49
+ argv = insn.argv
50
+ case op
51
+ when :send,
52
+ :opt_plus, :opt_minus, :opt_mult, :opt_div, :opt_mod, :opt_lt, :opt_le, :opt_gt, :opt_ge, :opt_neq, :opt_eq, :opt_ltlt, :opt_aref,
53
+ :opt_length, :opt_size, :opt_not, :opt_succ
54
+ fcall = false
55
+ flags = 0
56
+ case op
57
+ when :send
58
+ id = argv[0]
59
+ argc = argv[1]
60
+ blockiseq = argv[2]
61
+ bug() if blockiseq # should be convert to cast_off_prep, ...
62
+ flags = argv[3]
63
+ fcall = (flags & VM_CALL_FCALL_BIT) != 0
64
+ bug() if flags & VM_CALL_OPT_SEND_BIT != 0 # VM_CALL_OPT_SEND_BIT is set at the vm_call_method
65
+ bug() if flags & VM_CALL_SUPER_BIT != 0 # VM_CALL_SUPER_BIT is set at the invokesuper
66
+ #VM_CALL_VCALL_BIT: variable or call, 要検討
67
+ when :opt_plus
68
+ id = "+".intern
69
+ argc = 1
70
+ when :opt_minus
71
+ id = "-".intern
72
+ argc = 1
73
+ when :opt_mult
74
+ id = "*".intern
75
+ argc = 1
76
+ when :opt_div
77
+ id = "/".intern
78
+ argc = 1
79
+ when :opt_mod
80
+ id = "%".intern
81
+ argc = 1
82
+ when :opt_lt
83
+ id = "<".intern
84
+ argc = 1
85
+ when :opt_le
86
+ id = "<=".intern
87
+ argc = 1
88
+ when :opt_gt
89
+ id = ">".intern
90
+ argc = 1
91
+ when :opt_ge
92
+ id = ">=".intern
93
+ argc = 1
94
+ when :opt_neq
95
+ id = "!=".intern
96
+ argc = 1
97
+ when :opt_eq
98
+ id = "==".intern
99
+ argc = 1
100
+ when :opt_ltlt
101
+ id = "<<".intern
102
+ argc = 1
103
+ when :opt_aref
104
+ id = "[]".intern
105
+ argc = 1
106
+ when :opt_length
107
+ id = :length
108
+ argc = 0
109
+ when :opt_size
110
+ id = :size
111
+ argc = 0
112
+ when :opt_not
113
+ id = "!".intern
114
+ argc = 0
115
+ when :opt_succ
116
+ id = :succ
117
+ argc = 0
118
+ else
119
+ bug()
120
+ end
121
+
122
+ if (flags & VM_CALL_ARGS_BLOCKARG_BIT) != 0
123
+ blockarg = TmpVariable.new(stack.pop())
124
+ else
125
+ blockarg = nil
126
+ end
127
+
128
+ args = []
129
+ argc.times { args << TmpVariable.new(stack.pop()) }
130
+
131
+ if fcall
132
+ stack.pop();
133
+ irs << SubIR.new(Self.new(translator), TmpVariable.new(stack.push()), InsnInfo.new([:putself], insn.iseq, -1, -1, true), cfg)
134
+ end
135
+ recv = TmpVariable.new(stack.pop())
136
+ recv.is_also(insn.ic_class) if insn.ic_class
137
+ param = []
138
+ param << ParamIR.new(recv, insn, cfg)
139
+ param += args.reverse.map{|arg| ParamIR.new(arg, insn, cfg)}
140
+ if blockarg
141
+ param << ParamIR.new(blockarg, insn, cfg)
142
+ argc += 1
143
+ end
144
+
145
+ irs += param
146
+ irs << InvokeIR.new(id, flags, param, argc + 1, TmpVariable.new(stack.push()), insn, cfg)
147
+ when :invokeblock
148
+ num = argv[0]
149
+ flags = argv[1]
150
+
151
+ block_argument_is_unsupported(translator, insn) if flags & VM_CALL_ARGS_BLOCKARG_BIT != 0
152
+
153
+ args = []
154
+ num.times { args << TmpVariable.new(stack.pop()) }
155
+ param = []
156
+ param += args.reverse.map{|arg| ParamIR.new(arg, insn, cfg)}
157
+
158
+ irs += param
159
+ irs << YieldIR.new(flags, param, num, TmpVariable.new(stack.push()), insn, cfg)
160
+ when :putnil
161
+ irs << SubIR.new(Literal.new(nil, translator), TmpVariable.new(stack.push()), insn, cfg)
162
+ when :putself
163
+ irs << SubIR.new(Self.new(translator), TmpVariable.new(stack.push()), insn, cfg)
164
+ when :putstring
165
+ obj = argv[0]
166
+ param = []
167
+ param << ParamIR.new(Literal.new(obj, translator), insn, cfg)
168
+ irs += param
169
+ irs << Putstring.new(param, 1, TmpVariable.new(stack.push()), insn, cfg)
170
+ when :putobject
171
+ obj = argv[0]
172
+ irs << SubIR.new(Literal.new(obj, translator), TmpVariable.new(stack.push()), insn, cfg)
173
+ when :newarray
174
+ argc = argv[0]
175
+ args = []
176
+ argc.times { args << TmpVariable.new(stack.pop()) }
177
+ param = args.reverse.map{|arg| ParamIR.new(arg, insn, cfg)}
178
+ irs += param
179
+ irs << Newarray.new(param, argc, TmpVariable.new(stack.push()), insn, cfg)
180
+ when :newhash
181
+ argc = argv[0]
182
+ args = []
183
+ argc.times { args << TmpVariable.new(stack.pop()) }
184
+ param = args.reverse.map{|arg| ParamIR.new(arg, insn, cfg)}
185
+ irs += param
186
+ irs << Newhash.new(param, argc, TmpVariable.new(stack.push()), insn, cfg)
187
+ when :duparray
188
+ obj = argv[0]
189
+ param = []
190
+ param << ParamIR.new(Literal.new(obj, translator), insn, cfg)
191
+ irs += param
192
+ irs << Duparray.new(param, 1, TmpVariable.new(stack.push()), insn, cfg)
193
+ when :tostring
194
+ param = []
195
+ param << ParamIR.new(TmpVariable.new(stack.pop()), insn, cfg)
196
+ irs += param
197
+ irs << Tostring.new(param, 1, TmpVariable.new(stack.push()), insn, cfg)
198
+ when :toregexp
199
+ cnt = argv[1]
200
+ args = []
201
+ cnt.times { args << TmpVariable.new(stack.pop()) }
202
+ param = args.reverse.map{|arg| ParamIR.new(arg, insn, cfg)}
203
+ irs += param
204
+ irs << Toregexp.new(param, cnt, TmpVariable.new(stack.push()), insn, cfg)
205
+ when :concatstrings
206
+ argc = argv[0]
207
+ args = []
208
+ argc.times { args << TmpVariable.new(stack.pop()) }
209
+ param = args.reverse.map{|arg| ParamIR.new(arg, insn, cfg)}
210
+ irs += param
211
+ irs << Concatstrings.new(param, argc, TmpVariable.new(stack.push()), insn, cfg)
212
+ when :concatarray
213
+ argc = 2
214
+ args = []
215
+ argc.times { args << TmpVariable.new(stack.pop()) }
216
+ param = args.reverse.map{|arg| ParamIR.new(arg, insn, cfg)}
217
+ irs += param
218
+ irs << Concatarray.new(param, argc, TmpVariable.new(stack.push()), insn, cfg)
219
+ when :newrange
220
+ flag = argv[0]
221
+ argc = 2
222
+ args = []
223
+ argc.times { args << TmpVariable.new(stack.pop()) }
224
+ param = args.reverse.map{|arg| ParamIR.new(arg, insn, cfg)}
225
+ irs += param
226
+ irs << Newrange.new(param, argc, TmpVariable.new(stack.push()), insn, cfg)
227
+ when :opt_regexpmatch1
228
+ r = argv[0]
229
+ argc = 2
230
+ param = []
231
+ param << ParamIR.new(Literal.new(r, translator), insn, cfg)
232
+ param << ParamIR.new(TmpVariable.new(stack.pop()), insn, cfg)
233
+ irs += param
234
+ irs << OptRegexpmatch1.new(param, argc, TmpVariable.new(stack.push()), insn, cfg)
235
+ when :opt_regexpmatch2
236
+ argc = 2
237
+ param = []
238
+ param << ParamIR.new(TmpVariable.new(stack.pop()), insn, cfg)
239
+ param << ParamIR.new(TmpVariable.new(stack.pop()), insn, cfg)
240
+ irs += param
241
+ irs << OptRegexpmatch2.new(param, argc, TmpVariable.new(stack.push()), insn, cfg)
242
+ when :expandarray
243
+ num, flag = *argv
244
+ is_splat = (flag & 0x01) != 0
245
+
246
+ op = :expandarray_pre
247
+ # param が Array かどうかという情報は使用しないので、ガードは不要
248
+ expandarray_pre_insn = InsnInfo.new([op], insn.iseq, -1, -1, true)
249
+ param = []
250
+ param << ParamIR.new(TmpVariable.new(stack.pop()), expandarray_pre_insn, cfg)
251
+ irs += param
252
+ irs << ExpandarrayPre.new(param, 1, TmpVariable.new(stack.push()), expandarray_pre_insn, cfg)
253
+
254
+ depth = stack.pop()
255
+ if is_splat
256
+ ary_depth = depth + num + 1
257
+ else
258
+ ary_depth = depth + num
259
+ end
260
+ irs << SubIR.new(TmpVariable.new(depth), TmpVariable.new(ary_depth), expandarray_pre_insn, cfg)
261
+
262
+ if flag & 0x02 != 0
263
+ # post: ..., nil ,ary[-1], ..., ary[0..-num] # top
264
+ op = :expandarray_post_loop
265
+ num.times do |i|
266
+ # param は Array だと分かっているので、ガードは不要
267
+ expandarray_post_loop_insn = InsnInfo.new([op, num, i], insn.iseq, -1, -1, true)
268
+ param = []
269
+ param << ParamIR.new(TmpVariable.new(ary_depth), expandarray_post_loop_insn, cfg)
270
+ irs += param
271
+ irs << ExpandarrayPostLoop.new(param, 1, TmpVariable.new(stack.push()), expandarray_post_loop_insn, cfg)
272
+ end
273
+ op = :expandarray_post_splat
274
+ if is_splat
275
+ # param は Array だと分かっているので、ガードは不要
276
+ expandarray_post_splat_insn = InsnInfo.new([op, num], insn.iseq, -1, -1, true)
277
+ param = []
278
+ param << ParamIR.new(TmpVariable.new(ary_depth), expandarray_post_splat_insn, cfg)
279
+ irs += param
280
+ irs << ExpandarrayPostSplat.new(param, 1, TmpVariable.new(stack.push()), expandarray_post_splat_insn, cfg)
281
+ end
282
+ else
283
+ # normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top
284
+ op = :expandarray_splat
285
+ if is_splat
286
+ # param は Array だと分かっているので、ガードは不要
287
+ expandarray_splat_insn = InsnInfo.new([op, num], insn.iseq, -1, -1, true)
288
+ param = []
289
+ param << ParamIR.new(TmpVariable.new(ary_depth), expandarray_splat_insn, cfg)
290
+ irs += param
291
+ irs << ExpandarraySplat.new(param, 1, TmpVariable.new(stack.push()), expandarray_splat_insn, cfg)
292
+ end
293
+ op = :expandarray_loop
294
+ num.times do |i|
295
+ # param は Array だと分かっているので、ガードは不要
296
+ expandarray_loop_insn = InsnInfo.new([op, num - i - 1], insn.iseq, -1, -1, true)
297
+ param = []
298
+ param << ParamIR.new(TmpVariable.new(ary_depth), expandarray_loop_insn, cfg)
299
+ irs += param
300
+ irs << ExpandarrayLoop.new(param, 1, TmpVariable.new(stack.push()), expandarray_loop_insn, cfg)
301
+ end
302
+ end
303
+ when :splatarray
304
+ param = []
305
+ param << ParamIR.new(TmpVariable.new(stack.pop()), insn, cfg)
306
+ irs += param
307
+ irs << Splatarray.new(param, 1, TmpVariable.new(stack.push()), insn, cfg)
308
+ when :checkincludearray
309
+ flag = argv[0]
310
+ op = :checkincludearray_pre
311
+ # param が Array かどうかという情報は使用しないので、ガードは不要
312
+ checkincludearray_pre_insn = InsnInfo.new([op], insn.iseq, -1, -1, true)
313
+ param = []
314
+ param << ParamIR.new(TmpVariable.new(stack.pop()), checkincludearray_pre_insn, cfg) # ary
315
+ irs += param
316
+ irs << CheckincludearrayPre.new(param, 1, TmpVariable.new(stack.push()), checkincludearray_pre_insn, cfg)
317
+
318
+ if flag == true
319
+ op = :checkincludearray_case
320
+ # ary は Array だと分かっているので、ガードは不要
321
+ # obj の型情報は使用しないので、ガードは不要
322
+ checkincludearray_case_insn = InsnInfo.new([op], insn.iseq, -1, -1, true)
323
+ param = []
324
+ param << ParamIR.new(TmpVariable.new(stack.pop()), checkincludearray_case_insn, cfg) # ary
325
+ param << ParamIR.new(TmpVariable.new(stack.pop()), checkincludearray_case_insn, cfg) # obj
326
+ stack.push() # obj
327
+ irs += param
328
+ irs << CheckincludearrayCase.new(param, 2, TmpVariable.new(stack.push()), checkincludearray_case_insn, cfg) #result
329
+ elsif flag == false
330
+ op = :checkincludearray_when
331
+ # ary は Array だと分かっているので、ガードは不要
332
+ checkincludearray_when_insn = InsnInfo.new([op], insn.iseq, -1, -1, true)
333
+ param = []
334
+ param << ParamIR.new(TmpVariable.new(stack.pop()), checkincludearray_when_insn, cfg) # ary
335
+ stack.pop() # obj
336
+ result_depth = stack.push() # result
337
+ irs += param
338
+ irs << CheckincludearrayWhen.new(param, 1, TmpVariable.new(result_depth), checkincludearray_when_insn, cfg)
339
+ irs << SubIR.new(TmpVariable.new(result_depth), TmpVariable.new(stack.push()), checkincludearray_when_insn, cfg)
340
+ else
341
+ bug()
342
+ end
343
+ when :cast_off_decl_arg
344
+ if translator.inline_block?
345
+ irs << SubIR.new(Argument.new(*argv), LocalVariable.new(*argv), insn, cfg)
346
+ else
347
+ irs << SubIR.new(Argument.new(*argv), DynamicVariable.new(*argv), insn, cfg)
348
+ end
349
+ when :cast_off_decl_var
350
+ if translator.inline_block?
351
+ irs << SubIR.new(Literal.new(nil, translator), LocalVariable.new(*argv), insn, cfg)
352
+ else
353
+ ir = SubIR.new(Literal.new(nil, translator), DynamicVariable.new(*argv), insn, cfg)
354
+ ir.vanish()
355
+ irs << ir
356
+ end
357
+ when :cast_off_getconst
358
+ irs << SubIR.new(ConstWrapper.new(*argv, translator), TmpVariable.new(stack.push()), insn, cfg)
359
+ when :cast_off_getgvar
360
+ irs << SubIR.new(GlobalVariable.new(*argv, translator), TmpVariable.new(stack.push()), insn, cfg)
361
+ when :cast_off_getcvar
362
+ irs << SubIR.new(ClassVariable.new(*argv), TmpVariable.new(stack.push()), insn, cfg)
363
+ when :cast_off_getivar
364
+ irs << SubIR.new(InstanceVariable.new(*argv), TmpVariable.new(stack.push()), insn, cfg)
365
+ when :cast_off_getlvar
366
+ irs << SubIR.new(LocalVariable.new(*argv), TmpVariable.new(stack.push()), insn, cfg)
367
+ when :cast_off_getdvar
368
+ irs << SubIR.new(DynamicVariable.new(*argv), TmpVariable.new(stack.push()), insn, cfg)
369
+ when :getdynamic, :setdynamic
370
+ bug()
371
+ when :cast_off_setgvar
372
+ irs << SubIR.new(TmpVariable.new(stack.pop()), GlobalVariable.new(*argv, translator), insn, cfg)
373
+ when :cast_off_setcvar
374
+ irs << SubIR.new(TmpVariable.new(stack.pop()), ClassVariable.new(*argv), insn, cfg)
375
+ when :cast_off_setivar
376
+ irs << SubIR.new(TmpVariable.new(stack.pop()), InstanceVariable.new(*argv), insn, cfg)
377
+ when :cast_off_setlvar
378
+ irs << SubIR.new(TmpVariable.new(stack.pop()), LocalVariable.new(*argv), insn, cfg)
379
+ when :cast_off_setdvar
380
+ irs << SubIR.new(TmpVariable.new(stack.pop()), DynamicVariable.new(*argv), insn, cfg)
381
+ when :getspecial
382
+ param = []
383
+ irs << Getspecial.new(param, 0, TmpVariable.new(stack.push()), insn, cfg)
384
+ when :jump, :cast_off_enter_block, :cast_off_leave_block
385
+ bug("op = #{op}, depth = #{stack.depth}") if op == :cast_off_leave_block && (stack.depth - 1) != insn.iseq.depth
386
+ irs << JumpIR.new(nil, insn, cfg)
387
+ when :cast_off_break_block
388
+ bug("op = #{op}, depth = #{stack.depth}") if (stack.depth - 1) != insn.iseq.depth
389
+ d = stack.pop()
390
+ stack.push()
391
+ irs << SubIR.new(TmpVariable.new(d), TmpVariable.new(stack.push()), insn, cfg)
392
+ irs << JumpIR.new(TmpVariable.new(stack.pop()), insn, cfg)
393
+ when :branchunless, :branchif, :cast_off_continue_loop
394
+ target = argv[0]
395
+ irs << JumpIR.new(TmpVariable.new(stack.pop()), insn, cfg)
396
+ when :pop
397
+ stack.pop()
398
+ when :adjuststack
399
+ # same as popn instruction
400
+ num = argv[0]
401
+ num.times { stack.pop() }
402
+ when :setn
403
+ # deep <-----------------------
404
+ # e.g. num = 3, [:a, :b, :c, :d] => [:d, :b, :c, :d]
405
+ num = argv[0]
406
+ dst = stack.pop() - num
407
+ src = stack.push()
408
+ irs << SubIR.new(TmpVariable.new(src), TmpVariable.new(dst), insn, cfg)
409
+ when :dupn
410
+ # deep <-----------------------
411
+ # e.g. [:a, :b, :c] => [:a, :b, :c, :a, :b, :c]
412
+ num = argv[0]
413
+ num.times do
414
+ depth = stack.push()
415
+ irs << SubIR.new(TmpVariable.new(depth - num), TmpVariable.new(depth), insn, cfg)
416
+ end
417
+ when :dup
418
+ depth = stack.push()
419
+ irs << SubIR.new(TmpVariable.new(depth - 1), TmpVariable.new(depth), insn, cfg)
420
+ when :swap
421
+ tmp = stack.push()
422
+ stack.pop()
423
+ v0 = tmp - 1
424
+ v1 = tmp - 2
425
+ irs << SubIR.new(TmpVariable.new(v0), TmpVariable.new(tmp), insn, cfg)
426
+ irs << SubIR.new(TmpVariable.new(v1), TmpVariable.new(v0), insn, cfg)
427
+ irs << SubIR.new(TmpVariable.new(tmp), TmpVariable.new(v1), insn, cfg)
428
+ when :topn
429
+ n = argv[0]
430
+ dst = stack.push()
431
+ irs << SubIR.new(TmpVariable.new(dst - n - 1), TmpVariable.new(dst), insn, cfg)
432
+ when :throw
433
+ type, state, flag, level = insn.get_throw_info()
434
+ if flag != 0
435
+ bug()
436
+ else
437
+ case type
438
+ when :return
439
+ irs << ReturnIR.new(TmpVariable.new(stack.pop()), ReturnIR::ThrowObj.new(type, argv[0], state, flag, level), insn, cfg)
440
+ else
441
+ bug()
442
+ end
443
+ end
444
+ when :cast_off_prep
445
+ # stack には argc + 1 積まれている
446
+ depth = argv[0]
447
+ loop_args = argv[1]
448
+ send_insn = argv[2]
449
+ send_argv = send_insn.argv
450
+ send_id = send_argv[0]
451
+ send_argc = send_argv[1]
452
+ send_flags = send_argv[3]
453
+ fcall = (send_flags & VM_CALL_FCALL_BIT) != 0
454
+ bug() if send_flags & VM_CALL_OPT_SEND_BIT != 0 # VM_CALL_OPT_SEND_BIT is set at the vm_call_method
455
+ bug() if send_flags & VM_CALL_SUPER_BIT != 0 # VM_CALL_SUPER_BIT is set at the invokesuper
456
+ block_argument_is_unsupported(translator, insn) if send_flags & VM_CALL_ARGS_BLOCKARG_BIT != 0
457
+ #VM_CALL_VCALL_BIT: variable or call, 要検討
458
+ raise UnsupportedError.new(<<-EOS) if send_flags & VM_CALL_ARGS_SPLAT_BIT != 0
459
+
460
+ Currently, CastOff doesn't support a method invocation which takes a splat argument (like *arg) and which takes a block.
461
+ ------------------------------------------------------------------------------------------------------------------------
462
+ Target file is (#{translator.target_name()}).
463
+ Call site is (#{insn}).
464
+ EOS
465
+
466
+ send_args = []
467
+ send_argc.times { send_args << TmpVariable.new(stack.pop()) }
468
+
469
+ if fcall
470
+ stack.pop();
471
+ irs << SubIR.new(Self.new(translator), TmpVariable.new(stack.push()), InsnInfo.new([:putself], insn.iseq, -1, -1, true), cfg)
472
+ end
473
+ recv = TmpVariable.new(stack.pop())
474
+ param = []
475
+ param << ParamIR.new(recv, insn, cfg)
476
+ param += send_args.reverse.map{|arg| ParamIR.new(arg, insn, cfg)}
477
+
478
+ # loop のための key object を返す, reciever オブジェクト + context (map の場合は返り値の配列 + 帰納変数)
479
+ # rb_ary_each_context_t みたいなのを作る
480
+ # block = true だった場合、recv と id から関数名を特定して、それ用の関数を呼ぶ。返り値は loopkey
481
+ # loopkey は cast_off_ary_each_context_t みたいな構造体
482
+ loopkey = LoopKey.new(send_id, depth, loop_args, insn, cfg.translator)
483
+ translator.loopkey[depth] = loopkey
484
+ irs += param
485
+ irs << LoopIR.new(loopkey, op, param, send_argc + 1, TmpVariable.new(stack.push()), insn, cfg)
486
+ when :cast_off_loop
487
+ depth = argv[0]
488
+ send_insn = argv[2]
489
+ send_argv = send_insn.argv
490
+ send_id = send_argv[0]
491
+
492
+ # loopkey を引数で渡す。返り値は true(ループ継続) or false(ループ終了)
493
+ loopkey = translator.loopkey[depth]
494
+ bug() unless loopkey
495
+ param = []
496
+ param << ParamIR.new(TmpVariable.new(stack.pop()), insn, cfg)
497
+ irs += param
498
+ irs << LoopIR.new(loopkey, op, param, 1, TmpVariable.new(stack.push()), insn, cfg)
499
+ when :cast_off_cont
500
+ depth = argv[0]
501
+ args = argv[1]
502
+ if translator.inline_block?
503
+ args.each_with_index{|arg, i| irs << SubIR.new(TmpBuffer.new(i), LocalVariable.new(*arg), insn, cfg)}
504
+ else
505
+ args.each_with_index{|arg, i| irs << SubIR.new(TmpBuffer.new(i), DynamicVariable.new(*arg), insn, cfg)}
506
+ end
507
+ loopkey = translator.loopkey[depth]
508
+ loopkey.block_iseq = insn.iseq
509
+ insn.iseq.set_loopkey(loopkey)
510
+ insn.iseq.use_temporary_c_ary(args.size())
511
+ when :cast_off_finl
512
+ depth = argv[0]
513
+ send_insn = argv[2]
514
+ send_argv = send_insn.argv
515
+ send_id = send_argv[0]
516
+ loopkey = translator.loopkey[depth]
517
+ bug() unless loopkey
518
+ param = []
519
+ irs << LoopIR.new(loopkey, op, param, 0, TmpVariable.new(stack.push()), insn, cfg)
520
+ when :cast_off_fetch_args
521
+ param = []
522
+ if argv[0]
523
+ args = argv[0].last
524
+ if translator.inline_block?
525
+ args.map!{|arg| LocalVariable.new(*arg).to_name() }
526
+ else
527
+ args.map!{|arg| DynamicVariable.new(*arg).to_name() }
528
+ end
529
+ end
530
+ irs << CastOffFetchArgs.new(param, 0, TmpVariable.new(stack.push()), insn, cfg)
531
+ when :cast_off_handle_optional_args
532
+ irs << JumpIR.new(TmpVariable.new(stack.pop()), insn, cfg)
533
+ when :leave
534
+ depth = stack.pop()
535
+ unless depth == 0
536
+ if translator.inline_block?
537
+ # throw => leave
538
+ else
539
+ bug()
540
+ end
541
+ end
542
+ irs << ReturnIR.new(TmpVariable.new(depth), nil, insn, cfg)
543
+ when :defined
544
+ t = argv[0]
545
+ case t
546
+ when DEFINED_IVAR, DEFINED_GVAR, DEFINED_FUNC
547
+ # ok
548
+ when DEFINED_IVAR2
549
+ bug("unexpected defined instruction")
550
+ when DEFINED_CVAR
551
+ raise(UnsupportedError.new("Currently, CastOff cannot handle defined instruction for class variable"))
552
+ when DEFINED_CONST
553
+ raise(UnsupportedError.new("Currently, CastOff cannot handle defined instruction for constant"))
554
+ when DEFINED_METHOD
555
+ raise(UnsupportedError.new("Currently, CastOff cannot handle defined instruction for methods"))
556
+ when DEFINED_YIELD
557
+ raise(UnsupportedError.new("Currently, CastOff cannot handle defined instruction for yield"))
558
+ when DEFINED_REF
559
+ raise(UnsupportedError.new("Currently, CastOff cannot handle defined instruction for global-variable"))
560
+ when DEFINED_ZSUPER
561
+ raise(UnsupportedError.new("Currently, CastOff cannot handle defined instruction for super"))
562
+ else
563
+ bug()
564
+ end
565
+
566
+ param = []
567
+ param << ParamIR.new(TmpVariable.new(stack.pop()), insn, cfg)
568
+ irs += param
569
+ irs << Defined.new(param, 1, TmpVariable.new(stack.push()), insn, cfg)
570
+ else
571
+ raise(UnsupportedError, "unsupported RubyVM instruction #{insn} ")
572
+ end
573
+ unless stack.depth == insn.depth + insn.stack_usage()
574
+ bug("stack.depth = #{stack.depth}, insn.depth = #{insn.depth + insn.stack_usage()}, insn = #{insn}\n#{irs.join("\n")}\n")
575
+ end
576
+ end
577
+ irs
578
+ end
579
+
580
+ class IR
581
+ include CastOff::Util
582
+
583
+ attr_reader :insn, :alias
584
+
585
+ def initialize(insn, cfg)
586
+ @insn = insn
587
+ @cfg = cfg
588
+ @translator = cfg.translator
589
+ @configuration = @translator.configuration
590
+ @dependency = @translator.dependency
591
+ @information = nil
592
+ @alias = nil
593
+ @alive = false
594
+ @valish_p = false
595
+ @sampling_variable = []
596
+ end
597
+
598
+ def vanish()
599
+ @vanish_p = true
600
+ end
601
+
602
+ def vanish?
603
+ @vanish_p
604
+ end
605
+
606
+ ### unboxing begin ###
607
+ def unboxing_prelude()
608
+ bug()
609
+ end
610
+
611
+ def propergate_value_which_can_not_unbox(defs)
612
+ bug()
613
+ end
614
+
615
+ def propergate_unbox_value(defs)
616
+ bug()
617
+ end
618
+ ### unboxing end ###
619
+
620
+ def sampling_variable()
621
+ s = []
622
+ if @configuration.development?
623
+ @sampling_variable.each do |var|
624
+ next if var.is_a?(Literal)
625
+ s << " sampling_variable(#{var}, ID2SYM(rb_intern(#{var.source.inspect})));"
626
+ end
627
+ end
628
+ s.empty? ? nil : s.join("\n")
629
+ end
630
+
631
+ def add_sampling_variable(var)
632
+ @sampling_variable |= [var]
633
+ end
634
+
635
+ def alive()
636
+ @alive ? false : (@alive = true)
637
+ end
638
+
639
+ def alive?
640
+ @alive
641
+ end
642
+
643
+ def reset()
644
+ @alive = false
645
+ @variables.each{|v| v.reset()}
646
+ end
647
+
648
+ def standard_guard_target()
649
+ nil
650
+ end
651
+
652
+ def propergate_guard_usage()
653
+ # nothing to do
654
+ end
655
+
656
+ def generate_guard(vars)
657
+ target = standard_guard_target()
658
+ if target.is_a?(Variable) && !target.dynamic? && @insn.need_guard?
659
+ # FIXME target <= should be dup
660
+ StandardGuard.new(target, vars, @insn, @cfg)
661
+ else
662
+ nil
663
+ end
664
+ end
665
+
666
+ def get_usage()
667
+ blocks = []
668
+ usage = {}
669
+ irs = [self]
670
+ change = true
671
+ while change
672
+ change = false
673
+ @cfg.blocks.each do |b|
674
+ foo = b.irs & irs
675
+ bar = b.information.variable_definition & irs
676
+ if foo.size > 0 || bar.size > 0
677
+ vars = []
678
+ bar.each do |ir|
679
+ result_variable = ir.result_variable
680
+ next unless result_variable
681
+ vars << result_variable
682
+ end
683
+ b.irs.each do |ir|
684
+ case ir
685
+ when SubIR
686
+ src = ir.src
687
+ dst = ir.dst
688
+ if src != dst
689
+ if vars.include?(dst)
690
+ vars.reject! {|v| v == dst}
691
+ #vars -= [dst]
692
+ end
693
+ if vars.include?(src)
694
+ if dst.is_a?(Pointer)
695
+ usage[:escape] = ir
696
+ return usage
697
+ end
698
+ vars |= [dst]
699
+ if !irs.include?(ir)
700
+ irs << ir
701
+ change = true
702
+ end
703
+ end
704
+ end
705
+ when JumpIR
706
+ # nothing to do
707
+ when ParamIR
708
+ if vars.include?(ir.param_value) && !irs.include?(ir)
709
+ irs << ir
710
+ change = true
711
+ end
712
+ when CallIR
713
+ argc = ir.argc
714
+ return_value = ir.return_value
715
+ param = ir.param_variables()
716
+ param.each do |p|
717
+ if vars.include?(p)
718
+ usage[[param[0], ir]] = vars.index(param[0])
719
+ break
720
+ end
721
+ end
722
+ if vars.include?(return_value)
723
+ vars.reject! {|v| v == return_value}
724
+ #vars -= [return_value]
725
+ end
726
+ when ReturnIR
727
+ if vars.include?(ir.return_value)
728
+ usage[:escape] = ir
729
+ return usage
730
+ end
731
+ end
732
+ result_variable = ir.result_variable
733
+ vars |= [result_variable] if foo.include?(ir) && result_variable
734
+ end
735
+ end
736
+ end
737
+ end
738
+ usage
739
+ end
740
+
741
+ def set_info(d)
742
+ @information = d
743
+ end
744
+
745
+ def get_definition(target)
746
+ case target
747
+ when Self, Literal
748
+ return [target]
749
+ when Variable
750
+ ds = @information.variable_definition_of(target)
751
+ bug() if ds.empty?
752
+ ary = []
753
+ ds.each do |d|
754
+ case d
755
+ when SubIR
756
+ src = d.src
757
+ if src.is_a?(TmpVariable)
758
+ ary += d.get_definition(src)
759
+ else
760
+ ary << d
761
+ end
762
+ when CallIR
763
+ ary << d
764
+ else
765
+ bug()
766
+ end
767
+ end
768
+ return ary
769
+ else
770
+ raise(UnsupportedError.new("Currently, CastOff cannot compile this method or block"))
771
+ end
772
+ bug()
773
+ end
774
+
775
+ def get_definition_str(target)
776
+ ary = get_definition(target)
777
+ ary.map {|d|
778
+ case d
779
+ when Self, Literal
780
+ d.source
781
+ when SubIR
782
+ d.src.source
783
+ when LoopIR, VMInsnIR
784
+ "vm internal value"
785
+ when InvokeIR
786
+ "result of #{d.to_verbose_string}"
787
+ when YieldIR
788
+ "result of yield"
789
+ else
790
+ bug()
791
+ end
792
+ }.join("\n")
793
+ end
794
+
795
+ def dispatch_method?
796
+ # FIXME 型情報を活用(Fixnum#+ とかはインスタンス変数を触らないよね)
797
+ return true if !@translator.inline_block? && self.is_a?(LoopIR)
798
+ self.is_a?(InvokeIR) || self.is_a?(YieldIR)
799
+ end
800
+
801
+ def inlining_target?
802
+ false
803
+ end
804
+ end
805
+ end
806
+ end
807
+ end
808
+