fastruby 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/README +3 -2
- data/Rakefile +1 -1
- data/benchmarks/benchmark7.rb +77 -0
- data/ext/fastruby_base/fastruby_base.c +3 -1
- data/ext/fastruby_base/fastruby_base.inl +79 -1
- data/lib/fastruby/builder.rb +43 -75
- data/lib/fastruby/object.rb +1 -1
- data/lib/fastruby/set_tree.rb +6 -0
- data/lib/fastruby/translator/modules/call.rb +2 -3
- data/lib/fastruby/translator/modules/defn.rb +51 -73
- data/lib/fastruby/translator/modules/iter.rb +16 -20
- data/lib/fastruby/translator/translator.rb +253 -91
- data/lib/fastruby.rb +1 -10
- data/lib/fastruby_load_path.rb +29 -0
- data/spec/call/base_call_spec.rb +82 -0
- data/spec/defn/multiple_args_spec.rb +11 -0
- data/spec/defn/replacement_spec.rb +102 -0
- metadata +8 -4
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
|
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
@@ -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
|
@@ -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
|
+
}
|
data/lib/fastruby/builder.rb
CHANGED
@@ -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
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
def build(signature, noreturn = false)
|
59
|
+
return nil unless tree
|
60
|
+
|
61
|
+
no_cache = false
|
60
62
|
|
61
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
217
|
-
nil
|
218
|
-
else
|
219
|
-
ret = @owner.instance_method(mname)
|
177
|
+
ret = Object.new
|
220
178
|
|
221
|
-
|
222
|
-
|
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
|
239
|
-
|
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
|
243
|
-
|
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_)
|
data/lib/fastruby/object.rb
CHANGED
data/lib/fastruby/set_tree.rb
CHANGED
@@ -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
|
@@ -32,45 +32,9 @@ module FastRuby
|
|
32
32
|
hash = Hash.new
|
33
33
|
value_cast = ( ["VALUE"]*(args_tree.size+2) ).join(",")
|
34
34
|
|
35
|
-
|
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
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
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
|
-
|
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 (
|
94
|
-
|
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
|
-
|
97
|
-
|
98
|
-
|
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
|
-
|
102
|
-
|
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
|
-
|
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
|
-
|
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*)
|
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
|
-
|
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}))#{
|
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
|
-
|
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))#{
|
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 (#{
|
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
|