fastruby 0.0.12 → 0.0.13

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.
@@ -0,0 +1,91 @@
1
+ =begin
2
+
3
+ This file is part of the fastruby project, http://github.com/tario/fastruby
4
+
5
+ Copyright (c) 2011 Roberto Dario Seminara <robertodarioseminara@gmail.com>
6
+
7
+ fastruby is free software: you can redistribute it and/or modify
8
+ it under the terms of the gnu general public license as published by
9
+ the free software foundation, either version 3 of the license, or
10
+ (at your option) any later version.
11
+
12
+ fastruby is distributed in the hope that it will be useful,
13
+ but without any warranty; without even the implied warranty of
14
+ merchantability or fitness for a particular purpose. see the
15
+ gnu general public license for more details.
16
+
17
+ you should have received a copy of the gnu general public license
18
+ along with fastruby. if not, see <http://www.gnu.org/licenses/>.
19
+
20
+ =end
21
+ module FastRuby
22
+ module FlowControlTranslator
23
+
24
+ register_translator_module self
25
+
26
+ def to_c_case(tree)
27
+
28
+ tmpvarname = "tmp" + rand(1000000).to_s;
29
+
30
+ code = tree[2..-2].map{|subtree|
31
+
32
+ # this subtree is a when
33
+ subtree[1][1..-1].map{|subsubtree|
34
+ c_calltree = s(:call, nil, :inline_c, s(:arglist, s(:str, tmpvarname), s(:false)))
35
+ calltree = s(:call, subsubtree, :===, s(:arglist, c_calltree))
36
+ "
37
+ if (RTEST(#{to_c_call(calltree, tmpvarname)})) {
38
+ return #{to_c(subtree[2])};
39
+ }
40
+
41
+ "
42
+ }.join("\n")
43
+
44
+ }.join("\n")
45
+
46
+ inline_block "
47
+
48
+ VALUE #{tmpvarname} = #{to_c tree[1]};
49
+
50
+ #{code};
51
+
52
+ return #{to_c tree[-1]};
53
+ "
54
+ end
55
+
56
+ def to_c_if(tree)
57
+ condition_tree = tree[1]
58
+ impl_tree = tree[2]
59
+ else_tree = tree[3]
60
+
61
+ inline_block "
62
+ if (RTEST(#{to_c condition_tree})) {
63
+ last_expression = #{to_c impl_tree};
64
+ }#{else_tree ?
65
+ " else {
66
+ last_expression = #{to_c else_tree};
67
+ }
68
+ " : ""
69
+ }
70
+
71
+ return last_expression;
72
+ "
73
+ end
74
+
75
+ def to_c_for(tree)
76
+ alter_tree = tree.dup
77
+ alter_tree[0] = :iter
78
+ alter_tree[1] = [:call, alter_tree[1], :each, [:arglist]]
79
+ to_c alter_tree
80
+ end
81
+
82
+ def to_c_while(tree)
83
+ inline_block("
84
+ while (#{to_c tree[1]}) {
85
+ #{to_c tree[2]};
86
+ }
87
+ return Qnil;
88
+ ")
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,584 @@
1
+ =begin
2
+
3
+ This file is part of the fastruby project, http://github.com/tario/fastruby
4
+
5
+ Copyright (c) 2011 Roberto Dario Seminara <robertodarioseminara@gmail.com>
6
+
7
+ fastruby is free software: you can redistribute it and/or modify
8
+ it under the terms of the gnu general public license as published by
9
+ the free software foundation, either version 3 of the license, or
10
+ (at your option) any later version.
11
+
12
+ fastruby is distributed in the hope that it will be useful,
13
+ but without any warranty; without even the implied warranty of
14
+ merchantability or fitness for a particular purpose. see the
15
+ gnu general public license for more details.
16
+
17
+ you should have received a copy of the gnu general public license
18
+ along with fastruby. if not, see <http://www.gnu.org/licenses/>.
19
+
20
+ =end
21
+ module FastRuby
22
+ module IterTranslator
23
+
24
+ register_translator_module IterTranslator
25
+
26
+ def to_c_iter(tree)
27
+
28
+ call_tree = tree[1]
29
+ args_tree = tree[2]
30
+ recv_tree = call_tree[1]
31
+
32
+ directive_code = directive(call_tree)
33
+ if directive_code
34
+ return directive_code
35
+ end
36
+
37
+ other_call_tree = call_tree.dup
38
+ other_call_tree[1] = s(:lvar, :arg)
39
+
40
+ mname = call_tree[2]
41
+
42
+ call_args_tree = call_tree[3]
43
+
44
+ caller_code = nil
45
+
46
+ recvtype = infer_type(recv_tree || s(:self))
47
+
48
+ address = nil
49
+ mobject = nil
50
+ len = nil
51
+
52
+ extra_inference = {}
53
+
54
+ if recvtype
55
+
56
+ inference_complete = true
57
+ signature = [recvtype]
58
+
59
+ call_args_tree[1..-1].each do |arg|
60
+ argtype = infer_type(arg)
61
+ if argtype
62
+ signature << argtype
63
+ else
64
+ inference_complete = false
65
+ end
66
+ end
67
+
68
+ if recvtype.respond_to? :fastruby_method and inference_complete
69
+ method_tree = nil
70
+ begin
71
+ method_tree = recvtype.instance_method(call_tree[2]).fastruby.tree
72
+ rescue NoMethodError
73
+ end
74
+
75
+ if method_tree
76
+ mobject = recvtype.build(signature, call_tree[2])
77
+ yield_signature = mobject.yield_signature
78
+
79
+ if not args_tree
80
+ elsif args_tree.first == :lasgn
81
+ if yield_signature[0]
82
+ extra_inference[args_tree.last] = yield_signature[0]
83
+ end
84
+ elsif args_tree.first == :masgn
85
+ yield_args = args_tree[1][1..-1].map(&:last)
86
+ (0...yield_signature.size-1).each do |i|
87
+ extra_inference[yield_args[i]] = yield_signature[i]
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ anonymous_impl = tree[3]
95
+
96
+ str_lvar_initialization = "#{@frame_struct} *pframe;
97
+ #{@locals_struct} *plocals;
98
+ pframe = (void*)param;
99
+ plocals = (void*)pframe->plocals;
100
+ "
101
+
102
+ str_arg_initialization = ""
103
+
104
+ str_impl = ""
105
+
106
+ with_extra_inference(extra_inference) do
107
+
108
+ on_block do
109
+ # if impl_tree is a block, implement the last node with a return
110
+ if anonymous_impl
111
+ if anonymous_impl[0] == :block
112
+ str_impl = anonymous_impl[1..-2].map{ |subtree|
113
+ to_c(subtree)
114
+ }.join(";")
115
+
116
+ if anonymous_impl[-1][0] != :return and anonymous_impl[-1][0] != :break and anonymous_impl[-1][0] != :next
117
+ str_impl = str_impl + ";last_expression = (#{to_c(anonymous_impl[-1])});"
118
+ else
119
+ str_impl = str_impl + ";#{to_c(anonymous_impl[-1])};"
120
+ end
121
+ else
122
+ if anonymous_impl[0] != :return and anonymous_impl[0] != :break and anonymous_impl[0] != :next
123
+ str_impl = str_impl + ";last_expression = (#{to_c(anonymous_impl)});"
124
+ else
125
+ str_impl = str_impl + ";#{to_c(anonymous_impl)};"
126
+ end
127
+ end
128
+ else
129
+ str_impl = "last_expression = Qnil;"
130
+ end
131
+ end
132
+ end
133
+
134
+
135
+ if not args_tree
136
+ str_arg_initialization = ""
137
+ elsif args_tree.first == :lasgn
138
+ str_arg_initialization = "plocals->#{args_tree[1]} = arg;"
139
+ elsif args_tree.first == :masgn
140
+ arguments = args_tree[1][1..-1].map(&:last)
141
+
142
+ (0..arguments.size-1).each do |i|
143
+ str_arg_initialization << "plocals->#{arguments[i]} = rb_ary_entry(arg,#{i});\n"
144
+ end
145
+ end
146
+ rb_funcall_caller_code = nil
147
+
148
+ if call_args_tree.size > 1
149
+
150
+ str_recv = "pframe->next_recv"
151
+
152
+ str_recv = "plocals->self" unless recv_tree
153
+ if call_args_tree.last[0] == :splat
154
+ rb_funcall_caller_code = proc { |name| "
155
+ static VALUE #{name}(VALUE param) {
156
+ // call to #{call_tree[2]}
157
+
158
+ #{str_lvar_initialization}
159
+
160
+ VALUE array = #{to_c call_args_tree.last[1]};
161
+
162
+ if (TYPE(array) != T_ARRAY) {
163
+ array = rb_ary_new4(1,&array);
164
+ }
165
+
166
+ int argc = #{call_args_tree.size-2};
167
+ VALUE argv[#{call_args_tree.size} + RARRAY(array)->len];
168
+
169
+ #{
170
+ i = -1
171
+ call_args_tree[1..-2].map {|arg|
172
+ i = i + 1
173
+ "argv[#{i}] = #{to_c arg}"
174
+ }.join(";\n")
175
+ };
176
+
177
+ int array_len = RARRAY(array)->len;
178
+
179
+ int i;
180
+ for (i=0; i<array_len;i++) {
181
+ argv[argc] = rb_ary_entry(array,i);
182
+ argc++;
183
+ }
184
+
185
+ return rb_funcall2(#{str_recv}, #{intern_num call_tree[2]}, argc, argv);
186
+ }
187
+ "
188
+ }
189
+ else
190
+ str_called_code_args = call_args_tree[1..-1].map{ |subtree| to_c subtree }.join(",")
191
+ rb_funcall_caller_code = proc { |name| "
192
+ static VALUE #{name}(VALUE param) {
193
+ // call to #{call_tree[2]}
194
+
195
+ #{str_lvar_initialization}
196
+ return rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, #{call_args_tree.size-1}, #{str_called_code_args});
197
+ }
198
+ "
199
+ }
200
+ end
201
+
202
+ rb_funcall_caller_code_with_lambda = rb_funcall_caller_code
203
+ else
204
+ str_recv = "pframe->next_recv"
205
+ str_recv = "plocals->self" unless recv_tree
206
+
207
+ rb_funcall_caller_code = proc { |name| "
208
+ static VALUE #{name}(VALUE param) {
209
+ // call to #{call_tree[2]}
210
+ #{str_lvar_initialization}
211
+ return rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, 0);
212
+ }
213
+ "
214
+ }
215
+
216
+ rb_funcall_caller_code_with_lambda = proc { |name| "
217
+ static VALUE #{name}(VALUE param) {
218
+ // call to #{call_tree[2]}
219
+ #{str_lvar_initialization}
220
+ VALUE ret = rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, 0);
221
+
222
+ // freeze all stacks
223
+ struct FASTRUBYTHREADDATA* thread_data = rb_current_thread_data();
224
+
225
+ if (thread_data != 0) {
226
+ VALUE rb_stack_chunk = thread_data->rb_stack_chunk;
227
+
228
+ // add reference to stack chunk to lambda object
229
+ rb_ivar_set(ret,#{intern_num :_fastruby_stack_chunk},rb_stack_chunk);
230
+
231
+ // freeze the complete chain of stack chunks
232
+ while (rb_stack_chunk != Qnil) {
233
+ struct STACKCHUNK* stack_chunk;
234
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
235
+
236
+ stack_chunk_freeze(stack_chunk);
237
+
238
+ rb_stack_chunk = rb_ivar_get(rb_stack_chunk,#{intern_num :_parent_stack_chunk});
239
+ }
240
+ }
241
+
242
+ return ret;
243
+ }
244
+ "
245
+ }
246
+
247
+ end
248
+
249
+ rb_funcall_block_code_with_lambda = proc { |name| "
250
+ static VALUE #{name}(VALUE arg, VALUE _plocals) {
251
+ // block for call to #{call_tree[2]}
252
+ VALUE last_expression = Qnil;
253
+
254
+ #{@frame_struct} frame;
255
+ #{@frame_struct} *pframe = (void*)&frame;
256
+ #{@locals_struct} *plocals = (void*)_plocals;
257
+
258
+ frame.plocals = plocals;
259
+ frame.parent_frame = 0;
260
+ frame.return_value = Qnil;
261
+ frame.rescue = 0;
262
+ frame.targetted = 0;
263
+ frame.thread_data = rb_current_thread_data();
264
+
265
+ // create a fake parent frame representing the lambda method frame and a fake locals scope
266
+ VALUE old_call_frame = ((typeof(plocals))(pframe->plocals))->call_frame;
267
+ ((typeof(plocals))(pframe->plocals))->call_frame = LONG2FIX(pframe);
268
+
269
+ int aux = setjmp(frame.jmp);
270
+ if (aux != 0) {
271
+ if (aux == FASTRUBY_TAG_BREAK) {
272
+ return frame.return_value;
273
+ } else if (aux == FASTRUBY_TAG_NEXT) {
274
+ return pframe->thread_data->accumulator;
275
+ } else if (aux == FASTRUBY_TAG_REDO) {
276
+ // do nothing and let execute the block again
277
+ } else if (aux == FASTRUBY_TAG_RAISE) {
278
+ rb_funcall(((typeof(plocals))(pframe->plocals))->self, #{intern_num :raise}, 1, frame.thread_data->exception);
279
+ return Qnil;
280
+ } else {
281
+ if (aux == FASTRUBY_TAG_RETURN) {
282
+ if (plocals->targetted == 1) {
283
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
284
+ return ((typeof(plocals))(pframe->plocals))->return_value;
285
+ } else {
286
+ rb_raise(rb_eLocalJumpError, \"unexpected return\");
287
+ }
288
+ } else {
289
+ rb_raise(rb_eLocalJumpError, \"unexpected return\");
290
+ }
291
+
292
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
293
+ return frame.return_value;
294
+
295
+ }
296
+ }
297
+
298
+ #{str_arg_initialization}
299
+ #{str_impl}
300
+
301
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
302
+ return last_expression;
303
+ }
304
+ "
305
+ }
306
+
307
+ rb_funcall_block_code_proc_new = proc { |name| "
308
+ static VALUE #{name}(VALUE arg, VALUE _plocals) {
309
+ // block for call to #{call_tree[2]}
310
+ VALUE last_expression = Qnil;
311
+
312
+ #{@frame_struct} frame;
313
+ #{@frame_struct} *pframe = (void*)&frame;
314
+ #{@locals_struct} *plocals = (void*)_plocals;
315
+
316
+ frame.plocals = plocals;
317
+ frame.parent_frame = 0;
318
+ frame.return_value = Qnil;
319
+ frame.rescue = 0;
320
+ frame.targetted = 0;
321
+ frame.thread_data = rb_current_thread_data();
322
+
323
+ // create a fake parent frame representing the lambda method frame and a fake locals scope
324
+ VALUE old_call_frame = ((typeof(plocals))(pframe->plocals))->call_frame;
325
+ ((typeof(plocals))(pframe->plocals))->call_frame = LONG2FIX(pframe);
326
+
327
+ int aux = setjmp(frame.jmp);
328
+ if (aux != 0) {
329
+ if (aux == FASTRUBY_TAG_NEXT) {
330
+ return pframe->thread_data->accumulator;
331
+ } else if (aux == FASTRUBY_TAG_REDO) {
332
+ // do nothing and let execute the block again
333
+ } else if (aux == FASTRUBY_TAG_RAISE) {
334
+ rb_funcall(((typeof(plocals))(pframe->plocals))->self, #{intern_num :raise}, 1, frame.thread_data->exception);
335
+ return Qnil;
336
+ } else {
337
+ if (plocals->targetted == 1) {
338
+ if (plocals->active == Qfalse) {
339
+ rb_raise(rb_eLocalJumpError,\"return from proc-closure\");
340
+ } else {
341
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
342
+ rb_jump_tag(aux);
343
+ }
344
+ } else {
345
+ rb_raise(rb_eLocalJumpError, \"unexpected return\");
346
+ }
347
+ }
348
+ }
349
+
350
+ #{str_arg_initialization}
351
+ #{str_impl}
352
+
353
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
354
+
355
+ return last_expression;
356
+ }
357
+ "
358
+ }
359
+
360
+
361
+ rb_funcall_block_code = proc { |name| "
362
+ static VALUE #{name}(VALUE arg, VALUE _plocals) {
363
+ // block for call to #{call_tree[2]}
364
+ VALUE last_expression = Qnil;
365
+
366
+ #{@frame_struct} frame;
367
+ #{@frame_struct} *pframe = (void*)&frame;
368
+ #{@locals_struct} *plocals = (void*)_plocals;
369
+
370
+ frame.plocals = plocals;
371
+ frame.parent_frame = 0;
372
+ frame.return_value = Qnil;
373
+ frame.rescue = 0;
374
+ frame.targetted = 0;
375
+ frame.thread_data = rb_current_thread_data();
376
+
377
+ int aux = setjmp(frame.jmp);
378
+ if (aux != 0) {
379
+
380
+ if (aux == FASTRUBY_TAG_NEXT) {
381
+ return pframe->thread_data->accumulator;
382
+ } else if (aux == FASTRUBY_TAG_REDO) {
383
+ // do nothing and let execute the block again
384
+ } else {
385
+ rb_jump_tag(aux);
386
+ return frame.return_value;
387
+ }
388
+ }
389
+
390
+
391
+ #{str_arg_initialization}
392
+ #{str_impl}
393
+
394
+ return last_expression;
395
+ }
396
+ "
397
+ }
398
+
399
+
400
+ fastruby_str_arg_initialization = ""
401
+
402
+ if not args_tree
403
+ fastruby_str_arg_initialization = ""
404
+ elsif args_tree.first == :lasgn
405
+ fastruby_str_arg_initialization = "plocals->#{args_tree[1]} = argv[0];"
406
+ elsif args_tree.first == :masgn
407
+ arguments = args_tree[1][1..-1].map(&:last)
408
+
409
+ (0..arguments.size-1).each do |i|
410
+ fastruby_str_arg_initialization << "plocals->#{arguments[i]} = #{i} < argc ? argv[#{i}] : Qnil;\n"
411
+ end
412
+ end
413
+
414
+ block_code = proc { |name| "
415
+ static VALUE #{name}(int argc, VALUE* argv, VALUE _locals, VALUE _parent_frame) {
416
+ // block for call to #{call_tree[2]}
417
+ VALUE last_expression = Qnil;
418
+ #{@frame_struct} frame;
419
+ #{@frame_struct} *pframe = (void*)&frame;
420
+ #{@frame_struct} *parent_frame = (void*)_parent_frame;
421
+ #{@locals_struct} *plocals;
422
+
423
+ frame.plocals = (void*)_locals;
424
+ frame.parent_frame = parent_frame;
425
+ frame.return_value = Qnil;
426
+ frame.rescue = 0;
427
+ frame.targetted = 0;
428
+ frame.thread_data = parent_frame->thread_data;
429
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
430
+
431
+ plocals = frame.plocals;
432
+
433
+ int aux = setjmp(frame.jmp);
434
+ if (aux != 0) {
435
+ if (pframe->targetted == 0) {
436
+ if (aux == FASTRUBY_TAG_NEXT) {
437
+ return pframe->thread_data->accumulator;
438
+ } else if (aux == FASTRUBY_TAG_REDO) {
439
+ // do nothing and let execute the block again
440
+ } else {
441
+ longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
442
+ }
443
+ }
444
+
445
+ }
446
+
447
+ #{fastruby_str_arg_initialization}
448
+ #{str_impl}
449
+
450
+ return last_expression;
451
+ }
452
+ "
453
+ }
454
+
455
+ str_recv = "plocals->self"
456
+
457
+ if recv_tree
458
+ str_recv = to_c recv_tree
459
+ end
460
+
461
+ caller_code = nil
462
+ convention_global_name = add_global_name("int",0)
463
+
464
+ call_frame_struct_code = "
465
+ #{@block_struct} block;
466
+ #{@locals_struct} *plocals = (void*)param;
467
+
468
+ block.block_function_address = (void*)#{anonymous_function(&block_code)};
469
+ block.block_function_param = (void*)param;
470
+
471
+ // create a call_frame
472
+ #{@frame_struct} call_frame;
473
+
474
+ call_frame.parent_frame = (void*)pframe;
475
+ call_frame.plocals = plocals;
476
+ call_frame.return_value = Qnil;
477
+ call_frame.targetted = 0;
478
+ call_frame.thread_data = rb_current_thread_data();
479
+
480
+ VALUE old_call_frame = plocals->call_frame;
481
+ plocals->call_frame = LONG2FIX(&call_frame);
482
+
483
+ int aux = setjmp(call_frame.jmp);
484
+ if (aux != 0) {
485
+ #{@frame_struct}* pframe_ = (void*)pframe;
486
+
487
+ if (aux == FASTRUBY_TAG_RETRY ) {
488
+ // do nothing and let the call execute again
489
+ } else {
490
+ if (call_frame.targetted == 0) {
491
+ longjmp(pframe_->jmp,aux);
492
+ }
493
+
494
+ plocals->call_frame = old_call_frame;
495
+ return call_frame.return_value;
496
+ }
497
+ }
498
+ "
499
+
500
+ funcall_call_code = "
501
+ return #{
502
+ frame_call(
503
+ protected_block(inline_block("
504
+
505
+ pframe->next_recv = #{recv_tree ? to_c(recv_tree) : "plocals->self"};
506
+
507
+ NODE* node = rb_method_node(CLASS_OF(pframe->next_recv), #{intern_num mname});
508
+ void* caller_func;
509
+ void* block_func;
510
+
511
+ if (
512
+ node == #{@proc_node_gvar} ||
513
+ node == #{@lambda_node_gvar}
514
+ ) {
515
+
516
+ caller_func = #{anonymous_function(&rb_funcall_caller_code_with_lambda)};
517
+ block_func = #{anonymous_function(&rb_funcall_block_code_with_lambda)};
518
+ } else if (node == #{@procnew_node_gvar} && pframe->next_recv == rb_cProc) {
519
+ caller_func = #{anonymous_function(&rb_funcall_caller_code_with_lambda)};
520
+ block_func = #{anonymous_function(&rb_funcall_block_code_proc_new)};
521
+ } else {
522
+ caller_func = #{anonymous_function(&rb_funcall_caller_code)};
523
+ block_func = #{anonymous_function(&rb_funcall_block_code)};
524
+ }
525
+
526
+ return rb_iterate(
527
+ caller_func,
528
+ (VALUE)pframe,
529
+ block_func,
530
+ (VALUE)plocals);
531
+
532
+ "), true)
533
+ )
534
+ };
535
+ "
536
+
537
+ if call_args_tree.size > 1 ? call_args_tree.last[0] == :splat : false
538
+ inline_block "
539
+ #{funcall_call_code}
540
+ "
541
+ else
542
+
543
+ if call_args_tree.size > 1
544
+ value_cast = ( ["VALUE"]*(call_tree[3].size) ).join(",") + ", VALUE, VALUE"
545
+
546
+ str_called_code_args = call_tree[3][1..-1].map{|subtree| to_c subtree}.join(",")
547
+
548
+ caller_code = proc { |name| "
549
+ static VALUE #{name}(VALUE param, VALUE pframe) {
550
+ // call to #{call_tree[2]}
551
+ #{call_frame_struct_code}
552
+
553
+ VALUE ret = ((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name)})(#{str_recv}, (VALUE)&block, (VALUE)&call_frame, #{str_called_code_args});
554
+ plocals->call_frame = old_call_frame;
555
+ return ret;
556
+ }
557
+ "
558
+ }
559
+
560
+ else
561
+ caller_code = proc { |name| "
562
+ static VALUE #{name}(VALUE param, VALUE pframe) {
563
+ #{call_frame_struct_code}
564
+
565
+ // call to #{call_tree[2]}
566
+ VALUE ret = ((VALUE(*)(VALUE,VALUE,VALUE))#{encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name)})(#{str_recv}, (VALUE)&block, (VALUE)&call_frame);
567
+ plocals->call_frame = old_call_frame;
568
+ return ret;
569
+ }
570
+ "
571
+ }
572
+ end
573
+
574
+ inline_block "
575
+ if (#{convention_global_name}) {
576
+ return #{anonymous_function(&caller_code)}((VALUE)plocals, (VALUE)pframe);
577
+ } else {
578
+ #{funcall_call_code}
579
+ }
580
+ "
581
+ end
582
+ end
583
+ end
584
+ end