fastruby 0.0.12 → 0.0.13
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 +8 -0
- data/README +0 -1
- data/Rakefile +1 -1
- data/lib/fastruby/builder.rb +9 -2
- data/lib/fastruby/translator/modules/block.rb +92 -0
- data/lib/fastruby/translator/modules/call.rb +137 -0
- data/lib/fastruby/translator/modules/defn.rb +221 -0
- data/lib/fastruby/translator/modules/exceptions.rb +134 -0
- data/lib/fastruby/translator/modules/flow.rb +91 -0
- data/lib/fastruby/translator/modules/iter.rb +584 -0
- data/lib/fastruby/translator/modules/literal.rb +86 -0
- data/lib/fastruby/translator/modules/logical.rb +38 -0
- data/lib/fastruby/translator/modules/method_group.rb +174 -0
- data/lib/fastruby/translator/modules/nonlocal.rb +96 -0
- data/lib/fastruby/translator/modules/variable.rb +190 -0
- data/lib/fastruby/translator/translator.rb +1171 -0
- data/lib/fastruby/translator/translator_modules.rb +49 -0
- data/lib/fastruby.rb +1 -1
- data/spec/call/multiple_args_spec.rb +87 -0
- data/spec/defn/multiple_args_spec.rb +271 -0
- metadata +19 -7
- data/lib/fastruby/translator/call.rb +0 -2594
- data/lib/fastruby/translator/iter.rb +0 -2594
- data/lib/fastruby/translator.rb +0 -2594
@@ -0,0 +1,1171 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the fastruby project, http://github.com/tario/fastruby
|
4
|
+
|
5
|
+
Copyright (c) 2011 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
fastruby is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
fastruby is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
require "set"
|
22
|
+
require "rubygems"
|
23
|
+
require "sexp"
|
24
|
+
require "fastruby/method_extension"
|
25
|
+
require "fastruby/set_tree"
|
26
|
+
require "fastruby/exceptions"
|
27
|
+
require "fastruby/translator/translator_modules"
|
28
|
+
|
29
|
+
|
30
|
+
module FastRuby
|
31
|
+
class Context
|
32
|
+
attr_accessor :infer_lvar_map
|
33
|
+
attr_accessor :alt_method_name
|
34
|
+
attr_accessor :locals
|
35
|
+
attr_accessor :options
|
36
|
+
attr_accessor :infer_self
|
37
|
+
attr_accessor :snippet_hash
|
38
|
+
attr_reader :no_cache
|
39
|
+
attr_reader :init_extra
|
40
|
+
attr_reader :extra_code
|
41
|
+
attr_reader :yield_signature
|
42
|
+
|
43
|
+
TranslatorModules.instance.load_under(FastRuby.fastruby_load_path + "/fastruby/translator/modules/")
|
44
|
+
TranslatorModules.instance.modls.each do |modl|
|
45
|
+
include modl
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(common_func = true)
|
49
|
+
@infer_lvar_map = Hash.new
|
50
|
+
@no_cache = false
|
51
|
+
@extra_code = ""
|
52
|
+
@options = {}
|
53
|
+
@init_extra = Array.new
|
54
|
+
@frame_struct = "struct {
|
55
|
+
void* parent_frame;
|
56
|
+
void* plocals;
|
57
|
+
jmp_buf jmp;
|
58
|
+
VALUE return_value;
|
59
|
+
int rescue;
|
60
|
+
VALUE last_error;
|
61
|
+
VALUE next_recv;
|
62
|
+
int targetted;
|
63
|
+
struct FASTRUBYTHREADDATA* thread_data;
|
64
|
+
}"
|
65
|
+
|
66
|
+
@block_struct = "struct {
|
67
|
+
void* block_function_address;
|
68
|
+
void* block_function_param;
|
69
|
+
}"
|
70
|
+
|
71
|
+
|
72
|
+
extra_code << "
|
73
|
+
#include \"node.h\"
|
74
|
+
|
75
|
+
#define FASTRUBY_TAG_RETURN 0x80
|
76
|
+
#define FASTRUBY_TAG_NEXT 0x81
|
77
|
+
#define FASTRUBY_TAG_BREAK 0x82
|
78
|
+
#define FASTRUBY_TAG_RAISE 0x83
|
79
|
+
#define FASTRUBY_TAG_REDO 0x84
|
80
|
+
#define FASTRUBY_TAG_RETRY 0x85
|
81
|
+
#define TAG_RAISE 0x6
|
82
|
+
|
83
|
+
#ifndef __INLINE_FASTRUBY_BASE
|
84
|
+
#include \"#{FastRuby.fastruby_load_path}/../ext/fastruby_base/fastruby_base.inl\"
|
85
|
+
#define __INLINE_FASTRUBY_BASE
|
86
|
+
#endif
|
87
|
+
"
|
88
|
+
|
89
|
+
ruby_code = "
|
90
|
+
$LOAD_PATH << #{FastRuby.fastruby_load_path.inspect}
|
91
|
+
require #{FastRuby.fastruby_script_path.inspect}
|
92
|
+
"
|
93
|
+
|
94
|
+
init_extra << "
|
95
|
+
rb_eval_string(#{ruby_code.inspect});
|
96
|
+
"
|
97
|
+
|
98
|
+
@lambda_node_gvar = add_global_name("NODE*", 0);
|
99
|
+
@proc_node_gvar = add_global_name("NODE*", 0);
|
100
|
+
@procnew_node_gvar = add_global_name("NODE*", 0);
|
101
|
+
|
102
|
+
init_extra << "
|
103
|
+
#{@lambda_node_gvar} = rb_method_node(rb_cObject, #{intern_num :lambda});
|
104
|
+
#{@proc_node_gvar} = rb_method_node(rb_cObject, #{intern_num :proc});
|
105
|
+
#{@procnew_node_gvar} = rb_method_node(CLASS_OF(rb_cProc), #{intern_num :new});
|
106
|
+
"
|
107
|
+
|
108
|
+
@common_func = common_func
|
109
|
+
if common_func
|
110
|
+
extra_code << "static VALUE _rb_gvar_set(void* ge,VALUE value) {
|
111
|
+
rb_gvar_set((struct global_entry*)ge,value);
|
112
|
+
return value;
|
113
|
+
}
|
114
|
+
"
|
115
|
+
|
116
|
+
extra_code << "static VALUE re_yield(int argc, VALUE* argv, VALUE param, VALUE _parent_frame) {
|
117
|
+
VALUE yield_args = rb_ary_new4(argc,argv);
|
118
|
+
VALUE* yield_args_p = &yield_args;
|
119
|
+
|
120
|
+
#{@frame_struct}* pframe;
|
121
|
+
pframe = (typeof(pframe))_parent_frame;
|
122
|
+
|
123
|
+
return #{protected_block("rb_yield_splat(*(VALUE*)yield_args_p)",true,"yield_args_p",true)};
|
124
|
+
}"
|
125
|
+
|
126
|
+
extra_code << "static VALUE _rb_ivar_set(VALUE recv,ID idvar, VALUE value) {
|
127
|
+
rb_ivar_set(recv,idvar,value);
|
128
|
+
return value;
|
129
|
+
}
|
130
|
+
"
|
131
|
+
|
132
|
+
extra_code << "static VALUE __rb_cvar_set(VALUE recv,ID idvar, VALUE value, int warn) {
|
133
|
+
rb_cvar_set(recv,idvar,value,warn);
|
134
|
+
return value;
|
135
|
+
}
|
136
|
+
"
|
137
|
+
|
138
|
+
extra_code << "static VALUE _lvar_assing(VALUE* destination,VALUE value) {
|
139
|
+
*destination = value;
|
140
|
+
return value;
|
141
|
+
}
|
142
|
+
|
143
|
+
/*
|
144
|
+
#{caller.join("\n")}
|
145
|
+
*/
|
146
|
+
|
147
|
+
"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def to_c(tree)
|
152
|
+
return "Qnil" unless tree
|
153
|
+
send("to_c_" + tree[0].to_s, tree);
|
154
|
+
end
|
155
|
+
|
156
|
+
def anonymous_function
|
157
|
+
|
158
|
+
name = "anonymous" + rand(10000000).to_s
|
159
|
+
extra_code << yield(name)
|
160
|
+
|
161
|
+
name
|
162
|
+
end
|
163
|
+
|
164
|
+
def frame_call(inner_code)
|
165
|
+
inline_block "
|
166
|
+
|
167
|
+
|
168
|
+
// create a call_frame
|
169
|
+
#{@frame_struct} call_frame;
|
170
|
+
typeof(call_frame)* old_pframe = (void*)pframe;
|
171
|
+
|
172
|
+
pframe = (typeof(pframe))&call_frame;
|
173
|
+
|
174
|
+
call_frame.parent_frame = (void*)pframe;
|
175
|
+
call_frame.plocals = plocals;
|
176
|
+
call_frame.return_value = Qnil;
|
177
|
+
call_frame.targetted = 0;
|
178
|
+
call_frame.thread_data = old_pframe->thread_data;
|
179
|
+
if (call_frame.thread_data == 0) call_frame.thread_data = rb_current_thread_data();
|
180
|
+
|
181
|
+
VALUE old_call_frame = plocals->call_frame;
|
182
|
+
plocals->call_frame = LONG2FIX(&call_frame);
|
183
|
+
|
184
|
+
int aux = setjmp(call_frame.jmp);
|
185
|
+
if (aux != 0) {
|
186
|
+
if (call_frame.targetted == 0) {
|
187
|
+
longjmp(old_pframe->jmp,aux);
|
188
|
+
}
|
189
|
+
|
190
|
+
if (aux == FASTRUBY_TAG_BREAK) {
|
191
|
+
plocals->call_frame = old_call_frame;
|
192
|
+
return call_frame.return_value;
|
193
|
+
} else if (aux == FASTRUBY_TAG_RETRY ) {
|
194
|
+
// do nothing and let the call execute again
|
195
|
+
} else {
|
196
|
+
plocals->call_frame = old_call_frame;
|
197
|
+
return call_frame.return_value;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
VALUE ret = #{inner_code};
|
202
|
+
plocals->call_frame = old_call_frame;
|
203
|
+
return ret;
|
204
|
+
"
|
205
|
+
end
|
206
|
+
|
207
|
+
def initialize_method_structs(args_tree)
|
208
|
+
@locals_struct = "struct {
|
209
|
+
VALUE return_value;
|
210
|
+
VALUE pframe;
|
211
|
+
VALUE block_function_address;
|
212
|
+
VALUE block_function_param;
|
213
|
+
VALUE call_frame;
|
214
|
+
VALUE active;
|
215
|
+
VALUE targetted;
|
216
|
+
#{@locals.map{|l| "VALUE #{l};\n"}.join}
|
217
|
+
#{args_tree[1..-1].map{|arg| "VALUE #{arg.to_s.gsub("*","")};\n"}.join};
|
218
|
+
}"
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
def to_c_method_defs(tree)
|
223
|
+
|
224
|
+
method_name = tree[2]
|
225
|
+
args_tree = tree[3]
|
226
|
+
|
227
|
+
impl_tree = tree[4][1]
|
228
|
+
|
229
|
+
initialize_method_structs(args_tree)
|
230
|
+
|
231
|
+
strargs = if args_tree.size > 1
|
232
|
+
|
233
|
+
"VALUE self, void* block_address, VALUE block_param, void* _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg.to_s.gsub("*","")}" }.join(",") }"
|
234
|
+
else
|
235
|
+
"VALUE self, void* block_address, VALUE block_param, void* _parent_frame"
|
236
|
+
end
|
237
|
+
|
238
|
+
extra_code << "static VALUE #{@alt_method_name + "_real"}(#{strargs}) {
|
239
|
+
#{func_frame}
|
240
|
+
|
241
|
+
#{args_tree[1..-1].map { |arg|
|
242
|
+
arg = arg.to_s
|
243
|
+
arg.gsub!("*","")
|
244
|
+
"plocals->#{arg} = #{arg};\n"
|
245
|
+
}.join("") }
|
246
|
+
|
247
|
+
plocals->block_function_address = LONG2FIX(block_address);
|
248
|
+
plocals->block_function_param = LONG2FIX(block_param);
|
249
|
+
|
250
|
+
return #{to_c impl_tree};
|
251
|
+
}"
|
252
|
+
|
253
|
+
strargs2 = if args_tree.size > 1
|
254
|
+
"VALUE self, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
|
255
|
+
else
|
256
|
+
"VALUE self"
|
257
|
+
end
|
258
|
+
|
259
|
+
value_cast = ( ["VALUE"]*(args_tree.size+1) ).join(",")
|
260
|
+
strmethodargs = ""
|
261
|
+
|
262
|
+
if args_tree.size > 1
|
263
|
+
strmethodargs = "self,block_address,block_param,&frame,#{args_tree[1..-1].map(&:to_s).join(",") }"
|
264
|
+
else
|
265
|
+
strmethodargs = "self,block_address,block_param,&frame"
|
266
|
+
end
|
267
|
+
|
268
|
+
"
|
269
|
+
VALUE #{@alt_method_name}(#{strargs2}) {
|
270
|
+
#{@frame_struct} frame;
|
271
|
+
int argc = #{args_tree.size};
|
272
|
+
void* block_address = 0;
|
273
|
+
VALUE block_param = Qnil;
|
274
|
+
|
275
|
+
frame.plocals = 0;
|
276
|
+
frame.parent_frame = 0;
|
277
|
+
frame.return_value = Qnil;
|
278
|
+
frame.rescue = 0;
|
279
|
+
frame.targetted = 0;
|
280
|
+
frame.thread_data = rb_current_thread_data();
|
281
|
+
|
282
|
+
if (rb_block_given_p()) {
|
283
|
+
block_address = #{
|
284
|
+
anonymous_function{|name|
|
285
|
+
"static VALUE #{name}(int argc, VALUE* argv, VALUE param) {
|
286
|
+
return rb_yield_splat(rb_ary_new4(argc,argv));
|
287
|
+
}"
|
288
|
+
}
|
289
|
+
};
|
290
|
+
|
291
|
+
block_param = 0;
|
292
|
+
}
|
293
|
+
|
294
|
+
int aux = setjmp(frame.jmp);
|
295
|
+
if (aux != 0) {
|
296
|
+
rb_funcall(self, #{intern_num :raise}, 1, frame.thread_data->exception);
|
297
|
+
}
|
298
|
+
|
299
|
+
|
300
|
+
return #{@alt_method_name + "_real"}(#{strmethodargs});
|
301
|
+
}
|
302
|
+
"
|
303
|
+
end
|
304
|
+
|
305
|
+
def add_main
|
306
|
+
if options[:main]
|
307
|
+
|
308
|
+
extra_code << "
|
309
|
+
static VALUE #{@alt_method_name}(VALUE self__);
|
310
|
+
static VALUE main_proc_call(VALUE self__, VALUE class_self_) {
|
311
|
+
#{@alt_method_name}(class_self_);
|
312
|
+
return Qnil;
|
313
|
+
}
|
314
|
+
|
315
|
+
"
|
316
|
+
|
317
|
+
init_extra << "
|
318
|
+
{
|
319
|
+
VALUE newproc = rb_funcall(rb_cObject,#{intern_num :new},0);
|
320
|
+
rb_define_singleton_method(newproc, \"call\", main_proc_call, 1);
|
321
|
+
rb_gv_set(\"$last_obj_proc\", newproc);
|
322
|
+
|
323
|
+
}
|
324
|
+
"
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def define_method_at_init(klass,method_name, size, signature)
|
329
|
+
init_extra << "
|
330
|
+
{
|
331
|
+
VALUE method_name = rb_funcall(
|
332
|
+
#{literal_value FastRuby},
|
333
|
+
#{intern_num :make_str_signature},
|
334
|
+
2,
|
335
|
+
#{literal_value method_name},
|
336
|
+
#{literal_value signature}
|
337
|
+
);
|
338
|
+
|
339
|
+
rb_define_method(#{literal_value klass}, RSTRING(method_name)->ptr, #{alt_method_name}, #{size});
|
340
|
+
}
|
341
|
+
"
|
342
|
+
end
|
343
|
+
|
344
|
+
def to_c_method(tree)
|
345
|
+
method_name = tree[1]
|
346
|
+
args_tree = tree[2]
|
347
|
+
impl_tree = tree[3][1]
|
348
|
+
|
349
|
+
if (options[:main])
|
350
|
+
initialize_method_structs(args_tree)
|
351
|
+
|
352
|
+
strargs = if args_tree.size > 1
|
353
|
+
"VALUE block, VALUE _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg.to_s.gsub("*","")}" }.join(",") }"
|
354
|
+
else
|
355
|
+
"VALUE block, VALUE _parent_frame"
|
356
|
+
end
|
357
|
+
|
358
|
+
ret = "VALUE #{@alt_method_name || method_name}() {
|
359
|
+
|
360
|
+
#{@locals_struct} *plocals;
|
361
|
+
#{@frame_struct} frame;
|
362
|
+
#{@frame_struct} *pframe;
|
363
|
+
|
364
|
+
frame.parent_frame = 0;
|
365
|
+
frame.return_value = Qnil;
|
366
|
+
frame.rescue = 0;
|
367
|
+
frame.targetted = 0;
|
368
|
+
frame.thread_data = rb_current_thread_data();
|
369
|
+
|
370
|
+
|
371
|
+
int stack_chunk_instantiated = 0;
|
372
|
+
VALUE rb_previous_stack_chunk = Qnil;
|
373
|
+
VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
|
374
|
+
struct STACKCHUNK* stack_chunk = 0;
|
375
|
+
|
376
|
+
if (rb_stack_chunk != Qnil) {
|
377
|
+
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
378
|
+
}
|
379
|
+
|
380
|
+
if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
|
381
|
+
rb_previous_stack_chunk = rb_stack_chunk;
|
382
|
+
rb_gc_register_address(&rb_stack_chunk);
|
383
|
+
stack_chunk_instantiated = 1;
|
384
|
+
|
385
|
+
rb_stack_chunk = rb_stack_chunk_create(Qnil);
|
386
|
+
frame.thread_data->rb_stack_chunk = rb_stack_chunk;
|
387
|
+
|
388
|
+
rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
|
389
|
+
|
390
|
+
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
391
|
+
}
|
392
|
+
|
393
|
+
int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
|
394
|
+
|
395
|
+
plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
|
396
|
+
plocals->active = Qtrue;
|
397
|
+
plocals->targetted = Qfalse;
|
398
|
+
plocals->pframe = LONG2FIX(&frame);
|
399
|
+
frame.plocals = plocals;
|
400
|
+
|
401
|
+
pframe = (void*)&frame;
|
402
|
+
|
403
|
+
VALUE last_expression = Qnil;
|
404
|
+
|
405
|
+
int aux = setjmp(pframe->jmp);
|
406
|
+
if (aux != 0) {
|
407
|
+
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
408
|
+
|
409
|
+
if (stack_chunk_instantiated) {
|
410
|
+
rb_gc_unregister_address(&rb_stack_chunk);
|
411
|
+
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
412
|
+
}
|
413
|
+
|
414
|
+
plocals->active = Qfalse;
|
415
|
+
return plocals->return_value;
|
416
|
+
}
|
417
|
+
|
418
|
+
plocals->self = self;
|
419
|
+
|
420
|
+
#{args_tree[1..-1].map { |arg|
|
421
|
+
arg = arg.to_s
|
422
|
+
arg.gsub!("*","")
|
423
|
+
"plocals->#{arg} = #{arg};\n"
|
424
|
+
}.join("") }
|
425
|
+
|
426
|
+
plocals->block_function_address = LONG2FIX(0);
|
427
|
+
plocals->block_function_param = LONG2FIX(Qnil);
|
428
|
+
plocals->call_frame = LONG2FIX(0);
|
429
|
+
|
430
|
+
VALUE ret = #{to_c impl_tree};
|
431
|
+
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
432
|
+
|
433
|
+
if (stack_chunk_instantiated) {
|
434
|
+
rb_gc_unregister_address(&rb_stack_chunk);
|
435
|
+
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
436
|
+
}
|
437
|
+
|
438
|
+
plocals->active = Qfalse;
|
439
|
+
return ret;
|
440
|
+
|
441
|
+
}"
|
442
|
+
|
443
|
+
add_main
|
444
|
+
ret
|
445
|
+
else
|
446
|
+
|
447
|
+
initialize_method_structs(args_tree)
|
448
|
+
|
449
|
+
strargs = if args_tree.size > 1
|
450
|
+
"VALUE block, VALUE _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg.to_s.gsub("*","")}" }.join(",") }"
|
451
|
+
else
|
452
|
+
"VALUE block, VALUE _parent_frame"
|
453
|
+
end
|
454
|
+
|
455
|
+
ret = "VALUE #{@alt_method_name || method_name}(#{strargs}) {
|
456
|
+
|
457
|
+
#{@frame_struct} frame;
|
458
|
+
#{@frame_struct} *pframe;
|
459
|
+
|
460
|
+
frame.parent_frame = (void*)_parent_frame;
|
461
|
+
frame.return_value = Qnil;
|
462
|
+
frame.rescue = 0;
|
463
|
+
frame.targetted = 0;
|
464
|
+
frame.thread_data = ((typeof(pframe))_parent_frame)->thread_data;
|
465
|
+
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
466
|
+
|
467
|
+
int stack_chunk_instantiated = 0;
|
468
|
+
VALUE rb_previous_stack_chunk = Qnil;
|
469
|
+
VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
|
470
|
+
struct STACKCHUNK* stack_chunk = 0;
|
471
|
+
|
472
|
+
if (rb_stack_chunk != Qnil) {
|
473
|
+
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
474
|
+
}
|
475
|
+
|
476
|
+
if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
|
477
|
+
rb_previous_stack_chunk = rb_stack_chunk;
|
478
|
+
rb_gc_register_address(&rb_stack_chunk);
|
479
|
+
stack_chunk_instantiated = 1;
|
480
|
+
|
481
|
+
rb_stack_chunk = rb_stack_chunk_create(Qnil);
|
482
|
+
frame.thread_data->rb_stack_chunk = rb_stack_chunk;
|
483
|
+
|
484
|
+
rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
|
485
|
+
|
486
|
+
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
487
|
+
}
|
488
|
+
|
489
|
+
|
490
|
+
#{@locals_struct} *plocals;
|
491
|
+
|
492
|
+
int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
|
493
|
+
|
494
|
+
plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
|
495
|
+
frame.plocals = plocals;
|
496
|
+
plocals->active = Qtrue;
|
497
|
+
plocals->targetted = Qfalse;
|
498
|
+
plocals->pframe = LONG2FIX(&frame);
|
499
|
+
plocals->call_frame = LONG2FIX(0);
|
500
|
+
|
501
|
+
pframe = (void*)&frame;
|
502
|
+
|
503
|
+
#{@block_struct} *pblock;
|
504
|
+
VALUE last_expression = Qnil;
|
505
|
+
|
506
|
+
int aux = setjmp(pframe->jmp);
|
507
|
+
if (aux != 0) {
|
508
|
+
plocals->active = Qfalse;
|
509
|
+
|
510
|
+
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
511
|
+
|
512
|
+
if (stack_chunk_instantiated) {
|
513
|
+
rb_gc_unregister_address(&rb_stack_chunk);
|
514
|
+
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
515
|
+
}
|
516
|
+
|
517
|
+
if (plocals->targetted == Qfalse) {
|
518
|
+
longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
|
519
|
+
}
|
520
|
+
|
521
|
+
return plocals->return_value;
|
522
|
+
}
|
523
|
+
|
524
|
+
plocals->self = self;
|
525
|
+
|
526
|
+
#{args_tree[1..-1].map { |arg|
|
527
|
+
arg = arg.to_s
|
528
|
+
arg.gsub!("*","")
|
529
|
+
"plocals->#{arg} = #{arg};\n"
|
530
|
+
}.join("") }
|
531
|
+
|
532
|
+
pblock = (void*)block;
|
533
|
+
if (pblock) {
|
534
|
+
plocals->block_function_address = LONG2FIX(pblock->block_function_address);
|
535
|
+
plocals->block_function_param = LONG2FIX(pblock->block_function_param);
|
536
|
+
} else {
|
537
|
+
plocals->block_function_address = LONG2FIX(0);
|
538
|
+
plocals->block_function_param = LONG2FIX(Qnil);
|
539
|
+
}
|
540
|
+
|
541
|
+
VALUE __ret = #{to_c impl_tree};
|
542
|
+
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
543
|
+
|
544
|
+
if (stack_chunk_instantiated) {
|
545
|
+
rb_gc_unregister_address(&rb_stack_chunk);
|
546
|
+
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
547
|
+
}
|
548
|
+
|
549
|
+
plocals->active = Qfalse;
|
550
|
+
return __ret;
|
551
|
+
}"
|
552
|
+
|
553
|
+
add_main
|
554
|
+
ret
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
def locals_accessor
|
559
|
+
"plocals->"
|
560
|
+
end
|
561
|
+
|
562
|
+
def locals_scope(locals)
|
563
|
+
old_locals = @locals
|
564
|
+
old_locals_struct = @locals_struct
|
565
|
+
|
566
|
+
@locals = locals
|
567
|
+
@locals_struct = "struct {
|
568
|
+
VALUE return_value;
|
569
|
+
VALUE pframe;
|
570
|
+
VALUE block_function_address;
|
571
|
+
VALUE block_function_param;
|
572
|
+
VALUE call_frame;
|
573
|
+
VALUE active;
|
574
|
+
VALUE targetted;
|
575
|
+
#{@locals.map{|l| "VALUE #{l};\n"}.join}
|
576
|
+
}"
|
577
|
+
|
578
|
+
begin
|
579
|
+
yield
|
580
|
+
ensure
|
581
|
+
@locals = old_locals
|
582
|
+
@locals_struct = old_locals_struct
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
def infer_type(recv)
|
587
|
+
if recv[0] == :call
|
588
|
+
if recv[2] == :infer
|
589
|
+
eval(recv[3].last.last.to_s)
|
590
|
+
end
|
591
|
+
elsif recv[0] == :lvar
|
592
|
+
@infer_lvar_map[recv[1]]
|
593
|
+
elsif recv[0] == :self
|
594
|
+
@infer_self
|
595
|
+
elsif recv[0] == :str or recv[0] == :lit
|
596
|
+
recv[1].class
|
597
|
+
else
|
598
|
+
nil
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
def on_block
|
603
|
+
old_on_block = @on_block
|
604
|
+
@on_block = true
|
605
|
+
return yield
|
606
|
+
ensure
|
607
|
+
@on_block = old_on_block
|
608
|
+
end
|
609
|
+
|
610
|
+
def with_extra_inference(extra_inference)
|
611
|
+
previous_infer_lvar_map = @infer_lvar_map
|
612
|
+
begin
|
613
|
+
@infer_lvar_map = @infer_lvar_map.merge(extra_inference)
|
614
|
+
yield
|
615
|
+
ensure
|
616
|
+
@infer_lvar_map = previous_infer_lvar_map
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
def directive(tree)
|
621
|
+
recv = tree[1]
|
622
|
+
mname = tree[2]
|
623
|
+
args = tree[3]
|
624
|
+
|
625
|
+
if mname == :infer
|
626
|
+
return to_c(recv)
|
627
|
+
elsif mname == :lvar_type
|
628
|
+
lvar_name = args[1][1] || args[1][2]
|
629
|
+
lvar_type = eval(args[2][1].to_s)
|
630
|
+
|
631
|
+
@infer_lvar_map[lvar_name] = lvar_type
|
632
|
+
return ""
|
633
|
+
elsif mname == :block_given?
|
634
|
+
return "FIX2LONG(plocals->block_function_address) == 0 ? Qfalse : Qtrue"
|
635
|
+
elsif mname == :inline_c
|
636
|
+
|
637
|
+
code = args[1][1]
|
638
|
+
|
639
|
+
unless (args[2] == s(:false))
|
640
|
+
return anonymous_function{ |name| "
|
641
|
+
static VALUE #{name}(VALUE param) {
|
642
|
+
#{@frame_struct} *pframe = (void*)param;
|
643
|
+
#{@locals_struct} *plocals = (void*)pframe->plocals;
|
644
|
+
#{code};
|
645
|
+
return Qnil;
|
646
|
+
}
|
647
|
+
"
|
648
|
+
}+"((VALUE)pframe)"
|
649
|
+
else
|
650
|
+
code
|
651
|
+
end
|
652
|
+
|
653
|
+
else
|
654
|
+
nil
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
def inline_block_reference(arg, nolocals = false)
|
659
|
+
code = nil
|
660
|
+
|
661
|
+
if arg.instance_of? FastRuby::FastRubySexp
|
662
|
+
code = to_c(arg);
|
663
|
+
else
|
664
|
+
code = arg
|
665
|
+
end
|
666
|
+
|
667
|
+
anonymous_function{ |name| "
|
668
|
+
static VALUE #{name}(VALUE param) {
|
669
|
+
#{@frame_struct} *pframe = (void*)param;
|
670
|
+
|
671
|
+
#{nolocals ? "" : "#{@locals_struct} *plocals = (void*)pframe->plocals;"}
|
672
|
+
VALUE last_expression = Qnil;
|
673
|
+
|
674
|
+
#{code};
|
675
|
+
return last_expression;
|
676
|
+
}
|
677
|
+
"
|
678
|
+
}
|
679
|
+
end
|
680
|
+
|
681
|
+
def inline_block(code, repass_var = nil, nolocals = false)
|
682
|
+
anonymous_function{ |name| "
|
683
|
+
static VALUE #{name}(VALUE param#{repass_var ? ",void* " + repass_var : "" }) {
|
684
|
+
#{@frame_struct} *pframe = (void*)param;
|
685
|
+
|
686
|
+
#{nolocals ? "" : "#{@locals_struct} *plocals = (void*)pframe->plocals;"}
|
687
|
+
VALUE last_expression = Qnil;
|
688
|
+
|
689
|
+
#{code}
|
690
|
+
}
|
691
|
+
"
|
692
|
+
} + "((VALUE)pframe#{repass_var ? ", " + repass_var : "" })"
|
693
|
+
end
|
694
|
+
|
695
|
+
def inline_ruby(proced, parameter)
|
696
|
+
"rb_funcall(#{proced.__id__}, #{intern_num :call}, 1, #{parameter})"
|
697
|
+
end
|
698
|
+
|
699
|
+
def protected_block(inner_code, always_rescue = false,repass_var = nil, nolocals = false)
|
700
|
+
body = nil
|
701
|
+
rescue_args = nil
|
702
|
+
if repass_var
|
703
|
+
body = anonymous_function{ |name| "
|
704
|
+
static VALUE #{name}(VALUE param) {
|
705
|
+
|
706
|
+
#{@frame_struct} frame;
|
707
|
+
|
708
|
+
typeof(frame)* pframe;
|
709
|
+
typeof(frame)* parent_frame = ((typeof(pframe))((void**)param)[0]);
|
710
|
+
|
711
|
+
frame.parent_frame = 0;
|
712
|
+
frame.return_value = Qnil;
|
713
|
+
frame.rescue = 0;
|
714
|
+
frame.last_error = Qnil;
|
715
|
+
frame.targetted = 0;
|
716
|
+
frame.thread_data = parent_frame->thread_data;
|
717
|
+
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
718
|
+
|
719
|
+
pframe = &frame;
|
720
|
+
|
721
|
+
#{
|
722
|
+
nolocals ? "frame.plocals = 0;" : "#{@locals_struct}* plocals = parent_frame->plocals;
|
723
|
+
frame.plocals = plocals;
|
724
|
+
"
|
725
|
+
}
|
726
|
+
|
727
|
+
int aux = setjmp(frame.jmp);
|
728
|
+
if (aux != 0) {
|
729
|
+
|
730
|
+
if (frame.targetted == 1) {
|
731
|
+
return frame.return_value;
|
732
|
+
} else {
|
733
|
+
rb_jump_tag(aux);
|
734
|
+
}
|
735
|
+
}
|
736
|
+
|
737
|
+
VALUE #{repass_var} = (VALUE)((void**)param)[1];
|
738
|
+
return #{inner_code};
|
739
|
+
}
|
740
|
+
"
|
741
|
+
}
|
742
|
+
|
743
|
+
rescue_args = ""
|
744
|
+
rescue_args = "(VALUE)(VALUE[]){(VALUE)pframe,(VALUE)#{repass_var}}"
|
745
|
+
else
|
746
|
+
|
747
|
+
body = anonymous_function{ |name| "
|
748
|
+
static VALUE #{name}(VALUE param) {
|
749
|
+
#{@frame_struct} frame;
|
750
|
+
|
751
|
+
typeof(frame)* pframe;
|
752
|
+
typeof(frame)* parent_frame = (typeof(pframe))param;
|
753
|
+
|
754
|
+
frame.parent_frame = 0;
|
755
|
+
frame.return_value = Qnil;
|
756
|
+
frame.rescue = 0;
|
757
|
+
frame.last_error = Qnil;
|
758
|
+
frame.targetted = 0;
|
759
|
+
frame.thread_data = parent_frame->thread_data;
|
760
|
+
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
761
|
+
|
762
|
+
pframe = &frame;
|
763
|
+
|
764
|
+
#{
|
765
|
+
nolocals ? "frame.plocals = 0;" : "#{@locals_struct}* plocals = parent_frame->plocals;
|
766
|
+
frame.plocals = plocals;
|
767
|
+
"
|
768
|
+
}
|
769
|
+
|
770
|
+
int aux = setjmp(frame.jmp);
|
771
|
+
if (aux != 0) {
|
772
|
+
|
773
|
+
if (frame.targetted == 1) {
|
774
|
+
return frame.return_value;
|
775
|
+
} else {
|
776
|
+
rb_jump_tag(aux);
|
777
|
+
}
|
778
|
+
}
|
779
|
+
|
780
|
+
return #{inner_code};
|
781
|
+
}
|
782
|
+
"
|
783
|
+
}
|
784
|
+
|
785
|
+
rescue_args = "(VALUE)pframe"
|
786
|
+
end
|
787
|
+
|
788
|
+
wrapper_code = " if (state != 0) {
|
789
|
+
if (state < 0x80) {
|
790
|
+
|
791
|
+
if (state == TAG_RAISE) {
|
792
|
+
// raise emulation
|
793
|
+
pframe->thread_data->exception = rb_eval_string(\"$!\");
|
794
|
+
longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
|
795
|
+
return Qnil;
|
796
|
+
} else {
|
797
|
+
rb_jump_tag(state);
|
798
|
+
}
|
799
|
+
} else {
|
800
|
+
longjmp(pframe->jmp, state);
|
801
|
+
}
|
802
|
+
|
803
|
+
}
|
804
|
+
"
|
805
|
+
|
806
|
+
rescue_code = "rb_protect(#{body},#{rescue_args},&state)"
|
807
|
+
|
808
|
+
if always_rescue
|
809
|
+
inline_block "
|
810
|
+
int state;
|
811
|
+
pframe->last_error = Qnil;
|
812
|
+
VALUE result = #{rescue_code};
|
813
|
+
|
814
|
+
#{wrapper_code}
|
815
|
+
|
816
|
+
return result;
|
817
|
+
", repass_var, nolocals
|
818
|
+
else
|
819
|
+
inline_block "
|
820
|
+
VALUE result;
|
821
|
+
int state;
|
822
|
+
pframe->last_error = Qnil;
|
823
|
+
|
824
|
+
if (pframe->rescue) {
|
825
|
+
result = #{rescue_code};
|
826
|
+
#{wrapper_code}
|
827
|
+
} else {
|
828
|
+
return #{inner_code};
|
829
|
+
}
|
830
|
+
|
831
|
+
return result;
|
832
|
+
", repass_var, nolocals
|
833
|
+
end
|
834
|
+
end
|
835
|
+
|
836
|
+
def func_frame
|
837
|
+
"
|
838
|
+
#{@locals_struct} *plocals = malloc(sizeof(typeof(*plocals)));
|
839
|
+
#{@frame_struct} frame;
|
840
|
+
#{@frame_struct} *pframe;
|
841
|
+
|
842
|
+
frame.plocals = plocals;
|
843
|
+
frame.parent_frame = (void*)_parent_frame;
|
844
|
+
frame.return_value = Qnil;
|
845
|
+
frame.rescue = 0;
|
846
|
+
frame.targetted = 0;
|
847
|
+
frame.thread_data = ((typeof(pframe))_parent_frame)->thread_data;
|
848
|
+
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
849
|
+
|
850
|
+
plocals->pframe = LONG2FIX(&frame);
|
851
|
+
plocals->targetted = Qfalse;
|
852
|
+
|
853
|
+
pframe = (void*)&frame;
|
854
|
+
|
855
|
+
#{@block_struct} *pblock;
|
856
|
+
VALUE last_expression = Qnil;
|
857
|
+
|
858
|
+
int aux = setjmp(pframe->jmp);
|
859
|
+
if (aux != 0) {
|
860
|
+
|
861
|
+
if (plocals->targetted == Qfalse) {
|
862
|
+
longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
|
863
|
+
}
|
864
|
+
|
865
|
+
return plocals->return_value;
|
866
|
+
}
|
867
|
+
|
868
|
+
plocals->self = self;
|
869
|
+
"
|
870
|
+
end
|
871
|
+
|
872
|
+
def c_escape(str)
|
873
|
+
str.inspect
|
874
|
+
end
|
875
|
+
|
876
|
+
def literal_value(value)
|
877
|
+
@literal_value_hash = Hash.new unless @literal_value_hash
|
878
|
+
return @literal_value_hash[value] if @literal_value_hash[value]
|
879
|
+
|
880
|
+
name = self.add_global_name("VALUE", "Qnil");
|
881
|
+
|
882
|
+
begin
|
883
|
+
|
884
|
+
str = Marshal.dump(value)
|
885
|
+
|
886
|
+
|
887
|
+
if value.instance_of? Module
|
888
|
+
|
889
|
+
container_str = value.to_s.split("::")[0..-2].join("::")
|
890
|
+
|
891
|
+
init_extra << "
|
892
|
+
#{name} = rb_define_module_under(
|
893
|
+
#{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
|
894
|
+
,\"#{value.to_s.split("::").last}\");
|
895
|
+
|
896
|
+
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
897
|
+
"
|
898
|
+
elsif value.instance_of? Class
|
899
|
+
container_str = value.to_s.split("::")[0..-2].join("::")
|
900
|
+
|
901
|
+
init_extra << "
|
902
|
+
#{name} = rb_define_class_under(
|
903
|
+
#{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
|
904
|
+
,\"#{value.to_s.split("::").last}\"
|
905
|
+
,#{value.superclass == Object ? "rb_cObject" : literal_value(value.superclass)});
|
906
|
+
|
907
|
+
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
908
|
+
"
|
909
|
+
elsif value.instance_of? Array
|
910
|
+
init_extra << "
|
911
|
+
#{name} = rb_ary_new3(#{value.size}, #{value.map{|x| literal_value x}.join(",")} );
|
912
|
+
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
913
|
+
"
|
914
|
+
else
|
915
|
+
|
916
|
+
init_extra << "
|
917
|
+
#{name} = rb_marshal_load(rb_str_new(#{c_escape str}, #{str.size}));
|
918
|
+
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
919
|
+
|
920
|
+
"
|
921
|
+
end
|
922
|
+
rescue TypeError => e
|
923
|
+
@no_cache = true
|
924
|
+
FastRuby.logger.info "#{value} disabling cache for extension"
|
925
|
+
init_extra << "
|
926
|
+
#{name} = rb_funcall(rb_const_get(rb_cObject, #{intern_num :ObjectSpace}), #{intern_num :_id2ref}, 1, INT2FIX(#{value.__id__}));
|
927
|
+
"
|
928
|
+
|
929
|
+
end
|
930
|
+
@literal_value_hash[value] = name
|
931
|
+
|
932
|
+
name
|
933
|
+
end
|
934
|
+
|
935
|
+
def encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name = nil)
|
936
|
+
name = self.add_global_name("void*", 0);
|
937
|
+
cruby_name = self.add_global_name("void*", 0);
|
938
|
+
cruby_len = self.add_global_name("int", 0);
|
939
|
+
args_tree = call_tree[3]
|
940
|
+
method_tree = nil
|
941
|
+
|
942
|
+
begin
|
943
|
+
method_tree = recvtype.instance_method(@method_name.to_sym).fastruby.tree
|
944
|
+
rescue NoMethodError
|
945
|
+
end
|
946
|
+
|
947
|
+
|
948
|
+
strargs_signature = (0..args_tree.size-2).map{|x| "VALUE arg#{x}"}.join(",")
|
949
|
+
strargs = (0..args_tree.size-2).map{|x| "arg#{x}"}.join(",")
|
950
|
+
inprocstrargs = (1..args_tree.size-1).map{|x| "((VALUE*)method_arguments)[#{x}]"}.join(",")
|
951
|
+
|
952
|
+
if args_tree.size > 1
|
953
|
+
strargs_signature = "," + strargs_signature
|
954
|
+
toprocstrargs = "self,"+strargs
|
955
|
+
strargs = "," + strargs
|
956
|
+
inprocstrargs = ","+inprocstrargs
|
957
|
+
else
|
958
|
+
toprocstrargs = "self"
|
959
|
+
end
|
960
|
+
|
961
|
+
ruby_wrapper = anonymous_function{ |funcname| "
|
962
|
+
static VALUE #{funcname}(VALUE self,void* block,void* frame#{strargs_signature}){
|
963
|
+
#{@frame_struct}* pframe = frame;
|
964
|
+
|
965
|
+
VALUE method_arguments[#{args_tree.size}] = {#{toprocstrargs}};
|
966
|
+
|
967
|
+
return #{
|
968
|
+
protected_block "rb_funcall(((VALUE*)method_arguments)[0], #{intern_num mname.to_sym}, #{args_tree.size-1}#{inprocstrargs});", false, "method_arguments"
|
969
|
+
};
|
970
|
+
}
|
971
|
+
"
|
972
|
+
}
|
973
|
+
|
974
|
+
value_cast = ( ["VALUE"]*(args_tree.size) ).join(",")
|
975
|
+
|
976
|
+
cruby_wrapper = anonymous_function{ |funcname| "
|
977
|
+
static VALUE #{funcname}(VALUE self,void* block,void* frame#{strargs_signature}){
|
978
|
+
#{@frame_struct}* pframe = frame;
|
979
|
+
|
980
|
+
VALUE method_arguments[#{args_tree.size}] = {#{toprocstrargs}};
|
981
|
+
|
982
|
+
// call to #{recvtype}::#{mname}
|
983
|
+
|
984
|
+
if (#{cruby_len} == -1) {
|
985
|
+
return #{
|
986
|
+
protected_block "((VALUE(*)(int,VALUE*,VALUE))#{cruby_name})(#{args_tree.size-1}, ((VALUE*)method_arguments)+1,*((VALUE*)method_arguments));", false, "method_arguments"
|
987
|
+
};
|
988
|
+
|
989
|
+
} else if (#{cruby_len} == -2) {
|
990
|
+
return #{
|
991
|
+
protected_block "((VALUE(*)(VALUE,VALUE))#{cruby_name})(*((VALUE*)method_arguments), rb_ary_new4(#{args_tree.size-1},((VALUE*)method_arguments)+1) );", false, "method_arguments"
|
992
|
+
};
|
993
|
+
|
994
|
+
} else {
|
995
|
+
return #{
|
996
|
+
protected_block "((VALUE(*)(#{value_cast}))#{cruby_name})(((VALUE*)method_arguments)[0] #{inprocstrargs});", false, "method_arguments"
|
997
|
+
};
|
998
|
+
}
|
999
|
+
}
|
1000
|
+
"
|
1001
|
+
}
|
1002
|
+
|
1003
|
+
recvdump = nil
|
1004
|
+
|
1005
|
+
begin
|
1006
|
+
recvdump = literal_value recvtype
|
1007
|
+
rescue
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
if recvdump and recvtype
|
1011
|
+
init_extra << "
|
1012
|
+
{
|
1013
|
+
VALUE recvtype = #{recvdump};
|
1014
|
+
rb_funcall(#{literal_value FastRuby}, #{intern_num :set_builder_module}, 1, recvtype);
|
1015
|
+
VALUE signature = #{literal_value signature};
|
1016
|
+
VALUE mname = #{literal_value mname};
|
1017
|
+
VALUE tree = #{literal_value method_tree};
|
1018
|
+
VALUE convention = rb_funcall(recvtype, #{intern_num :convention}, 3,signature,mname,#{inference_complete ? "Qtrue" : "Qfalse"});
|
1019
|
+
VALUE mobject = rb_funcall(recvtype, #{intern_num :method_from_signature},3,signature,mname,#{inference_complete ? "Qtrue" : "Qfalse"});
|
1020
|
+
|
1021
|
+
struct METHOD {
|
1022
|
+
VALUE klass, rklass;
|
1023
|
+
VALUE recv;
|
1024
|
+
ID id, oid;
|
1025
|
+
int safe_level;
|
1026
|
+
NODE *body;
|
1027
|
+
};
|
1028
|
+
|
1029
|
+
int len = 0;
|
1030
|
+
void* address = 0;
|
1031
|
+
|
1032
|
+
if (mobject != Qnil) {
|
1033
|
+
|
1034
|
+
struct METHOD *data;
|
1035
|
+
Data_Get_Struct(mobject, struct METHOD, data);
|
1036
|
+
|
1037
|
+
if (nd_type(data->body) == NODE_CFUNC) {
|
1038
|
+
address = data->body->nd_cfnc;
|
1039
|
+
len = data->body->nd_argc;
|
1040
|
+
}
|
1041
|
+
}
|
1042
|
+
|
1043
|
+
if (address==0) convention = #{literal_value :ruby};
|
1044
|
+
|
1045
|
+
#{convention_global_name ? convention_global_name + " = 0;" : ""}
|
1046
|
+
if (recvtype != Qnil) {
|
1047
|
+
|
1048
|
+
if (convention == #{literal_value :fastruby}) {
|
1049
|
+
#{convention_global_name ? convention_global_name + " = 1;" : ""}
|
1050
|
+
#{name} = address;
|
1051
|
+
} else if (convention == #{literal_value :fastruby_array}) {
|
1052
|
+
// ruby, wrap rb_funcall
|
1053
|
+
#{name} = (void*)#{ruby_wrapper};
|
1054
|
+
} else if (convention == #{literal_value :cruby}) {
|
1055
|
+
// cruby, wrap direct call
|
1056
|
+
#{cruby_name} = address;
|
1057
|
+
|
1058
|
+
if (#{cruby_name} == 0) {
|
1059
|
+
#{name} = (void*)#{ruby_wrapper};
|
1060
|
+
} else {
|
1061
|
+
#{cruby_len} = len;
|
1062
|
+
#{name} = (void*)#{cruby_wrapper};
|
1063
|
+
}
|
1064
|
+
} else {
|
1065
|
+
// ruby, wrap rb_funcall
|
1066
|
+
#{name} = (void*)#{ruby_wrapper};
|
1067
|
+
}
|
1068
|
+
} else {
|
1069
|
+
// ruby, wrap rb_funcall
|
1070
|
+
#{name} = (void*)#{ruby_wrapper};
|
1071
|
+
}
|
1072
|
+
|
1073
|
+
}
|
1074
|
+
"
|
1075
|
+
else
|
1076
|
+
init_extra << "
|
1077
|
+
// ruby, wrap rb_funcall
|
1078
|
+
#{name} = (void*)#{ruby_wrapper};
|
1079
|
+
"
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
name
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
def intern_num(symbol)
|
1086
|
+
@intern_num_hash = Hash.new unless @intern_num_hash
|
1087
|
+
return @intern_num_hash[symbol] if @intern_num_hash[symbol]
|
1088
|
+
|
1089
|
+
name = self.add_global_name("ID", 0);
|
1090
|
+
|
1091
|
+
init_extra << "
|
1092
|
+
#{name} = rb_intern(\"#{symbol.to_s}\");
|
1093
|
+
"
|
1094
|
+
|
1095
|
+
@intern_num_hash[symbol] = name
|
1096
|
+
|
1097
|
+
name
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
def add_global_name(ctype, default)
|
1101
|
+
name = "glb" + rand(1000000000).to_s
|
1102
|
+
|
1103
|
+
extra_code << "
|
1104
|
+
static #{ctype} #{name} = #{default};
|
1105
|
+
"
|
1106
|
+
name
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
def global_entry(glbname)
|
1110
|
+
name = add_global_name("struct global_entry*", 0);
|
1111
|
+
|
1112
|
+
init_extra << "
|
1113
|
+
#{name} = rb_global_entry(SYM2ID(#{literal_value glbname}));
|
1114
|
+
"
|
1115
|
+
|
1116
|
+
name
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
|
1120
|
+
def frame(code, jmp_code, not_jmp_code = "", rescued = nil)
|
1121
|
+
|
1122
|
+
anonymous_function{ |name| "
|
1123
|
+
static VALUE #{name}(VALUE param) {
|
1124
|
+
VALUE last_expression;
|
1125
|
+
#{@frame_struct} frame, *pframe, *parent_frame;
|
1126
|
+
#{@locals_struct} *plocals;
|
1127
|
+
|
1128
|
+
parent_frame = (void*)param;
|
1129
|
+
|
1130
|
+
frame.parent_frame = (void*)param;
|
1131
|
+
frame.plocals = parent_frame->plocals;
|
1132
|
+
frame.rescue = #{rescued ? rescued : "parent_frame->rescue"};
|
1133
|
+
frame.targetted = 0;
|
1134
|
+
frame.thread_data = parent_frame->thread_data;
|
1135
|
+
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
1136
|
+
|
1137
|
+
plocals = frame.plocals;
|
1138
|
+
pframe = &frame;
|
1139
|
+
|
1140
|
+
int aux = setjmp(frame.jmp);
|
1141
|
+
if (aux != 0) {
|
1142
|
+
last_expression = pframe->return_value;
|
1143
|
+
|
1144
|
+
// restore previous frame
|
1145
|
+
typeof(pframe) original_frame = pframe;
|
1146
|
+
pframe = parent_frame;
|
1147
|
+
|
1148
|
+
#{jmp_code};
|
1149
|
+
|
1150
|
+
if (original_frame->targetted == 0) {
|
1151
|
+
longjmp(pframe->jmp,aux);
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
return last_expression;
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
#{code};
|
1158
|
+
|
1159
|
+
// restore previous frame
|
1160
|
+
typeof(pframe) original_frame = pframe;
|
1161
|
+
pframe = parent_frame;
|
1162
|
+
#{not_jmp_code};
|
1163
|
+
|
1164
|
+
return last_expression;
|
1165
|
+
|
1166
|
+
}
|
1167
|
+
"
|
1168
|
+
} + "((VALUE)pframe)"
|
1169
|
+
end
|
1170
|
+
end
|
1171
|
+
end
|