26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
|
# File 'lib/fastruby/translator/modules/call.rb', line 26
def to_c_call(tree, result_var = nil)
directive_code = directive(tree)
repass_var = @repass_var
if directive_code
if result_var
return "#{result_var} = #{directive_code};\n"
else
return directive_code
end
end
if tree[2] == :require
tree[2] = :fastruby_require
elsif tree[2] == :raise
args = tree[3]
return _raise(args[1],args[2])
end
recv = tree[1]
mname = tree[2]
args = tree[3]
args_tree = tree[3]
block_pass_arg = args.find{|arg| if arg == :arglist
false
else
arg[0] == :block_pass
end}
if block_pass_arg
args_tree = args_tree.dup.reject{|st|
if st.respond_to? :node_type
st.node_type == :block_pass
else
false
end
}
args = args_tree
end
mname = :require_fastruby if mname == :require
argnum = args.size - 1
recv = recv || s(:self)
recvtype = infer_type(recv)
if args.size > 1
if (not recvtype) or args.last[0] == :splat
if block_pass_arg
call_tree = tree.dup
call_tree[3] = args.select{|arg| if arg == :arglist
true
else
arg[0] != :block_pass
end
}
block_arguments_tree = s(:masgn, s(:array, s(:splat, s(:lasgn, :__xblock_arguments))))
block_tree = s(:call, s(:lvar, :__x_proc), :call, s(:arglist, s(:splat, s(:lvar, :__xblock_arguments))))
replace_iter_tree = s(:block,
s(:lasgn, :__x_proc, s(:call, block_pass_arg[1], :to_proc, s(:arglist))),
s(:iter, call_tree, block_arguments_tree, block_tree)
).to_fastruby_sexp
if result_var
return to_c(replace_iter_tree,result_var)
else
return to_c(replace_iter_tree)
end
end
end
if args.last[0] == :splat
aux_varname = "_aux_" + rand(1000000).to_s
code = protected_block(
"
VALUE array = Qnil;
#{to_c args.last[1], "array"};
if (TYPE(array) != T_ARRAY) {
array = rb_ary_new4(1,&array);
}
int argc = #{args.size-2};
VALUE argv[#{args.size} + _RARRAY_LEN(array)];
VALUE #{aux_varname} = Qnil;
#{
i = -1
args[1..-2].map {|arg|
i = i + 1
"#{to_c arg, aux_varname};
argv[#{i}] = #{aux_varname};
"
}.join(";\n")
};
VALUE recv = Qnil;
#{to_c recv, "recv"};
int array_len = _RARRAY_LEN(array);
int i;
for (i=0; i<array_len;i++) {
argv[argc] = rb_ary_entry(array,i);
argc++;
}
last_expression = rb_funcall2(recv, #{intern_num tree[2]}, argc, argv);
", true, repass_var)
if result_var
return "#{result_var} = #{code};\n"
else
return code
end
end
end
if recvtype
address = nil
mobject = nil
inference_complete = true
signature = [recvtype]
args[1..-1].each do |arg|
argtype = infer_type(arg)
signature << argtype
unless argtype
inference_complete = false
end
end
if repass_var
= ","+repass_var
= ",VALUE " + repass_var
else
= ""
= ""
end
block_proc_tree = s(:call, block_pass_arg[1], :to_proc, s(:arglist)) if block_pass_arg
block_wrapping_proc = proc { |name| "
static VALUE #{name}(int argc, VALUE* argv, VALUE _locals, VALUE _parent_frame) {
return rb_proc_call(_locals, rb_ary_new4(argc, argv));
}
"
}
if argnum == 0
value_cast = "VALUE,VALUE,VALUE"
if block_pass_arg or result_var
code = "
{
VALUE recv = Qnil;
#{to_c recv, "recv"};
#{@block_struct} block, *pblock = Qfalse;
#{if block_pass_arg
"
VALUE proc = Qnil;
#{to_c(block_proc_tree, "proc") }
VALUE block_address_value = rb_ivar_get(proc, #{intern_num "__block_address"});
if (block_address_value != Qnil) {
block.block_function_address = NUM2PTR(block_address_value);
block.block_function_param = NUM2PTR(rb_ivar_get(proc, #{intern_num "__block_param"}));
block.proc = proc;
pblock = █
} else {
// create a block from a proc
block.block_function_address = ((void*)#{anonymous_function(&block_wrapping_proc)});
block.block_function_param = (void*)proc;
block.proc = proc;
pblock = █
}
"
end
}
#{if result_var
"
#{result_var} = ((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(recv, (VALUE)pblock, (VALUE)pframe);
"
else
"
((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(recv, (VALUE)pblock, (VALUE)pframe);
"
end
}
}
"
result_var ? code : inline_block(code)
else
"((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(#{to_c recv}, Qfalse, (VALUE)pframe)"
end
else
value_cast = ( ["VALUE"]*(args.size) ).join(",") + ",VALUE,VALUE"
suffix = "_" + rand(1000000).to_s+"_"
strargs = (0..args_tree.size-2).map{|i| "#{suffix}arg#{i}"}.join(",")
if block_pass_arg or result_var
code = "
{
VALUE recv = Qnil;
#{
(0..args_tree.size-2).map{ |x|
"VALUE #{suffix}arg#{x};"
}.join("\n")
}
#{
(0..args_tree.size-2).map{ |x|
to_c(args_tree[x+1], "#{suffix}arg#{x}") + ";"
}.join("\n")
}
#{to_c recv, "recv"};
#{@block_struct} block, *pblock = Qfalse;
#{if block_pass_arg
"
VALUE proc = Qnil;
#{to_c(block_proc_tree, "proc") }
VALUE block_address_value = rb_ivar_get(proc, #{intern_num "__block_address"});
if (block_address_value != Qnil) {
block.block_function_address = NUM2PTR(block_address_value);
block.block_function_param = NUM2PTR(rb_ivar_get(proc, #{intern_num "__block_param"}));
block.proc = proc;
pblock = █
} else {
// create a block from a proc
block.block_function_address = ((void*)#{anonymous_function(&block_wrapping_proc)});
block.block_function_param = (void*)proc;
block.proc = proc;
pblock = █
}
"
end
}
#{if result_var
"
#{result_var} = ((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(recv, (VALUE)pblock, (VALUE)pframe, #{strargs});
"
else
"
((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(recv, (VALUE)pblock, (VALUE)pframe, #{strargs});
"
end
}
}
"
result_var ? code : inline_block(code)
else
strargs = args[1..-1].map{|arg| to_c arg}.join(",")
"((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(#{to_c recv}, Qfalse, (VALUE)pframe, #{strargs})"
end
end
else if argnum == 0
code = protected_block("last_expression = rb_funcall(#{to_c recv}, #{intern_num tree[2]}, 0)", true, repass_var)
if result_var
"
#{result_var} = #{code};
"
else
code
end
else
strargs = args[1..-1].map{|arg| to_c arg}.join(",")
code = protected_block("last_expression = rb_funcall(#{to_c recv}, #{intern_num tree[2]}, #{argnum}, #{strargs} )", true, repass_var)
if result_var
"
#{result_var} = #{code};
"
else
code
end
end
end end
|