fastruby 0.0.21 → 0.0.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/Rakefile +1 -1
  2. data/benchmarks/benchmark.rb +3 -0
  3. data/benchmarks/benchmark.rb~ +3 -12
  4. data/benchmarks/benchmark8.rb +48 -0
  5. data/benchmarks/benchmark8.rb~ +46 -0
  6. data/lib/fastruby.rb +2 -1
  7. data/lib/fastruby.rb~ +2 -1
  8. data/lib/fastruby/builder.rb +18 -1
  9. data/lib/fastruby/builder.rb~ +18 -5
  10. data/lib/fastruby/modules/lvar_type/lasgn.rb~ +41 -0
  11. data/lib/fastruby/modules/translator/block.rb +1 -1
  12. data/lib/fastruby/modules/translator/block.rb~ +128 -0
  13. data/lib/fastruby/modules/translator/call.rb +62 -139
  14. data/lib/fastruby/modules/translator/call.rb~ +61 -140
  15. data/lib/fastruby/modules/translator/defn.rb +49 -105
  16. data/lib/fastruby/modules/translator/defn.rb~ +211 -0
  17. data/lib/fastruby/modules/translator/exceptions.rb +1 -0
  18. data/lib/fastruby/modules/translator/exceptions.rb~ +120 -0
  19. data/lib/fastruby/modules/translator/iter.rb +13 -20
  20. data/lib/fastruby/modules/translator/iter.rb~ +738 -0
  21. data/lib/fastruby/modules/translator/literal.rb +8 -1
  22. data/lib/fastruby/modules/translator/literal.rb~ +157 -0
  23. data/lib/fastruby/modules/translator/nonlocal.rb +7 -0
  24. data/lib/fastruby/modules/translator/nonlocal.rb~ +304 -0
  25. data/lib/fastruby/modules/translator/static.rb +1 -0
  26. data/lib/fastruby/modules/translator/static.rb~ +290 -0
  27. data/lib/fastruby/modules/translator/variable.rb +24 -6
  28. data/lib/fastruby/modules/translator/variable.rb~ +298 -0
  29. data/lib/fastruby/translator/translator.rb +411 -284
  30. data/lib/fastruby/translator/translator.rb~ +1728 -0
  31. data/spec/fastruby_only/base_spec.rb~ +74 -0
  32. data/spec/ruby/base_spec.rb~ +1 -338
  33. data/spec/ruby/block/break_spec.rb~ +21 -0
  34. data/spec/ruby/block/callcc_spec.rb~ +236 -0
  35. data/spec/ruby/block/lambda_spec.rb~ +1 -178
  36. data/spec/ruby/block/next_spec.rb~ +85 -0
  37. data/spec/ruby/block/proc_spec.rb~ +22 -0
  38. data/spec/ruby/block/redo_spec.rb~ +133 -0
  39. data/spec/ruby/block/retry_spec.rb~ +135 -0
  40. data/spec/ruby/block_spec.rb~ +494 -2
  41. data/spec/ruby/call/base_call_spec.rb~ +60 -2
  42. data/spec/ruby/defn/default_args_spec.rb~ +303 -0
  43. data/spec/ruby/defn/multiple_args_spec.rb~ +317 -0
  44. data/spec/ruby/defn/replacement_spec.rb +29 -1
  45. data/spec/ruby/defn/replacement_spec.rb~ +52 -21
  46. data/spec/ruby/exception/internal_ex_spec.rb~ +2 -2
  47. data/spec/ruby/variable_spec.rb~ +46 -23
  48. data/spec/static/flow_spec.rb~ +48 -0
  49. metadata +34 -12
@@ -250,6 +250,8 @@ module FastRuby
250
250
 
251
251
 
252
252
  def _raise(class_tree, message_tree = nil)
253
+ @has_raise = true
254
+ @has_inline_block = true
253
255
  class_tree = to_c class_tree unless class_tree.instance_of? String
254
256
 
255
257
  if message_tree.instance_of? String
@@ -443,6 +445,8 @@ module FastRuby
443
445
  block_argument = tree[3].find{|x| x.to_s[0] == ?&}
444
446
  impl_tree = tree[4][1]
445
447
  end
448
+
449
+ @method_arguments = original_args_tree[1..-1]
446
450
 
447
451
  if "0".respond_to?(:ord)
448
452
  @alt_method_name = "_" + method_name.to_s.gsub("_x_", "_x__x_").gsub(/\W/){|x| "_x_#{x.ord}" } + "_" + rand(10000000000).to_s
@@ -450,6 +454,14 @@ module FastRuby
450
454
  @alt_method_name = "_" + method_name.to_s.gsub("_x_", "_x__x_").gsub(/\W/){|x| "_x_#{x[0]}" } + "_" + rand(10000000000).to_s
451
455
  end
452
456
 
