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,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
|
+
|