fastruby 0.0.13 → 0.0.14

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.
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ 0.0.14 Support for method replacement ("monkey patching")
2
+
3
+ Internal: Implemented method hash to store implementation pointers
4
+
5
+ Internal: Fixed inference of arguments on methods with splat arguments
6
+
1
7
  0.0.13 Argument splat method calls (not optimized yet)
2
8
 
3
9
  Array arguments on methods (optional arguments, variable number of arguments)
data/README CHANGED
@@ -57,10 +57,11 @@ I will stabilize the API and document it for next releases. I promise
57
57
 
58
58
  == Known Limitations & Issues
59
59
 
60
- * monkey patching does not work with fastruby methods
61
60
  * callcc is not supported, it works but using it may result in unexpected behaviour
62
61
  * recursive methods will be slow since the optimization of method calls only works with already defined methods
63
- * calls with blocks to ruby or cruby methods are almost as slow as normal ruby (if the called method is defined by fastruby, the call it's pretty fast)
62
+ * calls with blocks to ruby or cruby methods are almost as slow as normal ruby (if the called method is defined by fastruby, the call is pretty fast)
63
+ * When calling fastruby methods from normal ruby, the max. number of arguments allowed is 15
64
+ * replacement of methods using identical code strings will work, but it will generate duplicated objects on the cache each time te snippet run
64
65
 
65
66
  == Usage
66
67
 
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ require "rspec/core/rake_task"
7
7
 
8
8
  spec = Gem::Specification.new do |s|
9
9
  s.name = 'fastruby'
10
- s.version = '0.0.13'
10
+ s.version = '0.0.14'
11
11
  s.author = 'Dario Seminara'
12
12
  s.email = 'robertodarioseminara@gmail.com'
13
13
  s.platform = Gem::Platform::RUBY
@@ -0,0 +1,77 @@
1
+ require "rubygems"
2
+ require "fastruby"
3
+
4
+ class X
5
+ fastruby "
6
+ def factorial(n)
7
+ if n > 1
8
+ n * factorial((n-1).infer(Fixnum))
9
+ else
10
+ 1
11
+ end
12
+ end
13
+ "
14
+ end
15
+
16
+ class Y
17
+ fastruby "
18
+ def bar(x)
19
+ i = 100000
20
+
21
+ lvar_type(i,Fixnum)
22
+
23
+ ret = 0
24
+ while i > 0
25
+ x.factorial(20)
26
+ i = i - 1
27
+ end
28
+ return ret
29
+ end
30
+
31
+ "
32
+ end
33
+
34
+ class X2
35
+ def factorial(n)
36
+ if n > 1
37
+ n * factorial(n-1)
38
+ else
39
+ 1
40
+ end
41
+ end
42
+ end
43
+
44
+ class Y2
45
+ def bar(x)
46
+ i = 100000
47
+
48
+ ret = 0
49
+ while i > 0
50
+ x.factorial(20)
51
+ i = i - 1
52
+ end
53
+ return ret
54
+ end
55
+
56
+ end
57
+
58
+
59
+ x = X.new
60
+ y = Y.new
61
+ y2 = Y2.new
62
+ x2 = X2.new
63
+
64
+ Y.build([Y,X],:bar)
65
+
66
+ require 'benchmark'
67
+
68
+ Benchmark::bm(20) do |b|
69
+
70
+ b.report("fastruby") do
71
+ y.bar(x)
72
+ end
73
+
74
+ b.report("ruby") do
75
+ y2.bar(x2)
76
+ end
77
+ end
@@ -1,5 +1,7 @@
1
1
  #include "fastruby_base.inl"
2
2
 
3
3
  void Init_fastruby_base() {
4
- Init_stack_chunk();
4
+ init_stack_chunk();
5
+ init_class_extension();
6
+ init_fastruby_method();
5
7
  }
@@ -25,6 +25,13 @@ struct FASTRUBYTHREADDATA {
25
25
  VALUE rb_stack_chunk;
26
26
  };
27
27
 
28
+ struct METHOD {
29
+ VALUE klass, rklass;
30
+ VALUE recv;
31
+ ID id, oid;
32
+ int safe_level;
33
+ NODE *body;
34
+ };
28
35
 
29
36
  static inline void stack_chunk_initialize(struct STACKCHUNK* sc) {
30
37
  // initialize pointers with zeros
@@ -207,7 +214,7 @@ static inline struct FASTRUBYTHREADDATA* rb_current_thread_data() {
207
214
  Data_Get_Struct(rb_thread_data,struct FASTRUBYTHREADDATA,thread_data);
208
215
  return thread_data;
209
216
  }
210
-
217
+
211
218
  static void init_stack_chunk() {
212
219
 
213
220
  rb_mFastRuby = rb_define_module("FastRuby");
@@ -220,3 +227,74 @@ static void init_stack_chunk() {
220
227
  rb_define_method(rb_cStackChunk, "alloc", rb_stack_chunk_alloc,1);
221
228
  }
222
229
 
230
+ static VALUE clear_method_hash_addresses(VALUE klass,VALUE rb_method_hash) {
231
+
232
+ if (rb_method_hash != Qnil) {
233
+ VALUE rb_values = rb_funcall(rb_method_hash, rb_intern("values"),0);
234
+ void** address;
235
+ int i;
236
+
237
+ for (i = 0; i < RARRAY(rb_values)->len; i++) {
238
+ address = (void**)FIX2LONG(rb_ary_entry(rb_values,i));
239
+ *address = 0;
240
+ }
241
+ }
242
+
243
+ return Qnil;
244
+ }
245
+
246
+ static VALUE has_fastruby_function(VALUE self, VALUE rb_method_hash, VALUE mname) {
247
+ ID id = rb_intern(RSTRING(mname)->ptr);
248
+ VALUE tmp = rb_hash_aref(rb_method_hash, LONG2FIX(id));
249
+
250
+ if (tmp != Qnil) {
251
+ void** address = (void**)FIX2LONG(tmp);
252
+
253
+ if (*address == 0) {
254
+ return Qfalse;
255
+ } else {
256
+ return Qtrue;
257
+ }
258
+ }
259
+
260
+ return Qfalse;
261
+ }
262
+
263
+ static void init_class_extension() {
264
+ VALUE rb_mFastRubyBuilderModule = rb_define_module_under(rb_mFastRuby, "BuilderModule");
265
+ rb_define_method(rb_mFastRubyBuilderModule, "clear_method_hash_addresses",clear_method_hash_addresses,1);
266
+ rb_define_method(rb_mFastRubyBuilderModule, "has_fastruby_function",has_fastruby_function,2);
267
+ }
268
+
269
+ static VALUE fastruby_method_tree(VALUE self) {
270
+ VALUE rb_tree_pointer = rb_ivar_get(self, rb_intern("@tree"));
271
+ if (rb_tree_pointer == Qnil) return Qnil;
272
+ VALUE* tree_pointer = (VALUE*)FIX2LONG(rb_tree_pointer);
273
+ return *tree_pointer;
274
+ }
275
+
276
+ static VALUE fastruby_method_tree_pointer(VALUE self) {
277
+ VALUE rb_tree_pointer = rb_ivar_get(self, rb_intern("@tree"));
278
+
279
+ if (rb_tree_pointer == Qnil) {
280
+ VALUE* tree_pointer = malloc(sizeof(VALUE*));
281
+ *tree_pointer = Qnil;
282
+ rb_tree_pointer = LONG2FIX(tree_pointer);
283
+ rb_ivar_set(self, rb_intern("@tree"), rb_tree_pointer);
284
+ }
285
+
286
+ return rb_tree_pointer;
287
+ }
288
+
289
+ static VALUE fastruby_method_tree_eq(VALUE self, VALUE val) {
290
+ VALUE* tree_pointer = (VALUE*)FIX2LONG(fastruby_method_tree_pointer(self));
291
+ *tree_pointer = val;
292
+ return Qnil;
293
+ }
294
+
295
+ static void init_fastruby_method() {
296
+ VALUE rb_cFastRubyMethod = rb_define_class_under(rb_mFastRuby, "Method", rb_cObject);
297
+ rb_define_method(rb_cFastRubyMethod, "tree_pointer", fastruby_method_tree_pointer,0);
298
+ rb_define_method(rb_cFastRubyMethod, "tree", fastruby_method_tree,0);
299
+ rb_define_method(rb_cFastRubyMethod, "tree=", fastruby_method_tree_eq,1);
300
+ }
@@ -22,6 +22,9 @@ require "fastruby/inline_extension"
22
22
  require "fastruby/method_extension"
23
23
  require "fastruby/logging"
24
24
  require "fastruby/getlocals"
25
+ require "fastruby_load_path"
26
+
27
+ require FastRuby.fastruby_load_path + "/../ext/fastruby_base/fastruby_base"
25
28
 
26
29
  module FastRuby
27
30
 
@@ -43,7 +46,6 @@ module FastRuby
43
46
  end
44
47
 
45
48
  class Method
46
- attr_accessor :tree
47
49
  attr_accessor :locals
48
50
  attr_accessor :options
49
51
  attr_accessor :snippet_hash
@@ -53,75 +55,28 @@ module FastRuby
53
55
  @owner = owner
54
56
  end
55
57
 
56
- def method_from_signature(signature, inference_complete)
57
- begin
58
- recvtype = @owner
59
- if recvtype.respond_to? :fastruby_method and inference_complete
58
+ def build(signature, noreturn = false)
59
+ return nil unless tree
60
+
61
+ no_cache = false
60
62
 
61
- method_tree = nil
62
- begin
63
- method_tree = recvtype.instance_method(@method_name.to_sym).fastruby.tree
64
- rescue NoMethodError
65
- end
63
+ mname = FastRuby.make_str_signature(@method_name, signature)
66
64
 
67
- if method_tree
68
- recvtype.build(signature, @method_name.to_sym)
69
- else
70
- recvtype.instance_method(@method_name.to_sym)
71
- end
72
- else
73
- recvtype.instance_method(@method_name.to_sym)
65
+ if @owner.respond_to? :method_hash
66
+ method_hash = @owner.method_hash(@method_name.to_sym) || {}
67
+ if (@owner.has_fastruby_function(method_hash,mname.to_s))
68
+ FastRuby.logger.info "NOT Building #{@owner}::#{@method_name} for signature #{signature.inspect}, it's already done"
69
+ return nil
74
70
  end
75
- rescue NameError
76
- nil
77
71
  end
78
- end
79
-
80
- def convention(signature, inference_complete)
81
- recvtype = @owner
82
- if recvtype.respond_to? :fastruby_method and inference_complete
83
72
 
84
- method_tree = nil
85
- begin
86
- method_tree = recvtype.instance_method(@method_name.to_sym).fastruby.tree
87
- rescue NoMethodError, NameError
88
- end
73
+ FastRuby.logger.info "Building #{@owner}::#{@method_name} for signature #{signature.inspect}"
89
74
 
90
- if method_tree
91
-
92
- args_tree = method_tree[2]
93
-
94
- if args_tree.any?{|x|x.to_s.match(/\*/)}
95
- :fastruby_array
96
- else
97
- :fastruby
98
- end
99
- else
100
- :cruby
101
- end
102
- else
103
- :cruby
104
- end
105
- end
106
-
107
- def build(signature, noreturn = false)
75
+
108
76
  require "fastruby/translator/translator"
109
77
  require "rubygems"
110
78
  require "inline"
111
79
 
112
- no_cache = false
113
-
114
- mname = FastRuby.make_str_signature(@method_name, signature)
115
-
116
- begin
117
- if (@owner.instance_method(mname))
118
- FastRuby.logger.info "NOT Building #{@owner}::#{@method_name} for signature #{signature.inspect}, it's already done"
119
- return @owner.instance_method(mname)
120
- end
121
- rescue NameError
122
- FastRuby.logger.info "Building #{@owner}::#{@method_name} for signature #{signature.inspect}"
123
- end
124
-
125
80
  context = FastRuby::Context.new
126
81
  context.locals = locals
127
82
  context.options = options
@@ -134,11 +89,17 @@ module FastRuby
134
89
 
135
90
  (1..signature.size).each do |i|
136
91
  arg = args_tree[i]
137
- context.infer_lvar_map[arg] = signature[i]
92
+ if arg
93
+ if arg.to_s.match(/\*/)
94
+ context.infer_lvar_map[arg.to_s.gsub("*","").to_sym] = Array
95
+ else
96
+ context.infer_lvar_map[arg.to_sym] = signature[i]
97
+ end
98
+ end
138
99
  end
139
100
 
140
101
  context.infer_self = signature[0]
141
- c_code = context.to_c_method(tree)
102
+ c_code = context.to_c_method(tree,signature)
142
103
 
143
104
  unless options[:main]
144
105
  context.define_method_at_init(@owner,@method_name, args_tree.size+1, signature)
@@ -213,16 +174,13 @@ module FastRuby
213
174
  FastRuby.cache.insert(snippet_hash, so_name) unless no_cache
214
175
  end
215
176
 
216
- if noreturn then
217
- nil
218
- else
219
- ret = @owner.instance_method(mname)
177
+ ret = Object.new
220
178
 
221
- ret.extend MethodExtent
222
- ret.yield_signature = context.yield_signature
179
+ ret.extend MethodExtent
180
+ ret.yield_signature = context.yield_signature
181
+
182
+ ret
223
183
 
224
- ret
225
- end
226
184
  end
227
185
 
228
186
  module MethodExtent
@@ -235,12 +193,22 @@ module FastRuby
235
193
  fastruby_method(method_name.to_sym).build(signature, noreturn)
236
194
  end
237
195
 
238
- def convention(signature, method_name, inference_complete)
239
- fastruby_method(method_name.to_sym).convention(signature, inference_complete)
196
+ def register_method_value(method_name,key,value)
197
+ @method_hash = Hash.new unless @method_hash
198
+ @method_hash[method_name] = Hash.new unless @method_hash[method_name]
199
+ @method_hash[method_name][key] = value
240
200
  end
241
-
242
- def method_from_signature(signature, method_name, inference_complete)
243
- fastruby_method(method_name.to_sym).method_from_signature(signature, inference_complete)
201
+
202
+ def method_hash(method_name)
203
+ @method_hash = Hash.new unless @method_hash
204
+ @method_hash[method_name]
205
+ end
206
+
207
+ def method_added(method_name)
208
+ if self.respond_to? :clear_method_hash_addresses
209
+ FastRuby.unset_tree(self,method_name)
210
+ self.clear_method_hash_addresses(method_hash(method_name))
211
+ end
244
212
  end
245
213
 
246
214
  def fastruby_method(mname_)
@@ -86,7 +86,7 @@ class Object
86
86
  else
87
87
 
88
88
  objs.sort{|x,y|
89
- (y =~ /Inline_Object/ ? 1 : 0) - (x =~ /Inline_Object/ ? 1 : 0)
89
+ File.new(x).ctime <=> File.new(y).ctime
90
90
  }.each do |obj|
91
91
 
92
92
  begin
@@ -35,6 +35,12 @@ module FastRuby
35
35
  end
36
36
  end
37
37
  end
38
+
39
+ def self.unset_tree(klass, method_name)
40
+ fastrubym = klass.fastruby_method(method_name)
41
+ fastrubym.tree = nil
42
+ nil
43
+ end
38
44
 
39
45
  def self.set_tree(klass, method_name, tree, snippet_hash, options = {})
40
46
  locals = Set.new
@@ -98,9 +98,8 @@ module FastRuby
98
98
 
99
99
  args[1..-1].each do |arg|
100
100
  argtype = infer_type(arg)
101
- if argtype
102
- signature << argtype
103
- else
101
+ signature << argtype
102
+ unless argtype
104
103
  inference_complete = false
105
104
  end
106
105
  end
@@ -32,45 +32,9 @@ module FastRuby
32
32
  hash = Hash.new
33
33
  value_cast = ( ["VALUE"]*(args_tree.size+2) ).join(",")
34
34
 
35
- multiple_arguments = args_tree[1..-1].find{|x| x.to_s =~ /\*/}
35
+ strmethodargs = "self,block,(VALUE)&frame"
36
36
 
37
- args_array_accessors = if multiple_arguments
38
- (0..args_tree.size-3).map{|x| "argv[#{x}]"} + ["argarray"]
39
- else
40
- (0..args_tree.size-2).map{|x| "argv[#{x}]"}
41
- end
42
-
43
- strmethodargs = ""
44
-
45
- if args_tree.size > 1
46
- strmethodargs = "self,block,(VALUE)&frame,#{args_array_accessors.map(&:to_s).join(",") }"
47
- else
48
- strmethodargs = "self,block,(VALUE)&frame"
49
- end
50
-
51
- strmakecall = if multiple_arguments
52
- "
53
- if (argc_ > #{args_tree.size-2}) {
54
- VALUE argarray = rb_ary_new4(argc_-#{args_tree.size-2}, argv+#{args_tree.size-2});
55
- return ((VALUE(*)(#{value_cast}))body->nd_cfnc)(#{strmethodargs});
56
- } else if (argc_ == #{args_tree.size-2}) {
57
- // pass pre-calculated method arguments plus an empty array
58
- VALUE argarray = rb_ary_new();
59
- return ((VALUE(*)(#{value_cast}))body->nd_cfnc)(#{strmethodargs});
60
- } else {
61
- rb_raise(rb_eArgError, \"wrong number of arguments (%d for #{args_tree.size-2}))\", argc_);
62
- }
63
- "
64
- else
65
- "if (argc_ == #{args_tree.size-1} && argc == #{args_tree.size+1}) {
66
- return ((VALUE(*)(#{value_cast}))body->nd_cfnc)(#{strmethodargs});
67
- } else {
68
- rb_raise(rb_eArgError, \"wrong number of arguments (%d for #{args_tree.size-1}))\", argc_);
69
- }"
70
- end
71
-
72
37
  anonymous_method_name = anonymous_function{ |anonymous_method_name| "VALUE #{anonymous_method_name}(int argc_, VALUE* argv, VALUE self) {
73
-
74
38
  VALUE klass = #{global_klass_variable};
75
39
  char method_name[0x100];
76
40
 
@@ -78,47 +42,58 @@ module FastRuby
78
42
  method_name[1] = 0;
79
43
 
80
44
  sprintf(method_name+1, \"#{method_name}\");
45
+ sprintf(method_name+strlen(method_name), \"%lu\", FIX2LONG(rb_obj_id(CLASS_OF(self))));
81
46
 
82
- int i;
83
- for (i=0; i<argc_; i++) {
84
- sprintf(method_name+strlen(method_name), \"%lu\", FIX2LONG(rb_obj_id(CLASS_OF(argv[i]))));
85
- }
47
+ int i;
48
+ for (i=0; i<argc_; i++) {
49
+ sprintf(method_name+strlen(method_name), \"%lu\", FIX2LONG(rb_obj_id(CLASS_OF(argv[i]))));
50
+ }
86
51
 
87
- NODE* body;
52
+ void** address = 0;
53
+ void* fptr = 0;
88
54
  ID id;
55
+ VALUE rb_method_hash;
89
56
 
90
57
  id = rb_intern(method_name);
91
- body = rb_method_node(klass,id);
58
+ rb_method_hash = rb_funcall(klass, #{intern_num :method_hash},1,#{literal_value method_name});
59
+
60
+ if (rb_method_hash != Qnil) {
61
+ VALUE tmp = rb_hash_aref(rb_method_hash, LONG2FIX(id));
62
+ if (tmp != Qnil) {
63
+ address = (void**)FIX2LONG(tmp);
64
+ fptr = *address;
65
+ }
66
+ }
92
67
 
93
- if (body == 0) {
94
- VALUE argv_class[argc_+1];
68
+ if (fptr == 0) {
69
+ VALUE argv_class[argc_+1];
70
+
71
+ argv_class[0] = CLASS_OF(self);
72
+ for (i=0; i<argc_; i++) {
73
+ argv_class[i+1] = CLASS_OF(argv[i]);
74
+ }
75
+
76
+ VALUE signature = rb_ary_new4(argc_+1,argv_class);
77
+
78
+ rb_funcall(#{global_klass_variable}, #{intern_num :build}, 2, signature,rb_str_new2(#{method_name.to_s.inspect}));
79
+
80
+ id = rb_intern(method_name);
81
+ rb_method_hash = rb_funcall(klass, #{intern_num :method_hash},1,#{literal_value method_name});
95
82
 
96
- argv_class[0] = CLASS_OF(self);
97
- for (i=0; i<argc_; i++) {
98
- argv_class[i+1] = CLASS_OF(argv[i]);
83
+ if (rb_method_hash != Qnil) {
84
+ VALUE tmp = rb_hash_aref(rb_method_hash, LONG2FIX(id));
85
+ if (tmp != Qnil) {
86
+ address = (void**)FIX2LONG(tmp);
87
+ fptr = *address;
88
+ }
99
89
  }
100
90
 
101
- VALUE signature = rb_ary_new4(argc_+1,argv_class);
102
- VALUE mobject = rb_funcall(#{global_klass_variable}, #{intern_num :build}, 2, signature,rb_str_new2(#{method_name.to_s.inspect}));
103
-
104
- struct METHOD {
105
- VALUE klass, rklass;
106
- VALUE recv;
107
- ID id, oid;
108
- int safe_level;
109
- NODE *body;
110
- };
111
-
112
- struct METHOD *data;
113
- Data_Get_Struct(mobject, struct METHOD, data);
114
- body = data->body;
115
-
116
- if (body == 0) {
117
- rb_raise(rb_eRuntimeError,\"method not found after build: '%s'\", method_name);
91
+ if (fptr == 0) {
92
+ rb_raise(rb_eRuntimeError, \"Error: method not found after build\");
118
93
  }
94
+
119
95
  }
120
96
 
121
- if (nd_type(body) == NODE_CFUNC) {
122
97
  struct {
123
98
  void* parent_frame;
124
99
  void* plocals;
@@ -137,8 +112,6 @@ module FastRuby
137
112
  frame.thread_data = rb_current_thread_data();
138
113
  frame.targetted = 0;
139
114
 
140
- int argc = body->nd_argc;
141
-
142
115
  VALUE block = Qfalse;
143
116
 
144
117
  if (rb_block_given_p()) {
@@ -166,10 +139,15 @@ module FastRuby
166
139
  return Qnil;
167
140
  }
168
141
 
169
- #{strmakecall}
170
- }
142
+ if (argc_ == 0) return ((VALUE(*)(VALUE,VALUE,VALUE))fptr)(#{strmethodargs});
143
+
144
+ #{ (1..15).map{ |i|
145
+ value_cast = ( ["VALUE"]*(i+3) ).join(",")
146
+ "if (argc_ == #{i}) return ((VALUE(*)(#{value_cast}))fptr)(#{strmethodargs}, #{(0..i-1).map{|x| "argv[#{x}]"}.join(",")});"
147
+ }.join("\n");
148
+ }
171
149
 
172
- return Qnil;
150
+ rb_raise(rb_eArgError, \"too many arguments: %d\", argc_);
173
151
  }"
174
152
  }
175
153
 
@@ -179,8 +157,9 @@ module FastRuby
179
157
  alt_options.delete(:main)
180
158
 
181
159
  inline_block "
160
+ rb_define_method(plocals->self, #{method_name.to_s.inspect}, #{anonymous_method_name}, -1 );
161
+
182
162
  #{global_klass_variable} = plocals->self;
183
-
184
163
  // set tree
185
164
  rb_funcall(#{literal_value FastRuby}, #{intern_num :set_tree}, 5,
186
165
  #{global_klass_variable},
@@ -191,7 +170,6 @@ module FastRuby
191
170
 
192
171
  );
193
172
 
194
- rb_define_method(plocals->self, #{method_name.to_s.inspect}, #{anonymous_method_name}, -1 );
195
173
  "
196
174
 
197
175
  end
@@ -463,10 +463,9 @@ module FastRuby
463
463
 
464
464
  call_frame_struct_code = "
465
465
  #{@block_struct} block;
466
- #{@locals_struct} *plocals = (void*)param;
467
466
 
468
467
  block.block_function_address = (void*)#{anonymous_function(&block_code)};
469
- block.block_function_param = (void*)param;
468
+ block.block_function_param = (void*)plocals;
470
469
 
471
470
  // create a call_frame
472
471
  #{@frame_struct} call_frame;
@@ -534,48 +533,45 @@ module FastRuby
534
533
  };
535
534
  "
536
535
 
537
- if call_args_tree.size > 1 ? call_args_tree.last[0] == :splat : false
536
+ recvtype = nil if call_args_tree.size > 1 ? call_args_tree.last[0] == :splat : false
537
+ unless recvtype
538
538
  inline_block "
539
539
  #{funcall_call_code}
540
540
  "
541
541
  else
542
+ encoded_address = encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name)
542
543
 
543
- if call_args_tree.size > 1
544
+ fastruby_call_code = if call_args_tree.size > 1
544
545
  value_cast = ( ["VALUE"]*(call_tree[3].size) ).join(",") + ", VALUE, VALUE"
545
546
 
546
- str_called_code_args = call_tree[3][1..-1].map{|subtree| to_c subtree}.join(",")
547
-
548
- caller_code = proc { |name| "
549
- static VALUE #{name}(VALUE param, VALUE pframe) {
547
+ "
550
548
  // call to #{call_tree[2]}
551
549
  #{call_frame_struct_code}
552
550
 
553
- VALUE ret = ((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name)})(#{str_recv}, (VALUE)&block, (VALUE)&call_frame, #{str_called_code_args});
551
+ VALUE ret = ((VALUE(*)(#{value_cast}))#{encoded_address})(#{str_recv}, (VALUE)&block, (VALUE)&call_frame, #{str_called_code_args});
554
552
  plocals->call_frame = old_call_frame;
555
553
  return ret;
556
- }
557
554
  "
558
- }
559
-
560
555
  else
561
- caller_code = proc { |name| "
562
- static VALUE #{name}(VALUE param, VALUE pframe) {
556
+ "
563
557
  #{call_frame_struct_code}
564
558
 
565
559
  // call to #{call_tree[2]}
566
- VALUE ret = ((VALUE(*)(VALUE,VALUE,VALUE))#{encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name)})(#{str_recv}, (VALUE)&block, (VALUE)&call_frame);
560
+ VALUE ret = ((VALUE(*)(VALUE,VALUE,VALUE))#{encoded_address})(#{str_recv}, (VALUE)&block, (VALUE)&call_frame);
567
561
  plocals->call_frame = old_call_frame;
568
562
  return ret;
569
- }
570
563
  "
571
- }
572
564
  end
573
565
 
574
566
  inline_block "
575
- if (#{convention_global_name}) {
576
- return #{anonymous_function(&caller_code)}((VALUE)plocals, (VALUE)pframe);
577
- } else {
567
+ if (#{@last_address_name} == 0) {
578
568
  #{funcall_call_code}
569
+ } else {
570
+ if (*#{@last_address_name} == 0) {
571
+ #{funcall_call_code}
572
+ } else {
573
+ #{fastruby_call_code}
574
+ }
579
575
  }
580
576
  "
581
577
  end