457
+ @has_yield = false
458
+ @has_dynamic_call = false
459
+ @has_nonlocal_goto = false
460
+ @has_inline_block = (options[:main] or tree.find_tree(:lasgn))
461
+ @has_plocals_ref = false
462
+ @has_raise = false
463
+ @has_inline_c = false
464
+
453
465
  args_tree = original_args_tree.select{|x| x.to_s[0] != ?&}
454
466
 
455
467
  initialize_method_structs(original_args_tree)
@@ -534,6 +546,7 @@ module FastRuby
534
546
  else
535
547
 
536
548
  if default_block_tree
549
+ @has_inline_block = true
537
550
  initialize_tree = default_block_tree[1..-1].find{|subtree| subtree[1] == arg_}
538
551
  if initialize_tree
539
552
  to_c(initialize_tree) + ";\n"
@@ -550,6 +563,7 @@ module FastRuby
550
563
  }.join("")
551
564
 
552
565
  if splat_arg
566
+ @has_splat_args = true
553
567
  if signature.size-1 < normalargsnum then
554
568
  read_arguments_code << "
555
569
  plocals->#{splat_arg.to_s.gsub("*","")} = rb_ary_new3(0);
@@ -569,6 +583,8 @@ module FastRuby
569
583
  end
570
584
 
571
585
  if block_argument
586
+
587
+ @has_yield = true
572
588
 
573
589
  proc_reyield_block_tree = s(:iter, s(:call, nil, :proc, s(:arglist)), s(:masgn, s(:array, s(:splat, s(:lasgn, :__xproc_arguments)))), s(:yield, s(:splat, s(:lvar, :__xproc_arguments))))
574
590
 
@@ -615,11 +631,29 @@ module FastRuby
615
631
  }
616
632
 
617
633
  evaluate_tree = tree.transform &trs
634
+
635
+ impl_code = to_c(impl_tree, "last_expression")
636
+
637
+ put_setjmp = (@has_dynamic_call or @has_nonlocal_goto or @has_yield or @has_raise or @has_inline_c)
638
+ put_block_init = @has_yield
639
+ if options[:main]
640
+ put_block_init = false
641
+ end
618
642
 
619
643
  scope_mode = FastRuby::ScopeModeHelper.get_scope_mode(evaluate_tree)
644
+ if scope_mode == :dag or put_setjmp or put_block_init or @has_splat_args
645
+ put_frame = true
646
+ put_locals = true
647
+ else
648
+ put_frame = @has_inline_block
649
+ put_locals = @has_plocals_ref
650
+ end
651
+
620
652
  ret = "VALUE #{@alt_method_name || method_name}(#{options[:main] ? "VALUE self" : strargs}) {
621
653
  #{validate_arguments_code}
622
654
 
655
+ #{if put_frame
656
+ "
623
657
  #{@frame_struct} frame;
624
658
  #{@frame_struct} * volatile pframe;
625
659
 
@@ -629,12 +663,15 @@ module FastRuby
629
663
  frame.targetted = 0;
630
664
  frame.thread_data = #{options[:main] ? "0" : "((typeof(pframe))_parent_frame)->thread_data"};
631
665
  if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
632
-
633
- int stack_chunk_instantiated = 0;
666
+ "
667
+ end
668
+ }
634
669
 
635
670
  #{
636
671
  if scope_mode == :dag
637
672
  "
673
+ int stack_chunk_instantiated = 0;
674
+
638
675
  volatile VALUE rb_previous_stack_chunk = Qnil;
639
676
  VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
640
677
  struct STACKCHUNK* volatile stack_chunk = 0;
@@ -670,6 +707,8 @@ else
670
707
  end
671
708
  }
672
709
 
710
+ #{if put_locals and put_frame
711
+ "
673
712
  plocals->parent_locals = (frame.thread_data->last_plocals);
674
713
  void* volatile old_parent_locals = frame.thread_data->last_plocals;
675
714
 
@@ -680,16 +719,26 @@ end
680
719
  }
681
720
 
682
721
  frame.plocals = plocals;
722
+ plocals->pframe = (&frame);
723
+ pframe = (void*)&frame;
724
+ "
725
+ end
726
+ }
727
+
728
+ #{if put_locals
729
+ "
683
730
  plocals->active = Qtrue;
684
731
  plocals->targetted = Qfalse;
685
- plocals->pframe = (&frame);
686
732
  plocals->call_frame = (0);
733
+ "
734
+ end
735
+ }
687
736
 
688
- pframe = (void*)&frame;
689
-
690
- #{@block_struct} * volatile pblock;
691
737
  volatile VALUE last_expression = Qnil;
692
738
 
739
+ #{if put_setjmp
740
+ "
741
+
693
742
  int aux = setjmp(pframe->jmp);
694
743
  if (aux != 0) {
695
744
  plocals->active = Qfalse;
@@ -722,12 +771,21 @@ end
722
771
 
723
772
  return plocals->return_value;
724
773
  }
