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.
- data/README +578 -0
- data/README.en +256 -0
- data/bin/CastOff +145 -0
- data/cast_off.gemspec +25 -0
- data/ext/cast_off/cast_off.c.rb +1386 -0
- data/ext/cast_off/cast_off.h +24 -0
- data/ext/cast_off/depend +70 -0
- data/ext/cast_off/extconf.rb +19 -0
- data/ext/cast_off/generated_c_include/inline_api.h +507 -0
- data/ext/cast_off/generated_c_include/iter_api.h +595 -0
- data/ext/cast_off/generated_c_include/unbox_api.h.rb +76 -0
- data/ext/cast_off/generated_c_include/vm_api.h +751 -0
- data/ext/cast_off/ruby_source/atomic.h +56 -0
- data/ext/cast_off/ruby_source/constant.h +34 -0
- data/ext/cast_off/ruby_source/debug.h +41 -0
- data/ext/cast_off/ruby_source/eval_intern.h +234 -0
- data/ext/cast_off/ruby_source/gc.h +98 -0
- data/ext/cast_off/ruby_source/id.h +175 -0
- data/ext/cast_off/ruby_source/insns.inc +179 -0
- data/ext/cast_off/ruby_source/insns_info.inc +695 -0
- data/ext/cast_off/ruby_source/internal.h +227 -0
- data/ext/cast_off/ruby_source/iseq.h +125 -0
- data/ext/cast_off/ruby_source/manual_update.h +135 -0
- data/ext/cast_off/ruby_source/method.h +105 -0
- data/ext/cast_off/ruby_source/node.h +503 -0
- data/ext/cast_off/ruby_source/thread_pthread.h +51 -0
- data/ext/cast_off/ruby_source/thread_win32.h +40 -0
- data/ext/cast_off/ruby_source/vm_core.h +756 -0
- data/ext/cast_off/ruby_source/vm_exec.h +184 -0
- data/ext/cast_off/ruby_source/vm_insnhelper.c +1748 -0
- data/ext/cast_off/ruby_source/vm_insnhelper.h +220 -0
- data/ext/cast_off/ruby_source/vm_opts.h +51 -0
- data/lib/cast_off.rb +15 -0
- data/lib/cast_off/compile.rb +629 -0
- data/lib/cast_off/compile/basicblock.rb +144 -0
- data/lib/cast_off/compile/cfg.rb +391 -0
- data/lib/cast_off/compile/code_manager.rb +284 -0
- data/lib/cast_off/compile/configuration.rb +2368 -0
- data/lib/cast_off/compile/dependency.rb +240 -0
- data/lib/cast_off/compile/information.rb +775 -0
- data/lib/cast_off/compile/instruction.rb +446 -0
- data/lib/cast_off/compile/ir/call_ir.rb +2348 -0
- data/lib/cast_off/compile/ir/guard_ir.rb +423 -0
- data/lib/cast_off/compile/ir/jump_ir.rb +223 -0
- data/lib/cast_off/compile/ir/operand.rb +934 -0
- data/lib/cast_off/compile/ir/param_ir.rb +98 -0
- data/lib/cast_off/compile/ir/return_ir.rb +92 -0
- data/lib/cast_off/compile/ir/simple_ir.rb +808 -0
- data/lib/cast_off/compile/ir/sub_ir.rb +212 -0
- data/lib/cast_off/compile/iseq.rb +454 -0
- data/lib/cast_off/compile/method_information.rb +1384 -0
- data/lib/cast_off/compile/namespace/namespace.rb +556 -0
- data/lib/cast_off/compile/namespace/uuid.rb +323 -0
- data/lib/cast_off/compile/stack.rb +65 -0
- data/lib/cast_off/compile/translator.rb +1562 -0
- data/lib/cast_off/suggestion.rb +98 -0
- data/lib/cast_off/util.rb +58 -0
- 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
|
+
|