fastruby 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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|