774
+ "
775
+ end
776
+ }
725
777
 
778
+ #{if put_locals
779
+ "
726
780
  plocals->self = self;
781
+ "
782
+ end
783
+ }
727
784
 
728
785
  #{
729
- unless options[:main]
786
+ if put_block_init
730
787
  "
788
+ #{@block_struct} * volatile pblock;
731
789
  pblock = (void*)block;
732
790
  if (pblock) {
733
791
  plocals->block_function_address = pblock->block_function_address;
@@ -740,9 +798,14 @@ end
740
798
  end
741
799
  }
742
800
 
801
+ #{if put_locals
802
+ "
743
803
  #{read_arguments_code}
804
+ "
805
+ end
806
+ }
744
807
 
745
- #{to_c impl_tree, "last_expression"};
808
+ #{impl_code};
746
809
 
747
810
  local_return:
748
811
  #{
@@ -757,10 +820,21 @@ if scope_mode == :dag
757
820
  "
758
821
  end
759
822
  }
823
+
824
+ #{if put_locals
825
+ "
760
826
  plocals->active = Qfalse;
827
+ "
828
+ end
829
+ }
761
830
 
831
+ #{if put_locals and put_frame
832
+ "
762
833
  frame.thread_data->last_plocals = old_parent_locals;
763
-
834
+ "
835
+ end
836
+ }
837
+
764
838
  return last_expression;
765
839
  }"
766
840
 
@@ -775,6 +849,7 @@ end
775
849
  end
776
850
 
777
851
  def locals_accessor
852
+ @has_plocals_ref = true
778
853
  "plocals->"
779
854
  end
780
855
 
@@ -830,9 +905,10 @@ end
830
905
  if mname == :infer
831
906
  return to_c(recv)
832
907
  elsif mname == :block_given?
908
+ @has_yield = true
833
909
  return "plocals->block_function_address == 0 ? Qfalse : Qtrue"
834
910
  elsif mname == :inline_c
835
-
911
+ @has_inline_c = true
836
912
  code = args[1][1]
837
913
 
838
914
  unless (args[2] == s(:false))
@@ -856,6 +932,8 @@ end
856
932
  end
857
933
 
858
934
  def inline_block_reference(arg, nolocals = false)
935
+ @has_inline_block = true
936
+
859
937
  code = nil
860
938
 
861
939
  if arg.instance_of? FastRuby::FastRubySexp
@@ -891,6 +969,7 @@ end
891
969
  end
892
970
 
893
971
  def inline_block(*args)
972
+ @has_inline_block = true
894
973
 
895
974
  unless block_given?
896
975
  code = args.first
@@ -1188,324 +1267,358 @@ fastruby_local_next:
1188
1267
 
1189
1268
  name
1190
1269
  end
1270
+
1271
+ def dynamic_block_call(signature, mname)
1272
+ dynamic_call(signature, mname, true)
1273
+ end
1191
1274
 
1192
- def encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name = nil, is_block_call = false)
1193
- name = self.add_global_name("void*", 0);
1194
- address_name = self.add_global_name("void**", 0);
1195
- @last_address_name = address_name
1196
- cfunc_address_name = self.add_global_name("void**", 0);
1197
- cfunc_real_address_name = self.add_global_name("void*", 0);
1198
- tree_pointer_name = self.add_global_name("VALUE*", 0);
1199
-
1200
- if call_tree[3].select{|st| st.respond_to?(:node_type) ? st[0] == :block_pass : false}
1201
- is_block_call = true
1202
- end
1203
-
1204
- args_tree = call_tree[3].reject{|st| st.respond_to?(:node_type) ? st[0] == :block_pass : false}
1205
- method_tree = nil
1275
+ # returns a anonymous function who made a dynamic call
1276
+ def dynamic_call(signature, mname, return_on_block_call = false, funcall_fallback = true, global_klass_variable = nil)
1277
+ # TODO: initialize the table
1278
+ @has_dynamic_call = true
1279
+ max_argument_size = 0
1280
+ recvtype = signature.first
1206
1281
 
1207
- begin
1208
- method_tree = recvtype.instance_method(@method_name.to_sym).fastruby.tree
1209
- rescue NoMethodError
1282
+ unless recvtype
1283
+ max_argument_size = max_argument_size + 1
1210
1284
  end
1211
1285
 
1212
- strargs_signature = (0..args_tree.size-2).map{|x| "VALUE arg#{x}"}.join(",")
1213
- strargs = (0..args_tree.size-2).map{|x| "arg#{x}"}.join(",")
1214
- inprocstrargs = (1..args_tree.size-1).map{|x| "((VALUE*)method_arguments)[#{x}]"}.join(",")
1286
+ compare_hash = {}
1287
+ (1..signature.size-1).each do |j|
1288
+ unless signature[j]
1289
+ compare_hash[max_argument_size] = j-1
1290
+ max_argument_size = max_argument_size + 1
1291
+ end
1292
+ end
1215
1293
 
