fastruby 0.0.20 → 0.0.21
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/lib/fastruby/builder.rb~ +5 -1
- data/lib/fastruby/corelib/fixnum.rb +1 -1
- data/lib/fastruby/corelib/fixnum.rb~ +0 -71
- data/lib/fastruby/corelib.rb~ +1 -1
- data/lib/fastruby/modules/inliner/call.rb~ +3 -1
- data/lib/fastruby/modules/translator/call.rb +1 -1
- data/lib/fastruby/modules/translator/call.rb~ +1 -1
- data/lib/fastruby/object.rb~ +0 -6
- data/lib/fastruby.rb +1 -1
- data/lib/fastruby.rb~ +1 -1
- data/spec/corelib/numeric/fixnum_spec.rb +1 -1
- data/spec/corelib/numeric/fixnum_spec.rb~ +7 -1
- metadata +12 -40
- data/lib/fastruby/builder/inference_updater.rb~ +0 -76
- data/lib/fastruby/builder/inliner.rb~ +0 -60
- data/lib/fastruby/builder/lvar_type.rb~ +0 -44
- data/lib/fastruby/builder/pipeline.rb~ +0 -43
- data/lib/fastruby/builder/reductor.rb~ +0 -42
- data/lib/fastruby/corelib/integer.rb~ +0 -96
- data/lib/fastruby/modules/inliner/defn.rb~ +0 -29
- data/lib/fastruby/modules/inliner/recursive.rb~ +0 -40
- data/lib/fastruby/modules/lvar_type/call.rb~ +0 -36
- data/lib/fastruby/modules/lvar_type/defn.rb~ +0 -42
- data/lib/fastruby/modules/lvar_type/lasgn.rb~ +0 -42
- data/lib/fastruby/modules/lvar_type/recursive.rb~ +0 -33
- data/lib/fastruby/modules/reductor/nontree.rb~ +0 -32
- data/lib/fastruby/modules/reductor/recursive.rb~ +0 -31
- data/lib/fastruby/modules/translator/defn.rb~ +0 -267
- data/lib/fastruby/modules/translator/directive.rb~ +0 -44
- data/lib/fastruby/modules/translator/exceptions.rb~ +0 -120
- data/lib/fastruby/modules/translator/iter.rb~ +0 -745
- data/lib/fastruby/modules/translator/literal.rb~ +0 -150
- data/lib/fastruby/modules/translator/nonlocal.rb~ +0 -298
- data/lib/fastruby/modules/translator/static.rb~ +0 -291
- data/lib/fastruby/modules/translator/variable.rb~ +0 -280
- data/lib/fastruby/set_tree.rb~ +0 -71
- data/lib/fastruby/sexp_extension.rb~ +0 -262
- data/lib/fastruby/translator/scope_mode_helper.rb~ +0 -138
- data/lib/fastruby/translator/translator.rb~ +0 -1600
- data/lib/fastruby/translator/translator_modules.rb~ +0 -53
- data/lib/fastruby_only/base.rb +0 -1
@@ -1,1600 +0,0 @@
|
|
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
|
-
class_tree = to_c class_tree unless class_tree.instance_of? String
|
254
|
-
|
255
|
-
if message_tree.instance_of? String
|
256
|
-
message_tree = "rb_str_new2(#{message_tree.inspect})"
|
257
|
-
else
|
258
|
-
message_tree = to_c message_tree
|
259
|
-
end
|
260
|
-
|
261
|
-
if message_tree
|
262
|
-
return inline_block("
|
263
|
-
pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},1,#{message_tree});
|
264
|
-
longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
|
265
|
-
return Qnil;
|
266
|
-
")
|
267
|
-
else
|
268
|
-
return inline_block("
|
269
|
-
pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},0);
|
270
|
-
longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
|
271
|
-
return Qnil;
|
272
|
-
")
|
273
|
-
end
|
274
|
-
|
275
|
-
end
|
276
|
-
|
277
|
-
def anonymous_function(*x)
|
278
|
-
|
279
|
-
name = "anonymous" + rand(10000000).to_s
|
280
|
-
extra_code << yield(name,*x)
|
281
|
-
|
282
|
-
name
|
283
|
-
end
|
284
|
-
|
285
|
-
def frame_call(inner_code, precode = "", postcode = "")
|
286
|
-
inline_block "
|
287
|
-
|
288
|
-
volatile VALUE ret = Qnil;
|
289
|
-
// create a call_frame
|
290
|
-
#{@frame_struct} call_frame;
|
291
|
-
typeof(call_frame)* volatile old_pframe = (void*)pframe;
|
292
|
-
|
293
|
-
pframe = (typeof(pframe))&call_frame;
|
294
|
-
|
295
|
-
call_frame.parent_frame = (void*)pframe;
|
296
|
-
call_frame.plocals = plocals;
|
297
|
-
call_frame.return_value = Qnil;
|
298
|
-
call_frame.targetted = 0;
|
299
|
-
call_frame.thread_data = old_pframe->thread_data;
|
300
|
-
if (call_frame.thread_data == 0) call_frame.thread_data = rb_current_thread_data();
|
301
|
-
|
302
|
-
void* volatile old_call_frame = plocals->call_frame;
|
303
|
-
plocals->call_frame = &call_frame;
|
304
|
-
|
305
|
-
#{precode}
|
306
|
-
|
307
|
-
int aux = setjmp(call_frame.jmp);
|
308
|
-
if (aux != 0) {
|
309
|
-
if (call_frame.targetted == 0) {
|
310
|
-
#{postcode}
|
311
|
-
longjmp(old_pframe->jmp,aux);
|
312
|
-
}
|
313
|
-
|
314
|
-
if (aux == FASTRUBY_TAG_BREAK) {
|
315
|
-
plocals->call_frame = old_call_frame;
|
316
|
-
#{postcode}
|
317
|
-
return call_frame.return_value;
|
318
|
-
} else if (aux == FASTRUBY_TAG_RETRY ) {
|
319
|
-
// do nothing and let the call execute again
|
320
|
-
} else {
|
321
|
-
plocals->call_frame = old_call_frame;
|
322
|
-
#{postcode}
|
323
|
-
return call_frame.return_value;
|
324
|
-
}
|
325
|
-
}
|
326
|
-
|
327
|
-
|
328
|
-
#{inner_code};
|
329
|
-
|
330
|
-
#{postcode}
|
331
|
-
|
332
|
-
plocals->call_frame = old_call_frame;
|
333
|
-
return ret;
|
334
|
-
"
|
335
|
-
end
|
336
|
-
|
337
|
-
def initialize_method_structs(args_tree)
|
338
|
-
@locals_struct = "struct {
|
339
|
-
int size;
|
340
|
-
void* call_frame;
|
341
|
-
void* parent_locals;
|
342
|
-
void* pframe;
|
343
|
-
void* block_function_address;
|
344
|
-
void* block_function_param;
|
345
|
-
VALUE active;
|
346
|
-
VALUE targetted;
|
347
|
-
VALUE return_value;
|
348
|
-
#{@locals.map{|l| "VALUE #{l};\n"}.join}
|
349
|
-
}"
|
350
|
-
|
351
|
-
end
|
352
|
-
|
353
|
-
def add_main
|
354
|
-
if options[:main]
|
355
|
-
|
356
|
-
extra_code << "
|
357
|
-
static VALUE #{@alt_method_name}(VALUE self__);
|
358
|
-
static VALUE main_proc_call(VALUE self__, VALUE signature, VALUE class_self_) {
|
359
|
-
#{@alt_method_name}(class_self_);
|
360
|
-
return Qnil;
|
361
|
-
}
|
362
|
-
|
363
|
-
"
|
364
|
-
|
365
|
-
init_extra << "
|
366
|
-
{
|
367
|
-
VALUE newproc = rb_funcall(rb_cObject,#{intern_num :new},0);
|
368
|
-
rb_define_singleton_method(newproc, \"call\", main_proc_call, 2);
|
369
|
-
rb_gv_set(\"$last_obj_proc\", newproc);
|
370
|
-
}
|
371
|
-
"
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
def define_method_at_init(method_name, size, signature)
|
376
|
-
extra_code << "
|
377
|
-
static VALUE main_proc_call(VALUE self__, VALUE signature, VALUE class_self_) {
|
378
|
-
VALUE method_name = rb_funcall(
|
379
|
-
#{literal_value FastRuby},
|
380
|
-
#{intern_num :make_str_signature},
|
381
|
-
2,
|
382
|
-
#{literal_value method_name},
|
383
|
-
signature
|
384
|
-
);
|
385
|
-
|
386
|
-
ID id = rb_intern(RSTRING_PTR(method_name));
|
387
|
-
|
388
|
-
rb_funcall(
|
389
|
-
#{literal_value FastRuby},
|
390
|
-
#{intern_num :set_builder_module},
|
391
|
-
1,
|
392
|
-
class_self_
|
393
|
-
);
|
394
|
-
|
395
|
-
VALUE rb_method_hash;
|
396
|
-
void** address = 0;
|
397
|
-
rb_method_hash = rb_funcall(class_self_, #{intern_num :method_hash},1,#{literal_value method_name});
|
398
|
-
|
399
|
-
if (rb_method_hash != Qnil) {
|
400
|
-
VALUE tmp = rb_hash_aref(rb_method_hash, PTR2NUM(id));
|
401
|
-
if (tmp != Qnil) {
|
402
|
-
address = (void*)NUM2PTR(tmp);
|
403
|
-
}
|
404
|
-
}
|
405
|
-
|
406
|
-
if (address == 0) {
|
407
|
-
address = malloc(sizeof(void*));
|
408
|
-
}
|
409
|
-
*address = #{@alt_method_name};
|
410
|
-
|
411
|
-
rb_funcall(
|
412
|
-
class_self_,
|
413
|
-
#{intern_num :register_method_value},
|
414
|
-
3,
|
415
|
-
#{literal_value method_name},
|
416
|
-
PTR2NUM(id),
|
417
|
-
PTR2NUM(address)
|
418
|
-
);
|
419
|
-
|
420
|
-
return Qnil;
|
421
|
-
}
|
422
|
-
"
|
423
|
-
|
424
|
-
init_extra << "
|
425
|
-
{
|
426
|
-
VALUE newproc = rb_funcall(rb_cObject,#{intern_num :new},0);
|
427
|
-
rb_define_singleton_method(newproc, \"call\", main_proc_call, 2);
|
428
|
-
rb_gv_set(\"$last_obj_proc\", newproc);
|
429
|
-
}
|
430
|
-
"
|
431
|
-
end
|
432
|
-
|
433
|
-
def to_c_method(tree, signature = nil)
|
434
|
-
|
435
|
-
if tree[0] == :defn
|
436
|
-
method_name = tree[1]
|
437
|
-
original_args_tree = tree[2]
|
438
|
-
block_argument = tree[2].find{|x| x.to_s[0] == ?&}
|
439
|
-
impl_tree = tree[3][1]
|
440
|
-
elsif tree[0] == :defs
|
441
|
-
method_name = tree[2]
|
442
|
-
original_args_tree = tree[3]
|
443
|
-
block_argument = tree[3].find{|x| x.to_s[0] == ?&}
|
444
|
-
impl_tree = tree[4][1]
|
445
|
-
end
|
446
|
-
|
447
|
-
if "0".respond_to?(:ord)
|
448
|
-
@alt_method_name = "_" + method_name.to_s.gsub("_x_", "_x__x_").gsub(/\W/){|x| "_x_#{x.ord}" } + "_" + rand(10000000000).to_s
|
449
|
-
else
|
450
|
-
@alt_method_name = "_" + method_name.to_s.gsub("_x_", "_x__x_").gsub(/\W/){|x| "_x_#{x[0]}" } + "_" + rand(10000000000).to_s
|
451
|
-
end
|
452
|
-
|
453
|
-
args_tree = original_args_tree.select{|x| x.to_s[0] != ?&}
|
454
|
-
|
455
|
-
initialize_method_structs(original_args_tree)
|
456
|
-
|
457
|
-
if options[:main] then
|
458
|
-
strargs = if args_tree.size > 1
|
459
|
-
"VALUE self, VALUE block, VALUE _parent_frame, #{(0..signature.size-1).map{|x| "VALUE arg#{x}"}.join(",")}"
|
460
|
-
else
|
461
|
-
"VALUE self, VALUE block, VALUE _parent_frame"
|
462
|
-
end
|
463
|
-
|
464
|
-
else
|
465
|
-
|
466
|
-
strargs = "VALUE self, VALUE block, VALUE _parent_frame, int argc, VALUE* argv"
|
467
|
-
|
468
|
-
splat_arg = args_tree[1..-1].find{|x| x.to_s.match(/\*/) }
|
469
|
-
|
470
|
-
maxargnum = args_tree[1..-1].count{ |x|
|
471
|
-
if x.instance_of? Symbol
|
472
|
-
not x.to_s.match(/\*/) and not x.to_s.match(/\&/)
|
473
|
-
else
|
474
|
-
false
|
475
|
-
end
|
476
|
-
}
|
477
|
-
|
478
|
-
minargnum = maxargnum
|
479
|
-
|
480
|
-
args_tree[1..-1].each do |subtree|
|
481
|
-
unless subtree.instance_of? Symbol
|
482
|
-
if subtree[0] == :block
|
483
|
-
minargnum = minargnum - (subtree.size-1)
|
484
|
-
end
|
485
|
-
end
|
486
|
-
end
|
487
|
-
|
488
|
-
if args_tree[1..-1].find{|x| x.to_s.match(/\*/)}
|
489
|
-
maxargnum = 2147483647
|
490
|
-
end
|
491
|
-
|
492
|
-
read_arguments_code = ""
|
493
|
-
|
494
|
-
|
495
|
-
validate_arguments_code = if signature.size-1 < minargnum
|
496
|
-
"
|
497
|
-
rb_raise(rb_eArgError, \"wrong number of arguments (#{signature.size-1} for #{minargnum})\");
|
498
|
-
"
|
499
|
-
elsif signature.size-1 > maxargnum
|
500
|
-
"
|
501
|
-
rb_raise(rb_eArgError, \"wrong number of arguments (#{signature.size-1} for #{maxargnum})\");
|
502
|
-
"
|
503
|
-
else
|
504
|
-
|
505
|
-
default_block_tree = args_tree[1..-1].find{|subtree|
|
506
|
-
unless subtree.instance_of? Symbol
|
507
|
-
if subtree[0] == :block
|
508
|
-
next true
|
509
|
-
end
|
510
|
-
end
|
511
|
-
|
512
|
-
false
|
513
|
-
}
|
514
|
-
|
515
|
-
i = -1
|
516
|
-
|
517
|
-
normalargsnum = args_tree[1..-1].count{|subtree|
|
518
|
-
if subtree.instance_of? Symbol
|
519
|
-
unless subtree.to_s.match(/\*/) or subtree.to_s.match(/\&/)
|
520
|
-
next true
|
521
|
-
end
|
522
|
-
end
|
523
|
-
|
524
|
-
false
|
525
|
-
}
|
526
|
-
|
527
|
-
read_arguments_code = args_tree[1..-1].map { |arg_|
|
528
|
-
arg = arg_.to_s
|
529
|
-
i = i + 1
|
530
|
-
|
531
|
-
if i < normalargsnum
|
532
|
-
if i < signature.size-1
|
533
|
-
"plocals->#{arg} = argv[#{i}];\n"
|
534
|
-
else
|
535
|
-
|
536
|
-
if default_block_tree
|
537
|
-
initialize_tree = default_block_tree[1..-1].find{|subtree| subtree[1] == arg_}
|
538
|
-
if initialize_tree
|
539
|
-
to_c(initialize_tree) + ";\n"
|
540
|
-
else
|
541
|
-
""
|
542
|
-
end
|
543
|
-
else
|
544
|
-
";\n"
|
545
|
-
end
|
546
|
-
end
|
547
|
-
else
|
548
|
-
""
|
549
|
-
end
|
550
|
-
}.join("")
|
551
|
-
|
552
|
-
if splat_arg
|
553
|
-
if signature.size-1 < normalargsnum then
|
554
|
-
read_arguments_code << "
|
555
|
-
plocals->#{splat_arg.to_s.gsub("*","")} = rb_ary_new3(0);
|
556
|
-
"
|
557
|
-
else
|
558
|
-
read_arguments_code << "
|
559
|
-
plocals->#{splat_arg.to_s.gsub("*","")} = rb_ary_new4(
|
560
|
-
#{(signature.size-1) - (normalargsnum)}, argv+#{normalargsnum}
|
561
|
-
);
|
562
|
-
"
|
563
|
-
end
|
564
|
-
|
565
|
-
end
|
566
|
-
|
567
|
-
|
568
|
-
""
|
569
|
-
end
|
570
|
-
|
571
|
-
if block_argument
|
572
|
-
|
573
|
-
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))))
|
574
|
-
|
575
|
-
require "fastruby/sexp_extension"
|
576
|
-
|
577
|
-
read_arguments_code << "
|
578
|
-
if (pblock ? pblock->proc != Qnil : 0) {
|
579
|
-
plocals->#{block_argument.to_s.gsub("&","")} = pblock->proc;
|
580
|
-
} else {
|
581
|
-
plocals->#{block_argument.to_s.gsub("&","")} = #{to_c FastRuby::FastRubySexp.from_sexp(proc_reyield_block_tree)};
|
582
|
-
}
|
583
|
-
"
|
584
|
-
|
585
|
-
read_arguments_code << "
|
586
|
-
if (pblock) {
|
587
|
-
rb_ivar_set(plocals->#{block_argument.to_s.gsub("&","")},
|
588
|
-
#{intern_num "__block_address"}, PTR2NUM(pblock->block_function_address));
|
589
|
-
rb_ivar_set(plocals->#{block_argument.to_s.gsub("&","")},
|
590
|
-
#{intern_num "__block_param"}, PTR2NUM(pblock->block_function_param));
|
591
|
-
}
|
592
|
-
|
593
|
-
"
|
594
|
-
end
|
595
|
-
|
596
|
-
end
|
597
|
-
|
598
|
-
require "fastruby/sexp_extension"
|
599
|
-
|
600
|
-
trs = lambda{|tree|
|
601
|
-
if not tree.respond_to? :node_type
|
602
|
-
next tree
|
603
|
-
elsif tree.node_type == :call
|
604
|
-
mmname = tree[2]
|
605
|
-
next trs.call(tree[1]) || tree[1] if mmname == :infer
|
606
|
-
next fs(:nil) if mmname == :_throw or mmname == :_loop or mmname == :_raise
|
607
|
-
next fs(:nil) if mmname == :== and infer_value(tree)
|
608
|
-
elsif tree.node_type == :iter
|
609
|
-
mmname = tree[1][2]
|
610
|
-
next fs(:nil) if mmname == :_static
|
611
|
-
next fs(:block, trs.call(tree[3]) || tree[3]) if mmname == :_catch
|
612
|
-
end
|
613
|
-
|
614
|
-
tree.map &trs
|
615
|
-
}
|
616
|
-
|
617
|
-
evaluate_tree = tree.transform &trs
|
618
|
-
|
619
|
-
scope_mode = FastRuby::ScopeModeHelper.get_scope_mode(evaluate_tree)
|
620
|
-
ret = "VALUE #{@alt_method_name || method_name}(#{options[:main] ? "VALUE self" : strargs}) {
|
621
|
-
#{validate_arguments_code}
|
622
|
-
|
623
|
-
#{@frame_struct} frame;
|
624
|
-
#{@frame_struct} * volatile pframe;
|
625
|
-
|
626
|
-
frame.parent_frame = #{options[:main] ? "0" : "(void*)_parent_frame"};
|
627
|
-
frame.return_value = Qnil;
|
628
|
-
frame.rescue = 0;
|
629
|
-
frame.targetted = 0;
|
630
|
-
frame.thread_data = #{options[:main] ? "0" : "((typeof(pframe))_parent_frame)->thread_data"};
|
631
|
-
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
632
|
-
|
633
|
-
int stack_chunk_instantiated = 0;
|
634
|
-
|
635
|
-
#{
|
636
|
-
if scope_mode == :dag
|
637
|
-
"
|
638
|
-
volatile VALUE rb_previous_stack_chunk = Qnil;
|
639
|
-
VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
|
640
|
-
struct STACKCHUNK* volatile stack_chunk = 0;
|
641
|
-
|
642
|
-
if (rb_stack_chunk != Qnil) {
|
643
|
-
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
644
|
-
}
|
645
|
-
|
646
|
-
if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
|
647
|
-
rb_previous_stack_chunk = rb_stack_chunk;
|
648
|
-
rb_gc_register_address(&rb_stack_chunk);
|
649
|
-
stack_chunk_instantiated = 1;
|
650
|
-
|
651
|
-
rb_stack_chunk = rb_stack_chunk_create(Qnil);
|
652
|
-
frame.thread_data->rb_stack_chunk = rb_stack_chunk;
|
653
|
-
|
654
|
-
rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
|
655
|
-
|
656
|
-
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
657
|
-
}
|
658
|
-
|
659
|
-
#{@locals_struct}* volatile plocals;
|
660
|
-
|
661
|
-
volatile int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
|
662
|
-
plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
|
663
|
-
|
664
|
-
"
|
665
|
-
else
|
666
|
-
"
|
667
|
-
#{@locals_struct} locals;
|
668
|
-
typeof(locals) * volatile plocals = &locals;
|
669
|
-
"
|
670
|
-
end
|
671
|
-
}
|
672
|
-
|
673
|
-
plocals->parent_locals = (frame.thread_data->last_plocals);
|
674
|
-
void* volatile old_parent_locals = frame.thread_data->last_plocals;
|
675
|
-
|
676
|
-
#{
|
677
|
-
if scope_mode == :dag
|
678
|
-
"frame.thread_data->last_plocals = plocals;\n"
|
679
|
-
end
|
680
|
-
}
|
681
|
-
|
682
|
-
frame.plocals = plocals;
|
683
|
-
plocals->active = Qtrue;
|
684
|
-
plocals->targetted = Qfalse;
|
685
|
-
plocals->pframe = (&frame);
|
686
|
-
plocals->call_frame = (0);
|
687
|
-
|
688
|
-
pframe = (void*)&frame;
|
689
|
-
|
690
|
-
#{@block_struct} * volatile pblock;
|
691
|
-
volatile VALUE last_expression = Qnil;
|
692
|
-
|
693
|
-
int aux = setjmp(pframe->jmp);
|
694
|
-
if (aux != 0) {
|
695
|
-
plocals->active = Qfalse;
|
696
|
-
|
697
|
-
#{
|
698
|
-
if scope_mode == :dag
|
699
|
-
"
|
700
|
-
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
701
|
-
|
702
|
-
if (stack_chunk_instantiated) {
|
703
|
-
rb_gc_unregister_address(&rb_stack_chunk);
|
704
|
-
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
705
|
-
}
|
706
|
-
"
|
707
|
-
end
|
708
|
-
}
|
709
|
-
#{
|
710
|
-
unless options[:main]
|
711
|
-
"
|
712
|
-
if (plocals->targetted == Qfalse || aux != FASTRUBY_TAG_RETURN) {
|
713
|
-
frame.thread_data->last_plocals = old_parent_locals;
|
714
|
-
|
715
|
-
longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
|
716
|
-
}
|
717
|
-
"
|
718
|
-
end
|
719
|
-
}
|
720
|
-
|
721
|
-
frame.thread_data->last_plocals = old_parent_locals;
|
722
|
-
|
723
|
-
return plocals->return_value;
|
724
|
-
}
|
725
|
-
|
726
|
-
plocals->self = self;
|
727
|
-
|
728
|
-
#{
|
729
|
-
unless options[:main]
|
730
|
-
"
|
731
|
-
pblock = (void*)block;
|
732
|
-
if (pblock) {
|
733
|
-
plocals->block_function_address = pblock->block_function_address;
|
734
|
-
plocals->block_function_param = pblock->block_function_param;
|
735
|
-
} else {
|
736
|
-
plocals->block_function_address = (0);
|
737
|
-
plocals->block_function_param = 0;
|
738
|
-
}
|
739
|
-
"
|
740
|
-
end
|
741
|
-
}
|
742
|
-
|
743
|
-
#{read_arguments_code}
|
744
|
-
|
745
|
-
#{to_c impl_tree, "last_expression"};
|
746
|
-
|
747
|
-
local_return:
|
748
|
-
#{
|
749
|
-
if scope_mode == :dag
|
750
|
-
"
|
751
|
-
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
752
|
-
|
753
|
-
if (stack_chunk_instantiated) {
|
754
|
-
rb_gc_unregister_address(&rb_stack_chunk);
|
755
|
-
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
756
|
-
}
|
757
|
-
"
|
758
|
-
end
|
759
|
-
}
|
760
|
-
plocals->active = Qfalse;
|
761
|
-
|
762
|
-
frame.thread_data->last_plocals = old_parent_locals;
|
763
|
-
|
764
|
-
return last_expression;
|
765
|
-
}"
|
766
|
-
|
767
|
-
add_main
|
768
|
-
extra_code << ret
|
769
|
-
|
770
|
-
"
|
771
|
-
static VALUE dummy_#{@alt_method_name}_#{rand(1000000000000000000000000000000000)}(VALUE a) {
|
772
|
-
return Qnil;
|
773
|
-
}
|
774
|
-
"
|
775
|
-
end
|
776
|
-
|
777
|
-
def locals_accessor
|
778
|
-
"plocals->"
|
779
|
-
end
|
780
|
-
|
781
|
-
def locals_scope(locals)
|
782
|
-
old_locals = @locals
|
783
|
-
old_locals_struct = @locals_struct
|
784
|
-
|
785
|
-
@locals = locals
|
786
|
-
@locals_struct = "struct {
|
787
|
-
int size;
|
788
|
-
void* call_frame;
|
789
|
-
void* parent_locals;
|
790
|
-
void* pframe;
|
791
|
-
void* block_function_address;
|
792
|
-
void* block_function_param;
|
793
|
-
VALUE active;
|
794
|
-
VALUE targetted;
|
795
|
-
VALUE return_value;
|
796
|
-
#{@locals.map{|l| "VALUE #{l};\n"}.join}
|
797
|
-
}"
|
798
|
-
|
799
|
-
begin
|
800
|
-
yield
|
801
|
-
ensure
|
802
|
-
@locals = old_locals
|
803
|
-
@locals_struct = old_locals_struct
|
804
|
-
end
|
805
|
-
end
|
806
|
-
|
807
|
-
def infer_type(recv)
|
808
|
-
array = @inferencer.infer(recv).to_a
|
809
|
-
|
810
|
-
if array.size == 1
|
811
|
-
array[0]
|
812
|
-
else
|
813
|
-
nil
|
814
|
-
end
|
815
|
-
end
|
816
|
-
|
817
|
-
def on_block
|
818
|
-
old_on_block = @on_block
|
819
|
-
@on_block = true
|
820
|
-
return yield
|
821
|
-
ensure
|
822
|
-
@on_block = old_on_block
|
823
|
-
end
|
824
|
-
|
825
|
-
def directive(tree)
|
826
|
-
recv = tree[1]
|
827
|
-
mname = tree[2]
|
828
|
-
args = tree[3]
|
829
|
-
|
830
|
-
if mname == :infer
|
831
|
-
return to_c(recv)
|
832
|
-
elsif mname == :block_given?
|
833
|
-
return "plocals->block_function_address == 0 ? Qfalse : Qtrue"
|
834
|
-
elsif mname == :inline_c
|
835
|
-
|
836
|
-
code = args[1][1]
|
837
|
-
|
838
|
-
unless (args[2] == s(:false))
|
839
|
-
return anonymous_function{ |name| "
|
840
|
-
static VALUE #{name}(VALUE param) {
|
841
|
-
#{@frame_struct} *pframe = (void*)param;
|
842
|
-
#{@locals_struct} *plocals = (void*)pframe->plocals;
|
843
|
-
#{code};
|
844
|
-
|
845
|
-
return Qnil;
|
846
|
-
}
|
847
|
-
"
|
848
|
-
}+"((VALUE)pframe)"
|
849
|
-
else
|
850
|
-
code
|
851
|
-
end
|
852
|
-
|
853
|
-
else
|
854
|
-
nil
|
855
|
-
end
|
856
|
-
end
|
857
|
-
|
858
|
-
def inline_block_reference(arg, nolocals = false)
|
859
|
-
code = nil
|
860
|
-
|
861
|
-
if arg.instance_of? FastRuby::FastRubySexp
|
862
|
-
code = to_c(arg);
|
863
|
-
else
|
864
|
-
code = arg
|
865
|
-
end
|
866
|
-
|
867
|
-
anonymous_function{ |name| "
|
868
|
-
static VALUE #{name}(VALUE param) {
|
869
|
-
#{@frame_struct} *pframe = (void*)param;
|
870
|
-
|
871
|
-
#{nolocals ? "" : "#{@locals_struct} *plocals = (void*)pframe->plocals;"}
|
872
|
-
VALUE last_expression = Qnil;
|
873
|
-
|
874
|
-
#{code};
|
875
|
-
return last_expression;
|
876
|
-
}
|
877
|
-
"
|
878
|
-
}
|
879
|
-
end
|
880
|
-
|
881
|
-
def catch_on_throw
|
882
|
-
old_catch_jmp_on_throw = @catch_jmp_on_throw || false
|
883
|
-
@catch_jmp_on_throw = true
|
884
|
-
begin
|
885
|
-
ret = yield
|
886
|
-
ensure
|
887
|
-
@catch_jmp_on_throw = old_catch_jmp_on_throw
|
888
|
-
end
|
889
|
-
|
890
|
-
ret
|
891
|
-
end
|
892
|
-
|
893
|
-
def inline_block(*args)
|
894
|
-
|
895
|
-
unless block_given?
|
896
|
-
code = args.first
|
897
|
-
return inline_block(*args[1..-1]) {
|
898
|
-
code
|
899
|
-
}
|
900
|
-
end
|
901
|
-
|
902
|
-
repass_var = args[0]
|
903
|
-
nolocals = args[1] || false
|
904
|
-
|
905
|
-
code = catch_on_throw{ yield }
|
906
|
-
|
907
|
-
anonymous_function{ |name| "
|
908
|
-
static VALUE #{name}(VALUE param#{repass_var ? ",void* " + repass_var : "" }) {
|
909
|
-
#{@frame_struct} * volatile pframe = (void*)param;
|
910
|
-
|
911
|
-
#{nolocals ? "" : "#{@locals_struct} * volatile plocals = (void*)pframe->plocals;"}
|
912
|
-
volatile VALUE last_expression = Qnil;
|
913
|
-
|
914
|
-
#{code}
|
915
|
-
return Qnil;
|
916
|
-
|
917
|
-
|
918
|
-
#{@catch_blocks.map { |cb|
|
919
|
-
"#{cb.to_s}_end:
|
920
|
-
|
921
|
-
plocals->return_value = last_expression;
|
922
|
-
plocals->targetted = 1;
|
923
|
-
longjmp(pframe->jmp, #{intern_num( cb.to_s + "_end")});
|
924
|
-
|
925
|
-
#{cb.to_s}_start:
|
926
|
-
|
927
|
-
plocals->return_value = last_expression;
|
928
|
-
plocals->targetted = 1;
|
929
|
-
longjmp(pframe->jmp, #{intern_num( cb.to_s + "_start")});
|
930
|
-
|
931
|
-
"
|
932
|
-
|
933
|
-
}.join("\n")
|
934
|
-
}
|
935
|
-
#{unless nolocals
|
936
|
-
"
|
937
|
-
local_return:
|
938
|
-
plocals->return_value = last_expression;
|
939
|
-
plocals->targetted = 1;
|
940
|
-
longjmp(pframe->jmp, FASTRUBY_TAG_RETURN);
|
941
|
-
return last_expression;
|
942
|
-
"
|
943
|
-
end
|
944
|
-
}
|
945
|
-
fastruby_local_redo:
|
946
|
-
longjmp(pframe->jmp,FASTRUBY_TAG_REDO);
|
947
|
-
return Qnil;
|
948
|
-
fastruby_local_next:
|
949
|
-
longjmp(pframe->jmp,FASTRUBY_TAG_NEXT);
|
950
|
-
return Qnil;
|
951
|
-
|
952
|
-
|
953
|
-
}
|
954
|
-
"
|
955
|
-
} + "((VALUE)pframe#{repass_var ? ", " + repass_var : "" })"
|
956
|
-
end
|
957
|
-
|
958
|
-
def inline_ruby(proced, parameter)
|
959
|
-
"rb_funcall(#{proced.__id__}, #{intern_num :call}, 1, #{parameter})"
|
960
|
-
end
|
961
|
-
|
962
|
-
def protected_block(*args)
|
963
|
-
unless block_given?
|
964
|
-
inner_code = args.first
|
965
|
-
return protected_block(*args[1..-1]) {
|
966
|
-
inner_code
|
967
|
-
}
|
968
|
-
end
|
969
|
-
|
970
|
-
repass_var = args[1]
|
971
|
-
nolocals = args[2] || false
|
972
|
-
|
973
|
-
inline_block(repass_var, nolocals) do
|
974
|
-
generate_protected_block(yield, *args)
|
975
|
-
end
|
976
|
-
end
|
977
|
-
|
978
|
-
def generate_protected_block(inner_code, always_rescue = false,repass_var = nil, nolocals = false)
|
979
|
-
body = nil
|
980
|
-
rescue_args = nil
|
981
|
-
|
982
|
-
body = anonymous_function{ |name| "
|
983
|
-
static VALUE #{name}(VALUE param) {
|
984
|
-
|
985
|
-
#{@frame_struct} frame;
|
986
|
-
|
987
|
-
typeof(frame)* volatile pframe;
|
988
|
-
|
989
|
-
#{if repass_var
|
990
|
-
"typeof(frame)* parent_frame = ((typeof(pframe))((void**)param)[0]);"
|
991
|
-
else
|
992
|
-
"typeof(frame)* parent_frame = (typeof(pframe))param;"
|
993
|
-
end
|
994
|
-
}
|
995
|
-
|
996
|
-
frame.parent_frame = 0;
|
997
|
-
frame.return_value = Qnil;
|
998
|
-
frame.rescue = 0;
|
999
|
-
frame.last_error = Qnil;
|
1000
|
-
frame.targetted = 0;
|
1001
|
-
frame.thread_data = parent_frame->thread_data;
|
1002
|
-
frame.next_recv = parent_frame->next_recv;
|
1003
|
-
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
1004
|
-
|
1005
|
-
pframe = &frame;
|
1006
|
-
|
1007
|
-
#{
|
1008
|
-
nolocals ? "frame.plocals = 0;" : "#{@locals_struct}* plocals = parent_frame->plocals;
|
1009
|
-
frame.plocals = plocals;
|
1010
|
-
"
|
1011
|
-
}
|
1012
|
-
|
1013
|
-
int aux = setjmp(frame.jmp);
|
1014
|
-
if (aux != 0) {
|
1015
|
-
|
1016
|
-
if (frame.targetted == 1) {
|
1017
|
-
return frame.return_value;
|
1018
|
-
} else {
|
1019
|
-
frb_jump_tag(aux);
|
1020
|
-
}
|
1021
|
-
}
|
1022
|
-
|
1023
|
-
#{if repass_var
|
1024
|
-
"VALUE #{repass_var} = (VALUE)((void**)param)[1];"
|
1025
|
-
end
|
1026
|
-
}
|
1027
|
-
volatile VALUE last_expression = Qnil;
|
1028
|
-
#{inner_code};
|
1029
|
-
return last_expression;
|
1030
|
-
}
|
1031
|
-
"
|
1032
|
-
}
|
1033
|
-
|
1034
|
-
if repass_var
|
1035
|
-
rescue_args = ""
|
1036
|
-
rescue_args = "(VALUE)(VALUE[]){(VALUE)pframe,(VALUE)#{repass_var}}"
|
1037
|
-
else
|
1038
|
-
rescue_args = "(VALUE)pframe"
|
1039
|
-
end
|
1040
|
-
|
1041
|
-
wrapper_code = "
|
1042
|
-
if (str.state >= 0x80) {
|
1043
|
-
longjmp(pframe->jmp, str.state);
|
1044
|
-
} else {
|
1045
|
-
if (str.last_error != Qnil) {
|
1046
|
-
// raise emulation
|
1047
|
-
pframe->thread_data->exception = str.last_error;
|
1048
|
-
longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
|
1049
|
-
return Qnil;
|
1050
|
-
}
|
1051
|
-
}
|
1052
|
-
"
|
1053
|
-
|
1054
|
-
return_err_struct = "struct {
|
1055
|
-
VALUE last_error;
|
1056
|
-
int state;
|
1057
|
-
}
|
1058
|
-
"
|
1059
|
-
|
1060
|
-
rescue_body = anonymous_function{ |name| "
|
1061
|
-
static VALUE #{name}(VALUE param, VALUE err) {
|
1062
|
-
#{return_err_struct} *pstr = (void*)param;
|
1063
|
-
|
1064
|
-
if (rb_obj_is_instance_of(err, #{literal_value FastRuby::JumpTagException})) {
|
1065
|
-
pstr->state = FIX2INT(rb_funcall(err, #{intern_num :state}, 0));
|
1066
|
-
} else {
|
1067
|
-
pstr->last_error = err;
|
1068
|
-
}
|
1069
|
-
|
1070
|
-
return Qnil;
|
1071
|
-
}
|
1072
|
-
"
|
1073
|
-
}
|
1074
|
-
|
1075
|
-
rescue_code = "rb_rescue2(#{body}, #{rescue_args}, #{rescue_body}, (VALUE)&str, rb_eException, (VALUE)0)"
|
1076
|
-
|
1077
|
-
if always_rescue
|
1078
|
-
"
|
1079
|
-
#{return_err_struct} str;
|
1080
|
-
|
1081
|
-
str.state = 0;
|
1082
|
-
str.last_error = Qnil;
|
1083
|
-
|
1084
|
-
pframe->last_error = Qnil;
|
1085
|
-
VALUE result = #{rescue_code};
|
1086
|
-
|
1087
|
-
#{wrapper_code}
|
1088
|
-
|
1089
|
-
return result;
|
1090
|
-
"
|
1091
|
-
else
|
1092
|
-
"
|
1093
|
-
VALUE result;
|
1094
|
-
#{return_err_struct} str;
|
1095
|
-
|
1096
|
-
str.state = 0;
|
1097
|
-
str.last_error = Qnil;
|
1098
|
-
|
1099
|
-
pframe->last_error = Qnil;
|
1100
|
-
|
1101
|
-
if (pframe->rescue) {
|
1102
|
-
result = #{rescue_code};
|
1103
|
-
#{wrapper_code}
|
1104
|
-
} else {
|
1105
|
-
VALUE last_expression = Qnil;
|
1106
|
-
#{inner_code};
|
1107
|
-
return last_expression;
|
1108
|
-
}
|
1109
|
-
|
1110
|
-
return result;
|
1111
|
-
"
|
1112
|
-
end
|
1113
|
-
end
|
1114
|
-
|
1115
|
-
def c_escape(str)
|
1116
|
-
str.inspect
|
1117
|
-
end
|
1118
|
-
|
1119
|
-
def literal_value(value)
|
1120
|
-
@literal_value_hash = Hash.new unless @literal_value_hash
|
1121
|
-
return @literal_value_hash[value] if @literal_value_hash[value]
|
1122
|
-
|
1123
|
-
name = self.add_global_name("VALUE", "Qnil");
|
1124
|
-
|
1125
|
-
begin
|
1126
|
-
|
1127
|
-
str = Marshal.dump(value)
|
1128
|
-
|
1129
|
-
|
1130
|
-
if value.instance_of? Module
|
1131
|
-
|
1132
|
-
container_str = value.to_s.split("::")[0..-2].join("::")
|
1133
|
-
|
1134
|
-
init_extra << "
|
1135
|
-
#{name} = rb_define_module_under(
|
1136
|
-
#{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
|
1137
|
-
,\"#{value.to_s.split("::").last}\");
|
1138
|
-
|
1139
|
-
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
1140
|
-
"
|
1141
|
-
elsif value.instance_of? Class
|
1142
|
-
container_str = value.to_s.split("::")[0..-2].join("::")
|
1143
|
-
|
1144
|
-
str_class_name = value.to_s.split("::").last
|
1145
|
-
|
1146
|
-
if (str_class_name == "Object")
|
1147
|
-
init_extra << "
|
1148
|
-
#{name} = rb_cObject;
|
1149
|
-
"
|
1150
|
-
else
|
1151
|
-
init_extra << "
|
1152
|
-
#{name} = rb_define_class_under(
|
1153
|
-
#{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
|
1154
|
-
,\"#{str_class_name}\"
|
1155
|
-
,#{value.superclass == Object ? "rb_cObject" : literal_value(value.superclass)});
|
1156
|
-
|
1157
|
-
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
1158
|
-
"
|
1159
|
-
end
|
1160
|
-
elsif value.instance_of? Array
|
1161
|
-
init_extra << "
|
1162
|
-
#{name} = rb_ary_new3(#{value.size}, #{value.map{|x| literal_value x}.join(",")} );
|
1163
|
-
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
1164
|
-
"
|
1165
|
-
else
|
1166
|
-
|
1167
|
-
init_extra << "
|
1168
|
-
|
1169
|
-
{
|
1170
|
-
VALUE encoded_str = rb_str_new2(#{Base64.encode64(str).inspect});
|
1171
|
-
VALUE str = rb_funcall(rb_cObject, #{intern_num :decode64}, 1, encoded_str);
|
1172
|
-
#{name} = rb_marshal_load(str);
|
1173
|
-
|
1174
|
-
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
1175
|
-
}
|
1176
|
-
|
1177
|
-
"
|
1178
|
-
end
|
1179
|
-
rescue TypeError => e
|
1180
|
-
@no_cache = true
|
1181
|
-
FastRuby.logger.info "#{value} disabling cache for extension"
|
1182
|
-
init_extra << "
|
1183
|
-
#{name} = rb_funcall(rb_const_get(rb_cObject, #{intern_num :ObjectSpace}), #{intern_num :_id2ref}, 1, INT2FIX(#{value.__id__}));
|
1184
|
-
"
|
1185
|
-
|
1186
|
-
end
|
1187
|
-
@literal_value_hash[value] = name
|
1188
|
-
|
1189
|
-
name
|
1190
|
-
end
|
1191
|
-
|
1192
|
-
def encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name = nil, is_block_call = false)
|
1193
|
-
name = self.add_global_name("void*", 0);
|
1194
|
-
address_name = self.add_global_name("void**", 0);
|
1195
|
-
@last_address_name = address_name
|
1196
|
-
cfunc_address_name = self.add_global_name("void**", 0);
|
1197
|
-
cfunc_real_address_name = self.add_global_name("void*", 0);
|
1198
|
-
tree_pointer_name = self.add_global_name("VALUE*", 0);
|
1199
|
-
|
1200
|
-
if call_tree[3].select{|st| st.respond_to?(:node_type) ? st[0] == :block_pass : false}
|
1201
|
-
is_block_call = true
|
1202
|
-
end
|
1203
|
-
|
1204
|
-
args_tree = call_tree[3].reject{|st| st.respond_to?(:node_type) ? st[0] == :block_pass : false}
|
1205
|
-
method_tree = nil
|
1206
|
-
|
1207
|
-
begin
|
1208
|
-
method_tree = recvtype.instance_method(@method_name.to_sym).fastruby.tree
|
1209
|
-
rescue NoMethodError
|
1210
|
-
end
|
1211
|
-
|
1212
|
-
strargs_signature = (0..args_tree.size-2).map{|x| "VALUE arg#{x}"}.join(",")
|
1213
|
-
strargs = (0..args_tree.size-2).map{|x| "arg#{x}"}.join(",")
|
1214
|
-
inprocstrargs = (1..args_tree.size-1).map{|x| "((VALUE*)method_arguments)[#{x}]"}.join(",")
|
1215
|
-
|
1216
|
-
if args_tree.size > 1
|
1217
|
-
strargs_signature = "," + strargs_signature
|
1218
|
-
toprocstrargs = "self,"+strargs
|
1219
|
-
strargs = "," + strargs
|
1220
|
-
inprocstrargs = ","+inprocstrargs
|
1221
|
-
else
|
1222
|
-
toprocstrargs = "self"
|
1223
|
-
end
|
1224
|
-
|
1225
|
-
value_cast = ( ["VALUE"]*(args_tree.size) ).join(",") + ",VALUE,VALUE"
|
1226
|
-
|
1227
|
-
recvdump = nil
|
1228
|
-
|
1229
|
-
begin
|
1230
|
-
recvdump = literal_value recvtype
|
1231
|
-
rescue
|
1232
|
-
end
|
1233
|
-
|
1234
|
-
pureruby_wrapper = anonymous_function{ |funcname| "
|
1235
|
-
static VALUE #{funcname}(VALUE self,void* block,void* frame, int argc, VALUE* argv){
|
1236
|
-
#{@frame_struct}* pframe = frame;
|
1237
|
-
VALUE method_arguments[3];
|
1238
|
-
|
1239
|
-
method_arguments[0] = (VALUE)argc;
|
1240
|
-
method_arguments[1] = (VALUE)argv;
|
1241
|
-
method_arguments[2] = (VALUE)self;
|
1242
|
-
|
1243
|
-
return #{
|
1244
|
-
protected_block "last_expression = rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);", false, "method_arguments"
|
1245
|
-
};
|
1246
|
-
}
|
1247
|
-
"
|
1248
|
-
}
|
1249
|
-
|
1250
|
-
generic_wrapper = anonymous_function{ |funcname| "
|
1251
|
-
static VALUE #{funcname}(VALUE self,void* block,void* frame, int argc, VALUE* argv){
|
1252
|
-
#{@frame_struct}* pframe = frame;
|
1253
|
-
VALUE method_arguments[4];
|
1254
|
-
|
1255
|
-
method_arguments[0] = (VALUE)argc;
|
1256
|
-
method_arguments[1] = (VALUE)argv;
|
1257
|
-
method_arguments[2] = (VALUE)self;
|
1258
|
-
method_arguments[3] = (VALUE)block;
|
1259
|
-
|
1260
|
-
void* fptr = 0;
|
1261
|
-
|
1262
|
-
if (*#{address_name} == 0) {
|
1263
|
-
if (#{tree_pointer_name} != 0) {
|
1264
|
-
if (*#{tree_pointer_name} != Qnil) {
|
1265
|
-
VALUE signature = #{literal_value signature};
|
1266
|
-
VALUE recvtype = #{recvdump};
|
1267
|
-
VALUE mname = #{literal_value mname};
|
1268
|
-
|
1269
|
-
rb_funcall(recvtype, #{intern_num :build}, 2, signature, mname);
|
1270
|
-
}
|
1271
|
-
}
|
1272
|
-
}
|
1273
|
-
|
1274
|
-
fptr = *#{address_name};
|
1275
|
-
|
1276
|
-
if (fptr == 0) {
|
1277
|
-
fptr = *#{cfunc_address_name};
|
1278
|
-
if (fptr != 0) {
|
1279
|
-
return ( (VALUE(*)(VALUE,VALUE,VALUE,int,VALUE*) ) (fptr) )(self,(VALUE)block,(VALUE)frame, argc, argv);
|
1280
|
-
}
|
1281
|
-
}
|
1282
|
-
|
1283
|
-
if (fptr == 0) {
|
1284
|
-
if (block==0) {
|
1285
|
-
return #{
|
1286
|
-
protected_block "last_expression = rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);", false, "method_arguments"
|
1287
|
-
};
|
1288
|
-
|
1289
|
-
} else {
|
1290
|
-
return #{
|
1291
|
-
protected_block "
|
1292
|
-
#{@block_struct} *pblock;
|
1293
|
-
pblock = (typeof(pblock))( ((VALUE*)method_arguments)[3] );
|
1294
|
-
last_expression = rb_iterate(
|
1295
|
-
#{anonymous_function{|name_|
|
1296
|
-
"
|
1297
|
-
static VALUE #{name_} (VALUE data) {
|
1298
|
-
VALUE* method_arguments = (VALUE*)data;
|
1299
|
-
return rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);
|
1300
|
-
}
|
1301
|
-
"
|
1302
|
-
}},
|
1303
|
-
(VALUE)method_arguments,
|
1304
|
-
|
1305
|
-
#{anonymous_function{|name_|
|
1306
|
-
"
|
1307
|
-
static VALUE #{name_} (VALUE arg_, VALUE param, int argc, VALUE* argv) {
|
1308
|
-
|
1309
|
-
VALUE arg;
|
1310
|
-
#{
|
1311
|
-
# TODO: access directly to argc and argv for optimal execution
|
1312
|
-
if RUBY_VERSION =~ /^1\.9/
|
1313
|
-
"
|
1314
|
-
if (TYPE(arg_) == T_ARRAY) {
|
1315
|
-
if (_RARRAY_LEN(arg_) <= 1) {
|
1316
|
-
arg = rb_ary_new4(argc,argv);
|
1317
|
-
} else {
|
1318
|
-
arg = arg_;
|
1319
|
-
}
|
1320
|
-
} else {
|
1321
|
-
arg = rb_ary_new4(argc,argv);
|
1322
|
-
}
|
1323
|
-
"
|
1324
|
-
else
|
1325
|
-
"arg = arg_;"
|
1326
|
-
end
|
1327
|
-
}
|
1328
|
-
|
1329
|
-
return rb_proc_call(param, arg);
|
1330
|
-
}
|
1331
|
-
"
|
1332
|
-
}},
|
1333
|
-
pblock->proc
|
1334
|
-
);
|
1335
|
-
", false, "method_arguments"
|
1336
|
-
};
|
1337
|
-
}
|
1338
|
-
|
1339
|
-
} else {
|
1340
|
-
return ( (VALUE(*)(VALUE,VALUE,VALUE,int,VALUE*)) (fptr) )(self,(VALUE)block,(VALUE)frame,argc,argv);
|
1341
|
-
}
|
1342
|
-
}
|
1343
|
-
"
|
1344
|
-
}
|
1345
|
-
|
1346
|
-
|
1347
|
-
cfuncall1inprocargs = (0..args_tree.size-2).map{|x| "argv[#{x}]"}.join(",")
|
1348
|
-
cfuncall1inprocargs = ","+cfuncall1inprocargs if cfuncall1inprocargs != ""
|
1349
|
-
|
1350
|
-
cfunc_value_cast = (["VALUE"]*args_tree.size).join(",")
|
1351
|
-
cfunc_wrapper = anonymous_function{ |funcname| "
|
1352
|
-
static VALUE #{funcname}(VALUE self, void* block,void* frame, int argc, VALUE* argv){
|
1353
|
-
return rb_vm_call(ruby_current_thread, self, #{intern_num mname.to_sym}, argc, argv, #{cfunc_real_address_name});
|
1354
|
-
}
|
1355
|
-
"
|
1356
|
-
}
|
1357
|
-
|
1358
|
-
toprocstrargs = (0..25).map{|x| "arg#{x}"}.join(",")
|
1359
|
-
strargs_signature = (0..25).map{|x| "VALUE arg#{x}"}.join(",")
|
1360
|
-
|
1361
|
-
cfunc_wrapper_1 = anonymous_function{ |funcname| "
|
1362
|
-
static VALUE #{funcname}(VALUE self, void* block,void* frame, int argc, VALUE* argv){
|
1363
|
-
return ( (VALUE(*)(int, VALUE*, VALUE)) (#{cfunc_real_address_name}) )(argc,argv,self);
|
1364
|
-
}
|
1365
|
-
"
|
1366
|
-
}
|
1367
|
-
|
1368
|
-
cfunc_wrapper_2 = anonymous_function{ |funcname| "
|
1369
|
-
static VALUE #{funcname}(VALUE self, void* block,void* frame, int argc, VALUE* argv){
|
1370
|
-
VALUE args = rb_ary_new3(argc, argv);
|
1371
|
-
return ( (VALUE(*)(VALUE,VALUE)) (#{cfunc_real_address_name}) )(self,args);
|
1372
|
-
}
|
1373
|
-
"
|
1374
|
-
}
|
1375
|
-
|
1376
|
-
update_cfunc_method = anonymous_function{ |funcname| "
|
1377
|
-
static VALUE #{funcname}(){
|
1378
|
-
void** default_address = (void**)#{cfunc_address_name};
|
1379
|
-
ID default_id = rb_intern(\"default\");
|
1380
|
-
VALUE recvtype = #{recvdump};
|
1381
|
-
|
1382
|
-
if (1) {
|
1383
|
-
*default_address = 0;
|
1384
|
-
|
1385
|
-
#{
|
1386
|
-
if RUBY_VERSION == "1.9.2"
|
1387
|
-
|
1388
|
-
"
|
1389
|
-
rb_method_entry_t* me = rb_method_entry(recvtype,#{intern_num mname});
|
1390
|
-
if (me != 0) {
|
1391
|
-
rb_method_definition_t* def = me->def;
|
1392
|
-
|
1393
|
-
if (def->type == VM_METHOD_TYPE_CFUNC) {
|
1394
|
-
*default_address = #{cfunc_wrapper};
|
1395
|
-
#{cfunc_real_address_name} = (void*)me;
|
1396
|
-
}
|
1397
|
-
}
|
1398
|
-
"
|
1399
|
-
end
|
1400
|
-
}
|
1401
|
-
if (default_address != 0) {
|
1402
|
-
if (recvtype != Qnil) {
|
1403
|
-
rb_funcall(
|
1404
|
-
recvtype,
|
1405
|
-
#{intern_num :register_method_value},
|
1406
|
-
3,
|
1407
|
-
#{literal_value mname},
|
1408
|
-
PTR2NUM(default_id),
|
1409
|
-
PTR2NUM(default_address)
|
1410
|
-
);
|
1411
|
-
}
|
1412
|
-
}
|
1413
|
-
}
|
1414
|
-
return Qnil;
|
1415
|
-
}
|
1416
|
-
"
|
1417
|
-
}
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
if recvdump and recvtype
|
1422
|
-
init_extra << "
|
1423
|
-
{
|
1424
|
-
VALUE recvtype = #{recvdump};
|
1425
|
-
rb_funcall(#{literal_value FastRuby}, #{intern_num :set_builder_module}, 1, recvtype);
|
1426
|
-
VALUE signature = #{literal_value signature};
|
1427
|
-
VALUE mname = #{literal_value mname};
|
1428
|
-
VALUE tree = #{literal_value method_tree};
|
1429
|
-
VALUE rb_str_signature = rb_funcall(
|
1430
|
-
#{literal_value FastRuby},
|
1431
|
-
#{intern_num :make_str_signature},
|
1432
|
-
2,
|
1433
|
-
mname,
|
1434
|
-
signature);
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
VALUE fastruby_method = rb_funcall(recvtype, #{intern_num :fastruby_method}, 1, mname);
|
1439
|
-
#{tree_pointer_name} = (VALUE*)NUM2PTR(fastruby_method_tree_pointer(fastruby_method));
|
1440
|
-
|
1441
|
-
ID id;
|
1442
|
-
ID default_id = rb_intern(\"default\");
|
1443
|
-
VALUE rb_method_hash;
|
1444
|
-
void** address = 0;
|
1445
|
-
void** default_address = 0;
|
1446
|
-
id = rb_intern(RSTRING_PTR(rb_str_signature));
|
1447
|
-
rb_method_hash = rb_funcall(recvtype, #{intern_num :method_hash},1,mname);
|
1448
|
-
|
1449
|
-
if (rb_method_hash != Qnil) {
|
1450
|
-
VALUE tmp = rb_hash_aref(rb_method_hash, PTR2NUM(id));
|
1451
|
-
if (tmp != Qnil) {
|
1452
|
-
address = (void*)NUM2PTR(tmp);
|
1453
|
-
}
|
1454
|
-
|
1455
|
-
tmp = rb_hash_aref(rb_method_hash, PTR2NUM(default_id));
|
1456
|
-
if (tmp != Qnil) {
|
1457
|
-
default_address = (void*)NUM2PTR(tmp);
|
1458
|
-
}
|
1459
|
-
}
|
1460
|
-
|
1461
|
-
if (default_address==0) {
|
1462
|
-
default_address = malloc(sizeof(void*));
|
1463
|
-
*default_address = 0;
|
1464
|
-
}
|
1465
|
-
#{cfunc_address_name} = default_address;
|
1466
|
-
#{unless is_block_call
|
1467
|
-
"
|
1468
|
-
#{update_cfunc_method}();
|
1469
|
-
rb_iterate(#{anonymous_function{|funcname|
|
1470
|
-
"static VALUE #{funcname}(VALUE recv) {
|
1471
|
-
return rb_funcall(recv, #{intern_num :observe}, 1, #{literal_value(@alt_method_name + "#" + cfunc_address_name)});
|
1472
|
-
}
|
1473
|
-
"
|
1474
|
-
}},fastruby_method,#{update_cfunc_method},Qnil);
|
1475
|
-
"
|
1476
|
-
end
|
1477
|
-
}
|
1478
|
-
|
1479
|
-
if (address==0) {
|
1480
|
-
address = malloc(sizeof(void*));
|
1481
|
-
|
1482
|
-
if (recvtype != Qnil) {
|
1483
|
-
rb_funcall(
|
1484
|
-
recvtype,
|
1485
|
-
#{intern_num :register_method_value},
|
1486
|
-
3,
|
1487
|
-
#{literal_value mname},
|
1488
|
-
PTR2NUM(id),
|
1489
|
-
PTR2NUM(address)
|
1490
|
-
);
|
1491
|
-
}
|
1492
|
-
|
1493
|
-
*address = 0; //(void*)
|
1494
|
-
}
|
1495
|
-
|
1496
|
-
#{address_name} = address;
|
1497
|
-
#{name} = (void*)#{generic_wrapper};
|
1498
|
-
}
|
1499
|
-
"
|
1500
|
-
else
|
1501
|
-
init_extra << "
|
1502
|
-
// ruby, wrap rb_funcall
|
1503
|
-
#{name} = (void*)#{pureruby_wrapper};
|
1504
|
-
"
|
1505
|
-
end
|
1506
|
-
|
1507
|
-
name
|
1508
|
-
end
|
1509
|
-
|
1510
|
-
def intern_num(symbol)
|
1511
|
-
symbol = symbol.to_sym
|
1512
|
-
@intern_num_hash = Hash.new unless @intern_num_hash
|
1513
|
-
return @intern_num_hash[symbol] if @intern_num_hash[symbol]
|
1514
|
-
|
1515
|
-
name = self.add_global_name("ID", 0);
|
1516
|
-
|
1517
|
-
init_extra << "
|
1518
|
-
#{name} = rb_intern(\"#{symbol.to_s}\");
|
1519
|
-
"
|
1520
|
-
|
1521
|
-
@intern_num_hash[symbol] = name
|
1522
|
-
|
1523
|
-
name
|
1524
|
-
end
|
1525
|
-
|
1526
|
-
def add_global_name(ctype, default)
|
1527
|
-
name = "glb" + rand(1000000000).to_s
|
1528
|
-
|
1529
|
-
extra_code << "
|
1530
|
-
static #{ctype} #{name} = #{default};
|
1531
|
-
"
|
1532
|
-
name
|
1533
|
-
end
|
1534
|
-
|
1535
|
-
def global_entry(glbname)
|
1536
|
-
name = add_global_name("struct global_entry*", 0);
|
1537
|
-
|
1538
|
-
init_extra << "
|
1539
|
-
#{name} = rb_global_entry(SYM2ID(#{literal_value glbname}));
|
1540
|
-
"
|
1541
|
-
|
1542
|
-
name
|
1543
|
-
end
|
1544
|
-
|
1545
|
-
|
1546
|
-
def frame(code, jmp_code, not_jmp_code = "", rescued = nil)
|
1547
|
-
|
1548
|
-
anonymous_function{ |name| "
|
1549
|
-
static VALUE #{name}(VALUE param) {
|
1550
|
-
volatile VALUE last_expression = Qnil;
|
1551
|
-
#{@frame_struct} frame;
|
1552
|
-
|
1553
|
-
typeof(frame)* volatile pframe;
|
1554
|
-
typeof(frame)* volatile parent_frame;
|
1555
|
-
#{@locals_struct}* volatile plocals;
|
1556
|
-
|
1557
|
-
parent_frame = (void*)param;
|
1558
|
-
|
1559
|
-
frame.parent_frame = (void*)param;
|
1560
|
-
frame.plocals = parent_frame->plocals;
|
1561
|
-
frame.rescue = #{rescued ? rescued : "parent_frame->rescue"};
|
1562
|
-
frame.targetted = 0;
|
1563
|
-
frame.thread_data = parent_frame->thread_data;
|
1564
|
-
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
1565
|
-
|
1566
|
-
plocals = frame.plocals;
|
1567
|
-
pframe = &frame;
|
1568
|
-
|
1569
|
-
int aux = setjmp(frame.jmp);
|
1570
|
-
if (aux != 0) {
|
1571
|
-
last_expression = pframe->return_value;
|
1572
|
-
|
1573
|
-
// restore previous frame
|
1574
|
-
typeof(pframe) original_frame = pframe;
|
1575
|
-
pframe = parent_frame;
|
1576
|
-
|
1577
|
-
#{jmp_code};
|
1578
|
-
|
1579
|
-
if (original_frame->targetted == 0) {
|
1580
|
-
longjmp(pframe->jmp,aux);
|
1581
|
-
}
|
1582
|
-
|
1583
|
-
return last_expression;
|
1584
|
-
}
|
1585
|
-
|
1586
|
-
#{code};
|
1587
|
-
|
1588
|
-
// restore previous frame
|
1589
|
-
volatile typeof(pframe) original_frame = pframe;
|
1590
|
-
pframe = parent_frame;
|
1591
|
-
#{not_jmp_code};
|
1592
|
-
|
1593
|
-
return last_expression;
|
1594
|
-
|
1595
|
-
}
|
1596
|
-
"
|
1597
|
-
} + "((VALUE)pframe)"
|
1598
|
-
end
|
1599
|
-
end
|
1600
|
-
end
|