fastruby 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2594 @@
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
+ require "set"
22
+ require "fastruby/method_extension"
23
+ require "fastruby/set_tree"
24
+ require "fastruby/exceptions"
25
+ require "rubygems"
26
+ require "sexp"
27
+
28
+ module FastRuby
29
+ class Context
30
+ attr_accessor :infer_lvar_map
31
+ attr_accessor :alt_method_name
32
+ attr_accessor :locals
33
+ attr_accessor :options
34
+ attr_accessor :infer_self
35
+ attr_accessor :snippet_hash
36
+ attr_reader :no_cache
37
+ attr_reader :init_extra
38
+ attr_reader :extra_code
39
+ attr_reader :yield_signature
40
+
41
+ def initialize(common_func = true)
42
+ @infer_lvar_map = Hash.new
43
+ @no_cache = false
44
+ @extra_code = ""
45
+ @options = {}
46
+ @init_extra = Array.new
47
+ @frame_struct = "struct {
48
+ void* parent_frame;
49
+ void* plocals;
50
+ jmp_buf jmp;
51
+ VALUE return_value;
52
+ int rescue;
53
+ VALUE last_error;
54
+ VALUE next_recv;
55
+ int targetted;
56
+ struct FASTRUBYTHREADDATA* thread_data;
57
+ }"
58
+
59
+ @block_struct = "struct {
60
+ void* block_function_address;
61
+ void* block_function_param;
62
+ }"
63
+
64
+
65
+ extra_code << "
66
+ #include \"node.h\"
67
+
68
+ #define FASTRUBY_TAG_RETURN 0x80
69
+ #define FASTRUBY_TAG_NEXT 0x81
70
+ #define FASTRUBY_TAG_BREAK 0x82
71
+ #define FASTRUBY_TAG_RAISE 0x83
72
+ #define FASTRUBY_TAG_REDO 0x84
73
+ #define FASTRUBY_TAG_RETRY 0x85
74
+ #define TAG_RAISE 0x6
75
+
76
+ #ifndef __INLINE_FASTRUBY_BASE
77
+ #include \"#{FastRuby.fastruby_load_path}/../ext/fastruby_base/fastruby_base.inl\"
78
+ #define __INLINE_FASTRUBY_BASE
79
+ #endif
80
+ "
81
+
82
+ ruby_code = "
83
+ $LOAD_PATH << #{FastRuby.fastruby_load_path.inspect}
84
+ require #{FastRuby.fastruby_script_path.inspect}
85
+ "
86
+
87
+ init_extra << "
88
+ rb_eval_string(#{ruby_code.inspect});
89
+ "
90
+
91
+ @lambda_node_gvar = add_global_name("NODE*", 0);
92
+ @proc_node_gvar = add_global_name("NODE*", 0);
93
+ @procnew_node_gvar = add_global_name("NODE*", 0);
94
+
95
+ init_extra << "
96
+ #{@lambda_node_gvar} = rb_method_node(rb_cObject, #{intern_num :lambda});
97
+ #{@proc_node_gvar} = rb_method_node(rb_cObject, #{intern_num :proc});
98
+ #{@procnew_node_gvar} = rb_method_node(CLASS_OF(rb_cProc), #{intern_num :new});
99
+ "
100
+
101
+ @common_func = common_func
102
+ if common_func
103
+ extra_code << "static VALUE _rb_gvar_set(void* ge,VALUE value) {
104
+ rb_gvar_set((struct global_entry*)ge,value);
105
+ return value;
106
+ }
107
+ "
108
+
109
+ extra_code << "static VALUE re_yield(int argc, VALUE* argv, VALUE param, VALUE _parent_frame) {
110
+ VALUE yield_args = rb_ary_new4(argc,argv);
111
+ VALUE* yield_args_p = &yield_args;
112
+
113
+ #{@frame_struct}* pframe;
114
+ pframe = (typeof(pframe))_parent_frame;
115
+
116
+ return #{protected_block("rb_yield_splat(*(VALUE*)yield_args_p)",true,"yield_args_p",true)};
117
+ }"
118
+
119
+ extra_code << "static VALUE _rb_ivar_set(VALUE recv,ID idvar, VALUE value) {
120
+ rb_ivar_set(recv,idvar,value);
121
+ return value;
122
+ }
123
+ "
124
+
125
+ extra_code << "static VALUE __rb_cvar_set(VALUE recv,ID idvar, VALUE value, int warn) {
126
+ rb_cvar_set(recv,idvar,value,warn);
127
+ return value;
128
+ }
129
+ "
130
+
131
+ extra_code << "static VALUE _lvar_assing(VALUE* destination,VALUE value) {
132
+ *destination = value;
133
+ return value;
134
+ }
135
+
136
+ /*
137
+ #{caller.join("\n")}
138
+ */
139
+
140
+ "
141
+ end
142
+ end
143
+
144
+ def to_c(tree)
145
+ return "Qnil" unless tree
146
+ send("to_c_" + tree[0].to_s, tree);
147
+ end
148
+
149
+ def anonymous_function
150
+
151
+ name = "anonymous" + rand(10000000).to_s
152
+ extra_code << yield(name)
153
+
154
+ name
155
+ end
156
+
157
+ def to_c_dot2(tree)
158
+ "rb_range_new(#{to_c tree[1]}, #{to_c tree[2]},0)"
159
+ end
160
+
161
+ def to_c_attrasgn(tree)
162
+ to_c_call(tree)
163
+ end
164
+
165
+ def to_c_iter(tree)
166
+
167
+ call_tree = tree[1]
168
+ args_tree = tree[2]
169
+ recv_tree = call_tree[1]
170
+
171
+ directive_code = directive(call_tree)
172
+ if directive_code
173
+ return directive_code
174
+ end
175
+
176
+ other_call_tree = call_tree.dup
177
+ other_call_tree[1] = s(:lvar, :arg)
178
+
179
+ mname = call_tree[2]
180
+
181
+ call_args_tree = call_tree[3]
182
+
183
+ caller_code = nil
184
+
185
+ recvtype = infer_type(recv_tree || s(:self))
186
+
187
+ address = nil
188
+ mobject = nil
189
+ len = nil
190
+
191
+ extra_inference = {}
192
+
193
+ if recvtype
194
+
195
+ inference_complete = true
196
+ signature = [recvtype]
197
+
198
+ call_args_tree[1..-1].each do |arg|
199
+ argtype = infer_type(arg)
200
+ if argtype
201
+ signature << argtype
202
+ else
203
+ inference_complete = false
204
+ end
205
+ end
206
+
207
+ if recvtype.respond_to? :fastruby_method and inference_complete
208
+ method_tree = nil
209
+ begin
210
+ method_tree = recvtype.instance_method(call_tree[2]).fastruby.tree
211
+ rescue NoMethodError
212
+ end
213
+
214
+ if method_tree
215
+ mobject = recvtype.build(signature, call_tree[2])
216
+ yield_signature = mobject.yield_signature
217
+
218
+ if not args_tree
219
+ elsif args_tree.first == :lasgn
220
+ if yield_signature[0]
221
+ extra_inference[args_tree.last] = yield_signature[0]
222
+ end
223
+ elsif args_tree.first == :masgn
224
+ yield_args = args_tree[1][1..-1].map(&:last)
225
+ (0...yield_signature.size-1).each do |i|
226
+ extra_inference[yield_args[i]] = yield_signature[i]
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ anonymous_impl = tree[3]
234
+
235
+ str_lvar_initialization = "#{@frame_struct} *pframe;
236
+ #{@locals_struct} *plocals;
237
+ pframe = (void*)param;
238
+ plocals = (void*)pframe->plocals;
239
+ "
240
+
241
+ str_arg_initialization = ""
242
+
243
+ str_impl = ""
244
+
245
+ with_extra_inference(extra_inference) do
246
+
247
+ on_block do
248
+ # if impl_tree is a block, implement the last node with a return
249
+ if anonymous_impl
250
+ if anonymous_impl[0] == :block
251
+ str_impl = anonymous_impl[1..-2].map{ |subtree|
252
+ to_c(subtree)
253
+ }.join(";")
254
+
255
+ if anonymous_impl[-1][0] != :return and anonymous_impl[-1][0] != :break and anonymous_impl[-1][0] != :next
256
+ str_impl = str_impl + ";last_expression = (#{to_c(anonymous_impl[-1])});"
257
+ else
258
+ str_impl = str_impl + ";#{to_c(anonymous_impl[-1])};"
259
+ end
260
+ else
261
+ if anonymous_impl[0] != :return and anonymous_impl[0] != :break and anonymous_impl[0] != :next
262
+ str_impl = str_impl + ";last_expression = (#{to_c(anonymous_impl)});"
263
+ else
264
+ str_impl = str_impl + ";#{to_c(anonymous_impl)};"
265
+ end
266
+ end
267
+ else
268
+ str_impl = "last_expression = Qnil;"
269
+ end
270
+ end
271
+ end
272
+
273
+
274
+ if not args_tree
275
+ str_arg_initialization = ""
276
+ elsif args_tree.first == :lasgn
277
+ str_arg_initialization = "plocals->#{args_tree[1]} = arg;"
278
+ elsif args_tree.first == :masgn
279
+ arguments = args_tree[1][1..-1].map(&:last)
280
+
281
+ (0..arguments.size-1).each do |i|
282
+ str_arg_initialization << "plocals->#{arguments[i]} = rb_ary_entry(arg,#{i});\n"
283
+ end
284
+ end
285
+ rb_funcall_caller_code = nil
286
+
287
+ if call_args_tree.size > 1
288
+
289
+ str_called_code_args = call_args_tree[1..-1].map{ |subtree| to_c subtree }.join(",")
290
+ str_recv = "pframe->next_recv"
291
+
292
+ str_recv = "plocals->self" unless recv_tree
293
+
294
+ rb_funcall_caller_code = proc { |name| "
295
+ static VALUE #{name}(VALUE param) {
296
+ // call to #{call_tree[2]}
297
+
298
+ #{str_lvar_initialization}
299
+ return rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, #{call_args_tree.size-1}, #{str_called_code_args});
300
+ }
301
+ "
302
+ }
303
+
304
+ rb_funcall_caller_code_with_lambda = rb_funcall_caller_code
305
+ else
306
+ str_recv = "pframe->next_recv"
307
+ str_recv = "plocals->self" unless recv_tree
308
+
309
+ rb_funcall_caller_code = proc { |name| "
310
+ static VALUE #{name}(VALUE param) {
311
+ // call to #{call_tree[2]}
312
+ #{str_lvar_initialization}
313
+ return rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, 0);
314
+ }
315
+ "
316
+ }
317
+
318
+ rb_funcall_caller_code_with_lambda = proc { |name| "
319
+ static VALUE #{name}(VALUE param) {
320
+ // call to #{call_tree[2]}
321
+ #{str_lvar_initialization}
322
+ VALUE ret = rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, 0);
323
+
324
+ // freeze all stacks
325
+ struct FASTRUBYTHREADDATA* thread_data = rb_current_thread_data();
326
+
327
+ if (thread_data != 0) {
328
+ VALUE rb_stack_chunk = thread_data->rb_stack_chunk;
329
+
330
+ // add reference to stack chunk to lambda object
331
+ rb_ivar_set(ret,#{intern_num :_fastruby_stack_chunk},rb_stack_chunk);
332
+
333
+ // freeze the complete chain of stack chunks
334
+ while (rb_stack_chunk != Qnil) {
335
+ struct STACKCHUNK* stack_chunk;
336
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
337
+
338
+ stack_chunk_freeze(stack_chunk);
339
+
340
+ rb_stack_chunk = rb_ivar_get(rb_stack_chunk,#{intern_num :_parent_stack_chunk});
341
+ }
342
+ }
343
+
344
+ return ret;
345
+ }
346
+ "
347
+ }
348
+
349
+ end
350
+
351
+ rb_funcall_block_code_with_lambda = proc { |name| "
352
+ static VALUE #{name}(VALUE arg, VALUE _plocals) {
353
+ // block for call to #{call_tree[2]}
354
+ VALUE last_expression = Qnil;
355
+
356
+ #{@frame_struct} frame;
357
+ #{@frame_struct} *pframe = (void*)&frame;
358
+ #{@locals_struct} *plocals = (void*)_plocals;
359
+
360
+ frame.plocals = plocals;
361
+ frame.parent_frame = 0;
362
+ frame.return_value = Qnil;
363
+ frame.rescue = 0;
364
+ frame.targetted = 0;
365
+ frame.thread_data = rb_current_thread_data();
366
+
367
+ // create a fake parent frame representing the lambda method frame and a fake locals scope
368
+ VALUE old_call_frame = ((typeof(plocals))(pframe->plocals))->call_frame;
369
+ ((typeof(plocals))(pframe->plocals))->call_frame = LONG2FIX(pframe);
370
+
371
+ int aux = setjmp(frame.jmp);
372
+ if (aux != 0) {
373
+ if (aux == FASTRUBY_TAG_BREAK) {
374
+ return frame.return_value;
375
+ } else if (aux == FASTRUBY_TAG_NEXT) {
376
+ return pframe->thread_data->accumulator;
377
+ } else if (aux == FASTRUBY_TAG_REDO) {
378
+ // do nothing and let execute the block again
379
+ } else if (aux == FASTRUBY_TAG_RAISE) {
380
+ rb_funcall(((typeof(plocals))(pframe->plocals))->self, #{intern_num :raise}, 1, frame.thread_data->exception);
381
+ return Qnil;
382
+ } else {
383
+ if (aux == FASTRUBY_TAG_RETURN) {
384
+ if (((typeof(pframe))(FIX2LONG(plocals->pframe)))->targetted == 1) {
385
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
386
+ return ((typeof(plocals))(pframe->plocals))->return_value;
387
+ } else {
388
+ rb_raise(rb_eLocalJumpError, \"unexpected return\");
389
+ }
390
+ } else {
391
+ rb_raise(rb_eLocalJumpError, \"unexpected return\");
392
+ }
393
+
394
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
395
+ return frame.return_value;
396
+
397
+ }
398
+ }
399
+
400
+ #{str_arg_initialization}
401
+ #{str_impl}
402
+
403
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
404
+ return last_expression;
405
+ }
406
+ "
407
+ }
408
+
409
+ rb_funcall_block_code_proc_new = proc { |name| "
410
+ static VALUE #{name}(VALUE arg, VALUE _plocals) {
411
+ // block for call to #{call_tree[2]}
412
+ VALUE last_expression = Qnil;
413
+
414
+ #{@frame_struct} frame;
415
+ #{@frame_struct} *pframe = (void*)&frame;
416
+ #{@locals_struct} *plocals = (void*)_plocals;
417
+
418
+ frame.plocals = plocals;
419
+ frame.parent_frame = 0;
420
+ frame.return_value = Qnil;
421
+ frame.rescue = 0;
422
+ frame.targetted = 0;
423
+ frame.thread_data = rb_current_thread_data();
424
+
425
+ // create a fake parent frame representing the lambda method frame and a fake locals scope
426
+ VALUE old_call_frame = ((typeof(plocals))(pframe->plocals))->call_frame;
427
+ ((typeof(plocals))(pframe->plocals))->call_frame = LONG2FIX(pframe);
428
+
429
+ int aux = setjmp(frame.jmp);
430
+ if (aux != 0) {
431
+ if (aux == FASTRUBY_TAG_NEXT) {
432
+ return pframe->thread_data->accumulator;
433
+ } else if (aux == FASTRUBY_TAG_REDO) {
434
+ // do nothing and let execute the block again
435
+ } else if (aux == FASTRUBY_TAG_RAISE) {
436
+ rb_funcall(((typeof(plocals))(pframe->plocals))->self, #{intern_num :raise}, 1, frame.thread_data->exception);
437
+ return Qnil;
438
+ } else {
439
+ if (((typeof(pframe))(FIX2LONG(plocals->pframe)))->targetted == 1) {
440
+
441
+ if (plocals->active == Qfalse) {
442
+ rb_raise(rb_eLocalJumpError,\"return from proc-closure\");
443
+ } else {
444
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
445
+ rb_jump_tag(aux);
446
+ }
447
+ } else {
448
+ rb_raise(rb_eLocalJumpError, \"unexpected return\");
449
+ }
450
+ }
451
+ }
452
+
453
+ #{str_arg_initialization}
454
+ #{str_impl}
455
+
456
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
457
+
458
+ return last_expression;
459
+ }
460
+ "
461
+ }
462
+
463
+
464
+ rb_funcall_block_code = proc { |name| "
465
+ static VALUE #{name}(VALUE arg, VALUE _plocals) {
466
+ // block for call to #{call_tree[2]}
467
+ VALUE last_expression = Qnil;
468
+
469
+ #{@frame_struct} frame;
470
+ #{@frame_struct} *pframe = (void*)&frame;
471
+ #{@locals_struct} *plocals = (void*)_plocals;
472
+
473
+ frame.plocals = plocals;
474
+ frame.parent_frame = 0;
475
+ frame.return_value = Qnil;
476
+ frame.rescue = 0;
477
+ frame.targetted = 0;
478
+ frame.thread_data = rb_current_thread_data();
479
+
480
+ int aux = setjmp(frame.jmp);
481
+ if (aux != 0) {
482
+
483
+ if (aux == FASTRUBY_TAG_NEXT) {
484
+ return pframe->thread_data->accumulator;
485
+ } else if (aux == FASTRUBY_TAG_REDO) {
486
+ // do nothing and let execute the block again
487
+ } else {
488
+ rb_jump_tag(aux);
489
+ return frame.return_value;
490
+ }
491
+ }
492
+
493
+
494
+ #{str_arg_initialization}
495
+ #{str_impl}
496
+
497
+ return last_expression;
498
+ }
499
+ "
500
+ }
501
+
502
+
503
+ fastruby_str_arg_initialization = ""
504
+
505
+ if not args_tree
506
+ fastruby_str_arg_initialization = ""
507
+ elsif args_tree.first == :lasgn
508
+ fastruby_str_arg_initialization = "plocals->#{args_tree[1]} = argv[0];"
509
+ elsif args_tree.first == :masgn
510
+ arguments = args_tree[1][1..-1].map(&:last)
511
+
512
+ (0..arguments.size-1).each do |i|
513
+ fastruby_str_arg_initialization << "plocals->#{arguments[i]} = #{i} < argc ? argv[#{i}] : Qnil;\n"
514
+ end
515
+ end
516
+
517
+ block_code = proc { |name| "
518
+ static VALUE #{name}(int argc, VALUE* argv, VALUE _locals, VALUE _parent_frame) {
519
+ // block for call to #{call_tree[2]}
520
+ VALUE last_expression = Qnil;
521
+ #{@frame_struct} frame;
522
+ #{@frame_struct} *pframe = (void*)&frame;
523
+ #{@frame_struct} *parent_frame = (void*)_parent_frame;
524
+ #{@locals_struct} *plocals;
525
+
526
+ frame.plocals = (void*)_locals;
527
+ frame.parent_frame = parent_frame;
528
+ frame.return_value = Qnil;
529
+ frame.rescue = 0;
530
+ frame.targetted = 0;
531
+ frame.thread_data = parent_frame->thread_data;
532
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
533
+
534
+ plocals = frame.plocals;
535
+
536
+ int aux = setjmp(frame.jmp);
537
+ if (aux != 0) {
538
+ if (pframe->targetted == 0) {
539
+ if (aux == FASTRUBY_TAG_NEXT) {
540
+ return pframe->thread_data->accumulator;
541
+ } else if (aux == FASTRUBY_TAG_REDO) {
542
+ // do nothing and let execute the block again
543
+ } else {
544
+ longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
545
+ }
546
+ }
547
+
548
+ }
549
+
550
+ #{fastruby_str_arg_initialization}
551
+ #{str_impl}
552
+
553
+ return last_expression;
554
+ }
555
+ "
556
+ }
557
+
558
+ str_recv = "plocals->self"
559
+
560
+ if recv_tree
561
+ str_recv = to_c recv_tree
562
+ end
563
+
564
+ caller_code = nil
565
+ convention_global_name = add_global_name("int",0)
566
+
567
+ call_frame_struct_code = "
568
+ #{@block_struct} block;
569
+ #{@locals_struct} *plocals = (void*)param;
570
+
571
+ block.block_function_address = (void*)#{anonymous_function(&block_code)};
572
+ block.block_function_param = (void*)param;
573
+
574
+ // create a call_frame
575
+ #{@frame_struct} call_frame;
576
+
577
+ call_frame.parent_frame = (void*)pframe;
578
+ call_frame.plocals = plocals;
579
+ call_frame.return_value = Qnil;
580
+ call_frame.targetted = 0;
581
+ call_frame.thread_data = rb_current_thread_data();
582
+
583
+ VALUE old_call_frame = plocals->call_frame;
584
+ plocals->call_frame = LONG2FIX(&call_frame);
585
+
586
+ int aux = setjmp(call_frame.jmp);
587
+ if (aux != 0) {
588
+ #{@frame_struct}* pframe_ = (void*)pframe;
589
+
590
+ if (aux == FASTRUBY_TAG_RETRY ) {
591
+ // do nothing and let the call execute again
592
+ } else {
593
+ if (call_frame.targetted == 0) {
594
+ longjmp(pframe_->jmp,aux);
595
+ }
596
+
597
+ plocals->call_frame = old_call_frame;
598
+ return call_frame.return_value;
599
+ }
600
+ }
601
+ "
602
+
603
+ if call_args_tree.size > 1
604
+ value_cast = ( ["VALUE"]*(call_tree[3].size) ).join(",") + ", VALUE, VALUE"
605
+
606
+ str_called_code_args = call_tree[3][1..-1].map{|subtree| to_c subtree}.join(",")
607
+
608
+ caller_code = proc { |name| "
609
+ static VALUE #{name}(VALUE param, VALUE pframe) {
610
+ // call to #{call_tree[2]}
611
+ #{call_frame_struct_code}
612
+
613
+ 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});
614
+ plocals->call_frame = old_call_frame;
615
+ return ret;
616
+ }
617
+ "
618
+ }
619
+
620
+ else
621
+ caller_code = proc { |name| "
622
+ static VALUE #{name}(VALUE param, VALUE pframe) {
623
+ #{call_frame_struct_code}
624
+
625
+ // call to #{call_tree[2]}
626
+ 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);
627
+ plocals->call_frame = old_call_frame;
628
+ return ret;
629
+ }
630
+ "
631
+ }
632
+ end
633
+
634
+ inline_block "
635
+ if (#{convention_global_name}) {
636
+ return #{anonymous_function(&caller_code)}((VALUE)plocals, (VALUE)pframe);
637
+ } else {
638
+ return #{
639
+ frame_call(
640
+ protected_block(inline_block("
641
+
642
+ pframe->next_recv = #{recv_tree ? to_c(recv_tree) : "plocals->self"};
643
+
644
+ NODE* node = rb_method_node(CLASS_OF(pframe->next_recv), #{intern_num mname});
645
+ void* caller_func;
646
+ void* block_func;
647
+
648
+ if (
649
+ node == #{@proc_node_gvar} ||
650
+ node == #{@lambda_node_gvar}
651
+ ) {
652
+
653
+ caller_func = #{anonymous_function(&rb_funcall_caller_code_with_lambda)};
654
+ block_func = #{anonymous_function(&rb_funcall_block_code_with_lambda)};
655
+ } else if (node == #{@procnew_node_gvar} && pframe->next_recv == rb_cProc) {
656
+ caller_func = #{anonymous_function(&rb_funcall_caller_code_with_lambda)};
657
+ block_func = #{anonymous_function(&rb_funcall_block_code_proc_new)};
658
+ } else {
659
+ caller_func = #{anonymous_function(&rb_funcall_caller_code)};
660
+ block_func = #{anonymous_function(&rb_funcall_block_code)};
661
+ }
662
+
663
+ return rb_iterate(
664
+ caller_func,
665
+ (VALUE)pframe,
666
+ block_func,
667
+ (VALUE)plocals);
668
+
669
+ "), true)
670
+ )
671
+ };
672
+ }
673
+ "
674
+ end
675
+
676
+ def frame_call(inner_code)
677
+ inline_block "
678
+
679
+
680
+ // create a call_frame
681
+ #{@frame_struct} call_frame;
682
+ typeof(call_frame)* old_pframe = (void*)pframe;
683
+
684
+ pframe = (typeof(pframe))&call_frame;
685
+
686
+ call_frame.parent_frame = (void*)pframe;
687
+ call_frame.plocals = plocals;
688
+ call_frame.return_value = Qnil;
689
+ call_frame.targetted = 0;
690
+ call_frame.thread_data = old_pframe->thread_data;
691
+ if (call_frame.thread_data == 0) call_frame.thread_data = rb_current_thread_data();
692
+
693
+ VALUE old_call_frame = plocals->call_frame;
694
+ plocals->call_frame = LONG2FIX(&call_frame);
695
+
696
+ int aux = setjmp(call_frame.jmp);
697
+ if (aux != 0) {
698
+ if (call_frame.targetted == 0) {
699
+ longjmp(old_pframe->jmp,aux);
700
+ }
701
+
702
+ if (aux == FASTRUBY_TAG_BREAK) {
703
+ plocals->call_frame = old_call_frame;
704
+ return call_frame.return_value;
705
+ } else if (aux == FASTRUBY_TAG_RETRY ) {
706
+ // do nothing and let the call execute again
707
+ } else {
708
+ plocals->call_frame = old_call_frame;
709
+ return call_frame.return_value;
710
+ }
711
+ }
712
+
713
+ VALUE ret = #{inner_code};
714
+ plocals->call_frame = old_call_frame;
715
+ return ret;
716
+ "
717
+ end
718
+
719
+ def to_c_yield(tree)
720
+
721
+ block_code = proc { |name| "
722
+ static VALUE #{name}(VALUE frame_param, VALUE* block_args) {
723
+
724
+ #{@locals_struct} *plocals;
725
+ #{@frame_struct} *pframe;
726
+ pframe = (void*)frame_param;
727
+ plocals = (void*)pframe->plocals;
728
+
729
+ if (FIX2LONG(plocals->block_function_address) == 0) {
730
+ #{_raise("rb_eLocalJumpError", "no block given")};
731
+ } else {
732
+ return ((VALUE(*)(int,VALUE*,VALUE,VALUE))FIX2LONG(plocals->block_function_address))(#{tree.size-1}, block_args, FIX2LONG(plocals->block_function_param), (VALUE)pframe);
733
+ }
734
+ }
735
+ "
736
+ }
737
+
738
+ new_yield_signature = tree[1..-1].map{|subtree| infer_type subtree}
739
+ # merge the new_yield_signature with the new
740
+ if @yield_signature
741
+ if new_yield_signature.size == @yield_signature.size
742
+ (0..new_yield_signature.size-1).each do |i|
743
+ if @yield_signature[i] != new_yield_signature[i]
744
+ @yield_signature[i] = nil
745
+ end
746
+ end
747
+ else
748
+ @yield_signature = new_yield_signature.map{|x| nil}
749
+ end
750
+ else
751
+ @yield_signature = new_yield_signature
752
+ end
753
+
754
+ ret = if tree.size > 1
755
+ anonymous_function(&block_code)+"((VALUE)pframe, (VALUE[]){#{tree[1..-1].map{|subtree| to_c subtree}.join(",")}})"
756
+ else
757
+ anonymous_function(&block_code)+"((VALUE)pframe, (VALUE[]){})"
758
+ end
759
+
760
+ protected_block(ret, false)
761
+ end
762
+
763
+ def to_c_block(tree)
764
+
765
+ str = ""
766
+ str = tree[1..-2].map{ |subtree|
767
+ to_c(subtree)
768
+ }.join(";")
769
+
770
+ if tree[-1]
771
+
772
+ if tree[-1][0] != :return
773
+ str = str + ";last_expression = #{to_c(tree[-1])};"
774
+ else
775
+ str = str + ";#{to_c(tree[-1])};"
776
+ end
777
+ end
778
+
779
+ str << "return last_expression;"
780
+
781
+ inline_block str
782
+ end
783
+
784
+ def to_c_cvar(tree)
785
+ "rb_cvar_get(CLASS_OF(plocals->self) != rb_cClass ? CLASS_OF(plocals->self) : plocals->self,#{intern_num tree[1]})"
786
+ end
787
+
788
+ def to_c_cvasgn(tree)
789
+ "__rb_cvar_set(CLASS_OF(plocals->self) != rb_cClass ? CLASS_OF(plocals->self) : plocals->self,#{intern_num tree[1]},#{to_c tree[2]},Qfalse)"
790
+ end
791
+
792
+ def to_c_return(tree)
793
+ inline_block "
794
+ plocals->return_value = #{to_c(tree[1])};
795
+ ((typeof(pframe))FIX2LONG(plocals->pframe))->targetted = 1;
796
+ longjmp(pframe->jmp, FASTRUBY_TAG_RETURN);
797
+ return Qnil;
798
+ "
799
+ end
800
+
801
+ def to_c_break(tree)
802
+ inline_block(
803
+ "
804
+
805
+ VALUE value = #{tree[1] ? to_c(tree[1]) : "Qnil"};
806
+
807
+ typeof(pframe) target_frame_;
808
+ target_frame_ = (void*)FIX2LONG(plocals->call_frame);
809
+
810
+ if (target_frame_ == 0) {
811
+ #{_raise("rb_eLocalJumpError","illegal break")};
812
+ }
813
+
814
+ plocals->call_frame = LONG2FIX(0);
815
+
816
+ target_frame_->return_value = value;
817
+ target_frame_->targetted = 1;
818
+ pframe->thread_data->exception = Qnil;
819
+ longjmp(pframe->jmp,FASTRUBY_TAG_BREAK);"
820
+ )
821
+ end
822
+
823
+ def to_c_retry(tree)
824
+ inline_block(
825
+ "
826
+ typeof(pframe) target_frame_;
827
+ target_frame_ = (void*)FIX2LONG(plocals->call_frame);
828
+
829
+ if (target_frame_ == 0) {
830
+ #{_raise("rb_eLocalJumpError","illegal retry")};
831
+ }
832
+
833
+ target_frame_->targetted = 1;
834
+ longjmp(pframe->jmp,FASTRUBY_TAG_RETRY);"
835
+ )
836
+ end
837
+
838
+ def to_c_redo(tree)
839
+ if @on_block
840
+ inline_block "
841
+ longjmp(pframe->jmp,FASTRUBY_TAG_REDO);
842
+ return Qnil;
843
+ "
844
+ else
845
+ _raise("rb_eLocalJumpError","illegal redo");
846
+ end
847
+ end
848
+
849
+ def to_c_next(tree)
850
+ if @on_block
851
+ inline_block "
852
+ pframe->thread_data->accumulator = #{tree[1] ? to_c(tree[1]) : "Qnil"};
853
+ longjmp(pframe->jmp,FASTRUBY_TAG_NEXT);
854
+ return Qnil;
855
+ "
856
+ else
857
+ _raise("rb_eLocalJumpError","illegal next");
858
+ end
859
+ end
860
+
861
+ def to_c_lit(tree)
862
+ literal_value tree[1]
863
+ end
864
+
865
+ def to_c_nil(tree)
866
+ "Qnil"
867
+ end
868
+
869
+ def to_c_str(tree)
870
+ literal_value tree[1]
871
+ end
872
+
873
+ def to_c_hash(tree)
874
+
875
+ hash_aset_code = ""
876
+ (0..(tree.size-3)/2).each do |i|
877
+ strkey = to_c tree[1 + i * 2]
878
+ strvalue = to_c tree[2 + i * 2]
879
+ hash_aset_code << "rb_hash_aset(hash, #{strkey}, #{strvalue});"
880
+ end
881
+
882
+ anonymous_function{ |name| "
883
+ static VALUE #{name}(VALUE value_params) {
884
+ #{@frame_struct} *pframe;
885
+ #{@locals_struct} *plocals;
886
+ pframe = (void*)value_params;
887
+ plocals = (void*)pframe->plocals;
888
+
889
+ VALUE hash = rb_hash_new();
890
+ #{hash_aset_code}
891
+ return hash;
892
+ }
893
+ " } + "((VALUE)pframe)"
894
+ end
895
+
896
+ def to_c_array(tree)
897
+ if tree.size > 1
898
+ strargs = tree[1..-1].map{|subtree| to_c subtree}.join(",")
899
+ "rb_ary_new3(#{tree.size-1}, #{strargs})"
900
+ else
901
+ "rb_ary_new3(0)"
902
+ end
903
+ end
904
+
905
+ def to_c_scope(tree)
906
+ if tree[1]
907
+ to_c(tree[1])
908
+ else
909
+ "Qnil"
910
+ end
911
+ end
912
+
913
+ def to_c_cdecl(tree)
914
+ if tree[1].instance_of? Symbol
915
+ inline_block "
916
+ // set constant #{tree[1].to_s}
917
+ VALUE val = #{to_c tree[2]};
918
+ rb_const_set(rb_cObject, #{intern_num tree[1]}, val);
919
+ return val;
920
+ "
921
+ elsif tree[1].instance_of? FastRuby::FastRubySexp
922
+
923
+ if tree[1].node_type == :colon2
924
+ inline_block "
925
+ // set constant #{tree[1].to_s}
926
+ VALUE val = #{to_c tree[2]};
927
+ VALUE klass = #{to_c tree[1][1]};
928
+ rb_const_set(klass, #{intern_num tree[1][2]}, val);
929
+ return val;
930
+ "
931
+ elsif tree[1].node_type == :colon3
932
+ inline_block "
933
+ // set constant #{tree[1].to_s}
934
+ VALUE val = #{to_c tree[2]};
935
+ rb_const_set(rb_cObject, #{intern_num tree[1][1]}, val);
936
+ return val;
937
+ "
938
+ end
939
+ end
940
+ end
941
+
942
+ def to_c_case(tree)
943
+
944
+ tmpvarname = "tmp" + rand(1000000).to_s;
945
+
946
+ code = tree[2..-2].map{|subtree|
947
+
948
+ # this subtree is a when
949
+ subtree[1][1..-1].map{|subsubtree|
950
+ c_calltree = s(:call, nil, :inline_c, s(:arglist, s(:str, tmpvarname), s(:false)))
951
+ calltree = s(:call, subsubtree, :===, s(:arglist, c_calltree))
952
+ "
953
+ if (RTEST(#{to_c_call(calltree, tmpvarname)})) {
954
+ return #{to_c(subtree[2])};
955
+ }
956
+
957
+ "
958
+ }.join("\n")
959
+
960
+ }.join("\n")
961
+
962
+ inline_block "
963
+
964
+ VALUE #{tmpvarname} = #{to_c tree[1]};
965
+
966
+ #{code};
967
+
968
+ return #{to_c tree[-1]};
969
+ "
970
+ end
971
+
972
+ def to_c_const(tree)
973
+ "rb_const_get(CLASS_OF(plocals->self), #{intern_num(tree[1])})"
974
+ end
975
+
976
+ def to_c_defn(tree)
977
+
978
+ method_name = tree[1]
979
+ args_tree = tree[2]
980
+
981
+ global_klass_variable = add_global_name("VALUE", "Qnil");
982
+
983
+ hash = Hash.new
984
+ value_cast = ( ["VALUE"]*(args_tree.size+2) ).join(",")
985
+
986
+ strmethodargs = ""
987
+ strmethodargs_class = (["self"] + args_tree[1..-1]).map{|arg| "CLASS_OF(#{arg.to_s})"}.join(",")
988
+
989
+ if args_tree.size > 1
990
+ strmethodargs = "self,block,(VALUE)&frame,#{args_tree[1..-1].map(&:to_s).join(",") }"
991
+ else
992
+ strmethodargs = "self,block,(VALUE)&frame"
993
+ end
994
+
995
+ strmethod_signature = (["self"] + args_tree[1..-1]).map { |arg|
996
+ "sprintf(method_name+strlen(method_name), \"%lu\", FIX2LONG(rb_obj_id(CLASS_OF(#{arg}))));\n"
997
+ }.join
998
+
999
+ anonymous_method_name = anonymous_function{ |anonymous_method_name| "VALUE #{anonymous_method_name}(#{(["self"]+args_tree[1..-1]).map{|arg| "VALUE #{arg}" }.join(",")}) {
1000
+
1001
+ VALUE klass = #{global_klass_variable};
1002
+ char method_name[0x100];
1003
+
1004
+ method_name[0] = '_';
1005
+ method_name[1] = 0;
1006
+
1007
+ sprintf(method_name+1, \"#{method_name}\");
1008
+ #{strmethod_signature}
1009
+
1010
+ NODE* body;
1011
+ ID id;
1012
+
1013
+ id = rb_intern(method_name);
1014
+ body = rb_method_node(klass,id);
1015
+
1016
+ if (body == 0) {
1017
+ VALUE argv_class[] = {#{strmethodargs_class} };
1018
+ VALUE signature = rb_ary_new4(#{args_tree.size},argv_class);
1019
+
1020
+ VALUE mobject = rb_funcall(#{global_klass_variable}, #{intern_num :build}, 2, signature,rb_str_new2(#{method_name.to_s.inspect}));
1021
+
1022
+ struct METHOD {
1023
+ VALUE klass, rklass;
1024
+ VALUE recv;
1025
+ ID id, oid;
1026
+ int safe_level;
1027
+ NODE *body;
1028
+ };
1029
+
1030
+ struct METHOD *data;
1031
+ Data_Get_Struct(mobject, struct METHOD, data);
1032
+ body = data->body;
1033
+
1034
+ if (body == 0) {
1035
+ rb_raise(rb_eRuntimeError,\"method not found after build: '%s'\", method_name);
1036
+ }
1037
+ }
1038
+
1039
+ if (nd_type(body) == NODE_CFUNC) {
1040
+ struct {
1041
+ void* parent_frame;
1042
+ void* plocals;
1043
+ jmp_buf jmp;
1044
+ VALUE return_value;
1045
+ int rescue;
1046
+ VALUE last_error;
1047
+ VALUE next_recv;
1048
+ int targetted;
1049
+ struct FASTRUBYTHREADDATA* thread_data;
1050
+ } frame;
1051
+
1052
+ frame.parent_frame = 0;
1053
+ frame.rescue = 0;
1054
+ frame.return_value = Qnil;
1055
+ frame.thread_data = rb_current_thread_data();
1056
+ frame.targetted = 0;
1057
+
1058
+ int argc = body->nd_argc;
1059
+
1060
+ VALUE block = Qfalse;
1061
+
1062
+ if (rb_block_given_p()) {
1063
+ struct {
1064
+ void *block_function_address;
1065
+ void *block_function_param;
1066
+ } block_struct;
1067
+
1068
+ block_struct.block_function_address = re_yield;
1069
+ block_struct.block_function_param = 0;
1070
+
1071
+ block = (VALUE)&block_struct;
1072
+ }
1073
+
1074
+ int aux = setjmp(frame.jmp);
1075
+ if (aux != 0) {
1076
+ if (aux == FASTRUBY_TAG_RAISE) {
1077
+ rb_funcall(self, #{intern_num :raise}, 1, frame.thread_data->exception);
1078
+ }
1079
+
1080
+ if (frame.targetted == 0) {
1081
+ rb_jump_tag(aux);
1082
+ }
1083
+
1084
+ return Qnil;
1085
+ }
1086
+
1087
+ if (argc == #{args_tree.size+1}) {
1088
+ return ((VALUE(*)(#{value_cast}))body->nd_cfnc)(#{strmethodargs});
1089
+ } else if (argc == -1) {
1090
+ VALUE argv[] = {#{(["block,(VALUE)&frame"]+args_tree[1..-1]).map(&:to_s).join(",")} };
1091
+ return ((VALUE(*)(int,VALUE*,VALUE))body->nd_cfnc)(#{args_tree.size},argv,self);
1092
+ } else if (argc == -2) {
1093
+ VALUE argv[] = {#{(["block,(VALUE)&frame"]+args_tree[1..-1]).map(&:to_s).join(",")} };
1094
+ return ((VALUE(*)(VALUE,VALUE))body->nd_cfnc)(self, rb_ary_new4(#{args_tree.size},argv));
1095
+ } else {
1096
+ rb_raise(rb_eArgError, \"wrong number of arguments (#{args_tree.size-1} for %d)\", argc);
1097
+ }
1098
+ }
1099
+
1100
+ return Qnil;
1101
+ }"
1102
+ }
1103
+
1104
+ alt_options = options.dup
1105
+
1106
+ alt_options.delete(:self)
1107
+ alt_options.delete(:main)
1108
+
1109
+ inline_block "
1110
+ #{global_klass_variable} = plocals->self;
1111
+
1112
+ // set tree
1113
+ rb_funcall(#{literal_value FastRuby}, #{intern_num :set_tree}, 5,
1114
+ #{global_klass_variable},
1115
+ rb_str_new2(#{method_name.to_s.inspect}),
1116
+ #{literal_value tree},
1117
+ #{literal_value snippet_hash},
1118
+ #{literal_value alt_options}
1119
+
1120
+ );
1121
+
1122
+ rb_define_method(plocals->self, #{method_name.to_s.inspect}, #{anonymous_method_name}, #{args_tree.size-1} );
1123
+ "
1124
+
1125
+ end
1126
+
1127
+ def to_c_defs(tree)
1128
+ args_tree = tree[3];
1129
+
1130
+ tmp = FastRuby.build_defs(tree)
1131
+
1132
+ extra_code << tmp[0]
1133
+ @init_extra = @init_extra + tmp[2]
1134
+
1135
+ inline_block "
1136
+ rb_define_singleton_method(#{to_c tree[1]}, \"#{tree[2].to_s}\", (void*)#{tmp[1]}, #{args_tree.size-1});
1137
+ return Qnil;
1138
+ "
1139
+ end
1140
+
1141
+ def to_c_defined(tree)
1142
+ nt = tree[1].node_type
1143
+
1144
+ if nt == :self
1145
+ 'rb_str_new2("self")'
1146
+ elsif nt == :true
1147
+ 'rb_str_new2("true")'
1148
+ elsif nt == :false
1149
+ 'rb_str_new2("false")'
1150
+ elsif nt == :nil
1151
+ 'rb_str_new2("nil")'
1152
+ elsif nt == :lvar
1153
+ 'rb_str_new2("local-variable")'
1154
+ elsif nt == :gvar
1155
+ "rb_gvar_defined((struct global_entry*)#{global_entry(tree[1][1])}) ? #{literal_value "global-variable"} : Qnil"
1156
+ elsif nt == :const
1157
+ "rb_const_defined(rb_cObject, #{intern_num tree[1][1]}) ? #{literal_value "constant"} : Qnil"
1158
+ elsif nt == :call
1159
+ "rb_method_node(CLASS_OF(#{to_c tree[1][1]}), #{intern_num tree[1][2]}) ? #{literal_value "method"} : Qnil"
1160
+ elsif nt == :yield
1161
+ "rb_block_given_p() ? #{literal_value "yield"} : Qnil"
1162
+ elsif nt == :ivar
1163
+ "rb_ivar_defined(plocals->self,#{intern_num tree[1][1]}) ? #{literal_value "instance-variable"} : Qnil"
1164
+ elsif nt == :attrset or
1165
+ nt == :op_asgn1 or
1166
+ nt == :op_asgn2 or
1167
+ nt == :op_asgn_or or
1168
+ nt == :op_asgn_and or
1169
+ nt == :op_asgn_masgn or
1170
+ nt == :masgn or
1171
+ nt == :lasgn or
1172
+ nt == :dasgn or
1173
+ nt == :dasgn_curr or
1174
+ nt == :gasgn or
1175
+ nt == :iasgn or
1176
+ nt == :cdecl or
1177
+ nt == :cvdecl or
1178
+ nt == :cvasgn
1179
+ literal_value "assignment"
1180
+ else
1181
+ literal_value "expression"
1182
+ end
1183
+ end
1184
+
1185
+ def initialize_method_structs(args_tree)
1186
+ @locals_struct = "struct {
1187
+ VALUE return_value;
1188
+ VALUE pframe;
1189
+ VALUE block_function_address;
1190
+ VALUE block_function_param;
1191
+ VALUE call_frame;
1192
+ VALUE active;
1193
+ #{@locals.map{|l| "VALUE #{l};\n"}.join}
1194
+ #{args_tree[1..-1].map{|arg| "VALUE #{arg};\n"}.join};
1195
+ }"
1196
+
1197
+ end
1198
+
1199
+ def to_c_method_defs(tree)
1200
+
1201
+ method_name = tree[2]
1202
+ args_tree = tree[3]
1203
+
1204
+ impl_tree = tree[4][1]
1205
+
1206
+ initialize_method_structs(args_tree)
1207
+
1208
+ strargs = if args_tree.size > 1
1209
+ "VALUE self, void* block_address, VALUE block_param, void* _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
1210
+ else
1211
+ "VALUE self, void* block_address, VALUE block_param, void* _parent_frame"
1212
+ end
1213
+
1214
+ extra_code << "static VALUE #{@alt_method_name + "_real"}(#{strargs}) {
1215
+ #{func_frame}
1216
+
1217
+ #{args_tree[1..-1].map { |arg|
1218
+ "plocals->#{arg} = #{arg};\n"
1219
+ }.join("") }
1220
+
1221
+ plocals->block_function_address = LONG2FIX(block_address);
1222
+ plocals->block_function_param = LONG2FIX(block_param);
1223
+
1224
+ return #{to_c impl_tree};
1225
+ }"
1226
+
1227
+ strargs2 = if args_tree.size > 1
1228
+ "VALUE self, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
1229
+ else
1230
+ "VALUE self"
1231
+ end
1232
+
1233
+ value_cast = ( ["VALUE"]*(args_tree.size+1) ).join(",")
1234
+ strmethodargs = ""
1235
+
1236
+ if args_tree.size > 1
1237
+ strmethodargs = "self,block_address,block_param,&frame,#{args_tree[1..-1].map(&:to_s).join(",") }"
1238
+ else
1239
+ strmethodargs = "self,block_address,block_param,&frame"
1240
+ end
1241
+
1242
+ "
1243
+ VALUE #{@alt_method_name}(#{strargs2}) {
1244
+ #{@frame_struct} frame;
1245
+ int argc = #{args_tree.size};
1246
+ void* block_address = 0;
1247
+ VALUE block_param = Qnil;
1248
+
1249
+ frame.plocals = 0;
1250
+ frame.parent_frame = 0;
1251
+ frame.return_value = Qnil;
1252
+ frame.rescue = 0;
1253
+ frame.targetted = 0;
1254
+ frame.thread_data = rb_current_thread_data();
1255
+
1256
+ if (rb_block_given_p()) {
1257
+ block_address = #{
1258
+ anonymous_function{|name|
1259
+ "static VALUE #{name}(int argc, VALUE* argv, VALUE param) {
1260
+ return rb_yield_splat(rb_ary_new4(argc,argv));
1261
+ }"
1262
+ }
1263
+ };
1264
+
1265
+ block_param = 0;
1266
+ }
1267
+
1268
+ int aux = setjmp(frame.jmp);
1269
+ if (aux != 0) {
1270
+ rb_funcall(self, #{intern_num :raise}, 1, frame.thread_data->exception);
1271
+ }
1272
+
1273
+
1274
+ return #{@alt_method_name + "_real"}(#{strmethodargs});
1275
+ }
1276
+ "
1277
+ end
1278
+
1279
+ def add_main
1280
+ if options[:main]
1281
+
1282
+ extra_code << "
1283
+ static VALUE #{@alt_method_name}(VALUE self__);
1284
+ static VALUE main_proc_call(VALUE self__, VALUE class_self_) {
1285
+ #{@alt_method_name}(class_self_);
1286
+ return Qnil;
1287
+ }
1288
+
1289
+ "
1290
+
1291
+ init_extra << "
1292
+ {
1293
+ VALUE newproc = rb_funcall(rb_cObject,#{intern_num :new},0);
1294
+ rb_define_singleton_method(newproc, \"call\", main_proc_call, 1);
1295
+ rb_gv_set(\"$last_obj_proc\", newproc);
1296
+
1297
+ }
1298
+ "
1299
+ end
1300
+ end
1301
+
1302
+ def define_method_at_init(klass,method_name, size, signature)
1303
+ init_extra << "
1304
+ {
1305
+ VALUE method_name = rb_funcall(
1306
+ #{literal_value FastRuby},
1307
+ #{intern_num :make_str_signature},
1308
+ 2,
1309
+ #{literal_value method_name},
1310
+ #{literal_value signature}
1311
+ );
1312
+
1313
+ rb_define_method(#{literal_value klass}, RSTRING(method_name)->ptr, #{alt_method_name}, #{size});
1314
+ }
1315
+ "
1316
+ end
1317
+
1318
+ def to_c_method(tree)
1319
+ method_name = tree[1]
1320
+ args_tree = tree[2]
1321
+ impl_tree = tree[3][1]
1322
+
1323
+ if (options[:main])
1324
+ initialize_method_structs(args_tree)
1325
+
1326
+ strargs = if args_tree.size > 1
1327
+ "VALUE block, VALUE _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
1328
+ else
1329
+ "VALUE block, VALUE _parent_frame"
1330
+ end
1331
+
1332
+ ret = "VALUE #{@alt_method_name || method_name}() {
1333
+
1334
+ #{@locals_struct} *plocals;
1335
+ #{@frame_struct} frame;
1336
+ #{@frame_struct} *pframe;
1337
+
1338
+ frame.parent_frame = 0;
1339
+ frame.return_value = Qnil;
1340
+ frame.rescue = 0;
1341
+ frame.targetted = 0;
1342
+ frame.thread_data = rb_current_thread_data();
1343
+
1344
+
1345
+ int stack_chunk_instantiated = 0;
1346
+ VALUE rb_previous_stack_chunk = Qnil;
1347
+ VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
1348
+ struct STACKCHUNK* stack_chunk = 0;
1349
+
1350
+ if (rb_stack_chunk != Qnil) {
1351
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
1352
+ }
1353
+
1354
+ if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
1355
+ rb_previous_stack_chunk = rb_stack_chunk;
1356
+ rb_gc_register_address(&rb_stack_chunk);
1357
+ stack_chunk_instantiated = 1;
1358
+
1359
+ rb_stack_chunk = rb_stack_chunk_create(Qnil);
1360
+ frame.thread_data->rb_stack_chunk = rb_stack_chunk;
1361
+
1362
+ rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
1363
+
1364
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
1365
+ }
1366
+
1367
+ int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
1368
+
1369
+ plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
1370
+ plocals->active = Qtrue;
1371
+ plocals->pframe = LONG2FIX(&frame);
1372
+ frame.plocals = plocals;
1373
+
1374
+ pframe = (void*)&frame;
1375
+
1376
+ VALUE last_expression = Qnil;
1377
+
1378
+ int aux = setjmp(pframe->jmp);
1379
+ if (aux != 0) {
1380
+ stack_chunk_set_current_position(stack_chunk, previous_stack_position);
1381
+
1382
+ if (stack_chunk_instantiated) {
1383
+ rb_gc_unregister_address(&rb_stack_chunk);
1384
+ frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
1385
+ }
1386
+
1387
+ plocals->active = Qfalse;
1388
+ return plocals->return_value;
1389
+ }
1390
+
1391
+ plocals->self = self;
1392
+
1393
+ #{args_tree[1..-1].map { |arg|
1394
+ "plocals->#{arg} = #{arg};\n"
1395
+ }.join("") }
1396
+
1397
+ plocals->block_function_address = LONG2FIX(0);
1398
+ plocals->block_function_param = LONG2FIX(Qnil);
1399
+ plocals->call_frame = LONG2FIX(0);
1400
+
1401
+ VALUE ret = #{to_c impl_tree};
1402
+ stack_chunk_set_current_position(stack_chunk, previous_stack_position);
1403
+
1404
+ if (stack_chunk_instantiated) {
1405
+ rb_gc_unregister_address(&rb_stack_chunk);
1406
+ frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
1407
+ }
1408
+
1409
+ plocals->active = Qfalse;
1410
+ return ret;
1411
+
1412
+ }"
1413
+
1414
+ add_main
1415
+ ret
1416
+ else
1417
+
1418
+ initialize_method_structs(args_tree)
1419
+
1420
+ strargs = if args_tree.size > 1
1421
+ "VALUE block, VALUE _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
1422
+ else
1423
+ "VALUE block, VALUE _parent_frame"
1424
+ end
1425
+
1426
+ ret = "VALUE #{@alt_method_name || method_name}(#{strargs}) {
1427
+
1428
+ #{@frame_struct} frame;
1429
+ #{@frame_struct} *pframe;
1430
+
1431
+ frame.parent_frame = (void*)_parent_frame;
1432
+ frame.return_value = Qnil;
1433
+ frame.rescue = 0;
1434
+ frame.targetted = 0;
1435
+ frame.thread_data = ((typeof(pframe))_parent_frame)->thread_data;
1436
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
1437
+
1438
+ int stack_chunk_instantiated = 0;
1439
+ VALUE rb_previous_stack_chunk = Qnil;
1440
+ VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
1441
+ struct STACKCHUNK* stack_chunk = 0;
1442
+
1443
+ if (rb_stack_chunk != Qnil) {
1444
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
1445
+ }
1446
+
1447
+ if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
1448
+ rb_previous_stack_chunk = rb_stack_chunk;
1449
+ rb_gc_register_address(&rb_stack_chunk);
1450
+ stack_chunk_instantiated = 1;
1451
+
1452
+ rb_stack_chunk = rb_stack_chunk_create(Qnil);
1453
+ frame.thread_data->rb_stack_chunk = rb_stack_chunk;
1454
+
1455
+ rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
1456
+
1457
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
1458
+ }
1459
+
1460
+
1461
+ #{@locals_struct} *plocals;
1462
+
1463
+ int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
1464
+
1465
+ plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
1466
+ frame.plocals = plocals;
1467
+ plocals->active = Qtrue;
1468
+ plocals->pframe = LONG2FIX(&frame);
1469
+ plocals->call_frame = LONG2FIX(0);
1470
+
1471
+ pframe = (void*)&frame;
1472
+
1473
+ #{@block_struct} *pblock;
1474
+ VALUE last_expression = Qnil;
1475
+
1476
+ int aux = setjmp(pframe->jmp);
1477
+ if (aux != 0) {
1478
+ plocals->active = Qfalse;
1479
+
1480
+ stack_chunk_set_current_position(stack_chunk, previous_stack_position);
1481
+
1482
+ if (stack_chunk_instantiated) {
1483
+ rb_gc_unregister_address(&rb_stack_chunk);
1484
+ frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
1485
+ }
1486
+
1487
+ if (pframe->targetted == 0) {
1488
+ longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
1489
+ }
1490
+
1491
+ return plocals->return_value;
1492
+ }
1493
+
1494
+ plocals->self = self;
1495
+
1496
+ #{args_tree[1..-1].map { |arg|
1497
+ "plocals->#{arg} = #{arg};\n"
1498
+ }.join("") }
1499
+
1500
+ pblock = (void*)block;
1501
+ if (pblock) {
1502
+ plocals->block_function_address = LONG2FIX(pblock->block_function_address);
1503
+ plocals->block_function_param = LONG2FIX(pblock->block_function_param);
1504
+ } else {
1505
+ plocals->block_function_address = LONG2FIX(0);
1506
+ plocals->block_function_param = LONG2FIX(Qnil);
1507
+ }
1508
+
1509
+ VALUE __ret = #{to_c impl_tree};
1510
+ stack_chunk_set_current_position(stack_chunk, previous_stack_position);
1511
+
1512
+ if (stack_chunk_instantiated) {
1513
+ rb_gc_unregister_address(&rb_stack_chunk);
1514
+ frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
1515
+ }
1516
+
1517
+ plocals->active = Qfalse;
1518
+ return __ret;
1519
+ }"
1520
+
1521
+ add_main
1522
+ ret
1523
+ end
1524
+ end
1525
+
1526
+ def locals_accessor
1527
+ "plocals->"
1528
+ end
1529
+
1530
+ def to_c_gvar(tree)
1531
+ if (tree[1] == :$!)
1532
+ "pframe->thread_data->exception"
1533
+ else
1534
+ "rb_gvar_get((struct global_entry*)#{global_entry(tree[1])})"
1535
+ end
1536
+ end
1537
+
1538
+ def to_c_gasgn(tree)
1539
+ "_rb_gvar_set((void*)#{global_entry(tree[1])}, #{to_c tree[2]})"
1540
+ end
1541
+
1542
+ def to_c_ivar(tree)
1543
+ "rb_ivar_get(#{locals_accessor}self,#{intern_num tree[1]})"
1544
+ end
1545
+
1546
+ def to_c_iasgn(tree)
1547
+ "_rb_ivar_set(#{locals_accessor}self,#{intern_num tree[1]},#{to_c tree[2]})"
1548
+ end
1549
+
1550
+ def to_c_colon3(tree)
1551
+ "rb_const_get_from(rb_cObject, #{intern_num tree[1]})"
1552
+ end
1553
+ def to_c_colon2(tree)
1554
+ inline_block "
1555
+ VALUE klass = #{to_c tree[1]};
1556
+
1557
+ if (rb_is_const_id(#{intern_num tree[2]})) {
1558
+ switch (TYPE(klass)) {
1559
+ case T_CLASS:
1560
+ case T_MODULE:
1561
+ return rb_const_get_from(klass, #{intern_num tree[2]});
1562
+ break;
1563
+ default:
1564
+ #{_raise("rb_eTypeError","not a class/module")};
1565
+ break;
1566
+ }
1567
+ }
1568
+ else {
1569
+ return rb_funcall(klass, #{intern_num tree[2]}, 0, 0);
1570
+ }
1571
+
1572
+ return Qnil;
1573
+ "
1574
+ end
1575
+
1576
+ def to_c_lasgn(tree)
1577
+ if options[:validate_lvar_types]
1578
+ klass = @infer_lvar_map[tree[1]]
1579
+ if klass
1580
+
1581
+ verify_type_function = proc { |name| "
1582
+ static VALUE #{name}(VALUE arg, void* pframe ) {
1583
+ if (CLASS_OF(arg)!=#{literal_value klass}) {
1584
+ #{_raise(literal_value(FastRuby::TypeMismatchAssignmentException), "Illegal assignment at runtime (type mismatch)")};
1585
+ }
1586
+ return arg;
1587
+ }
1588
+ "
1589
+ }
1590
+
1591
+
1592
+ "_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(&verify_type_function)}(#{to_c tree[2]},pframe))"
1593
+ else
1594
+ "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
1595
+ end
1596
+ else
1597
+ "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
1598
+ end
1599
+ end
1600
+
1601
+ def to_c_lvar(tree)
1602
+ locals_accessor + tree[1].to_s
1603
+ end
1604
+
1605
+ def to_c_self(tree)
1606
+ locals_accessor + "self"
1607
+ end
1608
+
1609
+ def to_c_false(tree)
1610
+ "Qfalse"
1611
+ end
1612
+
1613
+ def to_c_true(tree)
1614
+ "Qtrue"
1615
+ end
1616
+
1617
+ def to_c_and(tree)
1618
+ "(RTEST(#{to_c tree[1]}) && RTEST(#{to_c tree[2]})) ? Qtrue : Qfalse"
1619
+ end
1620
+
1621
+ def to_c_or(tree)
1622
+ "(RTEST(#{to_c tree[1]}) || RTEST(#{to_c tree[2]})) ? Qtrue : Qfalse"
1623
+ end
1624
+
1625
+ def to_c_not(tree)
1626
+ "RTEST(#{to_c tree[1]}) ? Qfalse : Qtrue"
1627
+ end
1628
+
1629
+ def to_c_if(tree)
1630
+ condition_tree = tree[1]
1631
+ impl_tree = tree[2]
1632
+ else_tree = tree[3]
1633
+
1634
+ inline_block "
1635
+ if (RTEST(#{to_c condition_tree})) {
1636
+ last_expression = #{to_c impl_tree};
1637
+ }#{else_tree ?
1638
+ " else {
1639
+ last_expression = #{to_c else_tree};
1640
+ }
1641
+ " : ""
1642
+ }
1643
+
1644
+ return last_expression;
1645
+ "
1646
+ end
1647
+
1648
+ def to_c_rescue(tree)
1649
+ if tree[1][0] == :resbody
1650
+ else_tree = tree[2]
1651
+
1652
+ if else_tree
1653
+ to_c else_tree
1654
+ else
1655
+ "Qnil"
1656
+ end
1657
+ else
1658
+ resbody_tree = tree[2]
1659
+ else_tree = nil
1660
+ if tree[-1]
1661
+ if tree[-1][0] != :resbody
1662
+ else_tree = tree[-1]
1663
+ end
1664
+ end
1665
+
1666
+ catch_condition_array = []
1667
+ lasgn_code = ""
1668
+ resbody_code = to_c(resbody_tree[2])
1669
+
1670
+ rescue_code = ""
1671
+
1672
+ tree[1..-1].each do |resbody_tree|
1673
+ next if resbody_tree[0] != :resbody
1674
+
1675
+ if resbody_tree[1].size == 1
1676
+ resbody_tree[1][1] = [:const, :Exception]
1677
+ end
1678
+
1679
+ if resbody_tree[1].last[0] == :lasgn
1680
+ lasgn_code = to_c(resbody_tree[1].last)
1681
+ end
1682
+
1683
+ resbody_tree[1][1..-1].each do |xtree|
1684
+ if xtree[0] != :lasgn
1685
+ trapcode = "rb_eException";
1686
+
1687
+ if xtree
1688
+ trapcode = to_c(xtree)
1689
+ end
1690
+
1691
+ catch_condition_array << "(rb_obj_is_kind_of(frame.thread_data->exception,#{trapcode}) == Qtrue)"
1692
+ end
1693
+ end
1694
+
1695
+ rescue_code << "
1696
+ if (aux == FASTRUBY_TAG_RAISE) {
1697
+ if (#{catch_condition_array.join(" || ")})
1698
+ {
1699
+ // trap exception
1700
+ frame.targetted = 1;
1701
+
1702
+ #{lasgn_code};
1703
+
1704
+ #{resbody_code};
1705
+ }
1706
+ }
1707
+ "
1708
+ end
1709
+
1710
+ frame_call(
1711
+ frame(to_c(tree[1])+";","
1712
+ #{rescue_code}
1713
+ ", else_tree ? to_c(else_tree) : nil, 1)
1714
+
1715
+ )
1716
+ end
1717
+ end
1718
+
1719
+ def to_c_ensure(tree)
1720
+ if tree.size == 2
1721
+ to_c tree[1]
1722
+ else
1723
+ ensured_code = to_c tree[2]
1724
+ inline_block "
1725
+ #{frame(to_c(tree[1]),ensured_code,ensured_code,1)};
1726
+ "
1727
+ end
1728
+ end
1729
+
1730
+ def _raise(class_tree, message_tree = nil)
1731
+ class_tree = to_c class_tree unless class_tree.instance_of? String
1732
+
1733
+ if message_tree.instance_of? String
1734
+ message_tree = "rb_str_new2(#{message_tree.inspect})"
1735
+ else
1736
+ message_tree = to_c message_tree
1737
+ end
1738
+
1739
+ if message_tree
1740
+ return inline_block("
1741
+ pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},1,#{message_tree});
1742
+ longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
1743
+ return Qnil;
1744
+ ")
1745
+ else
1746
+ return inline_block("
1747
+ pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},0);
1748
+ longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
1749
+ return Qnil;
1750
+ ")
1751
+ end
1752
+
1753
+ end
1754
+
1755
+ def to_c_call(tree, repass_var = nil)
1756
+ directive_code = directive(tree)
1757
+ if directive_code
1758
+ return directive_code
1759
+ end
1760
+
1761
+ if tree[2] == :require
1762
+ tree[2] = :fastruby_require
1763
+ elsif tree[2] == :raise
1764
+ # raise code
1765
+ args = tree[3]
1766
+ return _raise(args[1],args[2])
1767
+ end
1768
+
1769
+ recv = tree[1]
1770
+ mname = tree[2]
1771
+ args = tree[3]
1772
+
1773
+ mname = :require_fastruby if mname == :require
1774
+
1775
+ strargs = args[1..-1].map{|arg| to_c arg}.join(",")
1776
+
1777
+ argnum = args.size - 1
1778
+
1779
+ recv = recv || s(:self)
1780
+
1781
+ recvtype = infer_type(recv)
1782
+
1783
+ if recvtype
1784
+
1785
+ address = nil
1786
+ mobject = nil
1787
+
1788
+ inference_complete = true
1789
+ signature = [recvtype]
1790
+
1791
+ args[1..-1].each do |arg|
1792
+ argtype = infer_type(arg)
1793
+ if argtype
1794
+ signature << argtype
1795
+ else
1796
+ inference_complete = false
1797
+ end
1798
+ end
1799
+
1800
+ if repass_var
1801
+ extraargs = ","+repass_var
1802
+ extraargs_signature = ",VALUE " + repass_var
1803
+ else
1804
+ extraargs = ""
1805
+ extraargs_signature = ""
1806
+ end
1807
+
1808
+ if argnum == 0
1809
+ value_cast = "VALUE,VALUE,VALUE"
1810
+ "((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(#{to_c recv}, Qfalse, (VALUE)pframe)"
1811
+ else
1812
+ value_cast = ( ["VALUE"]*(args.size) ).join(",") + ",VALUE,VALUE"
1813
+ "((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(#{to_c recv}, Qfalse, (VALUE)pframe, #{strargs})"
1814
+ end
1815
+
1816
+ else # else recvtype
1817
+ if argnum == 0
1818
+ protected_block("rb_funcall(#{to_c recv}, #{intern_num tree[2]}, 0)", true, repass_var)
1819
+ else
1820
+ protected_block("rb_funcall(#{to_c recv}, #{intern_num tree[2]}, #{argnum}, #{strargs} )", true, repass_var)
1821
+ end
1822
+ end # if recvtype
1823
+ end
1824
+
1825
+ def get_class_name(argument)
1826
+ if argument.instance_of? Symbol
1827
+ argument.to_s
1828
+ elsif argument.instance_of? FastRuby::FastRubySexp
1829
+ if argument[0] == :colon3
1830
+ get_class_name(argument[1])
1831
+ elsif argument[0] == :colon2
1832
+ get_class_name(argument[2])
1833
+ end
1834
+ end
1835
+ end
1836
+
1837
+ def get_container_tree(argument)
1838
+ if argument.instance_of? Symbol
1839
+ s(:self)
1840
+ elsif argument.instance_of? FastRuby::FastRubySexp
1841
+ if argument[0] == :colon3
1842
+ s(:const, :Object)
1843
+ elsif argument[0] == :colon2
1844
+ argument[1]
1845
+ end
1846
+ end
1847
+ end
1848
+
1849
+ def locals_scope(locals)
1850
+ old_locals = @locals
1851
+ old_locals_struct = @locals_struct
1852
+
1853
+ @locals = locals
1854
+ @locals_struct = "struct {
1855
+ VALUE return_value;
1856
+ VALUE pframe;
1857
+ VALUE block_function_address;
1858
+ VALUE block_function_param;
1859
+ VALUE call_frame;
1860
+ VALUE active;
1861
+ #{@locals.map{|l| "VALUE #{l};\n"}.join}
1862
+ }"
1863
+
1864
+ begin
1865
+ yield
1866
+ ensure
1867
+ @locals = old_locals
1868
+ @locals_struct = old_locals_struct
1869
+ end
1870
+ end
1871
+
1872
+ def method_group(init_code, tree)
1873
+
1874
+ alt_locals = Set.new
1875
+ alt_locals << :self
1876
+
1877
+ FastRuby::GetLocalsProcessor.get_locals(tree).each do |local|
1878
+ alt_locals << local
1879
+ end
1880
+
1881
+ fun = nil
1882
+
1883
+ locals_scope(alt_locals) do
1884
+ fun = anonymous_function { |method_name| "static VALUE #{method_name}(VALUE self) {
1885
+
1886
+ #{@frame_struct} frame;
1887
+ typeof(&frame) pframe = &frame;
1888
+ #{@locals_struct} *plocals;
1889
+
1890
+ frame.parent_frame = 0;
1891
+ frame.return_value = Qnil;
1892
+ frame.rescue = 0;
1893
+ frame.targetted = 0;
1894
+ frame.thread_data = rb_current_thread_data();
1895
+
1896
+ int stack_chunk_instantiated = 0;
1897
+ VALUE rb_previous_stack_chunk = Qnil;
1898
+ VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
1899
+ struct STACKCHUNK* stack_chunk = 0;
1900
+
1901
+ if (rb_stack_chunk != Qnil) {
1902
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
1903
+ }
1904
+
1905
+ if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
1906
+ rb_previous_stack_chunk = rb_stack_chunk;
1907
+ rb_gc_register_address(&rb_stack_chunk);
1908
+ stack_chunk_instantiated = 1;
1909
+
1910
+ rb_stack_chunk = rb_stack_chunk_create(Qnil);
1911
+ frame.thread_data->rb_stack_chunk = rb_stack_chunk;
1912
+
1913
+ rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
1914
+
1915
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
1916
+ }
1917
+
1918
+ int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
1919
+
1920
+ plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
1921
+
1922
+ frame.plocals = plocals;
1923
+ plocals->active = Qtrue;
1924
+ plocals->self = self;
1925
+ plocals->call_frame = LONG2FIX(0);
1926
+
1927
+ #{to_c tree};
1928
+
1929
+ stack_chunk_set_current_position(stack_chunk, previous_stack_position);
1930
+
1931
+ if (stack_chunk_instantiated) {
1932
+ rb_gc_unregister_address(&rb_stack_chunk);
1933
+ frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
1934
+ }
1935
+
1936
+ plocals->active = Qfalse;
1937
+ return Qnil;
1938
+ }
1939
+ "
1940
+ }
1941
+ end
1942
+
1943
+ inline_block("
1944
+ #{init_code}
1945
+
1946
+ rb_funcall(tmpklass, #{intern_num :__id__},0);
1947
+
1948
+ #{fun}(tmpklass);
1949
+ return Qnil;
1950
+
1951
+
1952
+ ")
1953
+
1954
+ end
1955
+
1956
+
1957
+
1958
+ def to_c_class(tree)
1959
+ str_class_name = get_class_name(tree[1])
1960
+ container_tree = get_container_tree(tree[1])
1961
+
1962
+ if container_tree == s(:self)
1963
+ method_group("
1964
+ VALUE tmpklass = rb_define_class(
1965
+ #{str_class_name.inspect},
1966
+ #{tree[2] ? to_c(tree[2]) : "rb_cObject"}
1967
+ );
1968
+ ", tree[3])
1969
+ else
1970
+ method_group("
1971
+ VALUE container_klass = #{to_c(container_tree)};
1972
+ VALUE tmpklass = rb_define_class_under(
1973
+ container_klass,
1974
+ #{str_class_name.inspect},
1975
+ #{tree[2] ? to_c(tree[2]) : "rb_cObject"}
1976
+ );
1977
+ ", tree[3])
1978
+ end
1979
+ end
1980
+
1981
+ def to_c_module(tree)
1982
+ str_class_name = get_class_name(tree[1])
1983
+ container_tree = get_container_tree(tree[1])
1984
+
1985
+ if container_tree == s(:self)
1986
+ method_group("
1987
+ VALUE tmpklass = rb_define_module(#{str_class_name.inspect});
1988
+ ", tree[2])
1989
+ else
1990
+ method_group("
1991
+ VALUE container_klass = #{to_c(container_tree)};
1992
+ VALUE tmpklass = rb_define_module_under(container_klass,#{str_class_name.inspect});
1993
+ ", tree[2])
1994
+ end
1995
+ end
1996
+
1997
+ def to_c_for(tree)
1998
+ alter_tree = tree.dup
1999
+ alter_tree[0] = :iter
2000
+ alter_tree[1] = [:call, alter_tree[1], :each, [:arglist]]
2001
+ to_c alter_tree
2002
+ end
2003
+
2004
+ def to_c_while(tree)
2005
+ inline_block("
2006
+ while (#{to_c tree[1]}) {
2007
+ #{to_c tree[2]};
2008
+ }
2009
+ return Qnil;
2010
+ ")
2011
+ end
2012
+
2013
+ def infer_type(recv)
2014
+ if recv[0] == :call
2015
+ if recv[2] == :infer
2016
+ eval(recv[3].last.last.to_s)
2017
+ end
2018
+ elsif recv[0] == :lvar
2019
+ @infer_lvar_map[recv[1]]
2020
+ elsif recv[0] == :self
2021
+ @infer_self
2022
+ elsif recv[0] == :str or recv[0] == :lit
2023
+ recv[1].class
2024
+ else
2025
+ nil
2026
+ end
2027
+ end
2028
+
2029
+ def on_block
2030
+ old_on_block = @on_block
2031
+ @on_block = true
2032
+ return yield
2033
+ ensure
2034
+ @on_block = old_on_block
2035
+ end
2036
+
2037
+ def with_extra_inference(extra_inference)
2038
+ previous_infer_lvar_map = @infer_lvar_map
2039
+ begin
2040
+ @infer_lvar_map = @infer_lvar_map.merge(extra_inference)
2041
+ yield
2042
+ ensure
2043
+ @infer_lvar_map = previous_infer_lvar_map
2044
+ end
2045
+ end
2046
+
2047
+ def directive(tree)
2048
+ recv = tree[1]
2049
+ mname = tree[2]
2050
+ args = tree[3]
2051
+
2052
+ if mname == :infer
2053
+ return to_c(recv)
2054
+ elsif mname == :lvar_type
2055
+ lvar_name = args[1][1] || args[1][2]
2056
+ lvar_type = eval(args[2][1].to_s)
2057
+
2058
+ @infer_lvar_map[lvar_name] = lvar_type
2059
+ return ""
2060
+ elsif mname == :block_given?
2061
+ return "FIX2LONG(plocals->block_function_address) == 0 ? Qfalse : Qtrue"
2062
+ elsif mname == :inline_c
2063
+
2064
+ code = args[1][1]
2065
+
2066
+ unless (args[2] == s(:false))
2067
+ return anonymous_function{ |name| "
2068
+ static VALUE #{name}(VALUE param) {
2069
+ #{@frame_struct} *pframe = (void*)param;
2070
+ #{@locals_struct} *plocals = (void*)pframe->plocals;
2071
+ #{code};
2072
+ return Qnil;
2073
+ }
2074
+ "
2075
+ }+"((VALUE)pframe)"
2076
+ else
2077
+ code
2078
+ end
2079
+
2080
+ else
2081
+ nil
2082
+ end
2083
+ end
2084
+
2085
+ def inline_block_reference(arg, nolocals = false)
2086
+ code = nil
2087
+
2088
+ if arg.instance_of? FastRuby::FastRubySexp
2089
+ code = to_c(arg);
2090
+ else
2091
+ code = arg
2092
+ end
2093
+
2094
+ anonymous_function{ |name| "
2095
+ static VALUE #{name}(VALUE param) {
2096
+ #{@frame_struct} *pframe = (void*)param;
2097
+
2098
+ #{nolocals ? "" : "#{@locals_struct} *plocals = (void*)pframe->plocals;"}
2099
+ VALUE last_expression = Qnil;
2100
+
2101
+ #{code};
2102
+ return last_expression;
2103
+ }
2104
+ "
2105
+ }
2106
+ end
2107
+
2108
+ def inline_block(code, repass_var = nil, nolocals = false)
2109
+ anonymous_function{ |name| "
2110
+ static VALUE #{name}(VALUE param#{repass_var ? ",void* " + repass_var : "" }) {
2111
+ #{@frame_struct} *pframe = (void*)param;
2112
+
2113
+ #{nolocals ? "" : "#{@locals_struct} *plocals = (void*)pframe->plocals;"}
2114
+ VALUE last_expression = Qnil;
2115
+
2116
+ #{code}
2117
+ }
2118
+ "
2119
+ } + "((VALUE)pframe#{repass_var ? ", " + repass_var : "" })"
2120
+ end
2121
+
2122
+ def inline_ruby(proced, parameter)
2123
+ "rb_funcall(#{proced.__id__}, #{intern_num :call}, 1, #{parameter})"
2124
+ end
2125
+
2126
+ def protected_block(inner_code, always_rescue = false,repass_var = nil, nolocals = false)
2127
+ body = nil
2128
+ rescue_args = nil
2129
+ if repass_var
2130
+ body = anonymous_function{ |name| "
2131
+ static VALUE #{name}(VALUE param) {
2132
+
2133
+ #{@frame_struct} frame;
2134
+
2135
+ typeof(frame)* pframe;
2136
+ typeof(frame)* parent_frame = ((typeof(pframe))((void**)param)[0]);
2137
+
2138
+ frame.parent_frame = 0;
2139
+ frame.return_value = Qnil;
2140
+ frame.rescue = 0;
2141
+ frame.last_error = Qnil;
2142
+ frame.targetted = 0;
2143
+ frame.thread_data = parent_frame->thread_data;
2144
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
2145
+
2146
+ pframe = &frame;
2147
+
2148
+ #{
2149
+ nolocals ? "frame.plocals = 0;" : "#{@locals_struct}* plocals = parent_frame->plocals;
2150
+ frame.plocals = plocals;
2151
+ "
2152
+ }
2153
+
2154
+ int aux = setjmp(frame.jmp);
2155
+ if (aux != 0) {
2156
+
2157
+ if (frame.targetted == 1) {
2158
+ return frame.return_value;
2159
+ } else {
2160
+ rb_jump_tag(aux);
2161
+ }
2162
+ }
2163
+
2164
+ VALUE #{repass_var} = (VALUE)((void**)param)[1];
2165
+ return #{inner_code};
2166
+ }
2167
+ "
2168
+ }
2169
+
2170
+ rescue_args = ""
2171
+ rescue_args = "(VALUE)(VALUE[]){(VALUE)pframe,(VALUE)#{repass_var}}"
2172
+ else
2173
+
2174
+ body = anonymous_function{ |name| "
2175
+ static VALUE #{name}(VALUE param) {
2176
+ #{@frame_struct} frame;
2177
+
2178
+ typeof(frame)* pframe;
2179
+ typeof(frame)* parent_frame = (typeof(pframe))param;
2180
+
2181
+ frame.parent_frame = 0;
2182
+ frame.return_value = Qnil;
2183
+ frame.rescue = 0;
2184
+ frame.last_error = Qnil;
2185
+ frame.targetted = 0;
2186
+ frame.thread_data = parent_frame->thread_data;
2187
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
2188
+
2189
+ pframe = &frame;
2190
+
2191
+ #{
2192
+ nolocals ? "frame.plocals = 0;" : "#{@locals_struct}* plocals = parent_frame->plocals;
2193
+ frame.plocals = plocals;
2194
+ "
2195
+ }
2196
+
2197
+ int aux = setjmp(frame.jmp);
2198
+ if (aux != 0) {
2199
+
2200
+ if (frame.targetted == 1) {
2201
+ return frame.return_value;
2202
+ } else {
2203
+ rb_jump_tag(aux);
2204
+ }
2205
+ }
2206
+
2207
+ return #{inner_code};
2208
+ }
2209
+ "
2210
+ }
2211
+
2212
+ rescue_args = "(VALUE)pframe"
2213
+ end
2214
+
2215
+ wrapper_code = " if (state != 0) {
2216
+ if (state < 0x80) {
2217
+
2218
+ if (state == TAG_RAISE) {
2219
+ // raise emulation
2220
+ pframe->thread_data->exception = rb_eval_string(\"$!\");
2221
+ longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
2222
+ return Qnil;
2223
+ } else {
2224
+ rb_jump_tag(state);
2225
+ }
2226
+ } else {
2227
+ longjmp(pframe->jmp, state);
2228
+ }
2229
+
2230
+ }
2231
+ "
2232
+
2233
+ rescue_code = "rb_protect(#{body},#{rescue_args},&state)"
2234
+
2235
+ if always_rescue
2236
+ inline_block "
2237
+ int state;
2238
+ pframe->last_error = Qnil;
2239
+ VALUE result = #{rescue_code};
2240
+
2241
+ #{wrapper_code}
2242
+
2243
+ return result;
2244
+ ", repass_var, nolocals
2245
+ else
2246
+ inline_block "
2247
+ VALUE result;
2248
+ int state;
2249
+ pframe->last_error = Qnil;
2250
+
2251
+ if (pframe->rescue) {
2252
+ result = #{rescue_code};
2253
+ #{wrapper_code}
2254
+ } else {
2255
+ return #{inner_code};
2256
+ }
2257
+
2258
+ return result;
2259
+ ", repass_var, nolocals
2260
+ end
2261
+ end
2262
+
2263
+ def func_frame
2264
+ "
2265
+ #{@locals_struct} *plocals = malloc(sizeof(typeof(*plocals)));
2266
+ #{@frame_struct} frame;
2267
+ #{@frame_struct} *pframe;
2268
+
2269
+ frame.plocals = plocals;
2270
+ frame.parent_frame = (void*)_parent_frame;
2271
+ frame.return_value = Qnil;
2272
+ frame.rescue = 0;
2273
+ frame.targetted = 0;
2274
+ frame.thread_data = ((typeof(pframe))_parent_frame)->thread_data;
2275
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
2276
+
2277
+ plocals->pframe = LONG2FIX(&frame);
2278
+
2279
+ pframe = (void*)&frame;
2280
+
2281
+ #{@block_struct} *pblock;
2282
+ VALUE last_expression = Qnil;
2283
+
2284
+ int aux = setjmp(pframe->jmp);
2285
+ if (aux != 0) {
2286
+
2287
+ if (pframe->targetted == 0) {
2288
+ longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
2289
+ }
2290
+
2291
+ return plocals->return_value;
2292
+ }
2293
+
2294
+ plocals->self = self;
2295
+ "
2296
+ end
2297
+
2298
+ def c_escape(str)
2299
+ str.inspect
2300
+ end
2301
+
2302
+ def literal_value(value)
2303
+ @literal_value_hash = Hash.new unless @literal_value_hash
2304
+ return @literal_value_hash[value] if @literal_value_hash[value]
2305
+
2306
+ name = self.add_global_name("VALUE", "Qnil");
2307
+
2308
+ begin
2309
+
2310
+ str = Marshal.dump(value)
2311
+
2312
+
2313
+ if value.instance_of? Module
2314
+
2315
+ container_str = value.to_s.split("::")[0..-2].join("::")
2316
+
2317
+ init_extra << "
2318
+ #{name} = rb_define_module_under(
2319
+ #{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
2320
+ ,\"#{value.to_s.split("::").last}\");
2321
+
2322
+ rb_funcall(#{name},#{intern_num :gc_register_object},0);
2323
+ "
2324
+ elsif value.instance_of? Class
2325
+ container_str = value.to_s.split("::")[0..-2].join("::")
2326
+
2327
+ init_extra << "
2328
+ #{name} = rb_define_class_under(
2329
+ #{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
2330
+ ,\"#{value.to_s.split("::").last}\"
2331
+ ,#{value.superclass == Object ? "rb_cObject" : literal_value(value.superclass)});
2332
+
2333
+ rb_funcall(#{name},#{intern_num :gc_register_object},0);
2334
+ "
2335
+ elsif value.instance_of? Array
2336
+ init_extra << "
2337
+ #{name} = rb_ary_new3(#{value.size}, #{value.map{|x| literal_value x}.join(",")} );
2338
+ rb_funcall(#{name},#{intern_num :gc_register_object},0);
2339
+ "
2340
+ else
2341
+
2342
+ init_extra << "
2343
+ #{name} = rb_marshal_load(rb_str_new(#{c_escape str}, #{str.size}));
2344
+ rb_funcall(#{name},#{intern_num :gc_register_object},0);
2345
+
2346
+ "
2347
+ end
2348
+ rescue TypeError => e
2349
+ @no_cache = true
2350
+ FastRuby.logger.info "#{value} disabling cache for extension"
2351
+ init_extra << "
2352
+ #{name} = rb_funcall(rb_const_get(rb_cObject, #{intern_num :ObjectSpace}), #{intern_num :_id2ref}, 1, INT2FIX(#{value.__id__}));
2353
+ "
2354
+
2355
+ end
2356
+ @literal_value_hash[value] = name
2357
+
2358
+ name
2359
+ end
2360
+
2361
+ def encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name = nil)
2362
+ name = self.add_global_name("void*", 0);
2363
+ cruby_name = self.add_global_name("void*", 0);
2364
+ cruby_len = self.add_global_name("int", 0);
2365
+ args_tree = call_tree[3]
2366
+ method_tree = nil
2367
+
2368
+ begin
2369
+ method_tree = recvtype.instance_method(@method_name.to_sym).fastruby.tree
2370
+ rescue NoMethodError
2371
+ end
2372
+
2373
+
2374
+ strargs_signature = (0..args_tree.size-2).map{|x| "VALUE arg#{x}"}.join(",")
2375
+ strargs = (0..args_tree.size-2).map{|x| "arg#{x}"}.join(",")
2376
+ inprocstrargs = (1..args_tree.size-1).map{|x| "((VALUE*)method_arguments)[#{x}]"}.join(",")
2377
+
2378
+ if args_tree.size > 1
2379
+ strargs_signature = "," + strargs_signature
2380
+ toprocstrargs = "self,"+strargs
2381
+ strargs = "," + strargs
2382
+ inprocstrargs = ","+inprocstrargs
2383
+ else
2384
+ toprocstrargs = "self"
2385
+ end
2386
+
2387
+ ruby_wrapper = anonymous_function{ |funcname| "
2388
+ static VALUE #{funcname}(VALUE self,void* block,void* frame#{strargs_signature}){
2389
+ #{@frame_struct}* pframe = frame;
2390
+
2391
+ VALUE method_arguments[#{args_tree.size}] = {#{toprocstrargs}};
2392
+
2393
+ return #{
2394
+ protected_block "rb_funcall(((VALUE*)method_arguments)[0], #{intern_num mname.to_sym}, #{args_tree.size-1}#{inprocstrargs});", false, "method_arguments"
2395
+ };
2396
+ }
2397
+ "
2398
+ }
2399
+
2400
+ value_cast = ( ["VALUE"]*(args_tree.size) ).join(",")
2401
+
2402
+ cruby_wrapper = anonymous_function{ |funcname| "
2403
+ static VALUE #{funcname}(VALUE self,void* block,void* frame#{strargs_signature}){
2404
+ #{@frame_struct}* pframe = frame;
2405
+
2406
+ VALUE method_arguments[#{args_tree.size}] = {#{toprocstrargs}};
2407
+
2408
+ // call to #{recvtype}::#{mname}
2409
+
2410
+ if (#{cruby_len} == -1) {
2411
+ return #{
2412
+ protected_block "((VALUE(*)(int,VALUE*,VALUE))#{cruby_name})(#{args_tree.size-1}, ((VALUE*)method_arguments)+1,*((VALUE*)method_arguments));", false, "method_arguments"
2413
+ };
2414
+
2415
+ } else if (#{cruby_len} == -2) {
2416
+ return #{
2417
+ protected_block "((VALUE(*)(VALUE,VALUE))#{cruby_name})(*((VALUE*)method_arguments), rb_ary_new4(#{args_tree.size-1},((VALUE*)method_arguments)+1) );", false, "method_arguments"
2418
+ };
2419
+
2420
+ } else {
2421
+ return #{
2422
+ protected_block "((VALUE(*)(#{value_cast}))#{cruby_name})(((VALUE*)method_arguments)[0] #{inprocstrargs});", false, "method_arguments"
2423
+ };
2424
+ }
2425
+ }
2426
+ "
2427
+ }
2428
+
2429
+ recvdump = nil
2430
+
2431
+ begin
2432
+ recvdump = literal_value recvtype
2433
+ rescue
2434
+ end
2435
+
2436
+ if recvdump and recvtype
2437
+ init_extra << "
2438
+ {
2439
+ VALUE recvtype = #{recvdump};
2440
+ rb_funcall(#{literal_value FastRuby}, #{intern_num :set_builder_module}, 1, recvtype);
2441
+ VALUE signature = #{literal_value signature};
2442
+ VALUE mname = #{literal_value mname};
2443
+ VALUE tree = #{literal_value method_tree};
2444
+ VALUE convention = rb_funcall(recvtype, #{intern_num :convention}, 3,signature,mname,#{inference_complete ? "Qtrue" : "Qfalse"});
2445
+ VALUE mobject = rb_funcall(recvtype, #{intern_num :method_from_signature},3,signature,mname,#{inference_complete ? "Qtrue" : "Qfalse"});
2446
+
2447
+ struct METHOD {
2448
+ VALUE klass, rklass;
2449
+ VALUE recv;
2450
+ ID id, oid;
2451
+ int safe_level;
2452
+ NODE *body;
2453
+ };
2454
+
2455
+ int len = 0;
2456
+ void* address = 0;
2457
+
2458
+ if (mobject != Qnil) {
2459
+
2460
+ struct METHOD *data;
2461
+ Data_Get_Struct(mobject, struct METHOD, data);
2462
+
2463
+ if (nd_type(data->body) == NODE_CFUNC) {
2464
+ address = data->body->nd_cfnc;
2465
+ len = data->body->nd_argc;
2466
+ }
2467
+ }
2468
+
2469
+ if (address==0) convention = #{literal_value :ruby};
2470
+
2471
+ #{convention_global_name ? convention_global_name + " = 0;" : ""}
2472
+ if (recvtype != Qnil) {
2473
+
2474
+ if (convention == #{literal_value :fastruby}) {
2475
+ #{convention_global_name ? convention_global_name + " = 1;" : ""}
2476
+ #{name} = address;
2477
+ } else if (convention == #{literal_value :cruby}) {
2478
+ // cruby, wrap direct call
2479
+ #{cruby_name} = address;
2480
+
2481
+ if (#{cruby_name} == 0) {
2482
+ #{name} = (void*)#{ruby_wrapper};
2483
+ } else {
2484
+ #{cruby_len} = len;
2485
+ #{name} = (void*)#{cruby_wrapper};
2486
+ }
2487
+ } else {
2488
+ // ruby, wrap rb_funcall
2489
+ #{name} = (void*)#{ruby_wrapper};
2490
+ }
2491
+ } else {
2492
+ // ruby, wrap rb_funcall
2493
+ #{name} = (void*)#{ruby_wrapper};
2494
+ }
2495
+
2496
+ }
2497
+ "
2498
+ else
2499
+ init_extra << "
2500
+ // ruby, wrap rb_funcall
2501
+ #{name} = (void*)#{ruby_wrapper};
2502
+ "
2503
+ end
2504
+
2505
+ name
2506
+ end
2507
+
2508
+ def intern_num(symbol)
2509
+ @intern_num_hash = Hash.new unless @intern_num_hash
2510
+ return @intern_num_hash[symbol] if @intern_num_hash[symbol]
2511
+
2512
+ name = self.add_global_name("ID", 0);
2513
+
2514
+ init_extra << "
2515
+ #{name} = rb_intern(\"#{symbol.to_s}\");
2516
+ "
2517
+
2518
+ @intern_num_hash[symbol] = name
2519
+
2520
+ name
2521
+ end
2522
+
2523
+ def add_global_name(ctype, default)
2524
+ name = "glb" + rand(1000000000).to_s
2525
+
2526
+ extra_code << "
2527
+ static #{ctype} #{name} = #{default};
2528
+ "
2529
+ name
2530
+ end
2531
+
2532
+ def global_entry(glbname)
2533
+ name = add_global_name("struct global_entry*", 0);
2534
+
2535
+ init_extra << "
2536
+ #{name} = rb_global_entry(SYM2ID(#{literal_value glbname}));
2537
+ "
2538
+
2539
+ name
2540
+ end
2541
+
2542
+
2543
+ def frame(code, jmp_code, not_jmp_code = "", rescued = nil)
2544
+
2545
+ anonymous_function{ |name| "
2546
+ static VALUE #{name}(VALUE param) {
2547
+ VALUE last_expression;
2548
+ #{@frame_struct} frame, *pframe, *parent_frame;
2549
+ #{@locals_struct} *plocals;
2550
+
2551
+ parent_frame = (void*)param;
2552
+
2553
+ frame.parent_frame = (void*)param;
2554
+ frame.plocals = parent_frame->plocals;
2555
+ frame.rescue = #{rescued ? rescued : "parent_frame->rescue"};
2556
+ frame.targetted = 0;
2557
+ frame.thread_data = parent_frame->thread_data;
2558
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
2559
+
2560
+ plocals = frame.plocals;
2561
+ pframe = &frame;
2562
+
2563
+ int aux = setjmp(frame.jmp);
2564
+ if (aux != 0) {
2565
+ last_expression = pframe->return_value;
2566
+
2567
+ // restore previous frame
2568
+ typeof(pframe) original_frame = pframe;
2569
+ pframe = parent_frame;
2570
+
2571
+ #{jmp_code};
2572
+
2573
+ if (original_frame->targetted == 0) {
2574
+ longjmp(pframe->jmp,aux);
2575
+ }
2576
+
2577
+ return last_expression;
2578
+ }
2579
+
2580
+ #{code};
2581
+
2582
+ // restore previous frame
2583
+ typeof(pframe) original_frame = pframe;
2584
+ pframe = parent_frame;
2585
+ #{not_jmp_code};
2586
+
2587
+ return last_expression;
2588
+
2589
+ }
2590
+ "
2591
+ } + "((VALUE)pframe)"
2592
+ end
2593
+ end
2594
+ end