1216
- if args_tree.size > 1
1217
- strargs_signature = "," + strargs_signature
1218
- toprocstrargs = "self,"+strargs
1219
- strargs = "," + strargs
1220
- inprocstrargs = ","+inprocstrargs
1294
+ table_size = if compare_hash.size == 0
1295
+ 1
1296
+ elsif compare_hash.size == 1
1297
+ 16
1221
1298
  else
1222
- toprocstrargs = "self"
1299
+ 64
1223
1300
  end
1224
1301
 
1225
- value_cast = ( ["VALUE"]*(args_tree.size) ).join(",") + ",VALUE,VALUE"
1226
-
1227
- recvdump = nil
1302
+ table_name = reserve_table(table_size, max_argument_size)
1228
1303
 
1229
- begin
1230
- recvdump = literal_value recvtype
1231
- rescue
1232
- end
1233
-
1234
- pureruby_wrapper = anonymous_function{ |funcname| "
1235
- static VALUE #{funcname}(VALUE self,void* block,void* frame, int argc, VALUE* argv){
1236
- #{@frame_struct}* pframe = frame;
1237
- VALUE method_arguments[3];
1238
-
1239
- method_arguments[0] = (VALUE)argc;
1240
- method_arguments[1] = (VALUE)argv;
1241
- method_arguments[2] = (VALUE)self;
1242
-
1243
- return #{
1244
- protected_block "last_expression = rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);", false, "method_arguments"
1245
- };
1304
+ if recvtype
1305
+
1306
+ init_extra << "{
1307
+ memset(#{table_name},0,sizeof(#{table_name}));
1308
+
1309
+ VALUE mname = #{literal_value mname};
1310
+ VALUE recvtype = #{literal_value recvtype};
1311
+ rb_funcall(#{literal_value FastRuby}, #{intern_num :set_builder_module}, 1, recvtype);
1312
+ VALUE fastruby_method = rb_funcall(recvtype, #{intern_num :fastruby_method}, 1, mname);
1313
+ rb_iterate(#{anonymous_function{|funcname|
1314
+ "static VALUE #{funcname}(VALUE recv) {
1315
+ return rb_funcall(recv, #{intern_num :observe}, 1, #{literal_value(mname.to_s + "#" + table_name.to_s)});
1316
+ }
1317
+ "
1318
+ }},fastruby_method,
1319
+ #{anonymous_function{|funcname|
1320
+ "static VALUE #{funcname}() {
1321
+ // clear table
1322
+ memset(#{table_name},0,sizeof(#{table_name}));
1323
+ return Qnil;
1324
+ }
1325
+ "
1326
+ }
1327
+ }
1328
+ ,Qnil);
1246
1329
  }
