fastruby 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- extra_code << "static VALUE _rb_gvar_set(void* ge,VALUE value) {
46
- rb_gvar_set((struct global_entry*)ge,value);
47
- return value;
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
- extra_code << "static VALUE _lvar_assing(VALUE* destination,VALUE value) {
58
- *destination = value;
59
- return value;
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(method)
98
+ def anonymous_function
75
99
 
76
100
  name = "anonymous" + rand(10000000).to_s
77
- extra_code << method.call(name)
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 = @locals_struct + " *plocals;
183
- plocals = (void*)param;"
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 param) {
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
- #{str_lvar_initialization};
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)#{locals_pointer}, #{anonymous_function(block_code)}, (VALUE)#{locals_pointer})"
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 param) {
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
- #{str_lvar_initialization}
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)#{locals_pointer})"
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 locals_param, VALUE* block_args) {
445
+ static VALUE #{name}(VALUE frame_param, VALUE* block_args) {
361
446
 
362
447
  #{@locals_struct} *plocals;
363
- plocals = (void*)locals_param;
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)#{locals_pointer}, (VALUE[]){#{tree[1..-1].map{|subtree| to_c subtree}.join(",")}})"
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)#{locals_pointer}, (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
- "return #{to_c(tree[1])};\n"
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
- wrapper_func = proc { |name| "
564
+ anonymous_function{ |name| "
444
565
  static VALUE #{name}(VALUE value_params) {
445
- #{@locals_struct} *plocals = (void*)value_params;
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 to_c_method(tree)
510
- method_name = tree[1]
511
- args_tree = tree[2]
632
+ def to_c_defs(tree)
633
+ args_tree = tree[3];
512
634
 
513
- impl_tree = tree[3][1]
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
- @block_struct = "struct {
523
- void* block_function_address;
524
- void* block_function_param;
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
- str_impl = ""
528
- # if impl_tree is a block, implement the last node with a return
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
- if impl_tree[0] != :return
533
- str_impl = str_impl + ";last_expression = #{to_c(impl_tree)};"
534
- else
535
- str_impl = str_impl + ";#{to_c(impl_tree)};"
536
- end
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
- #{@locals_struct} locals;
547
- #{@locals_struct} *plocals = (void*)&locals;
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 #{str_impl};
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 to_c_call(tree)
692
- recv = tree[1]
693
- mname = tree[2]
694
- args = tree[3]
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 = getaddress(mobject)
749
- len = getlen(mobject)
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
- wrapper_func = proc { |name| "
775
- static VALUE #{name}(VALUE recv) {
776
- // call to #{recvtype}##{mname}
777
- if (rb_block_given_p()) {
778
- // no passing block, recall
779
- return rb_funcall(recv, #{tree[2].to_i}, 0);
780
- } else {
781
- return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_incall_args});
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
- wrapper_func = proc { |name| "
810
- static VALUE #{name}(VALUE recv, #{ (1..argnum).map{|x| "VALUE _arg"+x.to_s }.join(",")} ) {
811
- // call to #{recvtype}##{mname}
812
- if (rb_block_given_p()) {
813
- // no passing block, recall
814
- return rb_funcall(recv, #{tree[2].to_i}, #{argnum}, #{ (1..argnum).map{|x| "_arg"+x.to_s }.join(",")});
815
- } else {
816
- return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_incall_args});
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
- caller_code = proc { |name| "
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
- caller_code = proc { |name| "
1253
+ anonymous_function{ |name| "
920
1254
  static VALUE #{name}(VALUE param) {
921
- #{@locals_struct} *plocals = (void*)param;
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
- anonymous_function(caller_code) + "((VALUE)#{locals_pointer})"
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|