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,212 @@
1
+ # coding=utf-8
2
+
3
+ module CastOff::Compiler
4
+ module SimpleIR
5
+ class SubIR < IR
6
+ attr_reader :src, :dst, :variables_without_result, :variables, :result_variable, :values
7
+ def initialize(src, dst, insn, cfg)
8
+ super(insn, cfg)
9
+ @src = src
10
+ @dst = dst
11
+ @values = [@src, @dst]
12
+ @variables = []
13
+ @variables_without_result = []
14
+ if @src.is_a?(Variable)
15
+ @variables << @src
16
+ @variables_without_result << @src
17
+ end
18
+ bug() unless @dst.is_a?(Variable)
19
+ @variables << @dst
20
+ @result_variable = @dst
21
+ end
22
+
23
+ def to_debug_string()
24
+ "#{@dst.to_debug_string()} = #{@src.to_debug_string()}"
25
+ end
26
+
27
+ ### unboxing begin ###
28
+ def unboxing_prelude()
29
+ if @src.can_unbox? && @dst.can_unbox?
30
+ @src.can_unbox()
31
+ @dst.can_unbox()
32
+ else
33
+ @src.can_not_unbox()
34
+ @dst.can_not_unbox()
35
+ end
36
+ end
37
+
38
+ def propergate_value_which_can_not_unbox(defs)
39
+ change = false
40
+
41
+ # forward
42
+ change |= defs.can_not_unbox_variable_resolve_forward(@src)
43
+ if @src.can_not_unbox?
44
+ change |= @dst.can_not_unbox()
45
+ end
46
+
47
+ # backward
48
+ if @dst.can_not_unbox?
49
+ change |= @src.can_not_unbox()
50
+ end
51
+ if @src.can_not_unbox?
52
+ change |= defs.can_not_unbox_variable_resolve_backward(@src)
53
+ end
54
+ bug() unless @src.can_not_unbox? == @dst.can_not_unbox?
55
+
56
+ change
57
+ end
58
+
59
+ def propergate_box_value(defs)
60
+ change = false
61
+
62
+ # forward
63
+ change |= defs.box_value_resolve_forward(@src)
64
+ if @src.boxed?
65
+ change |= @dst.box()
66
+ end
67
+
68
+ # backward
69
+ if @dst.boxed?
70
+ change |= @src.box()
71
+ end
72
+ if @src.boxed?
73
+ change |= defs.box_value_resolve_backward(@src)
74
+ end
75
+ bug() unless @src.boxed? == @dst.boxed?
76
+ bug() unless @src.unboxed? == @dst.unboxed?
77
+
78
+ change
79
+ end
80
+
81
+ def propergate_unbox_value(defs)
82
+ #return false if @src.unboxed? && @dst.unboxed?
83
+ if @src.can_not_unbox?
84
+ bug() unless @dst.can_not_unbox?
85
+ return false
86
+ else
87
+ bug() if @dst.can_not_unbox?
88
+ change = false
89
+
90
+ if @src.instance_of?(Literal)
91
+ bug() unless @src.types.size == 1
92
+ bug() unless @src.static?
93
+ floatwrap = ClassWrapper.new(Float, true)
94
+ fixnumwrap = ClassWrapper.new(Fixnum, true)
95
+ case @src.types[0]
96
+ when floatwrap, fixnumwrap
97
+ change |= @src.unbox()
98
+ end
99
+ end
100
+
101
+ change |= defs.unbox_value_resolve(@src)
102
+ if @src.unboxed? && !@dst.unboxed?
103
+ @dst.unbox()
104
+ change = true
105
+ end
106
+ return change
107
+ end
108
+ end
109
+ ### unboxing end ###
110
+
111
+ def propergate_exact_class(defs)
112
+ change = defs.exact_class_resolve(@src)
113
+ if @src.class_exact? && !@dst.class_exact?
114
+ @dst.is_class_exact()
115
+ change = true
116
+ end
117
+ change
118
+ end
119
+
120
+ def to_c()
121
+ return '' if vanish?
122
+ ret = []
123
+ case @src
124
+ when Argument
125
+ if @translator.inline_block?
126
+ # nothing to do
127
+ else
128
+ ret << " #{@dst} = #{@src.lvar};"
129
+ end
130
+ when ConstWrapper
131
+ @insn.iseq.reference_constant
132
+ if @src.prefetch?
133
+ @translator.prefetch_constant(@src.to_name, @src.path, false)
134
+ ret << " #{@dst} = #{@src};"
135
+ else
136
+ if @src.cache?
137
+ ret << <<-EOS
138
+ if (UNLIKELY(#{@src} == Qundef)) {
139
+ #{@src.get_constant_chain()}
140
+ }
141
+ #{@dst} = #{@src};
142
+ EOS
143
+ else
144
+ ret << <<-EOS
145
+ #{@src.get_constant_chain()}
146
+ #{@dst} = #{@src};
147
+ EOS
148
+ end
149
+ end
150
+ when GlobalVariable
151
+ bug() unless @dst.is_a?(TmpVariable)
152
+ ret << " #{@dst} = rb_gvar_get(rb_global_entry(#{@translator.allocate_id(@src.id)}));"
153
+ ret << " #{@src} = #{@dst};"
154
+ when ClassVariable
155
+ bug() unless @dst.is_a?(TmpVariable)
156
+ ret << " #{@dst} = rb_cvar_get(cast_off_get_cvar_base(), #{@translator.allocate_id(@src.id)});"
157
+ ret << " #{@src} = #{@dst};"
158
+ when InstanceVariable
159
+ bug() unless @dst.is_a?(TmpVariable)
160
+ # FIXME 間にメソッド呼び出しをはさんでいない場合は、読んだ結果をローカル変数(instance_id)にキャッシュする
161
+ if @translator.use_fast_ivar?
162
+ ret << " #{@dst} = iv_table_ptr[#{@translator.get_ivar_index(@translator.allocate_id(@src.id), @src.to_name)}];"
163
+ else
164
+ ret << " #{@dst} = vm_getivar(self, #{@translator.allocate_id(@src.id)}, &#{@translator.get_ic(@src.to_name)});"
165
+ end
166
+ ret << " #{@src} = #{@dst};"
167
+ else
168
+ case @dst
169
+ when Argument, ConstWrapper
170
+ bug()
171
+ when InstanceVariable
172
+ # FIXME 間にメソッド呼び出しをはさんでいない場合は、書いた結果をローカル変数(instance_id)にキャッシュする
173
+ if @translator.use_fast_ivar?
174
+ ret << " iv_table_ptr[#{@translator.get_ivar_index(@translator.allocate_id(@dst.id), @dst.to_name)}] = #{@src};"
175
+ else
176
+ ret << " vm_setivar(self, #{@translator.allocate_id(@dst.id)}, #{@src}, &#{@translator.get_ic(@dst.to_name)});"
177
+ end
178
+ when ClassVariable
179
+ ret << " rb_cvar_set(cast_off_get_cvar_base(), #{@translator.allocate_id(@dst.id)}, #{@src});"
180
+ when GlobalVariable
181
+ ret << " rb_gvar_set(rb_global_entry(#{@translator.allocate_id(@dst.id)}), #{@src});"
182
+ else
183
+ ret << " #{@dst} = #{@src};"
184
+ end
185
+ end
186
+ s = sampling_variable()
187
+ ret << s if s
188
+ ret.join("\n")
189
+ end
190
+
191
+ def type_propergation(defs)
192
+ defs.type_resolve(@src) | @dst.union(@src)
193
+ end
194
+
195
+ def mark(defs)
196
+ if @dst.is_a?(Pointer)
197
+ # read に関しては、使われてないなら行う必要はない
198
+ if !alive?
199
+ alive()
200
+ defs.mark(@src)
201
+ true
202
+ else
203
+ defs.mark(@src)
204
+ end
205
+ else
206
+ alive? && defs.mark(@src)
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
212
+
@@ -0,0 +1,454 @@
1
+ # coding=utf-8
2
+
3
+ module CastOff
4
+ module Compiler
5
+ class Iseq
6
+ include CastOff::Util
7
+
8
+ attr_reader :iseq, :children, :parent, :depth, :lvars, :source, :name, :generation, :itype, :args, :source_file, :source_line, :parent_pc, :loopkey
9
+
10
+ class Args
11
+ include CastOff::Util
12
+
13
+ attr_reader :arg_size, :argc, :post_len, :post_start, :rest_index, :block_index, :opts, :opt_len
14
+
15
+ def initialize(args, iseq)
16
+ @iseq = iseq
17
+ case args
18
+ when Integer
19
+ @argc, @opts, @post_len, @post_start, @rest_index, @block_index, @simple = args, [], 0, 0, -1, -1, 1
20
+ when Array
21
+ bug() unless args.size == 7
22
+ @argc, @opts, @post_len, @post_start, @rest_index, @block_index, @simple = args
23
+ else
24
+ bug()
25
+ end
26
+ @opt_len = @opts.empty? ? 0 : (@opts.size() - 1)
27
+ @arg_size = @argc + @opt_len + @post_len + (@rest_index == -1 ? 0 : 1) + (@block_index == -1 ? 0 : 1)
28
+
29
+ case @iseq.itype
30
+ when :method
31
+ bug() if @simple == 2
32
+ when :block
33
+ # nothing to do
34
+ else
35
+ bug()
36
+ end
37
+
38
+ if @rest_index != -1
39
+ bug() unless @rest_index + 1 == @post_start
40
+ bug() unless @argc + @opt_len == @rest_index
41
+ end
42
+ end
43
+
44
+ def post?
45
+ @post_len != 0
46
+ end
47
+
48
+ def rest?
49
+ @rest_index != -1
50
+ end
51
+
52
+ def block?
53
+ @block_index != -1
54
+ end
55
+
56
+ def opt?
57
+ not @opts.empty?
58
+ end
59
+
60
+ def simple?
61
+ (@simple & 0x01) != 0
62
+ end
63
+
64
+ def splat?
65
+ (@simple & 0x02 == 0) && (@argc + @post_len > 0)
66
+ end
67
+ end
68
+
69
+ def initialize(iseq, parent, depth, ppc)
70
+ bug() unless iseq.is_a?(RubyVM::InstructionSequence)
71
+ @iseq = iseq
72
+ ary = iseq.to_a
73
+ @name = ary[5]
74
+ @source_file = ary[7]
75
+ @source_line = ary[8]
76
+ @itype = ary[9] # iseq type
77
+ args = ary[11]
78
+ @args = Args.new(args, self)
79
+ if @source_file && File.exist?(@source_file)
80
+ @source = File.readlines(@source_file)
81
+ else
82
+ @source = nil
83
+ end
84
+ @parent = parent
85
+ @children = {} # pc => iseq
86
+ bug() unless depth.is_a?(Fixnum)
87
+ @depth = depth
88
+ @parent_pc = ppc
89
+ @generation = 0
90
+
91
+ p = @parent
92
+ while p
93
+ p = p.parent
94
+ @generation += 1
95
+ end
96
+ bug() if !root? && @generation < 1
97
+
98
+ # for code generator
99
+ @argv_size = 1
100
+ @initialize_for_guards = []
101
+ @guard_codes = {}
102
+ @local_variable_declarations = []
103
+ @c_function_body = ""
104
+ @c_name = "iseq_#{@iseq.hash.to_s.gsub(/-/, "_")}"
105
+ @ifunc_name = "ifunc_#{@c_name}"
106
+ @ifunc_node_name = "ifunc_node_#{@c_name}"
107
+ @excs = {}
108
+ @reference_constant_p = false
109
+ @loopkey = nil
110
+ end
111
+
112
+ def set_local_variables(lvars)
113
+ @lvars = lvars
114
+ end
115
+
116
+ def set_loopkey(k)
117
+ bug() if root?
118
+ @loopkey = k
119
+ end
120
+
121
+ def add(child, pc)
122
+ bug() unless child.is_a?(Iseq)
123
+ bug() unless pc.is_a?(Fixnum)
124
+ bug() if @children[pc]
125
+ @children[pc] = child
126
+ end
127
+
128
+ def root?
129
+ !@parent
130
+ end
131
+
132
+ def ancestors
133
+ a = []
134
+ s = self.parent
135
+ while s
136
+ a << s
137
+ s = s.parent
138
+ end
139
+ a
140
+ end
141
+
142
+ def reference_constant
143
+ @reference_constant_p = true
144
+ end
145
+
146
+ def reference_constant?
147
+ @reference_constant_p
148
+ end
149
+
150
+ def append_c_function_body(code)
151
+ @c_function_body = [@c_function_body, code].join("\n")
152
+ end
153
+
154
+ def all_c_function_body()
155
+ o = own_c_function_body()
156
+ c = @children.values.map{|i| i.all_c_function_body() }.join("\n")
157
+ [o, c].join("\n")
158
+ end
159
+
160
+ def own_c_function_body()
161
+ @c_function_body
162
+ end
163
+
164
+ def use_temporary_c_ary(size)
165
+ @argv_size = size if size > @argv_size
166
+ "cast_off_argv"
167
+ end
168
+
169
+ def all_argv_size()
170
+ o = own_argv_size()
171
+ c = @children.values.map{|i| i.all_argv_size()}
172
+ [o, c].flatten.max()
173
+ end
174
+
175
+ def own_argv_size()
176
+ @argv_size
177
+ end
178
+
179
+ def declare_local_variable(v)
180
+ @local_variable_declarations << v
181
+ end
182
+
183
+ def all_local_variable_declarations()
184
+ o = own_local_variable_declarations()
185
+ c = @children.values.map{|i| i.all_local_variable_declarations() }
186
+ [o, c].flatten.uniq()
187
+ end
188
+
189
+ def own_local_variable_declarations()
190
+ @local_variable_declarations.uniq()
191
+ end
192
+
193
+ def initialize_for_guards(var)
194
+ @initialize_for_guards << var
195
+ end
196
+
197
+ def all_initializations_for_guards()
198
+ # 外のブロックで定義されたローカル変数は、LocalVariable とはならないため。
199
+ # ローカル変数は、全て初期化してしまって問題ない。
200
+ ret = []
201
+ ret += own_initializations_for_guards()
202
+ @children.values.each{|c| ret += c.all_initializations_for_guards() }
203
+ ret.uniq()
204
+ end
205
+
206
+ def own_initializations_for_guards()
207
+ @initialize_for_guards.map{|v| " #{v} = Qnil;"}.uniq()
208
+ end
209
+
210
+ def inject_guard(insn, code)
211
+ bug() unless insn.iseq == self
212
+ if @guard_codes[code]
213
+ @guard_codes[code] << insn
214
+ else
215
+ @guard_codes[code] = [insn]
216
+ end
217
+ end
218
+
219
+ def iterate_all_guards(&b)
220
+ iterate_own_guards(&b)
221
+ @children.values.each{|c| c.iterate_all_guards(&b)}
222
+ end
223
+
224
+ def iterate_own_guards()
225
+ @guard_codes.each{|(code, insns)| yield(code, insns)}
226
+ end
227
+
228
+ def iterate_all_iseq(&b)
229
+ yield(self)
230
+ @children.values.each{|c| c.iterate_all_iseq(&b)}
231
+ end
232
+
233
+ def declare_ifunc_node()
234
+ "static NODE *#{@ifunc_node_name}"
235
+ end
236
+
237
+ IfuncNodeGeneratorTemplate = ERB.new(<<-EOS, 0, '%-', 'io')
238
+ static void <%= ifunc_node_generator() %>()
239
+ {
240
+ %# NEW_IFUNC の第二引数は Proc に対して渡せる好きな値
241
+ %#<%= @ifunc_node_name %> = NEW_IFUNC(<%= @ifunc_name %>, <%= self %>->self);
242
+ <%= @ifunc_node_name %> = NEW_IFUNC(<%= @ifunc_name %>, Qnil);
243
+ %# nd_aid = 0 だと rb_frame_this_func で <ifunc> となる。
244
+ <%= @ifunc_node_name %>->nd_aid = 0;
245
+ rb_gc_register_mark_object((VALUE)<%= @ifunc_node_name %>);
246
+ }
247
+ EOS
248
+
249
+ def define_ifunc_node_generator()
250
+ IfuncNodeGeneratorTemplate.trigger(binding)
251
+ end
252
+
253
+ def ifunc_node_generator()
254
+ "generate_ifunc_node_#{@c_name}"
255
+ end
256
+
257
+ BlockGeneratorTemplate = ERB.new(<<-EOS, 0, '%-', 'io')
258
+ <%= declare_block_generator() %>
259
+ {
260
+ VALUE thval = rb_thread_current();
261
+ rb_thread_t * th = DATA_PTR(thval);
262
+ rb_control_frame_t *cfp = th->cfp;
263
+ rb_block_t *blockptr = (rb_block_t *)(&(cfp)->self);
264
+ /* cfp の self 以下が block 構造体のメンバとなる */
265
+
266
+ blockptr->iseq = (void *)<%= @ifunc_node_name %>;
267
+ blockptr->proc = 0;
268
+ blockptr->self = self; /* for CastOff.execute */
269
+
270
+ return blockptr;
271
+ }
272
+ EOS
273
+
274
+ def declare_block_generator()
275
+ "rb_block_t *#{block_generator()}(VALUE self)"
276
+ end
277
+
278
+ def define_block_generator()
279
+ BlockGeneratorTemplate.trigger(binding)
280
+ end
281
+
282
+ def block_generator()
283
+ "cast_off_create_block_#{@c_name}"
284
+ end
285
+
286
+ def declare_dfp(indent = 2)
287
+ indent = ' ' * indent
288
+ (0..@generation).map{|i| "#{indent}VALUE *dfp#{i};"}.join("\n")
289
+ end
290
+
291
+ def update_dfp(indent = 2)
292
+ indent = ' ' * indent
293
+ (0..@generation).map{|i| "#{indent}dfp#{i} = fetch_dfp(th, #{@generation - i});"}.join("\n")
294
+ end
295
+
296
+ IfuncTemplate = ERB.new(<<-'EOS', 0, '%-', 'io')
297
+ <%= declare_ifunc() %>
298
+ {
299
+ /* decl variables */
300
+ rb_thread_t *th = current_thread();
301
+ VALUE cast_off_argv[<%= own_argv_size() %>];
302
+ VALUE cast_off_tmp;
303
+ VALUE self = get_self(th);
304
+ int lambda_p = cast_off_lambda_p(arg, argc, argv);
305
+ int i, num;
306
+ <%= declare_dfp %>
307
+ <%= (own_local_variable_declarations).map{|v| " #{v};"}.join("\n") %>
308
+
309
+ % bug() if root?
310
+ expand_dframe(th, <%= @lvars.size %>, <%= self %>, 0);
311
+ <%= update_dfp %>
312
+
313
+ %inits = own_initializations_for_guards
314
+ %bug() if inits.uniq!
315
+ %inits.join("\n")
316
+
317
+ /* setup arguments */
318
+ if (lambda_p) {
319
+ % bug() if @args.simple? && @args.arg_size != @args.argc
320
+ num = cast_off_prepare_iter_api_lambda_args(<%= @args.arg_size %>, cast_off_argv, argc, argv, <%= @args.simple? ? 1 : 0 %>, <%= @args.argc %>, <%= @args.opt_len %>, <%= @args.post_len %>, <%= @args.post_start %>, <%= @args.rest_index %>);
321
+ } else {
322
+ num = cast_off_prepare_iter_api_block_args(<%= @args.arg_size %>, cast_off_argv, argc, argv, <%= @args.splat? ? 1 : 0 %>, <%= @args.argc %>, <%= @args.opt_len %>, <%= @args.post_len %>, <%= @args.post_start %>, <%= @args.rest_index %>);
323
+ }
324
+ %if @args.block?
325
+ cast_off_argv[<%= @args.block_index %>] = blockarg;
326
+ %end
327
+
328
+ <%= enclose_begin %>
329
+
330
+ %#if reference_constant?
331
+ %# check_cref(th);
332
+ %#end
333
+
334
+ /* body */
335
+ <%= own_c_function_body() %>
336
+
337
+ %iterate_own_guards do |code, insns|
338
+ {
339
+ long pc;
340
+ <%= enclose_end_deoptimize %>
341
+ %code_label = "deoptimize_#{code.hash.to_s.gsub(/-/, "_")}"
342
+ % insns.uniq.each do |insn|
343
+ <%= insn.guard_label %>:
344
+ pc = <%= insn.pc %>;
345
+ goto <%= code_label %>;
346
+ % end
347
+ <%= code_label %>:
348
+ <%= code %>
349
+ }
350
+ %end
351
+
352
+ <%= enclose_end %>
353
+ }
354
+ EOS
355
+
356
+ def declare_ifunc()
357
+ "static VALUE #{@ifunc_name}(VALUE arg, VALUE dummy, int argc, VALUE *argv, VALUE blockarg)"
358
+ end
359
+
360
+ def define_ifunc()
361
+ IfuncTemplate.trigger(binding)
362
+ end
363
+
364
+ ExceptionHandlerTemplate = ERB.new(<<-'EOS', 0, '%-', 'io')
365
+ {
366
+ int state;
367
+ rb_control_frame_t *volatile cfp;
368
+
369
+ th = current_thread();
370
+ cfp = th->cfp;
371
+
372
+ TH_PUSH_TAG(th);
373
+ if ((state = EXEC_TAG()) != 0) {
374
+ VALUE excval;
375
+
376
+ th = current_thread();
377
+ while (th->cfp != cfp) {
378
+ th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
379
+ }
380
+
381
+ %@excs.each do |(exc, entries)|
382
+ switch(state) {
383
+ % case exc
384
+ % when :break
385
+ case TAG_BREAK:
386
+ excval = catch_break(th);
387
+ if (excval != Qundef) {
388
+ switch((int)(cfp->pc - cfp->iseq->iseq_encoded)) {
389
+ % entries.each do |(pc, label, stack)|
390
+ case <%= pc %>:
391
+ <%= update_dfp(12) %>
392
+ tmp<%= stack - 1 %> = excval; /* FIXME */
393
+ goto <%= label %>;
394
+ % end
395
+ default:
396
+ rb_bug("failed to found break target");
397
+ }
398
+ }
399
+ % when :return
400
+ case TAG_RETURN:
401
+ excval = catch_return(th);
402
+ if (excval != Qundef) {
403
+ /* vm_pop_frame is called at the vm_call_method() */
404
+ TH_POP_TAG2();
405
+ return excval;
406
+ }
407
+ % else
408
+ % bug()
409
+ % end
410
+ }
411
+ TH_POP_TAG2();
412
+ TH_JUMP_TAG(th, state);
413
+ %end
414
+ }
415
+ EOS
416
+
417
+ def enclose_begin()
418
+ return '' if @excs.empty?
419
+ ExceptionHandlerTemplate.trigger(binding)
420
+ end
421
+
422
+ def enclose_end()
423
+ @excs.empty? ? '' : <<-EOS
424
+ TH_POP_TAG();
425
+ rb_bug("enclose_end: should not be reached");
426
+ }
427
+ EOS
428
+ end
429
+
430
+ def enclose_end_deoptimize()
431
+ @excs.empty? ? '' : 'TH_POP_TAG2();'
432
+ end
433
+
434
+ def catch_exception?
435
+ not @excs.empty?
436
+ end
437
+
438
+ def catch_exception(exc, pc, label, stack)
439
+ @excs[exc] ||= []
440
+ entry = [pc, label, stack]
441
+ @excs[exc] << entry unless @excs[exc].include?(entry)
442
+ end
443
+
444
+ def to_name
445
+ "#{@name}: #{@source_file} #{@source_line}"
446
+ end
447
+
448
+ def to_s
449
+ @c_name
450
+ end
451
+ end
452
+ end
453
+ end
454
+