1247
- "
1248
- }
1249
-
1250
- generic_wrapper = anonymous_function{ |funcname| "
1251
- static VALUE #{funcname}(VALUE self,void* block,void* frame, int argc, VALUE* argv){
1330
+ "
1331
+ else
1252
1332
 
1253
- #{@frame_struct}* pframe = frame;
1254
- VALUE method_arguments[4];
1255
-
1256
- method_arguments[0] = (VALUE)argc;
1257
- method_arguments[1] = (VALUE)argv;
1258
- method_arguments[2] = (VALUE)self;
1259
- method_arguments[3] = (VALUE)block;
1260
-
1261
- void* fptr = 0;
1262
-
1263
- if (*#{address_name} == 0) {
1264
- if (#{tree_pointer_name} != 0) {
1265
- if (*#{tree_pointer_name} != Qnil) {
1266
- VALUE signature = #{literal_value signature};
1267
- VALUE recvtype = #{recvdump};
1268
- VALUE mname = #{literal_value mname};
1269
-
1270
- rb_funcall(recvtype, #{intern_num :build}, 2, signature, mname);
1333
+ # TODO: implemente this in ruby
1334
+ init_extra << "
1335
+ {
1336
+ memset(#{table_name},0,sizeof(#{table_name}));
1337
+
1338
+ rb_iterate(#{anonymous_function{|funcname|
1339
+ "static VALUE #{funcname}(VALUE recv) {
1340
+ return rb_funcall(recv, #{intern_num :observe_method_name}, 1, #{literal_value(mname.to_sym)});
1341
+ }
1342
+ "
1343
+ }},#{literal_value FastRuby::Method},
1344
+ #{anonymous_function{|funcname|
1345
+ "static VALUE #{funcname}() {
1346
+ // clear table
1347
+ memset(#{table_name},0,sizeof(#{table_name}));
1348
+ return Qnil;
1271
1349
  }
1350
+ "
1272
1351
  }
1273
- }
1352
+ }
1353
+ ,Qnil);
1274
1354
 
1275
- fptr = *#{address_name};
1355
+ }
1356
+ "
1276
1357
 
1277
- if (fptr == 0) {
1278
- fptr = *#{cfunc_address_name};
1279
- if (fptr != 0) {
1280
- return ( (VALUE(*)(VALUE,VALUE,VALUE,int,VALUE*) ) (fptr) )(self,(VALUE)block,(VALUE)frame, argc, argv);
1281
- }
1282
- }
1358
+ end
1283
1359
 
1284
- if (fptr == 0) {
1285
- if (block==0) {
1286
- return #{
1287
- protected_block "last_expression = rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);", false, "method_arguments"
1288
- };
1360
+ anonymous_function{|funcname| "
1361
+ static VALUE #{funcname}(VALUE self,void* block,void* frame, int argc, VALUE* argv #{return_on_block_call ? ", int* block_call" : ""}){
1362
+ void* fptr = 0;
1363
+ #{if global_klass_variable
1364
+ "
1365
+ VALUE klass = #{global_klass_variable};
1366
+ "
1367
+ else
1368
+ "
1369
+ VALUE klass = CLASS_OF(self);
1370
+ "
1371
+ end
1372
+ }
1289
1373
 
1290
- } else {
1291
- return #{
1292
- protected_block "
1293
- #{@block_struct} *pblock;
1294
- pblock = (typeof(pblock))( ((VALUE*)method_arguments)[3] );
1295
- last_expression = rb_iterate(
1296
- #{anonymous_function{|name_|
1297
- "
1298
- static VALUE #{name_} (VALUE data) {
1299
- VALUE* method_arguments = (VALUE*)data;
1300
- return rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);
1301
- }
1302
- "
1303
- }},
1304
- (VALUE)method_arguments,
1305
-
1306
- #{anonymous_function{|name_|
1307
- "
1308
- static VALUE #{name_} (VALUE arg_, VALUE param, int argc, VALUE* argv) {
1309
-
1310
- VALUE arg;
1311
- #{
1312
- # TODO: access directly to argc and argv for optimal execution
1313
- if RUBY_VERSION =~ /^1\.9/
1314
- "
1315
- if (TYPE(arg_) == T_ARRAY) {
1316
- if (_RARRAY_LEN(arg_) <= 1) {
1317
- arg = rb_ary_new4(argc,argv);
1318
- } else {
1319
- arg = arg_;
1320
- }
1321
- } else {
1322
- arg = rb_ary_new4(argc,argv);
1323
- }
1374
+ char method_name[argc*40+64];
1375
+
1376
+ unsigned int fptr_hash = 0;
1377
+ int match = 1;
1378
+
1379
+ #{if table_size > 1
1380
+ "
1381
+ #{unless signature.first
1382
+ "fptr_hash = klass;
1324
1383
  "
1325
- else
1326
- "arg = arg_;"
1327
1384
  end
1328
1385
  }
1329
-
1330
- return rb_proc_call(param, arg);
1331
- }
1332
- "
1333
- }},
1334
- pblock->proc
1335
- );
1336
- ", false, "method_arguments"
1337
- };
1338
- }
1386
+
1387
+ #{
1388
+ compare_hash.map { |k,v|
1389
+ "if (#{v} < argc) {
1390
+ fptr_hash += CLASS_OF(argv[#{v}]);
1391
+ }
1392
+ "
1393
+ }.join("\n")
1394
+ };
1339
1395
 
1340
- } else {
1341
- return ( (VALUE(*)(VALUE,VALUE,VALUE,int,VALUE*)) (fptr) )(self,(VALUE)block,(VALUE)frame,argc,argv);
1342
- }
1343
- }
1344
- "
1345
- }
1396
+ fptr_hash = fptr_hash % #{table_size};
1346
1397
 
1398
+ int j = 0;
1347
1399
 
