fastruby 0.0.21 → 0.0.22

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.
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