101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
# File 'lib/fastruby/modules/inliner/call.rb', line 101
def method_tree_to_inlined_block(mobject, call_tree, method_name, block_args_tree = nil, block_tree = nil)
args_tree = call_tree[3]
recv_tree = call_tree[1] || fs(:self)
target_method_tree = mobject.tree
@method_index = (@method_index || 0) + 1
prefix = method_name.to_s + "_" + @method_index.to_s
target_method_tree_block = add_prefix(target_method_tree.find_tree(:scope)[1], prefix)
if target_method_tree_block.find_tree(:return)
inlined_name = inline_local_name(method_name, "main_return_tagname")
target_method_tree_block = catch_block(inlined_name,target_method_tree_block)
target_method_tree_block.walk_tree do |subtree|
if subtree[0] == :return
if subtree[1]
subtree[0..-1] = fs(:call, nil, :_throw, fs(:arglist, fs(:lit,inlined_name.to_sym), subtree[1]))
else
subtree[0..-1] = fs(:call, nil, :_throw, fs(:arglist, fs(:lit,inlined_name.to_sym), fs(:nil)))
end
end
end
end
target_method_tree_args = target_method_tree[2]
newblock = fs(:block)
(1..args_tree.size-1).each do |i|
itype = infer_type(args_tree[i])
inlined_name = inline_local_name(prefix, target_method_tree_args[i])
newblock << fs(:lasgn, inlined_name, recursive_inline(args_tree[i].duplicate))
end
inlined_name = inline_local_name(prefix, :self)
newblock << fs(:lasgn, inlined_name, recv_tree.duplicate)
return nil if target_method_tree_block.find_tree(:return)
break_tag = nil
if block_tree
block_tree = recursive_inline(block_tree)
if block_tree.find_tree(:break) break_tag = inline_local_name(prefix, "__break_tag")
end
end
block_num = 0
target_method_tree_block.walk_tree do |subtree|
if subtree.node_type == :call
if subtree[1] == nil
if subtree[2] == :block_given?
subtree[0..-1] = block_tree ? fs(:true) : fs(:false)
else
subtree[1] = recv_tree.duplicate
end
end
end
if subtree.node_type == :self
subtree[0] = :lvar
subtree[1] = inline_local_name(prefix, :self)
end
if subtree.node_type == :yield
if block_tree
yield_call_args = subtree.duplicate
subtree[0..-1] = fs(:block)
if block_args_tree
return nil if yield_call_args[1..-1].find{|x| x.node_type == :splat}
if block_args_tree.node_type == :masgn
return nil if block_args_tree[1].size != yield_call_args.size
return nil if block_args_tree[1][1..-1].find{|x| x.node_type == :splat}
(1..yield_call_args.size-1).each do |i|
inlined_name = block_args_tree[1][i][1]
subtree << fs(:lasgn, inlined_name, yield_call_args[i])
end
else
return nil if 2 != yield_call_args.size
inlined_name = block_args_tree[1]
subtree << fs(:lasgn, inlined_name, yield_call_args[1])
end
else
return nil if yield_call_args.size > 1
end
if block_tree.find_tree(:next) or block_tree.find_tree(:redo) or break_tag
inlined_name = inline_local_name(prefix, "block_block_#{block_num}")
block_num = block_num + 1
alt_block_tree = BlockProcessing.new(inlined_name, break_tag).process(block_tree)
alt_block_tree = catch_block(inlined_name,alt_block_tree)
else
alt_block_tree = block_tree.duplicate
end
subtree << alt_block_tree
else
subtree[0..-1] = fs(:call, fs(:nil), :raise, fs(:arglist, fs(:const, :LocalJumpError), fs(:str, "no block given")))
end
end
end
@inlined_methods << mobject
if break_tag
inner_block = fs(:block)
target_method_tree_block[1..-1].each do |subtree|
inner_block << subtree
end
newblock << catch_block(break_tag,inner_block)
else
target_method_tree_block[1..-1].each do |subtree|
newblock << subtree
end
end
newblock
end
|