1348
- cfuncall1inprocargs = (0..args_tree.size-2).map{|x| "argv[#{x}]"}.join(",")
1349
- cfuncall1inprocargs = ","+cfuncall1inprocargs if cfuncall1inprocargs != ""
1350
-
1351
- cfunc_value_cast = (["VALUE"]*args_tree.size).join(",")
1352
- cfunc_wrapper = anonymous_function{ |funcname| "
1353
- static VALUE #{funcname}(VALUE self, void* block,void* frame, int argc, VALUE* argv){
1354
- return rb_vm_call(ruby_current_thread, self, #{intern_num mname.to_sym}, argc, argv, #{cfunc_real_address_name});
1355
- }
1356
- "
1357
- }
1358
-
1359
- toprocstrargs = (0..25).map{|x| "arg#{x}"}.join(",")
1360
- strargs_signature = (0..25).map{|x| "VALUE arg#{x}"}.join(",")
1361
-
1362
- cfunc_wrapper_1 = anonymous_function{ |funcname| "
1363
- static VALUE #{funcname}(VALUE self, void* block,void* frame, int argc, VALUE* argv){
1364
- return ( (VALUE(*)(int, VALUE*, VALUE)) (#{cfunc_real_address_name}) )(argc,argv,self);
1365
- }
1366
- "
1367
- }
1368
-
1369
- cfunc_wrapper_2 = anonymous_function{ |funcname| "
1370
- static VALUE #{funcname}(VALUE self, void* block,void* frame, int argc, VALUE* argv){
1371
- VALUE args = rb_ary_new3(argc, argv);
1372
- return ( (VALUE(*)(VALUE,VALUE)) (#{cfunc_real_address_name}) )(self,args);
1373
- }
1374
- "
1375
- }
1400
+ if (argc+15 != #{table_name}[fptr_hash].argc) {
1401
+ match = 0;
1402
+ goto does_not_match;
1403
+ }
1376
1404
 
1377
- update_cfunc_method = anonymous_function{ |funcname| "
1378
- static VALUE #{funcname}(){
1379
- void** default_address = (void**)#{cfunc_address_name};
1380
- ID default_id = rb_intern(\"default\");
1381
- VALUE recvtype = #{recvdump};
1405
+ #{unless recvtype
1406
+ "
1407
+ if (match == 1 && #{table_name}[fptr_hash].argument_type[0] != klass ) {
1408
+ match = 0;
1409
+ goto does_not_match;
1410
+ }
1411
+ "
1412
+ end
1413
+ }
1382
1414
 
1383
- if (1) {
1384
- *default_address = 0;
1385
-
1386
- #{
1387
- if RUBY_VERSION == "1.9.2"
1388
-
1389
- "
1390
- rb_method_entry_t* me = rb_method_entry(recvtype,#{intern_num mname});
1391
- if (me != 0) {
1392
- rb_method_definition_t* def = me->def;
1393
-
1394
- if (def->type == VM_METHOD_TYPE_CFUNC) {
1395
- *default_address = #{cfunc_wrapper};
1396
- #{cfunc_real_address_name} = (void*)me;
1397
- }
1398
- }
1399
- "
1400
- end
1401
- }
1402
- if (default_address != 0) {
1403
- if (recvtype != Qnil) {
1404
- rb_funcall(
1405
- recvtype,
1406
- #{intern_num :register_method_value},
1407
- 3,
1408
- #{literal_value mname},
1409
- PTR2NUM(default_id),
1410
- PTR2NUM(default_address)
1411
- );
1412
- }
1413
- }
1414
- }
1415
- return Qnil;
1415
+ #{
1416
+ compare_hash.map { |k,v|
1417
+ "if (match == 1 && #{table_name}[fptr_hash].argument_type[#{k}] != CLASS_OF(argv[#{v}])) {
1418
+ match = 0;
1419
+ goto does_not_match;
1420
+ }
1421
+ "
1422
+ }.join("\n")
1423
+ };
1424
+ "
1425
+ end
1416
1426
  }
1417
- "
1418
- }
1419
-
1420
-
1421
1427
 
