fastruby 0.0.21 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -1
- data/benchmarks/benchmark.rb +3 -0
- data/benchmarks/benchmark.rb~ +3 -12
- data/benchmarks/benchmark8.rb +48 -0
- data/benchmarks/benchmark8.rb~ +46 -0
- data/lib/fastruby.rb +2 -1
- data/lib/fastruby.rb~ +2 -1
- data/lib/fastruby/builder.rb +18 -1
- data/lib/fastruby/builder.rb~ +18 -5
- data/lib/fastruby/modules/lvar_type/lasgn.rb~ +41 -0
- data/lib/fastruby/modules/translator/block.rb +1 -1
- data/lib/fastruby/modules/translator/block.rb~ +128 -0
- data/lib/fastruby/modules/translator/call.rb +62 -139
- data/lib/fastruby/modules/translator/call.rb~ +61 -140
- data/lib/fastruby/modules/translator/defn.rb +49 -105
- data/lib/fastruby/modules/translator/defn.rb~ +211 -0
- data/lib/fastruby/modules/translator/exceptions.rb +1 -0
- data/lib/fastruby/modules/translator/exceptions.rb~ +120 -0
- data/lib/fastruby/modules/translator/iter.rb +13 -20
- data/lib/fastruby/modules/translator/iter.rb~ +738 -0
- data/lib/fastruby/modules/translator/literal.rb +8 -1
- data/lib/fastruby/modules/translator/literal.rb~ +157 -0
- data/lib/fastruby/modules/translator/nonlocal.rb +7 -0
- data/lib/fastruby/modules/translator/nonlocal.rb~ +304 -0
- data/lib/fastruby/modules/translator/static.rb +1 -0
- data/lib/fastruby/modules/translator/static.rb~ +290 -0
- data/lib/fastruby/modules/translator/variable.rb +24 -6
- data/lib/fastruby/modules/translator/variable.rb~ +298 -0
- data/lib/fastruby/translator/translator.rb +411 -284
- data/lib/fastruby/translator/translator.rb~ +1728 -0
- data/spec/fastruby_only/base_spec.rb~ +74 -0
- data/spec/ruby/base_spec.rb~ +1 -338
- data/spec/ruby/block/break_spec.rb~ +21 -0
- data/spec/ruby/block/callcc_spec.rb~ +236 -0
- data/spec/ruby/block/lambda_spec.rb~ +1 -178
- data/spec/ruby/block/next_spec.rb~ +85 -0
- data/spec/ruby/block/proc_spec.rb~ +22 -0
- data/spec/ruby/block/redo_spec.rb~ +133 -0
- data/spec/ruby/block/retry_spec.rb~ +135 -0
- data/spec/ruby/block_spec.rb~ +494 -2
- data/spec/ruby/call/base_call_spec.rb~ +60 -2
- data/spec/ruby/defn/default_args_spec.rb~ +303 -0
- data/spec/ruby/defn/multiple_args_spec.rb~ +317 -0
- data/spec/ruby/defn/replacement_spec.rb +29 -1
- data/spec/ruby/defn/replacement_spec.rb~ +52 -21
- data/spec/ruby/exception/internal_ex_spec.rb~ +2 -2
- data/spec/ruby/variable_spec.rb~ +46 -23
- data/spec/static/flow_spec.rb~ +48 -0
- metadata +34 -12
@@ -0,0 +1,1728 @@
|
|
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
|
+
require "fastruby/translator/scope_mode_helper"
|
29
|
+
require "fastruby/modules"
|
30
|
+
require "define_method_handler"
|
31
|
+
require "base64"
|
32
|
+
|
33
|
+
module FastRuby
|
34
|
+
class Context
|
35
|
+
attr_accessor :locals
|
36
|
+
attr_accessor :options
|
37
|
+
attr_reader :no_cache
|
38
|
+
attr_reader :init_extra
|
39
|
+
attr_reader :extra_code
|
40
|
+
|
41
|
+
class Value
|
42
|
+
attr_accessor :value
|
43
|
+
def initialize(v); @value = v; end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.define_translator_for(ntype, options = {}, &blk)
|
47
|
+
condition_blk = proc do |*x|
|
48
|
+
tree = x.first; tree.node_type == ntype
|
49
|
+
end
|
50
|
+
|
51
|
+
if options[:arity]
|
52
|
+
if options[:arity] == 1
|
53
|
+
condition_blk = proc do |*x|
|
54
|
+
tree = x.first; x.size == 1 and tree.node_type == ntype
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
define_method_handler(:to_c, options, &blk).condition &condition_blk
|
60
|
+
end
|
61
|
+
|
62
|
+
define_method_handler(:to_c, :priority => 10000){|*x|
|
63
|
+
"Qnil"
|
64
|
+
}.condition{|*x| x.size == 1 and (not x.first)}
|
65
|
+
|
66
|
+
define_method_handler(:to_c, :priority => 1000){|tree, result_var|
|
67
|
+
"#{result_var} = #{to_c(tree)};"
|
68
|
+
}.condition{|*x| x.size == 2 and (not x.first)}
|
69
|
+
|
70
|
+
define_method_handler(:to_c, :priority => -9000){ |tree, result_var|
|
71
|
+
"#{result_var} = #{to_c(tree)};"
|
72
|
+
}.condition{|*x| x.size == 2 }
|
73
|
+
|
74
|
+
define_method_handler(:to_c, :priority => -10000) do |*x|
|
75
|
+
tree, result_var = x
|
76
|
+
|
77
|
+
raise "undefined translator for node type :#{tree.node_type}"
|
78
|
+
end
|
79
|
+
|
80
|
+
define_method_handler(:initialize_to_c){|*x|}.condition{|*x|false}
|
81
|
+
|
82
|
+
define_translator_for(:call, :priority => 100){ |*x|
|
83
|
+
tree, result_var = x
|
84
|
+
|
85
|
+
tree[2] = :fastruby_require
|
86
|
+
to_c(tree)
|
87
|
+
}.condition{|*x|
|
88
|
+
tree = x.first; tree.node_type == :call && tree[2] == :require
|
89
|
+
}
|
90
|
+
|
91
|
+
define_method_handler(:infer_value, :priority => -1000) do |tree|
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
FastRuby::Modules.load_all("translator")
|
96
|
+
|
97
|
+
def catch_block(*catchs)
|
98
|
+
old_catch_blocks = @catch_blocks.dup
|
99
|
+
begin
|
100
|
+
catchs.each &@catch_blocks.method(:<<)
|
101
|
+
return yield
|
102
|
+
ensure
|
103
|
+
@catch_blocks = old_catch_blocks
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def initialize(common_func = true, inferencer = nil)
|
108
|
+
initialize_to_c
|
109
|
+
|
110
|
+
@inferencer = inferencer
|
111
|
+
@catch_blocks = []
|
112
|
+
@no_cache = false
|
113
|
+
@extra_code = ""
|
114
|
+
@options = {}
|
115
|
+
@init_extra = Array.new
|
116
|
+
@frame_struct = "struct {
|
117
|
+
void* parent_frame;
|
118
|
+
void* plocals;
|
119
|
+
jmp_buf jmp;
|
120
|
+
VALUE return_value;
|
121
|
+
int rescue;
|
122
|
+
VALUE last_error;
|
123
|
+
VALUE next_recv;
|
124
|
+
int targetted;
|
125
|
+
struct FASTRUBYTHREADDATA* thread_data;
|
126
|
+
}"
|
127
|
+
|
128
|
+
@block_struct = "struct {
|
129
|
+
void* block_function_address;
|
130
|
+
void* block_function_param;
|
131
|
+
VALUE proc;
|
132
|
+
}"
|
133
|
+
|
134
|
+
extra_code << "
|
135
|
+
static void frb_jump_tag(int state) {
|
136
|
+
VALUE exception = rb_funcall(#{literal_value FastRuby::JumpTagException}, #{intern_num :new},1,INT2FIX(state));
|
137
|
+
rb_exc_raise(exception);
|
138
|
+
}
|
139
|
+
"
|
140
|
+
|
141
|
+
extra_code << "
|
142
|
+
#define FASTRUBY_TAG_RETURN 0x80
|
143
|
+
#define FASTRUBY_TAG_NEXT 0x81
|
144
|
+
#define FASTRUBY_TAG_BREAK 0x82
|
145
|
+
#define FASTRUBY_TAG_RAISE 0x83
|
146
|
+
#define FASTRUBY_TAG_REDO 0x84
|
147
|
+
#define FASTRUBY_TAG_RETRY 0x85
|
148
|
+
#define TAG_RAISE 0x6
|
149
|
+
|
150
|
+
# define PTR2NUM(x) (ULONG2NUM((unsigned long)(x)))
|
151
|
+
# define NUM2PTR(x) ((void*)(NUM2ULONG(x)))
|
152
|
+
|
153
|
+
#ifndef __INLINE_FASTRUBY_BASE
|
154
|
+
#include \"#{FastRuby.fastruby_load_path}/../ext/fastruby_base/fastruby_base.inl\"
|
155
|
+
#define __INLINE_FASTRUBY_BASE
|
156
|
+
#endif
|
157
|
+
"
|
158
|
+
|
159
|
+
ruby_code = "
|
160
|
+
unless $LOAD_PATH.include? #{FastRuby.fastruby_load_path.inspect}
|
161
|
+
$LOAD_PATH << #{FastRuby.fastruby_load_path.inspect}
|
162
|
+
end
|
163
|
+
require #{FastRuby.fastruby_script_path.inspect}
|
164
|
+
"
|
165
|
+
|
166
|
+
init_extra << "
|
167
|
+
rb_eval_string(#{ruby_code.inspect});
|
168
|
+
"
|
169
|
+
|
170
|
+
|
171
|
+
if RUBY_VERSION =~ /^1\.8/
|
172
|
+
|
173
|
+
@lambda_node_gvar = add_global_name("NODE*", 0);
|
174
|
+
@proc_node_gvar = add_global_name("NODE*", 0);
|
175
|
+
@procnew_node_gvar = add_global_name("NODE*", 0);
|
176
|
+
@callcc_node_gvar = add_global_name("NODE*", 0);
|
177
|
+
|
178
|
+
init_extra << "
|
179
|
+
#{@lambda_node_gvar} = rb_method_node(rb_cObject, #{intern_num :lambda});
|
180
|
+
#{@proc_node_gvar} = rb_method_node(rb_cObject, #{intern_num :proc});
|
181
|
+
#{@procnew_node_gvar} = rb_method_node(CLASS_OF(rb_cProc), #{intern_num :new});
|
182
|
+
#{@callcc_node_gvar} = rb_method_node(rb_mKernel, #{intern_num :callcc});
|
183
|
+
"
|
184
|
+
elsif RUBY_VERSION =~ /^1\.9/
|
185
|
+
|
186
|
+
@lambda_node_gvar = add_global_name("void*", 0);
|
187
|
+
@proc_node_gvar = add_global_name("void*", 0);
|
188
|
+
@procnew_node_gvar = add_global_name("void*", 0);
|
189
|
+
@callcc_node_gvar = add_global_name("void*", 0);
|
190
|
+
|
191
|
+
init_extra << "
|
192
|
+
#{@lambda_node_gvar} = rb_method_entry(rb_cObject, #{intern_num :lambda});
|
193
|
+
#{@proc_node_gvar} = rb_method_entry(rb_cObject, #{intern_num :proc});
|
194
|
+
#{@procnew_node_gvar} = rb_method_entry(CLASS_OF(rb_const_get(rb_cObject, #{intern_num :Proc})), #{intern_num :new});
|
195
|
+
#{@callcc_node_gvar} = rb_method_entry(rb_mKernel, #{intern_num :callcc});
|
196
|
+
"
|
197
|
+
end
|
198
|
+
|
199
|
+
@common_func = common_func
|
200
|
+
if common_func
|
201
|
+
extra_code << "static VALUE _rb_gvar_set(void* ge,VALUE value) {
|
202
|
+
rb_gvar_set((struct global_entry*)ge,value);
|
203
|
+
return value;
|
204
|
+
}
|
205
|
+
"
|
206
|
+
|
207
|
+
extra_code << "static VALUE re_yield(int argc, VALUE* argv, VALUE param, VALUE _parent_frame) {
|
208
|
+
VALUE yield_args = rb_ary_new4(argc,argv);
|
209
|
+
VALUE* yield_args_p = &yield_args;
|
210
|
+
|
211
|
+
#{@frame_struct}* pframe;
|
212
|
+
pframe = (typeof(pframe))_parent_frame;
|
213
|
+
|
214
|
+
return #{protected_block("last_expression = rb_yield_splat(*(VALUE*)yield_args_p)",true,"yield_args_p",true)};
|
215
|
+
}"
|
216
|
+
|
217
|
+
extra_code << "static VALUE _rb_ivar_set(VALUE recv,ID idvar, VALUE value) {
|
218
|
+
rb_ivar_set(recv,idvar,value);
|
219
|
+
return value;
|
220
|
+
}
|
221
|
+
"
|
222
|
+
|
223
|
+
extra_code << "static VALUE __rb_cvar_set(VALUE recv,ID idvar, VALUE value, int warn) {
|
224
|
+
#{if RUBY_VERSION =~ /^1\.9/
|
225
|
+
"rb_cvar_set(recv,idvar,value);"
|
226
|
+
elsif RUBY_VERSION =~ /^1\.8/
|
227
|
+
"rb_cvar_set(recv,idvar,value,warn);"
|
228
|
+
else
|
229
|
+
raise RuntimeError, "unsupported ruby version #{RUBY_VERSION}"
|
230
|
+
end
|
231
|
+
}
|
232
|
+
|
233
|
+
return value;
|
234
|
+
}
|
235
|
+
"
|
236
|
+
|
237
|
+
extra_code << "static VALUE _lvar_assing(VALUE* destination,VALUE value) {
|
238
|
+
*destination = value;
|
239
|
+
return value;
|
240
|
+
}
|
241
|
+
|
242
|
+
/*
|
243
|
+
#{caller.join("\n")}
|
244
|
+
*/
|
245
|
+
|
246
|
+
"
|
247
|
+
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
def _raise(class_tree, message_tree = nil)
|
253
|
+
@has_raise = true
|
254
|
+
@has_inline_block = true
|
255
|
+
class_tree = to_c class_tree unless class_tree.instance_of? String
|
256
|
+
|
257
|
+
if message_tree.instance_of? String
|
258
|
+
message_tree = "rb_str_new2(#{message_tree.inspect})"
|
259
|
+
else
|
260
|
+
message_tree = to_c message_tree
|
261
|
+
end
|
262
|
+
|
263
|
+
if message_tree
|
264
|
+
return inline_block("
|
265
|
+
pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},1,#{message_tree});
|
266
|
+
longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
|
267
|
+
return Qnil;
|
268
|
+
")
|
269
|
+
else
|
270
|
+
return inline_block("
|
271
|
+
pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},0);
|
272
|
+
longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
|
273
|
+
return Qnil;
|
274
|
+
")
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
def anonymous_function(*x)
|
280
|
+
|
281
|
+
name = "anonymous" + rand(10000000).to_s
|
282
|
+
extra_code << yield(name,*x)
|
283
|
+
|
284
|
+
name
|
285
|
+
end
|
286
|
+
|
287
|
+
def frame_call(inner_code, precode = "", postcode = "")
|
288
|
+
inline_block "
|
289
|
+
|
290
|
+
volatile VALUE ret = Qnil;
|
291
|
+
// create a call_frame
|
292
|
+
#{@frame_struct} call_frame;
|
293
|
+
typeof(call_frame)* volatile old_pframe = (void*)pframe;
|
294
|
+
|
295
|
+
pframe = (typeof(pframe))&call_frame;
|
296
|
+
|
297
|
+
call_frame.parent_frame = (void*)pframe;
|
298
|
+
call_frame.plocals = plocals;
|
299
|
+
call_frame.return_value = Qnil;
|
300
|
+
call_frame.targetted = 0;
|
301
|
+
call_frame.thread_data = old_pframe->thread_data;
|
302
|
+
if (call_frame.thread_data == 0) call_frame.thread_data = rb_current_thread_data();
|
303
|
+
|
304
|
+
void* volatile old_call_frame = plocals->call_frame;
|
305
|
+
plocals->call_frame = &call_frame;
|
306
|
+
|
307
|
+
#{precode}
|
308
|
+
|
309
|
+
int aux = setjmp(call_frame.jmp);
|
310
|
+
if (aux != 0) {
|
311
|
+
if (call_frame.targetted == 0) {
|
312
|
+
#{postcode}
|
313
|
+
longjmp(old_pframe->jmp,aux);
|
314
|
+
}
|
315
|
+
|
316
|
+
if (aux == FASTRUBY_TAG_BREAK) {
|
317
|
+
plocals->call_frame = old_call_frame;
|
318
|
+
#{postcode}
|
319
|
+
return call_frame.return_value;
|
320
|
+
} else if (aux == FASTRUBY_TAG_RETRY ) {
|
321
|
+
// do nothing and let the call execute again
|
322
|
+
} else {
|
323
|
+
plocals->call_frame = old_call_frame;
|
324
|
+
#{postcode}
|
325
|
+
return call_frame.return_value;
|
326
|
+
}
|
327
|
+
}
|
328
|
+
|
329
|
+
|
330
|
+
#{inner_code};
|
331
|
+
|
332
|
+
#{postcode}
|
333
|
+
|
334
|
+
plocals->call_frame = old_call_frame;
|
335
|
+
return ret;
|
336
|
+
"
|
337
|
+
end
|
338
|
+
|
339
|
+
def initialize_method_structs(args_tree)
|
340
|
+
@locals_struct = "struct {
|
341
|
+
int size;
|
342
|
+
void* call_frame;
|
343
|
+
void* parent_locals;
|
344
|
+
void* pframe;
|
345
|
+
void* block_function_address;
|
346
|
+
void* block_function_param;
|
347
|
+
VALUE active;
|
348
|
+
VALUE targetted;
|
349
|
+
VALUE return_value;
|
350
|
+
#{@locals.map{|l| "VALUE #{l};\n"}.join}
|
351
|
+
}"
|
352
|
+
|
353
|
+
end
|
354
|
+
|
355
|
+
def add_main
|
356
|
+
if options[:main]
|
357
|
+
|
358
|
+
extra_code << "
|
359
|
+
static VALUE #{@alt_method_name}(VALUE self__);
|
360
|
+
static VALUE main_proc_call(VALUE self__, VALUE signature, VALUE class_self_) {
|
361
|
+
#{@alt_method_name}(class_self_);
|
362
|
+
return Qnil;
|
363
|
+
}
|
364
|
+
|
365
|
+
"
|
366
|
+
|
367
|
+
init_extra << "
|
368
|
+
{
|
369
|
+
VALUE newproc = rb_funcall(rb_cObject,#{intern_num :new},0);
|
370
|
+
rb_define_singleton_method(newproc, \"call\", main_proc_call, 2);
|
371
|
+
rb_gv_set(\"$last_obj_proc\", newproc);
|
372
|
+
}
|
373
|
+
"
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
def define_method_at_init(method_name, size, signature)
|
378
|
+
extra_code << "
|
379
|
+
static VALUE main_proc_call(VALUE self__, VALUE signature, VALUE class_self_) {
|
380
|
+
VALUE method_name = rb_funcall(
|
381
|
+
#{literal_value FastRuby},
|
382
|
+
#{intern_num :make_str_signature},
|
383
|
+
2,
|
384
|
+
#{literal_value method_name},
|
385
|
+
signature
|
386
|
+
);
|
387
|
+
|
388
|
+
ID id = rb_intern(RSTRING_PTR(method_name));
|
389
|
+
|
390
|
+
rb_funcall(
|
391
|
+
#{literal_value FastRuby},
|
392
|
+
#{intern_num :set_builder_module},
|
393
|
+
1,
|
394
|
+
class_self_
|
395
|
+
);
|
396
|
+
|
397
|
+
VALUE rb_method_hash;
|
398
|
+
void** address = 0;
|
399
|
+
rb_method_hash = rb_funcall(class_self_, #{intern_num :method_hash},1,#{literal_value method_name});
|
400
|
+
|
401
|
+
if (rb_method_hash != Qnil) {
|
402
|
+
VALUE tmp = rb_hash_aref(rb_method_hash, PTR2NUM(id));
|
403
|
+
if (tmp != Qnil) {
|
404
|
+
address = (void*)NUM2PTR(tmp);
|
405
|
+
}
|
406
|
+
}
|
407
|
+
|
408
|
+
if (address == 0) {
|
409
|
+
address = malloc(sizeof(void*));
|
410
|
+
}
|
411
|
+
*address = #{@alt_method_name};
|
412
|
+
|
413
|
+
rb_funcall(
|
414
|
+
class_self_,
|
415
|
+
#{intern_num :register_method_value},
|
416
|
+
3,
|
417
|
+
#{literal_value method_name},
|
418
|
+
PTR2NUM(id),
|
419
|
+
PTR2NUM(address)
|
420
|
+
);
|
421
|
+
|
422
|
+
return Qnil;
|
423
|
+
}
|
424
|
+
"
|
425
|
+
|
426
|
+
init_extra << "
|
427
|
+
{
|
428
|
+
VALUE newproc = rb_funcall(rb_cObject,#{intern_num :new},0);
|
429
|
+
rb_define_singleton_method(newproc, \"call\", main_proc_call, 2);
|
430
|
+
rb_gv_set(\"$last_obj_proc\", newproc);
|
431
|
+
}
|
432
|
+
"
|
433
|
+
end
|
434
|
+
|
435
|
+
def to_c_method(tree, signature = nil)
|
436
|
+
|
437
|
+
if tree[0] == :defn
|
438
|
+
method_name = tree[1]
|
439
|
+
original_args_tree = tree[2]
|
440
|
+
block_argument = tree[2].find{|x| x.to_s[0] == ?&}
|
441
|
+
impl_tree = tree[3][1]
|
442
|
+
elsif tree[0] == :defs
|
443
|
+
method_name = tree[2]
|
444
|
+
original_args_tree = tree[3]
|
445
|
+
block_argument = tree[3].find{|x| x.to_s[0] == ?&}
|
446
|
+
impl_tree = tree[4][1]
|
447
|
+
end
|
448
|
+
|
449
|
+
@method_arguments = original_args_tree[1..-1]
|
450
|
+
|
451
|
+
if "0".respond_to?(:ord)
|
452
|
+
@alt_method_name = "_" + method_name.to_s.gsub("_x_", "_x__x_").gsub(/\W/){|x| "_x_#{x.ord}" } + "_" + rand(10000000000).to_s
|
453
|
+
else
|
454
|
+
@alt_method_name = "_" + method_name.to_s.gsub("_x_", "_x__x_").gsub(/\W/){|x| "_x_#{x[0]}" } + "_" + rand(10000000000).to_s
|
455
|
+
end
|
456
|
+
|
457
|
+
@has_yield = false
|
458
|
+
@has_dynamic_call = false
|
459
|
+
@has_nonlocal_goto = false
|
460
|
+
@has_inline_block = (options[:main] or tree.find_tree(:lasgn)
|
461
|
+
@has_plocals_ref = false
|
462
|
+
@has_raise = false
|
463
|
+
@has_inline_c = false
|
464
|
+
|
465
|
+
args_tree = original_args_tree.select{|x| x.to_s[0] != ?&}
|
466
|
+
|
467
|
+
initialize_method_structs(original_args_tree)
|
468
|
+
|
469
|
+
if options[:main] then
|
470
|
+
strargs = if args_tree.size > 1
|
471
|
+
"VALUE self, VALUE block, VALUE _parent_frame, #{(0..signature.size-1).map{|x| "VALUE arg#{x}"}.join(",")}"
|
472
|
+
else
|
473
|
+
"VALUE self, VALUE block, VALUE _parent_frame"
|
474
|
+
end
|
475
|
+
|
476
|
+
else
|
477
|
+
|
478
|
+
strargs = "VALUE self, VALUE block, VALUE _parent_frame, int argc, VALUE* argv"
|
479
|
+
|
480
|
+
splat_arg = args_tree[1..-1].find{|x| x.to_s.match(/\*/) }
|
481
|
+
|
482
|
+
maxargnum = args_tree[1..-1].count{ |x|
|
483
|
+
if x.instance_of? Symbol
|
484
|
+
not x.to_s.match(/\*/) and not x.to_s.match(/\&/)
|
485
|
+
else
|
486
|
+
false
|
487
|
+
end
|
488
|
+
}
|
489
|
+
|
490
|
+
minargnum = maxargnum
|
491
|
+
|
492
|
+
args_tree[1..-1].each do |subtree|
|
493
|
+
unless subtree.instance_of? Symbol
|
494
|
+
if subtree[0] == :block
|
495
|
+
minargnum = minargnum - (subtree.size-1)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
if args_tree[1..-1].find{|x| x.to_s.match(/\*/)}
|
501
|
+
maxargnum = 2147483647
|
502
|
+
end
|
503
|
+
|
504
|
+
read_arguments_code = ""
|
505
|
+
|
506
|
+
|
507
|
+
validate_arguments_code = if signature.size-1 < minargnum
|
508
|
+
"
|
509
|
+
rb_raise(rb_eArgError, \"wrong number of arguments (#{signature.size-1} for #{minargnum})\");
|
510
|
+
"
|
511
|
+
elsif signature.size-1 > maxargnum
|
512
|
+
"
|
513
|
+
rb_raise(rb_eArgError, \"wrong number of arguments (#{signature.size-1} for #{maxargnum})\");
|
514
|
+
"
|
515
|
+
else
|
516
|
+
|
517
|
+
default_block_tree = args_tree[1..-1].find{|subtree|
|
518
|
+
unless subtree.instance_of? Symbol
|
519
|
+
if subtree[0] == :block
|
520
|
+
next true
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
false
|
525
|
+
}
|
526
|
+
|
527
|
+
i = -1
|
528
|
+
|
529
|
+
normalargsnum = args_tree[1..-1].count{|subtree|
|
530
|
+
if subtree.instance_of? Symbol
|
531
|
+
unless subtree.to_s.match(/\*/) or subtree.to_s.match(/\&/)
|
532
|
+
next true
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
false
|
537
|
+
}
|
538
|
+
|
539
|
+
read_arguments_code = args_tree[1..-1].map { |arg_|
|
540
|
+
arg = arg_.to_s
|
541
|
+
i = i + 1
|
542
|
+
|
543
|
+
if i < normalargsnum
|
544
|
+
if i < signature.size-1
|
545
|
+
"plocals->#{arg} = argv[#{i}];\n"
|
546
|
+
else
|
547
|
+
|
548
|
+
if default_block_tree
|
549
|
+
@has_inline_block = true
|
550
|
+
initialize_tree = default_block_tree[1..-1].find{|subtree| subtree[1] == arg_}
|
551
|
+
if initialize_tree
|
552
|
+
to_c(initialize_tree) + ";\n"
|
553
|
+
else
|
554
|
+
""
|
555
|
+
end
|
556
|
+
else
|
557
|
+
";\n"
|
558
|
+
end
|
559
|
+
end
|
560
|
+
else
|
561
|
+
""
|
562
|
+
end
|
563
|
+
}.join("")
|
564
|
+
|
565
|
+
if splat_arg
|
566
|
+
@has_splat_args = true
|
567
|
+
if signature.size-1 < normalargsnum then
|
568
|
+
read_arguments_code << "
|
569
|
+
plocals->#{splat_arg.to_s.gsub("*","")} = rb_ary_new3(0);
|
570
|
+
"
|
571
|
+
else
|
572
|
+
read_arguments_code << "
|
573
|
+
plocals->#{splat_arg.to_s.gsub("*","")} = rb_ary_new4(
|
574
|
+
#{(signature.size-1) - (normalargsnum)}, argv+#{normalargsnum}
|
575
|
+
);
|
576
|
+
"
|
577
|
+
end
|
578
|
+
|
579
|
+
end
|
580
|
+
|
581
|
+
|
582
|
+
""
|
583
|
+
end
|
584
|
+
|
585
|
+
if block_argument
|
586
|
+
|
587
|
+
@has_yield = true
|
588
|
+
|
589
|
+
proc_reyield_block_tree = s(:iter, s(:call, nil, :proc, s(:arglist)), s(:masgn, s(:array, s(:splat, s(:lasgn, :__xproc_arguments)))), s(:yield, s(:splat, s(:lvar, :__xproc_arguments))))
|
590
|
+
|
591
|
+
require "fastruby/sexp_extension"
|
592
|
+
|
593
|
+
read_arguments_code << "
|
594
|
+
if (pblock ? pblock->proc != Qnil : 0) {
|
595
|
+
plocals->#{block_argument.to_s.gsub("&","")} = pblock->proc;
|
596
|
+
} else {
|
597
|
+
plocals->#{block_argument.to_s.gsub("&","")} = #{to_c FastRuby::FastRubySexp.from_sexp(proc_reyield_block_tree)};
|
598
|
+
}
|
599
|
+
"
|
600
|
+
|
601
|
+
read_arguments_code << "
|
602
|
+
if (pblock) {
|
603
|
+
rb_ivar_set(plocals->#{block_argument.to_s.gsub("&","")},
|
604
|
+
#{intern_num "__block_address"}, PTR2NUM(pblock->block_function_address));
|
605
|
+
rb_ivar_set(plocals->#{block_argument.to_s.gsub("&","")},
|
606
|
+
#{intern_num "__block_param"}, PTR2NUM(pblock->block_function_param));
|
607
|
+
}
|
608
|
+
|
609
|
+
"
|
610
|
+
end
|
611
|
+
|
612
|
+
end
|
613
|
+
|
614
|
+
require "fastruby/sexp_extension"
|
615
|
+
|
616
|
+
trs = lambda{|tree|
|
617
|
+
if not tree.respond_to? :node_type
|
618
|
+
next tree
|
619
|
+
elsif tree.node_type == :call
|
620
|
+
mmname = tree[2]
|
621
|
+
next trs.call(tree[1]) || tree[1] if mmname == :infer
|
622
|
+
next fs(:nil) if mmname == :_throw or mmname == :_loop or mmname == :_raise
|
623
|
+
next fs(:nil) if mmname == :== and infer_value(tree)
|
624
|
+
elsif tree.node_type == :iter
|
625
|
+
mmname = tree[1][2]
|
626
|
+
next fs(:nil) if mmname == :_static
|
627
|
+
next fs(:block, trs.call(tree[3]) || tree[3]) if mmname == :_catch
|
628
|
+
end
|
629
|
+
|
630
|
+
tree.map &trs
|
631
|
+
}
|
632
|
+
|
633
|
+
evaluate_tree = tree.transform &trs
|
634
|
+
|
635
|
+
impl_code = to_c(impl_tree, "last_expression")
|
636
|
+
|
637
|
+
put_setjmp = (@has_dynamic_call or @has_nonlocal_goto or @has_yield or @has_raise or @has_inline_c)
|
638
|
+
put_block_init = @has_yield
|
639
|
+
if options[:main]
|
640
|
+
put_block_init = false
|
641
|
+
end
|
642
|
+
|
643
|
+
scope_mode = FastRuby::ScopeModeHelper.get_scope_mode(evaluate_tree)
|
644
|
+
if scope_mode == :dag or put_setjmp or put_block_init or @has_splat_args
|
645
|
+
put_frame = true
|
646
|
+
put_locals = true
|
647
|
+
else
|
648
|
+
put_frame = @has_inline_block
|
649
|
+
put_locals = @has_plocals_ref
|
650
|
+
end
|
651
|
+
|
652
|
+
ret = "VALUE #{@alt_method_name || method_name}(#{options[:main] ? "VALUE self" : strargs}) {
|
653
|
+
#{validate_arguments_code}
|
654
|
+
|
655
|
+
#{if put_frame
|
656
|
+
"
|
657
|
+
#{@frame_struct} frame;
|
658
|
+
#{@frame_struct} * volatile pframe;
|
659
|
+
|
660
|
+
frame.parent_frame = #{options[:main] ? "0" : "(void*)_parent_frame"};
|
661
|
+
frame.return_value = Qnil;
|
662
|
+
frame.rescue = 0;
|
663
|
+
frame.targetted = 0;
|
664
|
+
frame.thread_data = #{options[:main] ? "0" : "((typeof(pframe))_parent_frame)->thread_data"};
|
665
|
+
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
666
|
+
"
|
667
|
+
end
|
668
|
+
}
|
669
|
+
|
670
|
+
#{
|
671
|
+
if scope_mode == :dag
|
672
|
+
"
|
673
|
+
int stack_chunk_instantiated = 0;
|
674
|
+
|
675
|
+
volatile VALUE rb_previous_stack_chunk = Qnil;
|
676
|
+
VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
|
677
|
+
struct STACKCHUNK* volatile stack_chunk = 0;
|
678
|
+
|
679
|
+
if (rb_stack_chunk != Qnil) {
|
680
|
+
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
681
|
+
}
|
682
|
+
|
683
|
+
if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
|
684
|
+
rb_previous_stack_chunk = rb_stack_chunk;
|
685
|
+
rb_gc_register_address(&rb_stack_chunk);
|
686
|
+
stack_chunk_instantiated = 1;
|
687
|
+
|
688
|
+
rb_stack_chunk = rb_stack_chunk_create(Qnil);
|
689
|
+
frame.thread_data->rb_stack_chunk = rb_stack_chunk;
|
690
|
+
|
691
|
+
rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
|
692
|
+
|
693
|
+
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
694
|
+
}
|
695
|
+
|
696
|
+
#{@locals_struct}* volatile plocals;
|
697
|
+
|
698
|
+
volatile int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
|
699
|
+
plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
|
700
|
+
|
701
|
+
"
|
702
|
+
else
|
703
|
+
"
|
704
|
+
#{@locals_struct} locals;
|
705
|
+
typeof(locals) * volatile plocals = &locals;
|
706
|
+
"
|
707
|
+
end
|
708
|
+
}
|
709
|
+
|
710
|
+
#{if put_locals and put_frame
|
711
|
+
"
|
712
|
+
plocals->parent_locals = (frame.thread_data->last_plocals);
|
713
|
+
void* volatile old_parent_locals = frame.thread_data->last_plocals;
|
714
|
+
|
715
|
+
#{
|
716
|
+
if scope_mode == :dag
|
717
|
+
"frame.thread_data->last_plocals = plocals;\n"
|
718
|
+
end
|
719
|
+
}
|
720
|
+
|
721
|
+
frame.plocals = plocals;
|
722
|
+
plocals->pframe = (&frame);
|
723
|
+
pframe = (void*)&frame;
|
724
|
+
"
|
725
|
+
end
|
726
|
+
}
|
727
|
+
|
728
|
+
#{if put_locals
|
729
|
+
"
|
730
|
+
plocals->active = Qtrue;
|
731
|
+
plocals->targetted = Qfalse;
|
732
|
+
plocals->call_frame = (0);
|
733
|
+
"
|
734
|
+
end
|
735
|
+
}
|
736
|
+
|
737
|
+
volatile VALUE last_expression = Qnil;
|
738
|
+
|
739
|
+
#{if put_setjmp
|
740
|
+
"
|
741
|
+
|
742
|
+
int aux = setjmp(pframe->jmp);
|
743
|
+
if (aux != 0) {
|
744
|
+
plocals->active = Qfalse;
|
745
|
+
|
746
|
+
#{
|
747
|
+
if scope_mode == :dag
|
748
|
+
"
|
749
|
+
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
750
|
+
|
751
|
+
if (stack_chunk_instantiated) {
|
752
|
+
rb_gc_unregister_address(&rb_stack_chunk);
|
753
|
+
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
754
|
+
}
|
755
|
+
"
|
756
|
+
end
|
757
|
+
}
|
758
|
+
#{
|
759
|
+
unless options[:main]
|
760
|
+
"
|
761
|
+
if (plocals->targetted == Qfalse || aux != FASTRUBY_TAG_RETURN) {
|
762
|
+
frame.thread_data->last_plocals = old_parent_locals;
|
763
|
+
|
764
|
+
longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
|
765
|
+
}
|
766
|
+
"
|
767
|
+
end
|
768
|
+
}
|
769
|
+
|
770
|
+
frame.thread_data->last_plocals = old_parent_locals;
|
771
|
+
|
772
|
+
return plocals->return_value;
|
773
|
+
}
|
774
|
+
"
|
775
|
+
end
|
776
|
+
}
|
777
|
+
|
778
|
+
#{if put_locals
|
779
|
+
"
|
780
|
+
plocals->self = self;
|
781
|
+
"
|
782
|
+
end
|
783
|
+
}
|
784
|
+
|
785
|
+
#{
|
786
|
+
if put_block_init
|
787
|
+
"
|
788
|
+
#{@block_struct} * volatile pblock;
|
789
|
+
pblock = (void*)block;
|
790
|
+
if (pblock) {
|
791
|
+
plocals->block_function_address = pblock->block_function_address;
|
792
|
+
plocals->block_function_param = pblock->block_function_param;
|
793
|
+
} else {
|
794
|
+
plocals->block_function_address = (0);
|
795
|
+
plocals->block_function_param = 0;
|
796
|
+
}
|
797
|
+
"
|
798
|
+
end
|
799
|
+
}
|
800
|
+
|
801
|
+
#{if put_locals
|
802
|
+
"
|
803
|
+
#{read_arguments_code}
|
804
|
+
"
|
805
|
+
end
|
806
|
+
}
|
807
|
+
|
808
|
+
#{impl_code};
|
809
|
+
|
810
|
+
local_return:
|
811
|
+
#{
|
812
|
+
if scope_mode == :dag
|
813
|
+
"
|
814
|
+
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
815
|
+
|
816
|
+
if (stack_chunk_instantiated) {
|
817
|
+
rb_gc_unregister_address(&rb_stack_chunk);
|
818
|
+
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
819
|
+
}
|
820
|
+
"
|
821
|
+
end
|
822
|
+
}
|
823
|
+
|
824
|
+
#{if put_locals
|
825
|
+
"
|
826
|
+
plocals->active = Qfalse;
|
827
|
+
"
|
828
|
+
end
|
829
|
+
}
|
830
|
+
|
831
|
+
#{if put_locals and put_frame
|
832
|
+
"
|
833
|
+
frame.thread_data->last_plocals = old_parent_locals;
|
834
|
+
"
|
835
|
+
end
|
836
|
+
}
|
837
|
+
|
838
|
+
return last_expression;
|
839
|
+
}"
|
840
|
+
|
841
|
+
add_main
|
842
|
+
extra_code << ret
|
843
|
+
|
844
|
+
"
|
845
|
+
static VALUE dummy_#{@alt_method_name}_#{rand(1000000000000000000000000000000000)}(VALUE a) {
|
846
|
+
return Qnil;
|
847
|
+
}
|
848
|
+
"
|
849
|
+
end
|
850
|
+
|
851
|
+
def locals_accessor
|
852
|
+
@has_plocals_ref = true
|
853
|
+
"plocals->"
|
854
|
+
end
|
855
|
+
|
856
|
+
def locals_scope(locals)
|
857
|
+
old_locals = @locals
|
858
|
+
old_locals_struct = @locals_struct
|
859
|
+
|
860
|
+
@locals = locals
|
861
|
+
@locals_struct = "struct {
|
862
|
+
int size;
|
863
|
+
void* call_frame;
|
864
|
+
void* parent_locals;
|
865
|
+
void* pframe;
|
866
|
+
void* block_function_address;
|
867
|
+
void* block_function_param;
|
868
|
+
VALUE active;
|
869
|
+
VALUE targetted;
|
870
|
+
VALUE return_value;
|
871
|
+
#{@locals.map{|l| "VALUE #{l};\n"}.join}
|
872
|
+
}"
|
873
|
+
|
874
|
+
begin
|
875
|
+
yield
|
876
|
+
ensure
|
877
|
+
@locals = old_locals
|
878
|
+
@locals_struct = old_locals_struct
|
879
|
+
end
|
880
|
+
end
|
881
|
+
|
882
|
+
def infer_type(recv)
|
883
|
+
array = @inferencer.infer(recv).to_a
|
884
|
+
|
885
|
+
if array.size == 1
|
886
|
+
array[0]
|
887
|
+
else
|
888
|
+
nil
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
def on_block
|
893
|
+
old_on_block = @on_block
|
894
|
+
@on_block = true
|
895
|
+
return yield
|
896
|
+
ensure
|
897
|
+
@on_block = old_on_block
|
898
|
+
end
|
899
|
+
|
900
|
+
def directive(tree)
|
901
|
+
recv = tree[1]
|
902
|
+
mname = tree[2]
|
903
|
+
args = tree[3]
|
904
|
+
|
905
|
+
if mname == :infer
|
906
|
+
return to_c(recv)
|
907
|
+
elsif mname == :block_given?
|
908
|
+
@has_yield = true
|
909
|
+
return "plocals->block_function_address == 0 ? Qfalse : Qtrue"
|
910
|
+
elsif mname == :inline_c
|
911
|
+
@has_inline_c = true
|
912
|
+
code = args[1][1]
|
913
|
+
|
914
|
+
unless (args[2] == s(:false))
|
915
|
+
return anonymous_function{ |name| "
|
916
|
+
static VALUE #{name}(VALUE param) {
|
917
|
+
#{@frame_struct} *pframe = (void*)param;
|
918
|
+
#{@locals_struct} *plocals = (void*)pframe->plocals;
|
919
|
+
#{code};
|
920
|
+
|
921
|
+
return Qnil;
|
922
|
+
}
|
923
|
+
"
|
924
|
+
}+"((VALUE)pframe)"
|
925
|
+
else
|
926
|
+
code
|
927
|
+
end
|
928
|
+
|
929
|
+
else
|
930
|
+
nil
|
931
|
+
end
|
932
|
+
end
|
933
|
+
|
934
|
+
def inline_block_reference(arg, nolocals = false)
|
935
|
+
@has_inline_block = true
|
936
|
+
|
937
|
+
code = nil
|
938
|
+
|
939
|
+
if arg.instance_of? FastRuby::FastRubySexp
|
940
|
+
code = to_c(arg);
|
941
|
+
else
|
942
|
+
code = arg
|
943
|
+
end
|
944
|
+
|
945
|
+
anonymous_function{ |name| "
|
946
|
+
static VALUE #{name}(VALUE param) {
|
947
|
+
#{@frame_struct} *pframe = (void*)param;
|
948
|
+
|
949
|
+
#{nolocals ? "" : "#{@locals_struct} *plocals = (void*)pframe->plocals;"}
|
950
|
+
VALUE last_expression = Qnil;
|
951
|
+
|
952
|
+
#{code};
|
953
|
+
return last_expression;
|
954
|
+
}
|
955
|
+
"
|
956
|
+
}
|
957
|
+
end
|
958
|
+
|
959
|
+
def catch_on_throw
|
960
|
+
old_catch_jmp_on_throw = @catch_jmp_on_throw || false
|
961
|
+
@catch_jmp_on_throw = true
|
962
|
+
begin
|
963
|
+
ret = yield
|
964
|
+
ensure
|
965
|
+
@catch_jmp_on_throw = old_catch_jmp_on_throw
|
966
|
+
end
|
967
|
+
|
968
|
+
ret
|
969
|
+
end
|
970
|
+
|
971
|
+
def inline_block(*args)
|
972
|
+
@has_inline_block = true
|
973
|
+
|
974
|
+
unless block_given?
|
975
|
+
code = args.first
|
976
|
+
return inline_block(*args[1..-1]) {
|
977
|
+
code
|
978
|
+
}
|
979
|
+
end
|
980
|
+
|
981
|
+
repass_var = args[0]
|
982
|
+
nolocals = args[1] || false
|
983
|
+
|
984
|
+
code = catch_on_throw{ yield }
|
985
|
+
|
986
|
+
anonymous_function{ |name| "
|
987
|
+
static VALUE #{name}(VALUE param#{repass_var ? ",void* " + repass_var : "" }) {
|
988
|
+
#{@frame_struct} * volatile pframe = (void*)param;
|
989
|
+
|
990
|
+
#{nolocals ? "" : "#{@locals_struct} * volatile plocals = (void*)pframe->plocals;"}
|
991
|
+
volatile VALUE last_expression = Qnil;
|
992
|
+
|
993
|
+
#{code}
|
994
|
+
return Qnil;
|
995
|
+
|
996
|
+
|
997
|
+
#{@catch_blocks.map { |cb|
|
998
|
+
"#{cb.to_s}_end:
|
999
|
+
|
1000
|
+
plocals->return_value = last_expression;
|
1001
|
+
plocals->targetted = 1;
|
1002
|
+
longjmp(pframe->jmp, #{intern_num( cb.to_s + "_end")});
|
1003
|
+
|
1004
|
+
#{cb.to_s}_start:
|
1005
|
+
|
1006
|
+
plocals->return_value = last_expression;
|
1007
|
+
plocals->targetted = 1;
|
1008
|
+
longjmp(pframe->jmp, #{intern_num( cb.to_s + "_start")});
|
1009
|
+
|
1010
|
+
"
|
1011
|
+
|
1012
|
+
}.join("\n")
|
1013
|
+
}
|
1014
|
+
#{unless nolocals
|
1015
|
+
"
|
1016
|
+
local_return:
|
1017
|
+
plocals->return_value = last_expression;
|
1018
|
+
plocals->targetted = 1;
|
1019
|
+
longjmp(pframe->jmp, FASTRUBY_TAG_RETURN);
|
1020
|
+
return last_expression;
|
1021
|
+
"
|
1022
|
+
end
|
1023
|
+
}
|
1024
|
+
fastruby_local_redo:
|
1025
|
+
longjmp(pframe->jmp,FASTRUBY_TAG_REDO);
|
1026
|
+
return Qnil;
|
1027
|
+
fastruby_local_next:
|
1028
|
+
longjmp(pframe->jmp,FASTRUBY_TAG_NEXT);
|
1029
|
+
return Qnil;
|
1030
|
+
|
1031
|
+
|
1032
|
+
}
|
1033
|
+
"
|
1034
|
+
} + "((VALUE)pframe#{repass_var ? ", " + repass_var : "" })"
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
def inline_ruby(proced, parameter)
|
1038
|
+
"rb_funcall(#{proced.__id__}, #{intern_num :call}, 1, #{parameter})"
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
def protected_block(*args)
|
1042
|
+
unless block_given?
|
1043
|
+
inner_code = args.first
|
1044
|
+
return protected_block(*args[1..-1]) {
|
1045
|
+
inner_code
|
1046
|
+
}
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
repass_var = args[1]
|
1050
|
+
nolocals = args[2] || false
|
1051
|
+
|
1052
|
+
inline_block(repass_var, nolocals) do
|
1053
|
+
generate_protected_block(yield, *args)
|
1054
|
+
end
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def generate_protected_block(inner_code, always_rescue = false,repass_var = nil, nolocals = false)
|
1058
|
+
body = nil
|
1059
|
+
rescue_args = nil
|
1060
|
+
|
1061
|
+
body = anonymous_function{ |name| "
|
1062
|
+
static VALUE #{name}(VALUE param) {
|
1063
|
+
|
1064
|
+
#{@frame_struct} frame;
|
1065
|
+
|
1066
|
+
typeof(frame)* volatile pframe;
|
1067
|
+
|
1068
|
+
#{if repass_var
|
1069
|
+
"typeof(frame)* parent_frame = ((typeof(pframe))((void**)param)[0]);"
|
1070
|
+
else
|
1071
|
+
"typeof(frame)* parent_frame = (typeof(pframe))param;"
|
1072
|
+
end
|
1073
|
+
}
|
1074
|
+
|
1075
|
+
frame.parent_frame = 0;
|
1076
|
+
frame.return_value = Qnil;
|
1077
|
+
frame.rescue = 0;
|
1078
|
+
frame.last_error = Qnil;
|
1079
|
+
frame.targetted = 0;
|
1080
|
+
frame.thread_data = parent_frame->thread_data;
|
1081
|
+
frame.next_recv = parent_frame->next_recv;
|
1082
|
+
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
1083
|
+
|
1084
|
+
pframe = &frame;
|
1085
|
+
|
1086
|
+
#{
|
1087
|
+
nolocals ? "frame.plocals = 0;" : "#{@locals_struct}* plocals = parent_frame->plocals;
|
1088
|
+
frame.plocals = plocals;
|
1089
|
+
"
|
1090
|
+
}
|
1091
|
+
|
1092
|
+
int aux = setjmp(frame.jmp);
|
1093
|
+
if (aux != 0) {
|
1094
|
+
|
1095
|
+
if (frame.targetted == 1) {
|
1096
|
+
return frame.return_value;
|
1097
|
+
} else {
|
1098
|
+
frb_jump_tag(aux);
|
1099
|
+
}
|
1100
|
+
}
|
1101
|
+
|
1102
|
+
#{if repass_var
|
1103
|
+
"VALUE #{repass_var} = (VALUE)((void**)param)[1];"
|
1104
|
+
end
|
1105
|
+
}
|
1106
|
+
volatile VALUE last_expression = Qnil;
|
1107
|
+
#{inner_code};
|
1108
|
+
return last_expression;
|
1109
|
+
}
|
1110
|
+
"
|
1111
|
+
}
|
1112
|
+
|
1113
|
+
if repass_var
|
1114
|
+
rescue_args = ""
|
1115
|
+
rescue_args = "(VALUE)(VALUE[]){(VALUE)pframe,(VALUE)#{repass_var}}"
|
1116
|
+
else
|
1117
|
+
rescue_args = "(VALUE)pframe"
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
wrapper_code = "
|
1121
|
+
if (str.state >= 0x80) {
|
1122
|
+
longjmp(pframe->jmp, str.state);
|
1123
|
+
} else {
|
1124
|
+
if (str.last_error != Qnil) {
|
1125
|
+
// raise emulation
|
1126
|
+
pframe->thread_data->exception = str.last_error;
|
1127
|
+
longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
|
1128
|
+
return Qnil;
|
1129
|
+
}
|
1130
|
+
}
|
1131
|
+
"
|
1132
|
+
|
1133
|
+
return_err_struct = "struct {
|
1134
|
+
VALUE last_error;
|
1135
|
+
int state;
|
1136
|
+
}
|
1137
|
+
"
|
1138
|
+
|
1139
|
+
rescue_body = anonymous_function{ |name| "
|
1140
|
+
static VALUE #{name}(VALUE param, VALUE err) {
|
1141
|
+
#{return_err_struct} *pstr = (void*)param;
|
1142
|
+
|
1143
|
+
if (rb_obj_is_instance_of(err, #{literal_value FastRuby::JumpTagException})) {
|
1144
|
+
pstr->state = FIX2INT(rb_funcall(err, #{intern_num :state}, 0));
|
1145
|
+
} else {
|
1146
|
+
pstr->last_error = err;
|
1147
|
+
}
|
1148
|
+
|
1149
|
+
return Qnil;
|
1150
|
+
}
|
1151
|
+
"
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
rescue_code = "rb_rescue2(#{body}, #{rescue_args}, #{rescue_body}, (VALUE)&str, rb_eException, (VALUE)0)"
|
1155
|
+
|
1156
|
+
if always_rescue
|
1157
|
+
"
|
1158
|
+
#{return_err_struct} str;
|
1159
|
+
|
1160
|
+
str.state = 0;
|
1161
|
+
str.last_error = Qnil;
|
1162
|
+
|
1163
|
+
pframe->last_error = Qnil;
|
1164
|
+
VALUE result = #{rescue_code};
|
1165
|
+
|
1166
|
+
#{wrapper_code}
|
1167
|
+
|
1168
|
+
return result;
|
1169
|
+
"
|
1170
|
+
else
|
1171
|
+
"
|
1172
|
+
VALUE result;
|
1173
|
+
#{return_err_struct} str;
|
1174
|
+
|
1175
|
+
str.state = 0;
|
1176
|
+
str.last_error = Qnil;
|
1177
|
+
|
1178
|
+
pframe->last_error = Qnil;
|
1179
|
+
|
1180
|
+
if (pframe->rescue) {
|
1181
|
+
result = #{rescue_code};
|
1182
|
+
#{wrapper_code}
|
1183
|
+
} else {
|
1184
|
+
VALUE last_expression = Qnil;
|
1185
|
+
#{inner_code};
|
1186
|
+
return last_expression;
|
1187
|
+
}
|
1188
|
+
|
1189
|
+
return result;
|
1190
|
+
"
|
1191
|
+
end
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
def c_escape(str)
|
1195
|
+
str.inspect
|
1196
|
+
end
|
1197
|
+
|
1198
|
+
def literal_value(value)
|
1199
|
+
@literal_value_hash = Hash.new unless @literal_value_hash
|
1200
|
+
return @literal_value_hash[value] if @literal_value_hash[value]
|
1201
|
+
|
1202
|
+
name = self.add_global_name("VALUE", "Qnil");
|
1203
|
+
|
1204
|
+
begin
|
1205
|
+
|
1206
|
+
str = Marshal.dump(value)
|
1207
|
+
|
1208
|
+
|
1209
|
+
if value.instance_of? Module
|
1210
|
+
|
1211
|
+
container_str = value.to_s.split("::")[0..-2].join("::")
|
1212
|
+
|
1213
|
+
init_extra << "
|
1214
|
+
#{name} = rb_define_module_under(
|
1215
|
+
#{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
|
1216
|
+
,\"#{value.to_s.split("::").last}\");
|
1217
|
+
|
1218
|
+
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
1219
|
+
"
|
1220
|
+
elsif value.instance_of? Class
|
1221
|
+
container_str = value.to_s.split("::")[0..-2].join("::")
|
1222
|
+
|
1223
|
+
str_class_name = value.to_s.split("::").last
|
1224
|
+
|
1225
|
+
if (str_class_name == "Object")
|
1226
|
+
init_extra << "
|
1227
|
+
#{name} = rb_cObject;
|
1228
|
+
"
|
1229
|
+
else
|
1230
|
+
init_extra << "
|
1231
|
+
#{name} = rb_define_class_under(
|
1232
|
+
#{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
|
1233
|
+
,\"#{str_class_name}\"
|
1234
|
+
,#{value.superclass == Object ? "rb_cObject" : literal_value(value.superclass)});
|
1235
|
+
|
1236
|
+
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
1237
|
+
"
|
1238
|
+
end
|
1239
|
+
elsif value.instance_of? Array
|
1240
|
+
init_extra << "
|
1241
|
+
#{name} = rb_ary_new3(#{value.size}, #{value.map{|x| literal_value x}.join(",")} );
|
1242
|
+
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
1243
|
+
"
|
1244
|
+
else
|
1245
|
+
|
1246
|
+
init_extra << "
|
1247
|
+
|
1248
|
+
{
|
1249
|
+
VALUE encoded_str = rb_str_new2(#{Base64.encode64(str).inspect});
|
1250
|
+
VALUE str = rb_funcall(rb_cObject, #{intern_num :decode64}, 1, encoded_str);
|
1251
|
+
#{name} = rb_marshal_load(str);
|
1252
|
+
|
1253
|
+
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
"
|
1257
|
+
end
|
1258
|
+
rescue TypeError => e
|
1259
|
+
@no_cache = true
|
1260
|
+
FastRuby.logger.info "#{value} disabling cache for extension"
|
1261
|
+
init_extra << "
|
1262
|
+
#{name} = rb_funcall(rb_const_get(rb_cObject, #{intern_num :ObjectSpace}), #{intern_num :_id2ref}, 1, INT2FIX(#{value.__id__}));
|
1263
|
+
"
|
1264
|
+
|
1265
|
+
end
|
1266
|
+
@literal_value_hash[value] = name
|
1267
|
+
|
1268
|
+
name
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
def dynamic_block_call(signature, mname)
|
1272
|
+
dynamic_call(signature, mname, true)
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
# returns a anonymous function who made a dynamic call
|
1276
|
+
def dynamic_call(signature, mname, return_on_block_call = false, funcall_fallback = true, global_klass_variable = nil)
|
1277
|
+
# TODO: initialize the table
|
1278
|
+
@has_dynamic_call = true
|
1279
|
+
max_argument_size = 0
|
1280
|
+
recvtype = signature.first
|
1281
|
+
|
1282
|
+
unless recvtype
|
1283
|
+
max_argument_size = max_argument_size + 1
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
compare_hash = {}
|
1287
|
+
(1..signature.size-1).each do |j|
|
1288
|
+
unless signature[j]
|
1289
|
+
compare_hash[max_argument_size] = j-1
|
1290
|
+
max_argument_size = max_argument_size + 1
|
1291
|
+
end
|
1292
|
+
end
|
1293
|
+
|
1294
|
+
table_size = if compare_hash.size == 0
|
1295
|
+
1
|
1296
|
+
elsif compare_hash.size == 1
|
1297
|
+
16
|
1298
|
+
else
|
1299
|
+
64
|
1300
|
+
end
|
1301
|
+
|
1302
|
+
table_name = reserve_table(table_size, max_argument_size)
|
1303
|
+
|
1304
|
+
if recvtype
|
1305
|
+
|
1306
|
+
init_extra << "{
|
1307
|
+
memset(#{table_name},0,sizeof(#{table_name}));
|
1308
|
+
|
1309
|
+
VALUE mname = #{literal_value mname};
|
1310
|
+
VALUE recvtype = #{literal_value recvtype};
|
1311
|
+
rb_funcall(#{literal_value FastRuby}, #{intern_num :set_builder_module}, 1, recvtype);
|
1312
|
+
VALUE fastruby_method = rb_funcall(recvtype, #{intern_num :fastruby_method}, 1, mname);
|
1313
|
+
rb_iterate(#{anonymous_function{|funcname|
|
1314
|
+
"static VALUE #{funcname}(VALUE recv) {
|
1315
|
+
return rb_funcall(recv, #{intern_num :observe}, 1, #{literal_value(mname.to_s + "#" + table_name.to_s)});
|
1316
|
+
}
|
1317
|
+
"
|
1318
|
+
}},fastruby_method,
|
1319
|
+
#{anonymous_function{|funcname|
|
1320
|
+
"static VALUE #{funcname}() {
|
1321
|
+
// clear table
|
1322
|
+
memset(#{table_name},0,sizeof(#{table_name}));
|
1323
|
+
return Qnil;
|
1324
|
+
}
|
1325
|
+
"
|
1326
|
+
}
|
1327
|
+
}
|
1328
|
+
,Qnil);
|
1329
|
+
}
|
1330
|
+
"
|
1331
|
+
else
|
1332
|
+
|
1333
|
+
# TODO: implemente this in ruby
|
1334
|
+
init_extra << "
|
1335
|
+
{
|
1336
|
+
memset(#{table_name},0,sizeof(#{table_name}));
|
1337
|
+
|
1338
|
+
rb_iterate(#{anonymous_function{|funcname|
|
1339
|
+
"static VALUE #{funcname}(VALUE recv) {
|
1340
|
+
return rb_funcall(recv, #{intern_num :observe_method_name}, 1, #{literal_value(mname.to_sym)});
|
1341
|
+
}
|
1342
|
+
"
|
1343
|
+
}},#{literal_value FastRuby::Method},
|
1344
|
+
#{anonymous_function{|funcname|
|
1345
|
+
"static VALUE #{funcname}() {
|
1346
|
+
// clear table
|
1347
|
+
memset(#{table_name},0,sizeof(#{table_name}));
|
1348
|
+
return Qnil;
|
1349
|
+
}
|
1350
|
+
"
|
1351
|
+
}
|
1352
|
+
}
|
1353
|
+
,Qnil);
|
1354
|
+
|
1355
|
+
}
|
1356
|
+
"
|
1357
|
+
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
anonymous_function{|funcname| "
|
1361
|
+
static VALUE #{funcname}(VALUE self,void* block,void* frame, int argc, VALUE* argv #{return_on_block_call ? ", int* block_call" : ""}){
|
1362
|
+
void* fptr = 0;
|
1363
|
+
#{if global_klass_variable
|
1364
|
+
"
|
1365
|
+
VALUE klass = #{global_klass_variable};
|
1366
|
+
"
|
1367
|
+
else
|
1368
|
+
"
|
1369
|
+
VALUE klass = CLASS_OF(self);
|
1370
|
+
"
|
1371
|
+
end
|
1372
|
+
}
|
1373
|
+
|
1374
|
+
char method_name[argc*40+64];
|
1375
|
+
|
1376
|
+
unsigned int fptr_hash = 0;
|
1377
|
+
int match = 1;
|
1378
|
+
|
1379
|
+
#{if table_size > 1
|
1380
|
+
"
|
1381
|
+
#{unless signature.first
|
1382
|
+
"fptr_hash = klass;
|
1383
|
+
"
|
1384
|
+
end
|
1385
|
+
}
|
1386
|
+
|
1387
|
+
#{
|
1388
|
+
compare_hash.map { |k,v|
|
1389
|
+
"if (#{v} < argc) {
|
1390
|
+
fptr_hash += CLASS_OF(argv[#{v}]);
|
1391
|
+
}
|
1392
|
+
"
|
1393
|
+
}.join("\n")
|
1394
|
+
};
|
1395
|
+
|
1396
|
+
fptr_hash = fptr_hash % #{table_size};
|
1397
|
+
|
1398
|
+
int j = 0;
|
1399
|
+
|
1400
|
+
if (argc+15 != #{table_name}[fptr_hash].argc) {
|
1401
|
+
match = 0;
|
1402
|
+
goto does_not_match;
|
1403
|
+
}
|
1404
|
+
|
1405
|
+
#{unless recvtype
|
1406
|
+
"
|
1407
|
+
if (match == 1 && #{table_name}[fptr_hash].argument_type[0] != klass ) {
|
1408
|
+
match = 0;
|
1409
|
+
goto does_not_match;
|
1410
|
+
}
|
1411
|
+
"
|
1412
|
+
end
|
1413
|
+
}
|
1414
|
+
|
1415
|
+
#{
|
1416
|
+
compare_hash.map { |k,v|
|
1417
|
+
"if (match == 1 && #{table_name}[fptr_hash].argument_type[#{k}] != CLASS_OF(argv[#{v}])) {
|
1418
|
+
match = 0;
|
1419
|
+
goto does_not_match;
|
1420
|
+
}
|
1421
|
+
"
|
1422
|
+
}.join("\n")
|
1423
|
+
};
|
1424
|
+
"
|
1425
|
+
end
|
1426
|
+
}
|
1427
|
+
|
1428
|
+
if (#{table_name}[fptr_hash].address == 0) match = 0;
|
1429
|
+
if (match == 1) {
|
1430
|
+
fptr = #{table_name}[fptr_hash].address;
|
1431
|
+
} else {
|
1432
|
+
does_not_match:
|
1433
|
+
method_name[0] = '_';
|
1434
|
+
method_name[1] = 0;
|
1435
|
+
|
1436
|
+
strncpy(method_name+1, \"#{mname}\",sizeof(method_name)-4);
|
1437
|
+
sprintf(method_name+strlen(method_name), \"%li\", (long)NUM2PTR(rb_obj_id(CLASS_OF(self))));
|
1438
|
+
|
1439
|
+
int i;
|
1440
|
+
for (i=0; i<argc; i++) {
|
1441
|
+
sprintf(method_name+strlen(method_name), \"%li\", (long)NUM2PTR(rb_obj_id(CLASS_OF(argv[i]))));
|
1442
|
+
}
|
1443
|
+
|
1444
|
+
void** address = 0;
|
1445
|
+
ID id;
|
1446
|
+
VALUE rb_method_hash;
|
1447
|
+
|
1448
|
+
id = rb_intern(method_name);
|
1449
|
+
|
1450
|
+
if (rb_respond_to(klass, #{intern_num :method_hash})) {
|
1451
|
+
rb_method_hash = rb_funcall(klass, #{intern_num :method_hash},1,#{literal_value mname});
|
1452
|
+
|
1453
|
+
if (rb_method_hash != Qnil) {
|
1454
|
+
VALUE tmp = rb_hash_aref(rb_method_hash, PTR2NUM(id));
|
1455
|
+
if (tmp != Qnil) {
|
1456
|
+
address = (void**)NUM2PTR(tmp);
|
1457
|
+
fptr = *address;
|
1458
|
+
}
|
1459
|
+
}
|
1460
|
+
|
1461
|
+
if (fptr == 0) {
|
1462
|
+
VALUE fastruby_method = rb_funcall(klass, #{intern_num :fastruby_method}, 1, #{literal_value mname});
|
1463
|
+
VALUE tree = rb_funcall(fastruby_method, #{intern_num :tree}, 0,0);
|
1464
|
+
|
1465
|
+
if (RTEST(tree)) {
|
1466
|
+
VALUE argv_class[argc+1];
|
1467
|
+
|
1468
|
+
argv_class[0] = CLASS_OF(self);
|
1469
|
+
for (i=0; i<argc; i++) {
|
1470
|
+
argv_class[i+1] = CLASS_OF(argv[i]);
|
1471
|
+
}
|
1472
|
+
|
1473
|
+
VALUE signature = rb_ary_new4(argc+1,argv_class);
|
1474
|
+
|
1475
|
+
rb_funcall(klass, #{intern_num :build}, 2, signature,rb_str_new2(#{mname.to_s.inspect}));
|
1476
|
+
|
1477
|
+
id = rb_intern(method_name);
|
1478
|
+
rb_method_hash = rb_funcall(klass, #{intern_num :method_hash},1,#{literal_value mname});
|
1479
|
+
|
1480
|
+
if (rb_method_hash != Qnil) {
|
1481
|
+
VALUE tmp = rb_hash_aref(rb_method_hash, PTR2NUM(id));
|
1482
|
+
if (tmp != Qnil) {
|
1483
|
+
address = (void**)NUM2PTR(tmp);
|
1484
|
+
fptr = *address;
|
1485
|
+
}
|
1486
|
+
}
|
1487
|
+
|
1488
|
+
if (fptr == 0) {
|
1489
|
+
rb_raise(rb_eRuntimeError, \"Error: method not found after build\");
|
1490
|
+
}
|
1491
|
+
}
|
1492
|
+
}
|
1493
|
+
}
|
1494
|
+
|
1495
|
+
// insert the value on table
|
1496
|
+
#{table_name}[fptr_hash].argc = argc+15;
|
1497
|
+
|
1498
|
+
#{unless recvtype
|
1499
|
+
"
|
1500
|
+
#{table_name}[fptr_hash].argument_type[0] = klass;
|
1501
|
+
"
|
1502
|
+
end
|
1503
|
+
}
|
1504
|
+
|
1505
|
+
#{
|
1506
|
+
compare_hash.map { |k,v|
|
1507
|
+
"if (#{v} < argc) {
|
1508
|
+
#{table_name}[fptr_hash].argument_type[#{k}] = CLASS_OF(argv[#{v}]);
|
1509
|
+
}
|
1510
|
+
"
|
1511
|
+
}.join("\n")
|
1512
|
+
};
|
1513
|
+
|
1514
|
+
#{table_name}[fptr_hash].address = fptr;
|
1515
|
+
}
|
1516
|
+
|
1517
|
+
if (fptr != 0) {
|
1518
|
+
return ((VALUE(*)(VALUE,VALUE,VALUE,int,VALUE*))fptr)(self,(VALUE)block,(VALUE)frame, argc, argv);
|
1519
|
+
}
|
1520
|
+
|
1521
|
+
#{if funcall_fallback
|
1522
|
+
"
|
1523
|
+
|
1524
|
+
#{@frame_struct}* pframe = frame;
|
1525
|
+
VALUE method_arguments[4];
|
1526
|
+
|
1527
|
+
method_arguments[0] = (VALUE)argc;
|
1528
|
+
method_arguments[1] = (VALUE)argv;
|
1529
|
+
method_arguments[2] = (VALUE)self;
|
1530
|
+
method_arguments[3] = (VALUE)block;
|
1531
|
+
|
1532
|
+
if (block == 0) {
|
1533
|
+
return #{
|
1534
|
+
protected_block "
|
1535
|
+
last_expression = rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);", true, "method_arguments"
|
1536
|
+
};
|
1537
|
+
|
1538
|
+
} else {
|
1539
|
+
#{
|
1540
|
+
if return_on_block_call
|
1541
|
+
"*block_call = 1;
|
1542
|
+
return Qnil;
|
1543
|
+
"
|
1544
|
+
else
|
1545
|
+
"
|
1546
|
+
return #{
|
1547
|
+
protected_block "
|
1548
|
+
#{@block_struct} *pblock;
|
1549
|
+
pblock = (typeof(pblock))( ((VALUE*)method_arguments)[3] );
|
1550
|
+
last_expression = rb_iterate(
|
1551
|
+
#{anonymous_function{|name_|
|
1552
|
+
"
|
1553
|
+
static VALUE #{name_} (VALUE data) {
|
1554
|
+
VALUE* method_arguments = (VALUE*)data;
|
1555
|
+
return rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);
|
1556
|
+
}
|
1557
|
+
"
|
1558
|
+
}},
|
1559
|
+
(VALUE)method_arguments,
|
1560
|
+
|
1561
|
+
#{anonymous_function{|name_|
|
1562
|
+
"
|
1563
|
+
static VALUE #{name_} (VALUE arg_, VALUE param, int argc, VALUE* argv) {
|
1564
|
+
#{@block_struct}* pblock = (void*)param;
|
1565
|
+
|
1566
|
+
if (pblock->proc != Qnil) {
|
1567
|
+
VALUE arg;
|
1568
|
+
#{
|
1569
|
+
# TODO: access directly to argc and argv for optimal execution
|
1570
|
+
if RUBY_VERSION =~ /^1\.9/
|
1571
|
+
"
|
1572
|
+
if (TYPE(arg_) == T_ARRAY) {
|
1573
|
+
if (_RARRAY_LEN(arg_) <= 1) {
|
1574
|
+
arg = rb_ary_new4(argc,argv);
|
1575
|
+
} else {
|
1576
|
+
arg = arg_;
|
1577
|
+
}
|
1578
|
+
} else {
|
1579
|
+
arg = rb_ary_new4(argc,argv);
|
1580
|
+
}
|
1581
|
+
"
|
1582
|
+
else
|
1583
|
+
"arg = arg_;"
|
1584
|
+
end
|
1585
|
+
}
|
1586
|
+
|
1587
|
+
return rb_proc_call(pblock->proc, arg);
|
1588
|
+
|
1589
|
+
} else {
|
1590
|
+
#{
|
1591
|
+
# TODO: access directly to argc and argv for optimal execution
|
1592
|
+
if RUBY_VERSION =~ /^1\.9/
|
1593
|
+
"return ((VALUE(*)(int,VALUE*,VALUE,VALUE))pblock->block_function_address)(argc,argv,(VALUE)pblock->block_function_param,(VALUE)0);"
|
1594
|
+
else
|
1595
|
+
"return Qnil;"
|
1596
|
+
end
|
1597
|
+
}
|
1598
|
+
}
|
1599
|
+
|
1600
|
+
}
|
1601
|
+
"
|
1602
|
+
}},
|
1603
|
+
(VALUE)pblock
|
1604
|
+
);
|
1605
|
+
", true, "method_arguments"
|
1606
|
+
};
|
1607
|
+
"
|
1608
|
+
end
|
1609
|
+
}
|
1610
|
+
}
|
1611
|
+
"
|
1612
|
+
else
|
1613
|
+
"
|
1614
|
+
rb_raise(rb_eRuntimeError, \"Error: invalid dynamic call for defn\");
|
1615
|
+
return Qnil;
|
1616
|
+
"
|
1617
|
+
end
|
1618
|
+
}
|
1619
|
+
}
|
1620
|
+
"
|
1621
|
+
}
|
1622
|
+
end
|
1623
|
+
|
1624
|
+
def intern_num(symbol)
|
1625
|
+
symbol = symbol.to_sym
|
1626
|
+
@intern_num_hash = Hash.new unless @intern_num_hash
|
1627
|
+
return @intern_num_hash[symbol] if @intern_num_hash[symbol]
|
1628
|
+
|
1629
|
+
name = self.add_global_name("ID", 0);
|
1630
|
+
|
1631
|
+
init_extra << "
|
1632
|
+
#{name} = rb_intern(\"#{symbol.to_s}\");
|
1633
|
+
"
|
1634
|
+
|
1635
|
+
@intern_num_hash[symbol] = name
|
1636
|
+
|
1637
|
+
name
|
1638
|
+
end
|
1639
|
+
|
1640
|
+
def reserve_table(size, argument_count)
|
1641
|
+
name = "glb_table" + rand(1000000000).to_s
|
1642
|
+
|
1643
|
+
extra_code << "
|
1644
|
+
static struct {
|
1645
|
+
VALUE argument_type[#{argument_count}];
|
1646
|
+
void* address;
|
1647
|
+
int argc;
|
1648
|
+
} #{name}[#{size}];
|
1649
|
+
"
|
1650
|
+
|
1651
|
+
name
|
1652
|
+
end
|
1653
|
+
|
1654
|
+
def add_global_name(ctype, default)
|
1655
|
+
name = "glb" + rand(1000000000).to_s
|
1656
|
+
|
1657
|
+
extra_code << "
|
1658
|
+
static #{ctype} #{name} = #{default};
|
1659
|
+
"
|
1660
|
+
name
|
1661
|
+
end
|
1662
|
+
|
1663
|
+
def global_entry(glbname)
|
1664
|
+
name = add_global_name("struct global_entry*", 0);
|
1665
|
+
|
1666
|
+
init_extra << "
|
1667
|
+
#{name} = rb_global_entry(SYM2ID(#{literal_value glbname}));
|
1668
|
+
"
|
1669
|
+
|
1670
|
+
name
|
1671
|
+
end
|
1672
|
+
|
1673
|
+
|
1674
|
+
def frame(code, jmp_code, not_jmp_code = "", rescued = nil)
|
1675
|
+
|
1676
|
+
anonymous_function{ |name| "
|
1677
|
+
static VALUE #{name}(VALUE param) {
|
1678
|
+
volatile VALUE last_expression = Qnil;
|
1679
|
+
#{@frame_struct} frame;
|
1680
|
+
|
1681
|
+
typeof(frame)* volatile pframe;
|
1682
|
+
typeof(frame)* volatile parent_frame;
|
1683
|
+
#{@locals_struct}* volatile plocals;
|
1684
|
+
|
1685
|
+
parent_frame = (void*)param;
|
1686
|
+
|
1687
|
+
frame.parent_frame = (void*)param;
|
1688
|
+
frame.plocals = parent_frame->plocals;
|
1689
|
+
frame.rescue = #{rescued ? rescued : "parent_frame->rescue"};
|
1690
|
+
frame.targetted = 0;
|
1691
|
+
frame.thread_data = parent_frame->thread_data;
|
1692
|
+
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
1693
|
+
|
1694
|
+
plocals = frame.plocals;
|
1695
|
+
pframe = &frame;
|
1696
|
+
|
1697
|
+
int aux = setjmp(frame.jmp);
|
1698
|
+
if (aux != 0) {
|
1699
|
+
last_expression = pframe->return_value;
|
1700
|
+
|
1701
|
+
// restore previous frame
|
1702
|
+
typeof(pframe) original_frame = pframe;
|
1703
|
+
pframe = parent_frame;
|
1704
|
+
|
1705
|
+
#{jmp_code};
|
1706
|
+
|
1707
|
+
if (original_frame->targetted == 0) {
|
1708
|
+
longjmp(pframe->jmp,aux);
|
1709
|
+
}
|
1710
|
+
|
1711
|
+
return last_expression;
|
1712
|
+
}
|
1713
|
+
|
1714
|
+
#{code};
|
1715
|
+
|
1716
|
+
// restore previous frame
|
1717
|
+
volatile typeof(pframe) original_frame = pframe;
|
1718
|
+
pframe = parent_frame;
|
1719
|
+
#{not_jmp_code};
|
1720
|
+
|
1721
|
+
return last_expression;
|
1722
|
+
|
1723
|
+
}
|
1724
|
+
"
|
1725
|
+
} + "((VALUE)pframe)"
|
1726
|
+
end
|
1727
|
+
end
|
1728
|
+
end
|