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