fastruby 0.0.3 → 0.0.4
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/CHANGELOG +21 -0
- data/README +1 -2
- data/Rakefile +2 -2
- data/TODO +0 -2
- data/lib/fastruby/builder.rb +19 -1
- data/lib/fastruby/custom_require.rb +48 -0
- data/lib/fastruby/object.rb +73 -10
- data/lib/fastruby/translator.rb +637 -131
- data/lib/fastruby.rb +4 -0
- data/spec/base_spec.rb +37 -0
- data/spec/block/break_spec.rb +190 -0
- data/spec/block/next_spec.rb +85 -0
- data/spec/exception_spec.rb +440 -0
- data/spec/module_spec.rb +36 -0
- data/spec/return_spec.rb +99 -0
- data/spec/singleton_spec.rb +76 -0
- data/spec/sugar_spec.rb +2 -2
- data/spec/variable_spec.rb +64 -0
- metadata +12 -4
data/lib/fastruby/translator.rb
CHANGED
@@ -26,6 +26,14 @@ require "fastruby/method_extension"
|
|
26
26
|
module FastRuby
|
27
27
|
class Context
|
28
28
|
|
29
|
+
class UnwindFastrubyFrame < Exception
|
30
|
+
def initialize(ex,target_frame,return_value)
|
31
|
+
@ex = ex
|
32
|
+
@target_frame = target_frame
|
33
|
+
@return_value = return_value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
29
37
|
attr_accessor :infer_lvar_map
|
30
38
|
attr_accessor :alt_method_name
|
31
39
|
attr_accessor :locals
|
@@ -34,32 +42,48 @@ module FastRuby
|
|
34
42
|
attr_reader :extra_code
|
35
43
|
attr_reader :yield_signature
|
36
44
|
|
37
|
-
def initialize
|
45
|
+
def initialize(common_func = true)
|
38
46
|
@infer_lvar_map = Hash.new
|
39
47
|
@extra_code = ""
|
40
48
|
@options = {}
|
49
|
+
@frame_struct = "struct {
|
50
|
+
void* parent_frame;
|
51
|
+
void* target_frame;
|
52
|
+
void* plocals;
|
53
|
+
jmp_buf jmp;
|
54
|
+
VALUE return_value;
|
55
|
+
VALUE exception;
|
56
|
+
int rescue;
|
57
|
+
VALUE last_error;
|
58
|
+
}"
|
59
|
+
|
60
|
+
@block_struct = "struct {
|
61
|
+
void* block_function_address;
|
62
|
+
void* block_function_param;
|
63
|
+
}"
|
41
64
|
|
42
65
|
extra_code << '#include "node.h"
|
43
66
|
'
|
44
67
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
extra_code << "static VALUE _rb_ivar_set(VALUE recv,ID idvar, VALUE value) {
|
52
|
-
rb_ivar_set(recv,idvar,value);
|
53
|
-
return value;
|
54
|
-
}
|
55
|
-
"
|
68
|
+
if common_func
|
69
|
+
extra_code << "static VALUE _rb_gvar_set(void* ge,VALUE value) {
|
70
|
+
rb_gvar_set((struct global_entry*)ge,value);
|
71
|
+
return value;
|
72
|
+
}
|
73
|
+
"
|
56
74
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
75
|
+
extra_code << "static VALUE _rb_ivar_set(VALUE recv,ID idvar, VALUE value) {
|
76
|
+
rb_ivar_set(recv,idvar,value);
|
77
|
+
return value;
|
78
|
+
}
|
79
|
+
"
|
62
80
|
|
81
|
+
extra_code << "static VALUE _lvar_assing(VALUE* destination,VALUE value) {
|
82
|
+
*destination = value;
|
83
|
+
return value;
|
84
|
+
}
|
85
|
+
"
|
86
|
+
end
|
63
87
|
end
|
64
88
|
|
65
89
|
def on_block
|
@@ -71,10 +95,10 @@ module FastRuby
|
|
71
95
|
send("to_c_" + tree[0].to_s, tree);
|
72
96
|
end
|
73
97
|
|
74
|
-
def anonymous_function
|
98
|
+
def anonymous_function
|
75
99
|
|
76
100
|
name = "anonymous" + rand(10000000).to_s
|
77
|
-
extra_code <<
|
101
|
+
extra_code << yield(name)
|
78
102
|
|
79
103
|
name
|
80
104
|
end
|
@@ -105,9 +129,6 @@ module FastRuby
|
|
105
129
|
|
106
130
|
caller_code = nil
|
107
131
|
|
108
|
-
str_lvar_initialization = @locals_struct + " *plocals;
|
109
|
-
plocals = (void*)param;"
|
110
|
-
|
111
132
|
recvtype = infer_type(recv_tree || s(:self))
|
112
133
|
|
113
134
|
address = nil
|
@@ -179,14 +200,19 @@ module FastRuby
|
|
179
200
|
|
180
201
|
anonymous_impl = tree[3]
|
181
202
|
|
182
|
-
str_lvar_initialization = @
|
183
|
-
|
203
|
+
str_lvar_initialization = "#{@frame_struct} *pframe;
|
204
|
+
#{@locals_struct} *plocals;
|
205
|
+
pframe = (void*)param;
|
206
|
+
plocals = (void*)pframe->plocals;
|
207
|
+
"
|
184
208
|
|
185
209
|
str_arg_initialization = ""
|
186
210
|
|
187
211
|
str_impl = ""
|
188
212
|
|
189
213
|
with_extra_inference(extra_inference) do
|
214
|
+
|
215
|
+
on_block do
|
190
216
|
# if impl_tree is a block, implement the last node with a return
|
191
217
|
if anonymous_impl
|
192
218
|
if anonymous_impl[0] == :block
|
@@ -209,7 +235,7 @@ module FastRuby
|
|
209
235
|
else
|
210
236
|
str_impl = "last_expression = Qnil;"
|
211
237
|
end
|
212
|
-
|
238
|
+
end
|
213
239
|
end
|
214
240
|
|
215
241
|
if convention == :ruby or convention == :cruby
|
@@ -260,11 +286,44 @@ module FastRuby
|
|
260
286
|
str_arg_initialization
|
261
287
|
|
262
288
|
block_code = proc { |name| "
|
263
|
-
static VALUE #{name}(VALUE arg, VALUE
|
289
|
+
static VALUE #{name}(VALUE arg, VALUE _parent_frame) {
|
264
290
|
// block for call to #{call_tree[2]}
|
265
291
|
VALUE last_expression = Qnil;
|
266
292
|
|
267
|
-
#{
|
293
|
+
#{@frame_struct} frame;
|
294
|
+
#{@frame_struct} *pframe = (void*)&frame;
|
295
|
+
#{@frame_struct} *parent_frame = (void*)_parent_frame;
|
296
|
+
#{@locals_struct} *plocals;
|
297
|
+
|
298
|
+
frame.plocals = parent_frame->plocals;
|
299
|
+
frame.parent_frame = parent_frame;
|
300
|
+
frame.return_value = Qnil;
|
301
|
+
frame.target_frame = &frame;
|
302
|
+
frame.exception = Qnil;
|
303
|
+
frame.rescue = 0;
|
304
|
+
|
305
|
+
plocals = frame.plocals;
|
306
|
+
|
307
|
+
if (setjmp(frame.jmp) != 0) {
|
308
|
+
if (pframe->target_frame != pframe) {
|
309
|
+
if (pframe->target_frame == (void*)-3) {
|
310
|
+
return pframe->return_value;
|
311
|
+
}
|
312
|
+
|
313
|
+
VALUE ex = rb_funcall(
|
314
|
+
(VALUE)#{UnwindFastrubyFrame.internal_value},
|
315
|
+
#{:new.to_i},
|
316
|
+
3,
|
317
|
+
pframe->exception,
|
318
|
+
LONG2FIX(pframe->target_frame),
|
319
|
+
pframe->return_value
|
320
|
+
);
|
321
|
+
rb_funcall(plocals->self, #{:raise.to_i}, 1, ex);
|
322
|
+
}
|
323
|
+
return frame.return_value;
|
324
|
+
}
|
325
|
+
|
326
|
+
|
268
327
|
#{str_arg_initialization}
|
269
328
|
#{str_impl}
|
270
329
|
|
@@ -273,7 +332,8 @@ module FastRuby
|
|
273
332
|
"
|
274
333
|
}
|
275
334
|
|
276
|
-
"rb_iterate(#{anonymous_function(caller_code)}, (VALUE)
|
335
|
+
protected_block("rb_iterate(#{anonymous_function(&caller_code)}, (VALUE)pframe, #{anonymous_function(&block_code)}, (VALUE)pframe)", true)
|
336
|
+
|
277
337
|
elsif convention == :fastruby
|
278
338
|
|
279
339
|
str_arg_initialization = ""
|
@@ -291,11 +351,37 @@ module FastRuby
|
|
291
351
|
end
|
292
352
|
|
293
353
|
block_code = proc { |name| "
|
294
|
-
static VALUE #{name}(int argc, VALUE* argv, VALUE
|
354
|
+
static VALUE #{name}(int argc, VALUE* argv, VALUE _locals, VALUE _parent_frame) {
|
295
355
|
// block for call to #{call_tree[2]}
|
296
356
|
VALUE last_expression = Qnil;
|
357
|
+
#{@frame_struct} frame;
|
358
|
+
#{@frame_struct} *pframe = (void*)&frame;
|
359
|
+
#{@frame_struct} *parent_frame = (void*)_parent_frame;
|
360
|
+
#{@locals_struct} *plocals;
|
361
|
+
|
362
|
+
frame.plocals = (void*)_locals;
|
363
|
+
frame.parent_frame = parent_frame;
|
364
|
+
frame.return_value = Qnil;
|
365
|
+
frame.target_frame = &frame;
|
366
|
+
frame.exception = Qnil;
|
367
|
+
frame.rescue = 0;
|
368
|
+
|
369
|
+
plocals = frame.plocals;
|
370
|
+
|
371
|
+
if (setjmp(frame.jmp) != 0) {
|
372
|
+
if (pframe->target_frame != pframe) {
|
373
|
+
if (pframe->target_frame == (void*)-3) {
|
374
|
+
return pframe->return_value;
|
375
|
+
}
|
376
|
+
// raise exception
|
377
|
+
((typeof(pframe))_parent_frame)->exception = pframe->exception;
|
378
|
+
((typeof(pframe))_parent_frame)->target_frame = pframe->target_frame;
|
379
|
+
((typeof(pframe))_parent_frame)->return_value = pframe->return_value;
|
380
|
+
longjmp(((typeof(pframe))_parent_frame)->jmp,1);
|
381
|
+
}
|
382
|
+
|
383
|
+
}
|
297
384
|
|
298
|
-
#{str_lvar_initialization};
|
299
385
|
#{str_arg_initialization}
|
300
386
|
#{str_impl}
|
301
387
|
|
@@ -313,59 +399,60 @@ module FastRuby
|
|
313
399
|
|
314
400
|
if call_args_tree.size > 1
|
315
401
|
value_cast = ( ["VALUE"]*(call_tree[3].size) ).join(",")
|
316
|
-
value_cast = value_cast + ", VALUE" if convention == :fastruby
|
402
|
+
value_cast = value_cast + ", VALUE, VALUE" if convention == :fastruby
|
317
403
|
|
318
404
|
str_called_code_args = call_tree[3][1..-1].map{|subtree| to_c subtree}.join(",")
|
319
405
|
|
320
406
|
caller_code = proc { |name| "
|
321
|
-
static VALUE #{name}(VALUE param) {
|
407
|
+
static VALUE #{name}(VALUE param, VALUE pframe) {
|
322
408
|
#{@block_struct} block;
|
409
|
+
#{@locals_struct} *plocals = (void*)param;
|
323
410
|
|
324
|
-
block.block_function_address = (void*)#{anonymous_function(block_code)};
|
411
|
+
block.block_function_address = (void*)#{anonymous_function(&block_code)};
|
325
412
|
block.block_function_param = (void*)param;
|
326
413
|
|
327
414
|
// call to #{call_tree[2]}
|
328
415
|
|
329
|
-
#{
|
330
|
-
|
331
|
-
return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_recv}, (VALUE)&block, #{str_called_code_args});
|
416
|
+
return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_recv}, (VALUE)&block, (VALUE)pframe, #{str_called_code_args});
|
332
417
|
}
|
333
418
|
"
|
334
419
|
}
|
335
420
|
|
336
421
|
else
|
337
422
|
caller_code = proc { |name| "
|
338
|
-
static VALUE #{name}(VALUE param) {
|
423
|
+
static VALUE #{name}(VALUE param, VALUE pframe) {
|
339
424
|
#{@block_struct} block;
|
425
|
+
#{@locals_struct} *plocals = (void*)param;
|
340
426
|
|
341
|
-
block.block_function_address = (void*)#{anonymous_function(block_code)};
|
427
|
+
block.block_function_address = (void*)#{anonymous_function(&block_code)};
|
342
428
|
block.block_function_param = (void*)param;
|
343
429
|
|
344
430
|
// call to #{call_tree[2]}
|
345
|
-
#{str_lvar_initialization}
|
346
431
|
|
347
|
-
return ((VALUE(*)(VALUE,VALUE))0x#{address.to_s(16)})(#{str_recv}, (VALUE)&block);
|
432
|
+
return ((VALUE(*)(VALUE,VALUE,VALUE))0x#{address.to_s(16)})(#{str_recv}, (VALUE)&block, (VALUE)pframe);
|
348
433
|
}
|
349
434
|
"
|
350
435
|
}
|
351
436
|
end
|
352
437
|
|
353
|
-
"#{anonymous_function(caller_code)}((VALUE)
|
438
|
+
"#{anonymous_function(&caller_code)}((VALUE)plocals, (VALUE)pframe)"
|
354
439
|
end
|
355
440
|
end
|
356
441
|
|
357
442
|
def to_c_yield(tree)
|
358
443
|
|
359
444
|
block_code = proc { |name| "
|
360
|
-
static VALUE #{name}(VALUE
|
445
|
+
static VALUE #{name}(VALUE frame_param, VALUE* block_args) {
|
361
446
|
|
362
447
|
#{@locals_struct} *plocals;
|
363
|
-
|
448
|
+
#{@frame_struct} *pframe;
|
449
|
+
pframe = (void*)frame_param;
|
450
|
+
plocals = (void*)pframe->plocals;
|
364
451
|
|
365
452
|
if (plocals->block_function_address == 0) {
|
366
453
|
rb_raise(rb_eLocalJumpError, \"no block given\");
|
367
454
|
} else {
|
368
|
-
return ((VALUE(*)(int,VALUE*,VALUE))plocals->block_function_address)(#{tree.size-1}, block_args, plocals->block_function_param);
|
455
|
+
return ((VALUE(*)(int,VALUE*,VALUE,VALUE))plocals->block_function_address)(#{tree.size-1}, block_args, plocals->block_function_param, (VALUE)pframe);
|
369
456
|
}
|
370
457
|
}
|
371
458
|
"
|
@@ -388,9 +475,9 @@ module FastRuby
|
|
388
475
|
end
|
389
476
|
|
390
477
|
if tree.size > 1
|
391
|
-
anonymous_function(block_code)+"((VALUE)
|
478
|
+
anonymous_function(&block_code)+"((VALUE)pframe, (VALUE[]){#{tree[1..-1].map{|subtree| to_c subtree}.join(",")}})"
|
392
479
|
else
|
393
|
-
anonymous_function(block_code)+"((VALUE)
|
480
|
+
anonymous_function(&block_code)+"((VALUE)pframe, (VALUE[]){})"
|
394
481
|
end
|
395
482
|
end
|
396
483
|
|
@@ -416,7 +503,41 @@ module FastRuby
|
|
416
503
|
end
|
417
504
|
|
418
505
|
def to_c_return(tree)
|
419
|
-
"
|
506
|
+
"pframe->target_frame = ((typeof(pframe))plocals->pframe); plocals->return_value = #{to_c(tree[1])}; longjmp(pframe->jmp, 1);\n"
|
507
|
+
end
|
508
|
+
|
509
|
+
def to_c_break(tree)
|
510
|
+
if @on_block
|
511
|
+
inline_block(
|
512
|
+
"
|
513
|
+
pframe->target_frame = (void*)-2;
|
514
|
+
pframe->return_value = #{tree[1] ? to_c(tree[1]) : "Qnil"};
|
515
|
+
pframe->exception = Qnil;
|
516
|
+
longjmp(pframe->jmp,1);"
|
517
|
+
)
|
518
|
+
else
|
519
|
+
inline_block("
|
520
|
+
pframe->target_frame = (void*)-1;
|
521
|
+
pframe->exception = (VALUE)#{LocalJumpError.exception.internal_value};
|
522
|
+
longjmp(pframe->jmp,1);
|
523
|
+
return Qnil;
|
524
|
+
")
|
525
|
+
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
def to_c_next(tree)
|
530
|
+
if @on_block
|
531
|
+
"Qnil; pframe->target_frame = (void*)-3; pframe->return_value = #{tree[1] ? to_c(tree[1]) : "Qnil"}; longjmp(pframe->jmp,1)"
|
532
|
+
else
|
533
|
+
inline_block("
|
534
|
+
pframe->target_frame = (void*)-1;
|
535
|
+
pframe->exception = (VALUE)#{LocalJumpError.exception.internal_value};
|
536
|
+
longjmp(pframe->jmp,1);
|
537
|
+
return Qnil;
|
538
|
+
")
|
539
|
+
|
540
|
+
end
|
420
541
|
end
|
421
542
|
|
422
543
|
def to_c_lit(tree)
|
@@ -440,16 +561,18 @@ module FastRuby
|
|
440
561
|
hash_aset_code << "rb_hash_aset(hash, #{strkey}, #{strvalue});"
|
441
562
|
end
|
442
563
|
|
443
|
-
|
564
|
+
anonymous_function{ |name| "
|
444
565
|
static VALUE #{name}(VALUE value_params) {
|
445
|
-
#{@
|
566
|
+
#{@frame_struct} *pframe;
|
567
|
+
#{@locals_struct} *plocals;
|
568
|
+
pframe = (void*)value_params;
|
569
|
+
plocals = (void*)pframe->plocals;
|
570
|
+
|
446
571
|
VALUE hash = rb_hash_new();
|
447
572
|
#{hash_aset_code}
|
448
573
|
return hash;
|
449
574
|
}
|
450
|
-
" }
|
451
|
-
|
452
|
-
anonymous_function(wrapper_func) + "((VALUE)#{locals_pointer})"
|
575
|
+
" } + "((VALUE)pframe)"
|
453
576
|
end
|
454
577
|
|
455
578
|
def to_c_array(tree)
|
@@ -506,54 +629,178 @@ module FastRuby
|
|
506
629
|
"rb_funcall(plocals->self,#{:fastruby.to_i},1,(VALUE)#{tree.internal_value})"
|
507
630
|
end
|
508
631
|
|
509
|
-
def
|
510
|
-
|
511
|
-
args_tree = tree[2]
|
632
|
+
def to_c_defs(tree)
|
633
|
+
args_tree = tree[3];
|
512
634
|
|
513
|
-
|
635
|
+
tmp = FastRuby.build_defs(tree)
|
636
|
+
|
637
|
+
extra_code << tmp[0]
|
514
638
|
|
639
|
+
inline_block "
|
640
|
+
rb_define_singleton_method(#{to_c tree[1]}, \"#{tree[2].to_s}\", (void*)#{tmp[1]}, #{args_tree.size-1});
|
641
|
+
return Qnil;
|
642
|
+
"
|
643
|
+
end
|
644
|
+
|
645
|
+
def to_c_defined(tree)
|
646
|
+
nt = tree[1].node_type
|
647
|
+
|
648
|
+
if nt == :self
|
649
|
+
'rb_str_new2("self")'
|
650
|
+
elsif nt == :true
|
651
|
+
'rb_str_new2("true")'
|
652
|
+
elsif nt == :false
|
653
|
+
'rb_str_new2("false")'
|
654
|
+
elsif nt == :nil
|
655
|
+
'rb_str_new2("nil")'
|
656
|
+
elsif nt == :lvar
|
657
|
+
'rb_str_new2("local-variable")'
|
658
|
+
elsif nt == :gvar
|
659
|
+
"rb_gvar_defined((struct global_entry*)0x#{global_entry(tree[1][1]).to_s(16)}) ? #{"global-variable".internal_value} : Qnil"
|
660
|
+
elsif nt == :const
|
661
|
+
"rb_const_defined(rb_cObject, #{tree[1][1].to_i}) ? #{"constant".internal_value} : Qnil"
|
662
|
+
elsif nt == :call
|
663
|
+
"rb_method_node(CLASS_OF(#{to_c tree[1][1]}), #{tree[1][2].to_i}) ? #{"method".internal_value} : Qnil"
|
664
|
+
elsif nt == :yield
|
665
|
+
"rb_block_given_p() ? #{"yield".internal_value} : Qnil"
|
666
|
+
elsif nt == :ivar
|
667
|
+
"rb_ivar_defined(plocals->self,#{tree[1][1].to_i}) ? #{"instance-variable".internal_value} : Qnil"
|
668
|
+
elsif nt == :attrset or
|
669
|
+
nt == :op_asgn1 or
|
670
|
+
nt == :op_asgn2 or
|
671
|
+
nt == :op_asgn_or or
|
672
|
+
nt == :op_asgn_and or
|
673
|
+
nt == :op_asgn_masgn or
|
674
|
+
nt == :masgn or
|
675
|
+
nt == :lasgn or
|
676
|
+
nt == :dasgn or
|
677
|
+
nt == :dasgn_curr or
|
678
|
+
nt == :gasgn or
|
679
|
+
nt == :iasgn or
|
680
|
+
nt == :cdecl or
|
681
|
+
nt == :cvdecl or
|
682
|
+
nt == :cvasgn
|
683
|
+
"assignment".internal_value
|
684
|
+
else
|
685
|
+
"expression".internal_value
|
686
|
+
end
|
687
|
+
end
|
688
|
+
|
689
|
+
def initialize_method_structs(args_tree)
|
515
690
|
@locals_struct = "struct {
|
516
|
-
#{@locals.map{|l| "VALUE #{l};\n"}.join}
|
517
|
-
#{args_tree[1..-1].map{|arg| "VALUE #{arg};\n"}.join};
|
518
691
|
void* block_function_address;
|
519
692
|
VALUE block_function_param;
|
693
|
+
jmp_buf jmp;
|
694
|
+
VALUE return_value;
|
695
|
+
void* pframe;
|
696
|
+
#{@locals.map{|l| "VALUE #{l};\n"}.join}
|
697
|
+
#{args_tree[1..-1].map{|arg| "VALUE #{arg};\n"}.join};
|
520
698
|
}"
|
699
|
+
end
|
521
700
|
|
522
|
-
|
523
|
-
|
524
|
-
|
701
|
+
def to_c_method_defs(tree)
|
702
|
+
|
703
|
+
method_name = tree[2]
|
704
|
+
args_tree = tree[3]
|
705
|
+
|
706
|
+
impl_tree = tree[4][1]
|
707
|
+
|
708
|
+
initialize_method_structs(args_tree)
|
709
|
+
|
710
|
+
strargs = if args_tree.size > 1
|
711
|
+
"VALUE self, void* block_address, VALUE block_param, void* _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
|
712
|
+
else
|
713
|
+
"VALUE self, void* block_address, VALUE block_param, void* _parent_frame"
|
714
|
+
end
|
715
|
+
|
716
|
+
extra_code << "static VALUE #{@alt_method_name + "_real"}(#{strargs}) {
|
717
|
+
#{func_frame}
|
718
|
+
|
719
|
+
#{args_tree[1..-1].map { |arg|
|
720
|
+
"locals.#{arg} = #{arg};\n"
|
721
|
+
}.join("") }
|
722
|
+
|
723
|
+
locals.block_function_address = block_address;
|
724
|
+
locals.block_function_param = block_param;
|
725
|
+
|
726
|
+
return #{to_c impl_tree};
|
525
727
|
}"
|
526
728
|
|
527
|
-
|
528
|
-
|
529
|
-
if impl_tree[0] == :block
|
530
|
-
str_impl = to_c impl_tree
|
729
|
+
strargs2 = if args_tree.size > 1
|
730
|
+
"VALUE self, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
|
531
731
|
else
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
732
|
+
"VALUE self"
|
733
|
+
end
|
734
|
+
|
735
|
+
value_cast = ( ["VALUE"]*(args_tree.size+1) ).join(",")
|
736
|
+
strmethodargs = ""
|
737
|
+
|
738
|
+
if args_tree.size > 1
|
739
|
+
strmethodargs = "self,block_address,block_param,&frame,#{args_tree[1..-1].map(&:to_s).join(",") }"
|
740
|
+
else
|
741
|
+
strmethodargs = "self,block_address,block_param,&frame"
|
537
742
|
end
|
538
743
|
|
744
|
+
"
|
745
|
+
VALUE #{@alt_method_name}(#{strargs2}) {
|
746
|
+
#{@frame_struct} frame;
|
747
|
+
int argc = #{args_tree.size};
|
748
|
+
void* block_address = 0;
|
749
|
+
VALUE block_param = Qnil;
|
750
|
+
|
751
|
+
|
752
|
+
frame.plocals = 0;
|
753
|
+
frame.parent_frame = 0;
|
754
|
+
frame.return_value = Qnil;
|
755
|
+
frame.target_frame = &frame;
|
756
|
+
frame.exception = Qnil;
|
757
|
+
frame.rescue = 0;
|
758
|
+
|
759
|
+
if (rb_block_given_p()) {
|
760
|
+
block_address = #{
|
761
|
+
anonymous_function{|name|
|
762
|
+
"static VALUE #{name}(int argc, VALUE* argv, VALUE param) {
|
763
|
+
return rb_yield_splat(rb_ary_new4(argc,argv));
|
764
|
+
}"
|
765
|
+
}
|
766
|
+
};
|
767
|
+
|
768
|
+
block_param = 0;
|
769
|
+
}
|
770
|
+
|
771
|
+
int aux = setjmp(frame.jmp);
|
772
|
+
if (aux != 0) {
|
773
|
+
rb_funcall(self, #{:raise.to_i}, 1, frame.exception);
|
774
|
+
}
|
775
|
+
|
776
|
+
|
777
|
+
return #{@alt_method_name + "_real"}(#{strmethodargs});
|
778
|
+
}
|
779
|
+
"
|
780
|
+
end
|
781
|
+
|
782
|
+
def to_c_method(tree)
|
783
|
+
method_name = tree[1]
|
784
|
+
args_tree = tree[2]
|
785
|
+
|
786
|
+
impl_tree = tree[3][1]
|
787
|
+
|
788
|
+
initialize_method_structs(args_tree)
|
789
|
+
|
539
790
|
strargs = if args_tree.size > 1
|
540
|
-
"VALUE block, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
|
791
|
+
"VALUE block, VALUE _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
|
541
792
|
else
|
542
|
-
"VALUE block"
|
793
|
+
"VALUE block, VALUE _parent_frame"
|
543
794
|
end
|
544
795
|
|
545
796
|
"VALUE #{@alt_method_name || method_name}(#{strargs}) {
|
546
|
-
|
547
|
-
#{
|
548
|
-
#{@block_struct} *pblock;
|
549
|
-
VALUE last_expression = Qnil;
|
797
|
+
|
798
|
+
#{func_frame}
|
550
799
|
|
551
800
|
#{args_tree[1..-1].map { |arg|
|
552
801
|
"locals.#{arg} = #{arg};\n"
|
553
802
|
}.join("") }
|
554
803
|
|
555
|
-
locals.self = self;
|
556
|
-
|
557
804
|
pblock = (void*)block;
|
558
805
|
if (pblock) {
|
559
806
|
locals.block_function_address = pblock->block_function_address;
|
@@ -563,7 +810,7 @@ module FastRuby
|
|
563
810
|
locals.block_function_param = Qnil;
|
564
811
|
}
|
565
812
|
|
566
|
-
return #{
|
813
|
+
return #{to_c impl_tree};
|
567
814
|
}"
|
568
815
|
end
|
569
816
|
|
@@ -571,10 +818,6 @@ module FastRuby
|
|
571
818
|
"plocals->"
|
572
819
|
end
|
573
820
|
|
574
|
-
def locals_pointer
|
575
|
-
"plocals"
|
576
|
-
end
|
577
|
-
|
578
821
|
def to_c_gvar(tree)
|
579
822
|
"rb_gvar_get((struct global_entry*)0x#{global_entry(tree[1]).to_s(16)})"
|
580
823
|
end
|
@@ -632,7 +875,7 @@ module FastRuby
|
|
632
875
|
}
|
633
876
|
|
634
877
|
|
635
|
-
"_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(verify_type_function)}(#{to_c tree[2]}))"
|
878
|
+
"_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(&verify_type_function)}(#{to_c tree[2]}))"
|
636
879
|
else
|
637
880
|
"_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
|
638
881
|
end
|
@@ -688,16 +931,67 @@ module FastRuby
|
|
688
931
|
"
|
689
932
|
end
|
690
933
|
|
691
|
-
def
|
692
|
-
|
693
|
-
|
694
|
-
|
934
|
+
def to_c_rescue(tree)
|
935
|
+
if tree[1][0] == :resbody
|
936
|
+
else_tree = tree[2]
|
937
|
+
|
938
|
+
if else_tree
|
939
|
+
to_c else_tree
|
940
|
+
else
|
941
|
+
"Qnil"
|
942
|
+
end
|
943
|
+
else
|
944
|
+
resbody_tree = tree[2]
|
945
|
+
else_tree = tree[3]
|
946
|
+
|
947
|
+
frame(to_c(tree[1])+";","
|
948
|
+
if (CLASS_OF(frame.exception) == #{to_c(resbody_tree[1][1])})
|
949
|
+
{
|
950
|
+
// trap exception
|
951
|
+
;original_frame->target_frame = &frame;
|
952
|
+
#{to_c(resbody_tree[2])};
|
953
|
+
}
|
954
|
+
", else_tree ? to_c(else_tree) : nil, 1)
|
955
|
+
end
|
956
|
+
end
|
957
|
+
|
958
|
+
def to_c_ensure(tree)
|
959
|
+
if tree.size == 2
|
960
|
+
to_c tree[1]
|
961
|
+
else
|
962
|
+
ensured_code = to_c tree[2]
|
963
|
+
inline_block "
|
964
|
+
#{frame(to_c(tree[1]),ensured_code,ensured_code,1)};
|
965
|
+
"
|
966
|
+
end
|
967
|
+
end
|
695
968
|
|
969
|
+
def to_c_call(tree)
|
696
970
|
directive_code = directive(tree)
|
697
971
|
if directive_code
|
698
972
|
return directive_code
|
699
973
|
end
|
700
974
|
|
975
|
+
if tree[2] == :require
|
976
|
+
tree[2] = :fastruby_require
|
977
|
+
elsif tree[2] == :raise
|
978
|
+
# raise code
|
979
|
+
args = tree[3]
|
980
|
+
|
981
|
+
return inline_block("
|
982
|
+
pframe->target_frame = (void*)-1;
|
983
|
+
pframe->exception = rb_funcall(#{to_c args[1]}, #{:exception.to_i},0);
|
984
|
+
longjmp(pframe->jmp, 1);
|
985
|
+
return Qnil;
|
986
|
+
")
|
987
|
+
end
|
988
|
+
|
989
|
+
recv = tree[1]
|
990
|
+
mname = tree[2]
|
991
|
+
args = tree[3]
|
992
|
+
|
993
|
+
mname = :require_fastruby if mname == :require
|
994
|
+
|
701
995
|
strargs = args[1..-1].map{|arg| to_c arg}.join(",")
|
702
996
|
|
703
997
|
argnum = args.size - 1
|
@@ -745,8 +1039,12 @@ module FastRuby
|
|
745
1039
|
convention = :cruby
|
746
1040
|
end
|
747
1041
|
|
748
|
-
address =
|
749
|
-
len =
|
1042
|
+
address = nil
|
1043
|
+
len = 0
|
1044
|
+
if mobject
|
1045
|
+
address = getaddress(mobject)
|
1046
|
+
len = getlen(mobject)
|
1047
|
+
end
|
750
1048
|
|
751
1049
|
extraargs = ""
|
752
1050
|
extraargs = ", Qfalse" if convention == :fastruby
|
@@ -754,10 +1052,10 @@ module FastRuby
|
|
754
1052
|
if address then
|
755
1053
|
if argnum == 0
|
756
1054
|
value_cast = "VALUE"
|
757
|
-
value_cast = value_cast + ", VALUE" if convention == :fastruby
|
1055
|
+
value_cast = value_cast + ", VALUE,VALUE" if convention == :fastruby
|
758
1056
|
|
759
1057
|
if convention == :fastruby
|
760
|
-
"((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{to_c recv}, Qfalse)"
|
1058
|
+
"((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{to_c recv}, Qfalse, (VALUE)pframe)"
|
761
1059
|
else
|
762
1060
|
|
763
1061
|
str_incall_args = nil
|
@@ -771,28 +1069,28 @@ module FastRuby
|
|
771
1069
|
str_incall_args = "recv"
|
772
1070
|
end
|
773
1071
|
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
//
|
779
|
-
|
780
|
-
|
781
|
-
|
1072
|
+
protected_block(
|
1073
|
+
|
1074
|
+
anonymous_function{ |name| "
|
1075
|
+
static VALUE #{name}(VALUE recv) {
|
1076
|
+
// call to #{recvtype}##{mname}
|
1077
|
+
if (rb_block_given_p()) {
|
1078
|
+
// no passing block, recall
|
1079
|
+
return rb_funcall(recv, #{tree[2].to_i}, 0);
|
1080
|
+
} else {
|
1081
|
+
return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_incall_args});
|
1082
|
+
}
|
782
1083
|
}
|
783
|
-
}
|
784
|
-
|
785
|
-
|
786
|
-
anonymous_function(wrapper_func) + "(#{to_c(recv)})"
|
787
|
-
|
1084
|
+
" } + "(#{to_c(recv)})"
|
1085
|
+
)
|
788
1086
|
end
|
789
1087
|
else
|
790
1088
|
value_cast = ( ["VALUE"]*(args.size) ).join(",")
|
791
|
-
value_cast = value_cast + ", VALUE" if convention == :fastruby
|
1089
|
+
value_cast = value_cast + ", VALUE, VALUE" if convention == :fastruby
|
792
1090
|
|
793
1091
|
wrapper_func = nil
|
794
1092
|
if convention == :fastruby
|
795
|
-
"((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{to_c recv}, Qfalse, #{strargs})"
|
1093
|
+
"((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{to_c recv}, Qfalse, (VALUE)pframe, #{strargs})"
|
796
1094
|
else
|
797
1095
|
|
798
1096
|
str_incall_args = nil
|
@@ -806,35 +1104,36 @@ module FastRuby
|
|
806
1104
|
str_incall_args = "recv, #{ (1..argnum).map{|x| "_arg"+x.to_s }.join(",")}"
|
807
1105
|
end
|
808
1106
|
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
//
|
814
|
-
|
815
|
-
|
816
|
-
|
1107
|
+
protected_block(
|
1108
|
+
|
1109
|
+
anonymous_function{ |name| "
|
1110
|
+
static VALUE #{name}(VALUE recv, #{ (1..argnum).map{|x| "VALUE _arg"+x.to_s }.join(",")} ) {
|
1111
|
+
// call to #{recvtype}##{mname}
|
1112
|
+
if (rb_block_given_p()) {
|
1113
|
+
// no passing block, recall
|
1114
|
+
return rb_funcall(recv, #{tree[2].to_i}, #{argnum}, #{ (1..argnum).map{|x| "_arg"+x.to_s }.join(",")});
|
1115
|
+
} else {
|
1116
|
+
return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_incall_args});
|
1117
|
+
}
|
817
1118
|
}
|
818
|
-
}
|
819
|
-
|
820
|
-
|
821
|
-
anonymous_function(wrapper_func) + "(#{to_c(recv)}, #{strargs})"
|
1119
|
+
" } + "(#{to_c(recv)}, #{strargs})"
|
1120
|
+
)
|
822
1121
|
end
|
823
1122
|
end
|
824
1123
|
else
|
825
1124
|
|
826
1125
|
if argnum == 0
|
827
|
-
"rb_funcall(#{to_c recv}, #{tree[2].to_i}, 0)"
|
1126
|
+
protected_block("rb_funcall(#{to_c recv}, #{tree[2].to_i}, 0)")
|
828
1127
|
else
|
829
|
-
"rb_funcall(#{to_c recv}, #{tree[2].to_i}, #{argnum}, #{strargs} )"
|
1128
|
+
protected_block("rb_funcall(#{to_c recv}, #{tree[2].to_i}, #{argnum}, #{strargs} )")
|
830
1129
|
end
|
831
1130
|
end
|
832
1131
|
|
833
1132
|
else
|
834
1133
|
if argnum == 0
|
835
|
-
"rb_funcall(#{to_c recv}, #{tree[2].to_i}, 0)"
|
1134
|
+
protected_block("rb_funcall(#{to_c recv}, #{tree[2].to_i}, 0)")
|
836
1135
|
else
|
837
|
-
"rb_funcall(#{to_c recv}, #{tree[2].to_i}, #{argnum}, #{strargs} )"
|
1136
|
+
protected_block("rb_funcall(#{to_c recv}, #{tree[2].to_i}, #{argnum}, #{strargs} )")
|
838
1137
|
end
|
839
1138
|
end
|
840
1139
|
end
|
@@ -847,6 +1146,13 @@ module FastRuby
|
|
847
1146
|
|
848
1147
|
end
|
849
1148
|
|
1149
|
+
def to_c_module(tree)
|
1150
|
+
inline_block("
|
1151
|
+
rb_funcall(plocals->self,#{:fastruby.to_i},1,(VALUE)#{tree.internal_value});
|
1152
|
+
return Qnil;
|
1153
|
+
")
|
1154
|
+
end
|
1155
|
+
|
850
1156
|
def to_c_while(tree)
|
851
1157
|
inline_block("
|
852
1158
|
while (#{to_c tree[1]}) {
|
@@ -872,6 +1178,14 @@ module FastRuby
|
|
872
1178
|
end
|
873
1179
|
end
|
874
1180
|
|
1181
|
+
def on_block
|
1182
|
+
old_on_block = @on_block
|
1183
|
+
@on_block = true
|
1184
|
+
return yield
|
1185
|
+
ensure
|
1186
|
+
@on_block = old_on_block
|
1187
|
+
end
|
1188
|
+
|
875
1189
|
def with_extra_inference(extra_inference)
|
876
1190
|
previous_infer_lvar_map = @infer_lvar_map
|
877
1191
|
begin
|
@@ -900,33 +1214,225 @@ module FastRuby
|
|
900
1214
|
elsif mname == :inline_c
|
901
1215
|
code = args[1][1]
|
902
1216
|
|
903
|
-
|
1217
|
+
return anonymous_function{ |name| "
|
904
1218
|
static VALUE #{name}(VALUE param) {
|
905
1219
|
#{@locals_struct} *plocals = (void*)param;
|
906
1220
|
#{code};
|
907
1221
|
return Qnil;
|
908
1222
|
}
|
909
1223
|
"
|
910
|
-
}
|
911
|
-
|
912
|
-
return anonymous_function(caller_code)+"((VALUE)plocals)"
|
1224
|
+
}+"((VALUE)plocals)"
|
913
1225
|
else
|
914
1226
|
nil
|
915
1227
|
end
|
916
1228
|
end
|
917
1229
|
|
1230
|
+
def inline_block_reference(arg)
|
1231
|
+
code = nil
|
1232
|
+
|
1233
|
+
if arg.instance_of? Sexp
|
1234
|
+
code = to_c(arg);
|
1235
|
+
else
|
1236
|
+
code = arg
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
anonymous_function{ |name| "
|
1240
|
+
static VALUE #{name}(VALUE param) {
|
1241
|
+
#{@frame_struct} *pframe = (void*)param;
|
1242
|
+
#{@locals_struct} *plocals = (void*)pframe->plocals;
|
1243
|
+
VALUE last_expression = Qnil;
|
1244
|
+
|
1245
|
+
#{code};
|
1246
|
+
return last_expression;
|
1247
|
+
}
|
1248
|
+
"
|
1249
|
+
}
|
1250
|
+
end
|
1251
|
+
|
918
1252
|
def inline_block(code)
|
919
|
-
|
1253
|
+
anonymous_function{ |name| "
|
920
1254
|
static VALUE #{name}(VALUE param) {
|
921
|
-
#{@
|
1255
|
+
#{@frame_struct} *pframe = (void*)param;
|
1256
|
+
#{@locals_struct} *plocals = (void*)pframe->plocals;
|
922
1257
|
VALUE last_expression = Qnil;
|
923
1258
|
|
924
1259
|
#{code}
|
925
1260
|
}
|
926
1261
|
"
|
927
|
-
}
|
1262
|
+
} + "((VALUE)pframe)"
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
def inline_ruby(proced, parameter)
|
1266
|
+
"rb_funcall(#{proced.internal_value}, #{:call.to_i}, 1, #{parameter})"
|
1267
|
+
end
|
1268
|
+
|
1269
|
+
def wrapped_break_block(inner_code)
|
1270
|
+
frame("return " + inner_code, "
|
1271
|
+
if (original_frame->target_frame == (void*)-2) {
|
1272
|
+
return pframe->return_value;
|
1273
|
+
}
|
1274
|
+
")
|
1275
|
+
end
|
928
1276
|
|
929
|
-
|
1277
|
+
def protected_block(inner_code, always_rescue = false)
|
1278
|
+
wrapper_code = "
|
1279
|
+
if (pframe->last_error != Qnil) {
|
1280
|
+
if (CLASS_OF(pframe->last_error)==(VALUE)#{UnwindFastrubyFrame.internal_value}) {
|
1281
|
+
#{@frame_struct} *pframe = (void*)param;
|
1282
|
+
|
1283
|
+
pframe->target_frame = (void*)FIX2LONG(rb_ivar_get(pframe->last_error, #{:@target_frame.to_i}));
|
1284
|
+
pframe->exception = rb_ivar_get(pframe->last_error, #{:@ex.to_i});
|
1285
|
+
pframe->return_value = rb_ivar_get(pframe->last_error, #{:@return_value.to_i});
|
1286
|
+
|
1287
|
+
if (pframe->target_frame == (void*)-2) {
|
1288
|
+
return pframe->return_value;
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
longjmp(pframe->jmp, 1);
|
1292
|
+
return Qnil;
|
1293
|
+
|
1294
|
+
} else {
|
1295
|
+
// raise emulation
|
1296
|
+
#{@frame_struct} *pframe = (void*)param;
|
1297
|
+
pframe->target_frame = (void*)-1;
|
1298
|
+
pframe->exception = pframe->last_error;
|
1299
|
+
longjmp(pframe->jmp, 1);
|
1300
|
+
return Qnil;
|
1301
|
+
}
|
1302
|
+
|
1303
|
+
}
|
1304
|
+
"
|
1305
|
+
rescue_code = "rb_rescue2(#{inline_block_reference "return #{inner_code};"},(VALUE)pframe,#{anonymous_function{|name| "
|
1306
|
+
static VALUE #{name}(VALUE param, VALUE error) {
|
1307
|
+
#{@frame_struct} *pframe = (void*)param;
|
1308
|
+
pframe->last_error = error;
|
1309
|
+
}
|
1310
|
+
"}}
|
1311
|
+
,(VALUE)pframe, rb_eException,(VALUE)0)"
|
1312
|
+
|
1313
|
+
if always_rescue
|
1314
|
+
inline_block "
|
1315
|
+
pframe->last_error = Qnil;
|
1316
|
+
VALUE result = #{rescue_code};
|
1317
|
+
|
1318
|
+
#{wrapper_code}
|
1319
|
+
|
1320
|
+
return result;
|
1321
|
+
"
|
1322
|
+
else
|
1323
|
+
inline_block "
|
1324
|
+
VALUE result;
|
1325
|
+
pframe->last_error = Qnil;
|
1326
|
+
|
1327
|
+
if (pframe->rescue) {
|
1328
|
+
result = #{rescue_code};
|
1329
|
+
} else {
|
1330
|
+
return #{inner_code};
|
1331
|
+
}
|
1332
|
+
|
1333
|
+
#{wrapper_code}
|
1334
|
+
|
1335
|
+
return result;
|
1336
|
+
"
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
|
1342
|
+
def func_frame
|
1343
|
+
"
|
1344
|
+
#{@locals_struct} locals;
|
1345
|
+
#{@locals_struct} *plocals = (void*)&locals;
|
1346
|
+
#{@frame_struct} frame;
|
1347
|
+
#{@frame_struct} *pframe;
|
1348
|
+
|
1349
|
+
frame.plocals = plocals;
|
1350
|
+
frame.parent_frame = (void*)_parent_frame;
|
1351
|
+
frame.return_value = Qnil;
|
1352
|
+
frame.target_frame = &frame;
|
1353
|
+
frame.exception = Qnil;
|
1354
|
+
frame.rescue = 0;
|
1355
|
+
|
1356
|
+
locals.pframe = &frame;
|
1357
|
+
|
1358
|
+
pframe = (void*)&frame;
|
1359
|
+
|
1360
|
+
#{@block_struct} *pblock;
|
1361
|
+
VALUE last_expression = Qnil;
|
1362
|
+
|
1363
|
+
int aux = setjmp(pframe->jmp);
|
1364
|
+
if (aux != 0) {
|
1365
|
+
|
1366
|
+
if (pframe->target_frame == (void*)-2) {
|
1367
|
+
return pframe->return_value;
|
1368
|
+
}
|
1369
|
+
|
1370
|
+
if (pframe->target_frame != pframe) {
|
1371
|
+
// raise exception
|
1372
|
+
((typeof(pframe))_parent_frame)->exception = pframe->exception;
|
1373
|
+
((typeof(pframe))_parent_frame)->target_frame = pframe->target_frame;
|
1374
|
+
((typeof(pframe))_parent_frame)->return_value = pframe->return_value;
|
1375
|
+
longjmp(((typeof(pframe))_parent_frame)->jmp,1);
|
1376
|
+
}
|
1377
|
+
|
1378
|
+
return plocals->return_value;
|
1379
|
+
}
|
1380
|
+
|
1381
|
+
locals.self = self;
|
1382
|
+
"
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
def frame(code, jmp_code, not_jmp_code = "", rescued = nil)
|
1386
|
+
|
1387
|
+
anonymous_function{ |name| "
|
1388
|
+
static VALUE #{name}(VALUE param) {
|
1389
|
+
VALUE last_expression;
|
1390
|
+
#{@frame_struct} frame, *pframe, *parent_frame;
|
1391
|
+
#{@locals_struct} *plocals;
|
1392
|
+
|
1393
|
+
parent_frame = (void*)param;
|
1394
|
+
|
1395
|
+
frame.parent_frame = (void*)param;
|
1396
|
+
frame.plocals = parent_frame->plocals;
|
1397
|
+
frame.target_frame = &frame;
|
1398
|
+
frame.rescue = #{rescued ? rescued : "parent_frame->rescue"};
|
1399
|
+
|
1400
|
+
plocals = frame.plocals;
|
1401
|
+
pframe = &frame;
|
1402
|
+
|
1403
|
+
int aux = setjmp(frame.jmp);
|
1404
|
+
if (aux != 0) {
|
1405
|
+
last_expression = pframe->return_value;
|
1406
|
+
|
1407
|
+
// restore previous frame
|
1408
|
+
typeof(pframe) original_frame = pframe;
|
1409
|
+
pframe = parent_frame;
|
1410
|
+
|
1411
|
+
#{jmp_code};
|
1412
|
+
|
1413
|
+
if (original_frame->target_frame != original_frame) {
|
1414
|
+
pframe->exception = original_frame->exception;
|
1415
|
+
pframe->target_frame = original_frame->target_frame;
|
1416
|
+
pframe->return_value = original_frame->return_value;
|
1417
|
+
|
1418
|
+
longjmp(pframe->jmp,1);
|
1419
|
+
}
|
1420
|
+
|
1421
|
+
return last_expression;
|
1422
|
+
}
|
1423
|
+
|
1424
|
+
#{code};
|
1425
|
+
|
1426
|
+
// restore previous frame
|
1427
|
+
typeof(pframe) original_frame = pframe;
|
1428
|
+
pframe = parent_frame;
|
1429
|
+
#{not_jmp_code};
|
1430
|
+
|
1431
|
+
return last_expression;
|
1432
|
+
|
1433
|
+
}
|
1434
|
+
"
|
1435
|
+
} + "((VALUE)pframe)"
|
930
1436
|
end
|
931
1437
|
|
932
1438
|
inline :C do |builder|
|