1422
- if recvdump and recvtype
1423
- init_extra << "
1424
- {
1425
- VALUE recvtype = #{recvdump};
1426
- rb_funcall(#{literal_value FastRuby}, #{intern_num :set_builder_module}, 1, recvtype);
1427
- VALUE signature = #{literal_value signature};
1428
- VALUE mname = #{literal_value mname};
1429
- VALUE tree = #{literal_value method_tree};
1430
- VALUE rb_str_signature = rb_funcall(
1431
- #{literal_value FastRuby},
1432
- #{intern_num :make_str_signature},
1433
- 2,
1434
- mname,
1435
- signature);
1436
-
1437
-
1438
-
1439
- VALUE fastruby_method = rb_funcall(recvtype, #{intern_num :fastruby_method}, 1, mname);
1440
- #{tree_pointer_name} = (VALUE*)NUM2PTR(fastruby_method_tree_pointer(fastruby_method));
1428
+ if (#{table_name}[fptr_hash].address == 0) match = 0;
1429
+ if (match == 1) {
1430
+ fptr = #{table_name}[fptr_hash].address;
1431
+ } else {
1432
+ does_not_match:
1433
+ method_name[0] = '_';
1434
+ method_name[1] = 0;
1435
+
1436
+ strncpy(method_name+1, \"#{mname}\",sizeof(method_name)-4);
1437
+ sprintf(method_name+strlen(method_name), \"%li\", (long)NUM2PTR(rb_obj_id(CLASS_OF(self))));
1441
1438
 
1439
+ int i;
1440
+ for (i=0; i<argc; i++) {
1441
+ sprintf(method_name+strlen(method_name), \"%li\", (long)NUM2PTR(rb_obj_id(CLASS_OF(argv[i]))));
1442
+ }
1443
+
1444
+ void** address = 0;
1442
1445
  ID id;
1443
- ID default_id = rb_intern(\"default\");
1444
1446
  VALUE rb_method_hash;
1445
- void** address = 0;
1446
- void** default_address = 0;
1447
- id = rb_intern(RSTRING_PTR(rb_str_signature));
1448
- rb_method_hash = rb_funcall(recvtype, #{intern_num :method_hash},1,mname);
1449
-
1450
- if (rb_method_hash != Qnil) {
1451
- VALUE tmp = rb_hash_aref(rb_method_hash, PTR2NUM(id));
1452
- if (tmp != Qnil) {
1453
- address = (void*)NUM2PTR(tmp);
1447
+
1448
+ id = rb_intern(method_name);
1449
+
1450
+ if (rb_respond_to(klass, #{intern_num :method_hash})) {
1451
+ rb_method_hash = rb_funcall(klass, #{intern_num :method_hash},1,#{literal_value mname});
1452
+
1453
+ if (rb_method_hash != Qnil) {
1454
+ VALUE tmp = rb_hash_aref(rb_method_hash, PTR2NUM(id));
1455
+ if (tmp != Qnil) {
1456
+ address = (void**)NUM2PTR(tmp);
1457
+ fptr = *address;
1458
+ }
1454
1459
  }
1455
1460
 
1456
- tmp = rb_hash_aref(rb_method_hash, PTR2NUM(default_id));
1457
- if (tmp != Qnil) {
1458
- default_address = (void*)NUM2PTR(tmp);
1461
+ if (fptr == 0) {
1462
+ VALUE fastruby_method = rb_funcall(klass, #{intern_num :fastruby_method}, 1, #{literal_value mname});
1463
+ VALUE tree = rb_funcall(fastruby_method, #{intern_num :tree}, 0,0);
1464
+
1465
+ if (RTEST(tree)) {
1466
+ VALUE argv_class[argc+1];
1467
+
1468
+ argv_class[0] = CLASS_OF(self);
1469
+ for (i=0; i<argc; i++) {
1470
+ argv_class[i+1] = CLASS_OF(argv[i]);
1471
+ }
1472
+
1473
+ VALUE signature = rb_ary_new4(argc+1,argv_class);
1474
+
1475
+ rb_funcall(klass, #{intern_num :build}, 2, signature,rb_str_new2(#{mname.to_s.inspect}));
1476
+
1477
+ id = rb_intern(method_name);
1478
+ rb_method_hash = rb_funcall(klass, #{intern_num :method_hash},1,#{literal_value mname});
1479
+
1480
+ if (rb_method_hash != Qnil) {
1481
+ VALUE tmp = rb_hash_aref(rb_method_hash, PTR2NUM(id));
1482
+ if (tmp != Qnil) {
1483
+ address = (void**)NUM2PTR(tmp);
1484
+ fptr = *address;
1485
+ }
1486
+ }
1487
+
1488
+ if (fptr == 0) {
1489
+ rb_raise(rb_eRuntimeError, \"Error: method not found after build\");
1490
+ }
1491
+ }
1459
1492
  }
1460
1493
  }
1461
1494
 
1462
- if (default_address==0) {
1463
- default_address = malloc(sizeof(void*));
1464
- *default_address = 0;
1465
- }
1466
- #{cfunc_address_name} = default_address;
1467
- #{unless is_block_call
1495
+ // insert the value on table
1496
+ #{table_name}[fptr_hash].argc = argc+15;
1497
+
1498
+ #{unless recvtype
1468
1499
  "
1469
- #{update_cfunc_method}();
1470
- rb_iterate(#{anonymous_function{|funcname|
1471
- "static VALUE #{funcname}(VALUE recv) {
1472
- return rb_funcall(recv, #{intern_num :observe}, 1, #{literal_value(@alt_method_name + "#" + cfunc_address_name)});
1473
- }
1474
- "
1475
- }},fastruby_method,#{update_cfunc_method},Qnil);
1500
+ #{table_name}[fptr_hash].argument_type[0] = klass;
1476
1501
  "
1477
1502
  end
1478
1503
  }
1479
1504
 
1480
- if (address==0) {
1481
- address = malloc(sizeof(void*));
1482
-
1483
- if (recvtype != Qnil) {
1484
- rb_funcall(
1485
- recvtype,
1486
- #{intern_num :register_method_value},
1487
- 3,
1488
- #{literal_value mname},
1489
- PTR2NUM(id),
1490
- PTR2NUM(address)
1491
- );
1505
+ #{
1506
+ compare_hash.map { |k,v|
1507
+ "if (#{v} < argc) {
1508
+ #{table_name}[fptr_hash].argument_type[#{k}] = CLASS_OF(argv[#{v}]);
1492
1509
  }
1493
-
1494
- *address = 0; //(void*)
1495
- }
1510
+ "
1511
+ }.join("\n")
1512
+ };
1513
+
1514
+ #{table_name}[fptr_hash].address = fptr;
1515
+ }
1516
+
1517
+ if (fptr != 0) {
1518
+ return ((VALUE(*)(VALUE,VALUE,VALUE,int,VALUE*))fptr)(self,(VALUE)block,(VALUE)frame, argc, argv);
1519
+ }
1520
+
1521
+ #{if funcall_fallback
1522
+ "
1523
+
1524
+ #{@frame_struct}* pframe = frame;
1525
+ VALUE method_arguments[4];
1526
+
1527
+ method_arguments[0] = (VALUE)argc;
1528
+ method_arguments[1] = (VALUE)argv;
1529
+ method_arguments[2] = (VALUE)self;
1530
+ method_arguments[3] = (VALUE)block;
1531
+
1532
+ if (block == 0) {
1533
+ return #{
1534
+ protected_block "
1535
+ last_expression = rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);", true, "method_arguments"
1536
+ };
1496
1537
 
1497
- #{address_name} = address;
1498
- #{name} = (void*)#{generic_wrapper};
1538
+ } else {
1539
+ #{
1540
+ if return_on_block_call
1541
+ "*block_call = 1;
1542
+ return Qnil;
1543
+ "
1544
+ else
1545
+ "
1546
+ return #{
1547
+ protected_block "
1548
+ #{@block_struct} *pblock;
1549
+ pblock = (typeof(pblock))( ((VALUE*)method_arguments)[3] );
1550
+ last_expression = rb_iterate(
1551
+ #{anonymous_function{|name_|
1552
+ "
1553
+ static VALUE #{name_} (VALUE data) {
1554
+ VALUE* method_arguments = (VALUE*)data;
1555
+ return rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);
1556
+ }
1557
+ "
1558
+ }},
1559
+ (VALUE)method_arguments,
1560
+
1561
+ #{anonymous_function{|name_|
1562
+ "
1563
+ static VALUE #{name_} (VALUE arg_, VALUE param, int argc, VALUE* argv) {
1564
+ #{@block_struct}* pblock = (void*)param;
1565
+
1566
+ if (pblock->proc != Qnil) {
1567
+ VALUE arg;
1568
+ #{
1569
+ # TODO: access directly to argc and argv for optimal execution
1570
+ if RUBY_VERSION =~ /^1\.9/
1571
+ "
1572
+ if (TYPE(arg_) == T_ARRAY) {
1573
+ if (_RARRAY_LEN(arg_) <= 1) {
1574
+ arg = rb_ary_new4(argc,argv);
1575
+ } else {
1576
+ arg = arg_;
1577
+ }
1578
+ } else {
1579
+ arg = rb_ary_new4(argc,argv);
1580
+ }
1581
+ "
1582
+ else
1583
+ "arg = arg_;"
1584
+ end
1585
+ }
1586
+
1587
+ return rb_proc_call(pblock->proc, arg);
1588
+
1589
+ } else {
1590
+ #{
1591
+ # TODO: access directly to argc and argv for optimal execution
1592
+ if RUBY_VERSION =~ /^1\.9/
1593
+ "return ((VALUE(*)(int,VALUE*,VALUE,VALUE))pblock->block_function_address)(argc,argv,(VALUE)pblock->block_function_param,(VALUE)0);"
1594
+ else
1595
+ "return Qnil;"
1596
+ end
1597
+ }
1598
+ }
1599
+
1600
+ }
1601
+ "
1602
+ }},
1603
+ (VALUE)pblock
1604
+ );
1605
+ ", true, "method_arguments"
1606
+ };
1607
+ "
1608
+ end
1609
+ }
1610
+ }
1611
+ "
1612
+ else
1613
+ "
1614
+ rb_raise(rb_eRuntimeError, \"Error: invalid dynamic call for defn\");
1615
+ return Qnil;
1616
+ "
1617
+ end
1499
1618
  }
1619
+ }
1500
1620
  "
1501
- else
1502
- init_extra << "
1503
- // ruby, wrap rb_funcall
1504
- #{name} = (void*)#{pureruby_wrapper};
1505
- "
1506
- end
1507
-
1508
- name
1621
+ }
1509
1622
  end
1510
1623
 
1511
1624
  def intern_num(symbol)
@@ -1523,6 +1636,20 @@ fastruby_local_next:
1523
1636
 
1524
1637
  name
1525
1638
  end
1639
+
1640
+ def reserve_table(size, argument_count)
1641
+ name = "glb_table" + rand(1000000000).to_s
1642
+
1643
+ extra_code << "
1644
+ static struct {
1645
+ VALUE argument_type[#{argument_count}];
1646
+ void* address;
1647
+ int argc;
1648
+ } #{name}[#{size}];
1649
+ "
1650
+
1651
+ name
1652
+ end
1526
1653
 
1527
1654
  def add_global_name(ctype, default)
1528
1655
  name = "glb" + rand(1000000000).to_s