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,423 @@
1
+ # coding=utf-8
2
+
3
+ module CastOff
4
+ module Compiler
5
+ module SimpleIR
6
+ class GuardIR < IR
7
+ attr_reader :guard_value, :variables_without_result, :variables, :result_variable, :values
8
+
9
+ GUARD_DEOPTIMIZATION_TEMPLATE = ERB.new(<<-EOS, 0, '%-', 'g2')
10
+ /* depth = <%= @insn.depth %> */
11
+ % @information.undefined_variables.each do |var|
12
+ % @insn.iseq.initialize_for_guards(var) if var.is_a?(LocalVariable)
13
+ % end
14
+ % top = @insn.iseq
15
+ % a = [@insn.iseq]
16
+ % a = @insn.iseq.ancestors.reverse + a if @translator.inline_block?
17
+ % stacks = a.map{|s| s.depth}
18
+ % stacks.shift
19
+ % stacks.push(@insn.depth)
20
+ % stacks = stacks.zip(a.map{|s| s.depth}).map{|d0, d1| d0 - d1}
21
+ % valid = @translator.inline_block? ? @insn.depth : (@insn.depth - @insn.iseq.depth)
22
+ % bug() unless stacks.inject(0){|sum, d| sum + d} == valid
23
+ % a.each_with_index do |s, idx|
24
+ {
25
+ % local_c = s.lvars.size()
26
+ % stack_c = stacks[idx]
27
+ % if @translator.inline_block?
28
+ int local_c = <%= local_c %>;
29
+ VALUE local_v[<%= local_c %>];
30
+ % end
31
+ int stack_c = <%= stack_c %>;
32
+ VALUE stack_v[<%= stack_c %>];
33
+ rb_iseq_t *iseq = <%= s %>;
34
+ % s.lvars.each_with_index do |(var_name, var_id, op_idx, depth, var_annotation), i|
35
+ % if @translator.inline_block?
36
+ local_v[<%= i %>] = local<%= var_id %>_<%= var_name %>; /* FIXME */
37
+ % end
38
+ % end
39
+ % stack_c.times do |i|
40
+ stack_v[<%= i %>] = tmp<%= s.depth + i %>;
41
+ % end
42
+ % method_p = (s.itype == :method ? 1 : 0)
43
+ % lambda_p = (s.itype == :method ? 0 : 'lambda_p')
44
+ % top_p = (top == s ? 1 : 0)
45
+ % bottom_p = (s.root? ? 1 : 0)
46
+ % if @translator.inline_block?
47
+ % if s.root?
48
+ thval = rb_thread_current();
49
+ th = DATA_PTR(thval);
50
+ specval = 0;
51
+ lfp = 0;
52
+ dfp = 0;
53
+ % else
54
+ <%= s.loopkey.dopt_func %>(&<%= s.loopkey %>, specval);
55
+ % end
56
+ % if s == top
57
+ return cast_off_deoptimize_inline(self, iseq, NULL, pc, local_c, local_v, stack_c, stack_v, <%= top_p %>, <%= bottom_p %>, <%= method_p %>, lfp, dfp);
58
+ % else
59
+ % bug() unless idx + 1 < a.size
60
+ % biseq = a[idx + 1]
61
+ % bug() unless biseq.parent_pc
62
+ specval = cast_off_deoptimize_inline(self, iseq, <%= biseq %>, <%= biseq.parent_pc %>, local_c, local_v, stack_c, stack_v, <%= top_p %>, <%= bottom_p %>, <%= method_p %>, lfp, dfp);
63
+ % if s.root?
64
+ lfp = th->cfp->lfp;
65
+ % end
66
+ dfp = th->cfp->dfp;
67
+ % end
68
+ % else
69
+ {
70
+ VALUE return_value = cast_off_deoptimize_noinline(self, iseq, pc, stack_c, stack_v, <%= method_p %>, <%= lambda_p %>, <%= s.parent_pc ? s.parent_pc : -1 %>);
71
+ % if s.catch_exception?
72
+ TH_POP_TAG2();
73
+ % end
74
+ return return_value;
75
+ }
76
+ % end
77
+ }
78
+ % end
79
+ rb_bug("should not be reached");
80
+ EOS
81
+
82
+ GUARD_EXCEPTION_FUNCTION_TEMPLATE = ERB.new(<<-EOS, 0, '%-', 'g1')
83
+ NORETURN(static inline int <THROW_EXCEPTION_FUNCTION_NAME>(VALUE obj));
84
+ static inline int <THROW_EXCEPTION_FUNCTION_NAME>(VALUE obj)
85
+ {
86
+ VALUE path0 = rb_class_path(rb_class_of(obj));
87
+ VALUE path1 = rb_class_path(rb_obj_class(obj));
88
+ rb_raise(rb_eCastOffExecutionError, "\\
89
+ type mismatch: guard(<%= @guard_value %>:<%= "\#{@insn.pc}: \#{@insn.op}, depth = \#{@insn.depth}" %>)\\n\\
90
+ name = <%= @insn.iseq.name %>, line = <%= @source_line %>: source = %s\\n\\
91
+ expected <%= @guard_value.types %> but %s, %s\\n\\
92
+ <%= @translator.target_name() %>", <%= @source.to_s.inspect %>, RSTRING_PTR(path0), RSTRING_PTR(path1));
93
+ }
94
+ EOS
95
+
96
+ GUARD_TEMPLATE = ERB.new(<<-EOS, 0, '%-', 'g0')
97
+ %bug() if @guard_value.undefined? || @guard_value.dynamic?
98
+ <%= guard_begin() %>
99
+ #if 1
100
+ if(!sampling_table) register_sampling_table(rb_hash_new());
101
+ % get_definition(@guard_value).each do |defn|
102
+ % case defn
103
+ % when SubIR
104
+ % case defn.src
105
+ % when LocalVariable, DynamicVariable, InstanceVariable, ClassVariable, GlobalVariable, Self
106
+ sampling_variable(<%= @guard_value %>, ID2SYM(rb_intern("<%= defn.src.source %>")));
107
+ % when ConstWrapper, Literal
108
+ % # Fixme
109
+ % else
110
+ % bug(defn.src)
111
+ % end
112
+ % when InvokeIR
113
+ % recv = defn.param_variables.first
114
+ % bug() if recv.dynamic?
115
+ % recv.types.each do |k|
116
+ % recv_class = @translator.get_c_classname(k)
117
+ % bug() unless recv_class
118
+ __sampling_poscall(<%= @guard_value %>, <%= recv_class %>, ID2SYM(rb_intern("<%= defn.method_id %>")));
119
+ % end
120
+ % end
121
+ % end
122
+ rb_funcall(rb_mCastOff, rb_intern("re_compile"), 2, rb_str_new2("<%= @translator.signiture() %>"), sampling_table_val);
123
+ #endif
124
+ %if @configuration.deoptimize?
125
+ goto <%= @insn.guard_label %>;
126
+ % @insn.iseq.inject_guard(@insn, GUARD_DEOPTIMIZATION_TEMPLATE.trigger(binding))
127
+ %else
128
+ % func = @translator.declare_throw_exception_function(GUARD_EXCEPTION_FUNCTION_TEMPLATE.trigger(binding))
129
+ <%= func %>(<%= guard_value %>);
130
+ %end
131
+ <%= guard_end() %>
132
+ EOS
133
+
134
+ GUARD_CHECK_TEMPLATE = ERB.new(<<-EOS, 0, '%-', 'g3')
135
+ %if @guard_value.is_just?(NilClass)
136
+ if (UNLIKELY(!NIL_P(<%= @guard_value %>))) {
137
+ %elsif @guard_value.is_just?(TrueClass)
138
+ if (UNLIKELY(<%= @guard_value %> != Qtrue)) {
139
+ %elsif @guard_value.is_just?(FalseClass)
140
+ if (UNLIKELY(<%= @guard_value %> != Qfalse)) {
141
+ %elsif @guard_value.is_just?(Symbol)
142
+ if (UNLIKELY(!SYMBOL_P(<%= @guard_value %>))) {
143
+ %elsif @guard_value.is_just?(Fixnum)
144
+ if (UNLIKELY(!FIXNUM_P(<%= @guard_value %>))) {
145
+ %else
146
+ % if simple?
147
+ % func = @translator.declare_class_check_function(CLASS_CHECK_FUNCTION_TEMPLATE_SIMPLE.trigger(binding))
148
+ if (UNLIKELY(!<%= func %>(<%= @guard_value %>))) {
149
+ % else
150
+ % func = @translator.declare_class_check_function(CLASS_CHECK_FUNCTION_TEMPLATE_COMPLEX.trigger(binding))
151
+ if (UNLIKELY(!<%= func %>(<%= @guard_value %>, rb_class_of(<%= @guard_value %>)))) {
152
+ % end
153
+ %end
154
+
155
+ EOS
156
+
157
+ CLASS_CHECK_FUNCTION_TEMPLATE_SIMPLE = ERB.new(<<-EOS, 0, '%-', 'g4')
158
+ static inline int <CLASS_CHECK_FUNCTION_NAME>(VALUE obj)
159
+ {
160
+ if (0) {
161
+ %if @guard_value.is_also?(NilClass)
162
+ } else if (NIL_P(obj)) {
163
+ return 1;
164
+ %end
165
+ %if @guard_value.is_also?(TrueClass)
166
+ } else if (obj == Qtrue) {
167
+ return 1;
168
+ %end
169
+ %if @guard_value.is_also?(FalseClass)
170
+ } else if (obj == Qfalse) {
171
+ return 1;
172
+ %end
173
+ %if @guard_value.is_also?(Symbol)
174
+ } else if (SYMBOL_P(obj)) {
175
+ return 1;
176
+ %end
177
+ %if @guard_value.is_also?(Fixnum)
178
+ } else if (FIXNUM_P(obj)) {
179
+ return 1;
180
+ %end
181
+ } else {
182
+ return 0;
183
+ }
184
+ }
185
+ EOS
186
+
187
+ CLASS_CHECK_FUNCTION_TEMPLATE_COMPLEX = ERB.new(<<-EOS, 0, '%-', 'g4')
188
+ NOINLINE(static int <CLASS_CHECK_FUNCTION_NAME>_failed(VALUE obj, VALUE klass));
189
+
190
+ static inline int <CLASS_CHECK_FUNCTION_NAME>(VALUE obj, VALUE klass)
191
+ {
192
+ if (0) {
193
+ % @guard_value.types.each do |klass|
194
+ % name = @translator.get_c_classname(klass)
195
+ % raise(CompileError.new("can't generate guard for \#{klass}, you should pass binding to CastOff (\#{klass.singleton? ? 1 : 0})")) unless name
196
+ } else if (LIKELY(klass == <%= name %>)) {
197
+ return 1;
198
+ % end
199
+ } else {
200
+ if (LIKELY(<CLASS_CHECK_FUNCTION_NAME>_failed(obj, klass))) {
201
+ return 1;
202
+ } else {
203
+ return 0;
204
+ }
205
+ }
206
+ }
207
+
208
+ static int <CLASS_CHECK_FUNCTION_NAME>_failed(VALUE obj, VALUE klass)
209
+ {
210
+ if (UNLIKELY(FL_TEST(klass, FL_SINGLETON) && empty_method_table_p(klass))) {
211
+ return <CLASS_CHECK_FUNCTION_NAME>(obj, rb_obj_class(obj));
212
+ }
213
+ return 0;
214
+ }
215
+ EOS
216
+
217
+ def initialize(val, vars, insn, cfg)
218
+ super(insn, cfg)
219
+ @guard_value = val
220
+ bug() unless @guard_value.is_a?(Variable)
221
+ @values = [@guard_value]
222
+ @variables = []
223
+ @variables_without_result = []
224
+ @variables << @guard_value
225
+ @variables_without_result << @guard_value
226
+ @result_variable = nil
227
+ @dependent_variables = get_dependent_variables(vars)
228
+ @source = @insn.source
229
+ @source = @source.empty? ? nil : @source
230
+ @source_line = @insn.line.to_s
231
+ end
232
+
233
+ ### unboxing begin ###
234
+ def unboxing_prelude()
235
+ # TODO inline api の返り値で unbox 可能なものは、class_exact にして伝播させること。
236
+ if @guard_value.class_exact? && @guard_value.can_unbox?
237
+ @guard_value.can_unbox()
238
+ else
239
+ @guard_value.can_not_unbox()
240
+ end
241
+ end
242
+
243
+ def propergate_value_which_can_not_unbox(defs)
244
+ change = false
245
+
246
+ # forward
247
+ change |= defs.can_not_unbox_variable_resolve_forward(@guard_value)
248
+
249
+ # backward
250
+ if @guard_value.can_not_unbox?
251
+ change |= defs.can_not_unbox_variable_resolve_backward(@guard_value)
252
+ if @configuration.deoptimize?
253
+ @dependent_variables.each do |v|
254
+ change |= v.can_not_unbox()
255
+ end
256
+ end
257
+ end
258
+
259
+ change
260
+ end
261
+
262
+ def propergate_box_value(defs)
263
+ change = false
264
+
265
+ # forward
266
+ change |= defs.box_value_resolve_forward(@guard_value)
267
+
268
+ # backward
269
+ if @guard_value.boxed?
270
+ change |= defs.box_value_resolve_backward(@guard_value)
271
+ if @configuration.deoptimize?
272
+ @dependent_variables.each do |v|
273
+ v.box()
274
+ change |= defs.box_value_resolve_backward(v)
275
+ end
276
+ end
277
+ end
278
+
279
+ change
280
+ end
281
+
282
+ def propergate_unbox_value(defs)
283
+ return false if @guard_value.can_not_unbox?
284
+ bug() unless @guard_value.class_exact?
285
+ defs.unbox_value_resolve(@guard_value)
286
+ end
287
+ ### unboxing end ###
288
+
289
+ def propergate_exact_class(defs)
290
+ defs.exact_class_resolve(@guard_value)
291
+ end
292
+
293
+ def to_c()
294
+ if @configuration.inject_guard? && !@guard_value.class_exact?
295
+ bug() if @insn.pc == -1
296
+ bug() unless @insn.depth
297
+ GUARD_TEMPLATE.trigger(binding).chomp
298
+ end
299
+ end
300
+
301
+ def type_propergation(defs)
302
+ bug()
303
+ end
304
+
305
+ def mark(defs)
306
+ if !@alive
307
+ @alive = true
308
+ defs.mark(@guard_value)
309
+ if @configuration.deoptimize?
310
+ @dependent_variables.each{|v| defs.mark(v)}
311
+ end
312
+ true
313
+ else
314
+ false
315
+ end
316
+ end
317
+
318
+ private
319
+
320
+ def simple?
321
+ bug() if @guard_value.dynamic?
322
+ bug() if @guard_value.class_exact?
323
+ special_consts = [NilClass, TrueClass, FalseClass, Symbol, Fixnum]
324
+ special_consts.size.times do |i|
325
+ special_consts.combination(i + 1).each do |pattern|
326
+ return true if @guard_value.is_just?(pattern)
327
+ end
328
+ end
329
+ false
330
+ end
331
+
332
+ def guard_begin()
333
+ GUARD_CHECK_TEMPLATE.trigger(binding).chomp.chomp
334
+ end
335
+
336
+ def guard_end()
337
+ " }"
338
+ end
339
+
340
+ def get_dependent_variables(vars)
341
+ targets = []
342
+ s = @insn.iseq
343
+ level = @insn.iseq.generation
344
+ while s
345
+ s.lvars.each do |var_name, var_id, op_idx, depth, var_annotation|
346
+ bug() unless depth == level
347
+ if @translator.inline_block?
348
+ targets << "local#{var_id}_#{var_name}" # FIXME
349
+ else
350
+ targets << "dfp#{depth}[#{op_idx}]" # FIXME
351
+ end
352
+ end
353
+ level -= 1
354
+ s = s.parent
355
+ end
356
+ bug() unless level == -1
357
+ d = @insn.depth
358
+ while d > 0 do
359
+ d -= 1
360
+ targets << "tmp#{d}" # FIXME
361
+ end
362
+ vars.select{|v| targets.include?(v.to_name)}.uniq()
363
+ end
364
+ end
365
+
366
+ class StandardGuard < GuardIR
367
+ def to_debug_string()
368
+ "StandardGuard(#{@guard_value.to_debug_string()})"
369
+ end
370
+ end
371
+
372
+ class JumpGuard < GuardIR
373
+ def initialize(val, vars, insn, cfg)
374
+ super(val, vars, insn, cfg)
375
+ @bool = bool_value()
376
+ end
377
+
378
+ def type_propergation(defs)
379
+ defs.type_resolve(@guard_value) #分岐のみで使用されるインスタンス変数等のために必要
380
+ end
381
+
382
+ def reset()
383
+ super()
384
+ if @configuration.deoptimize?
385
+ @dependent_variables.map! do |v|
386
+ bug() unless v.is_a?(Variable)
387
+ @cfg.find_variable(v)
388
+ end
389
+ bug() if @dependent_variables.include?(nil)
390
+ end
391
+ end
392
+
393
+ def to_debug_string()
394
+ "JumpGuard(#{@guard_value.to_debug_string()})"
395
+ end
396
+
397
+ def to_c()
398
+ bug() unless @bool == bool_value()
399
+ super()
400
+ end
401
+
402
+ private
403
+
404
+ def bool_value()
405
+ bug() if @guard_value.dynamic?
406
+ return false if @guard_value.is_just?(NilClass) || @guard_value.is_just?(FalseClass)
407
+ return false if @guard_value.is_just?([NilClass, FalseClass])
408
+ bug() if @guard_value.is_also?(NilClass) || @guard_value.is_also?(FalseClass)
409
+ true
410
+ end
411
+
412
+ def guard_begin()
413
+ if @bool
414
+ " if (UNLIKELY(!RTEST(#{@guard_value}))) {"
415
+ else
416
+ " if (UNLIKELY(RTEST(#{@guard_value}))) {"
417
+ end
418
+ end
419
+ end
420
+ end
421
+ end
422
+ end
423
+
@@ -0,0 +1,223 @@
1
+ # coding=utf-8
2
+
3
+ module CastOff::Compiler
4
+ module SimpleIR
5
+ class JumpIR < IR
6
+ attr_reader :cond_value, :jump_targets, :jump_type, :variables_without_result, :variables, :result_variable, :values
7
+
8
+ def initialize(val, insn, cfg)
9
+ super(insn, cfg)
10
+
11
+ @cond_value = val
12
+ @jump_type = insn.op
13
+ argv = insn.argv
14
+ case @jump_type
15
+ when :jump, :branchif, :branchunless, :cast_off_enter_block, :cast_off_leave_block, :cast_off_continue_loop
16
+ @jump_targets = [argv[0]]
17
+ @must = nil
18
+ @post = nil
19
+ when :cast_off_break_block
20
+ @jump_targets = [argv[0]]
21
+ @raw_state = argv[1]
22
+ bug() unless @raw_state
23
+ @exc_pc = argv[2]
24
+ bug() unless @exc_pc >= 0
25
+ @must = nil
26
+ @post = nil
27
+ when :cast_off_handle_optional_args
28
+ @jump_targets = argv[0]
29
+ @must = argv[1]
30
+ @post = argv[2]
31
+ else
32
+ bug()
33
+ end
34
+ bug() unless @jump_targets.is_a?(Array)
35
+ @values = @cond_value ? [@cond_value] : []
36
+ @variables = []
37
+ @variables_without_result = []
38
+ if @cond_value.is_a?(Variable)
39
+ @variables << @cond_value
40
+ @variables_without_result << @cond_value
41
+ end
42
+ @result_variable = nil
43
+ end
44
+
45
+ ### unboxing begin ###
46
+ def unboxing_prelude()
47
+ @cond_value.can_not_unbox() if @cond_value
48
+ end
49
+
50
+ def propergate_value_which_can_not_unbox(defs)
51
+ return false unless @cond_value
52
+ bug() unless @cond_value.can_not_unbox?
53
+ defs.can_not_unbox_variable_resolve_backward(@cond_value)
54
+ end
55
+
56
+ def propergate_box_value(defs)
57
+ return false unless @cond_value
58
+ bug() unless @cond_value.boxed?
59
+ defs.box_value_resolve_backward(@cond_value)
60
+ end
61
+
62
+ def propergate_unbox_value(defs)
63
+ return false unless @cond_value
64
+ bug() unless @cond_value.can_not_unbox?
65
+ false
66
+ end
67
+ ### unboxing end ###
68
+
69
+ def propergate_exact_class(defs)
70
+ @cond_value ? defs.exact_class_resolve(@cond_value) : false
71
+ end
72
+
73
+ def to_debug_string()
74
+ "Jump(#{@jump_type}#{@cond_value ? " : #{@cond_value.to_debug_string()}" : ''}) => #{@jump_targets}"
75
+ end
76
+
77
+ def to_c()
78
+ ret = []
79
+ # FIXME detect backedge
80
+ # FIXME add interrupt check when ehable intterupt check option
81
+ s = sampling_variable()
82
+ ret << s if s
83
+ case @jump_type
84
+ when :cast_off_enter_block
85
+ if @translator.inline_block?
86
+ bug() unless @jump_targets.size() == 1
87
+ ret << " goto #{@jump_targets[0]};"
88
+ end
89
+ when :cast_off_leave_block
90
+ if @translator.inline_block?
91
+ bug() unless @jump_targets.size() == 1
92
+ ret << " goto #{@jump_targets[0]};"
93
+ else
94
+ ret << " return tmp#{@insn.iseq.depth};" # FIXME
95
+ end
96
+ when :cast_off_break_block
97
+ if @translator.inline_block?
98
+ bug() unless @jump_targets.size() == 1
99
+ ret << " goto #{@jump_targets[0]};"
100
+ else
101
+ ret << " break_block(#{@raw_state}, #{@exc_pc}, tmp#{@insn.iseq.depth});" # FIXME
102
+ end
103
+ when :cast_off_continue_loop
104
+ if @translator.inline_block?
105
+ bug() unless @jump_targets.size() == 1
106
+ ret << " if (RTEST(#{@cond_value})) goto #{@jump_targets[0]};"
107
+ end
108
+ when :jump
109
+ bug() unless @jump_targets.size() == 1
110
+ #ret << " RUBY_VM_CHECK_INTS();"
111
+ ret << " goto #{@jump_targets[0]};"
112
+ when :branchunless
113
+ bug() unless @jump_targets.size() == 1
114
+ ret << " if (!RTEST(#{@cond_value})) goto #{@jump_targets[0]};"
115
+ =begin
116
+ ret << <<-EOS
117
+ if (!RTEST(#{@cond_value})) {
118
+ RUBY_VM_CHECK_INTS();
119
+ goto #{@jump_targets[0]};
120
+ }
121
+ EOS
122
+ =end
123
+ when :branchif
124
+ bug() unless @jump_targets.size() == 1
125
+ ret << " if (RTEST(#{@cond_value})) goto #{@jump_targets[0]};"
126
+ =begin
127
+ ret << <<-EOS
128
+ if (RTEST(#{@cond_value})) {
129
+ RUBY_VM_CHECK_INTS();
130
+ goto #{@jump_targets[0]};
131
+ }
132
+ EOS
133
+ =end
134
+ when :cast_off_handle_optional_args
135
+ bug() unless @jump_targets.size() > 1
136
+ bug() unless @cond_value.is_just?(Fixnum)
137
+ ret << " switch(#{@cond_value}) {"
138
+ @jump_targets.each_with_index do |t, i|
139
+ ret << " case(INT2FIX(#{i + @must})): goto #{t};"
140
+ end
141
+ if @post
142
+ ret << <<-EOS
143
+ default: {
144
+ int num = FIX2INT(#{@cond_value});
145
+ if (num >= #{@jump_targets.size() + @must}) {
146
+ goto #{@jump_targets.last};
147
+ } else {
148
+ rb_bug("should not be reached");
149
+ }
150
+ }
151
+ EOS
152
+ else
153
+ ret << " default: rb_bug(\"should not be reached\");"
154
+ end
155
+ ret << " }"
156
+ else
157
+ bug("unexpected jump type #{@jump_type}")
158
+ end
159
+ ret.join("\n")
160
+ end
161
+
162
+ def type_propergation(defs)
163
+ @cond_value ? defs.type_resolve(@cond_value) : false
164
+ end
165
+
166
+ def unused_target()
167
+ case @jump_type
168
+ when :jump
169
+ bug()
170
+ when :cast_off_handle_optional_args, :cast_off_enter_block, :cast_off_leave_block, :cast_off_continue_loop, \
171
+ :cast_off_break_block
172
+ # nothing to do
173
+ return nil
174
+ when :branchif, :branchunless
175
+ bug() if @cond_value.undefined?
176
+ return nil if @cond_value.dynamic?
177
+ nil_wrapper = ClassWrapper.new(NilClass, true)
178
+ false_wrapper = ClassWrapper.new(FalseClass, true)
179
+ classes = @cond_value.types
180
+ bug() if classes.empty?
181
+ constant = true
182
+ bool = nil
183
+ classes.each do |c|
184
+ if c == nil_wrapper || c == false_wrapper
185
+ __bool = false
186
+ else
187
+ __bool = true
188
+ end
189
+ if bool.nil?
190
+ bool = __bool
191
+ else
192
+ unless bool == __bool
193
+ constant = false
194
+ break
195
+ end
196
+ end
197
+ end
198
+ if constant
199
+ bug() if bool.nil?
200
+ fallthrough = (bool && @jump_type == :branchunless) || (!bool && @jump_type == :branchif)
201
+ bug() if @jump_targets.size() != 1
202
+ target = @jump_targets[0]
203
+ return fallthrough ? target : :fallthrough
204
+ else
205
+ return nil
206
+ end
207
+ end
208
+ bug()
209
+ end
210
+
211
+ def mark(defs)
212
+ if !alive?
213
+ alive()
214
+ defs.mark(@cond_value) if @cond_value
215
+ true
216
+ else
217
+ false
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
223
+