fastruby 0.0.12 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +8 -0
- data/README +0 -1
- data/Rakefile +1 -1
- data/lib/fastruby/builder.rb +9 -2
- data/lib/fastruby/translator/modules/block.rb +92 -0
- data/lib/fastruby/translator/modules/call.rb +137 -0
- data/lib/fastruby/translator/modules/defn.rb +221 -0
- data/lib/fastruby/translator/modules/exceptions.rb +134 -0
- data/lib/fastruby/translator/modules/flow.rb +91 -0
- data/lib/fastruby/translator/modules/iter.rb +584 -0
- data/lib/fastruby/translator/modules/literal.rb +86 -0
- data/lib/fastruby/translator/modules/logical.rb +38 -0
- data/lib/fastruby/translator/modules/method_group.rb +174 -0
- data/lib/fastruby/translator/modules/nonlocal.rb +96 -0
- data/lib/fastruby/translator/modules/variable.rb +190 -0
- data/lib/fastruby/translator/translator.rb +1171 -0
- data/lib/fastruby/translator/translator_modules.rb +49 -0
- data/lib/fastruby.rb +1 -1
- data/spec/call/multiple_args_spec.rb +87 -0
- data/spec/defn/multiple_args_spec.rb +271 -0
- metadata +19 -7
- data/lib/fastruby/translator/call.rb +0 -2594
- data/lib/fastruby/translator/iter.rb +0 -2594
- data/lib/fastruby/translator.rb +0 -2594
@@ -1,2594 +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 "fastruby/method_extension"
|
23
|
-
require "fastruby/set_tree"
|
24
|
-
require "fastruby/exceptions"
|
25
|
-
require "rubygems"
|
26
|
-
require "sexp"
|
27
|
-
|
28
|
-
module FastRuby
|
29
|
-
class Context
|
30
|
-
attr_accessor :infer_lvar_map
|
31
|
-
attr_accessor :alt_method_name
|
32
|
-
attr_accessor :locals
|
33
|
-
attr_accessor :options
|
34
|
-
attr_accessor :infer_self
|
35
|
-
attr_accessor :snippet_hash
|
36
|
-
attr_reader :no_cache
|
37
|
-
attr_reader :init_extra
|
38
|
-
attr_reader :extra_code
|
39
|
-
attr_reader :yield_signature
|
40
|
-
|
41
|
-
def initialize(common_func = true)
|
42
|
-
@infer_lvar_map = Hash.new
|
43
|
-
@no_cache = false
|
44
|
-
@extra_code = ""
|
45
|
-
@options = {}
|
46
|
-
@init_extra = Array.new
|
47
|
-
@frame_struct = "struct {
|
48
|
-
void* parent_frame;
|
49
|
-
void* plocals;
|
50
|
-
jmp_buf jmp;
|
51
|
-
VALUE return_value;
|
52
|
-
int rescue;
|
53
|
-
VALUE last_error;
|
54
|
-
VALUE next_recv;
|
55
|
-
int targetted;
|
56
|
-
struct FASTRUBYTHREADDATA* thread_data;
|
57
|
-
}"
|
58
|
-
|
59
|
-
@block_struct = "struct {
|
60
|
-
void* block_function_address;
|
61
|
-
void* block_function_param;
|
62
|
-
}"
|
63
|
-
|
64
|
-
|
65
|
-
extra_code << "
|
66
|
-
#include \"node.h\"
|
67
|
-
|
68
|
-
#define FASTRUBY_TAG_RETURN 0x80
|
69
|
-
#define FASTRUBY_TAG_NEXT 0x81
|
70
|
-
#define FASTRUBY_TAG_BREAK 0x82
|
71
|
-
#define FASTRUBY_TAG_RAISE 0x83
|
72
|
-
#define FASTRUBY_TAG_REDO 0x84
|
73
|
-
#define FASTRUBY_TAG_RETRY 0x85
|
74
|
-
#define TAG_RAISE 0x6
|
75
|
-
|
76
|
-
#ifndef __INLINE_FASTRUBY_BASE
|
77
|
-
#include \"#{FastRuby.fastruby_load_path}/../ext/fastruby_base/fastruby_base.inl\"
|
78
|
-
#define __INLINE_FASTRUBY_BASE
|
79
|
-
#endif
|
80
|
-
"
|
81
|
-
|
82
|
-
ruby_code = "
|
83
|
-
$LOAD_PATH << #{FastRuby.fastruby_load_path.inspect}
|
84
|
-
require #{FastRuby.fastruby_script_path.inspect}
|
85
|
-
"
|
86
|
-
|
87
|
-
init_extra << "
|
88
|
-
rb_eval_string(#{ruby_code.inspect});
|
89
|
-
"
|
90
|
-
|
91
|
-
@lambda_node_gvar = add_global_name("NODE*", 0);
|
92
|
-
@proc_node_gvar = add_global_name("NODE*", 0);
|
93
|
-
@procnew_node_gvar = add_global_name("NODE*", 0);
|
94
|
-
|
95
|
-
init_extra << "
|
96
|
-
#{@lambda_node_gvar} = rb_method_node(rb_cObject, #{intern_num :lambda});
|
97
|
-
#{@proc_node_gvar} = rb_method_node(rb_cObject, #{intern_num :proc});
|
98
|
-
#{@procnew_node_gvar} = rb_method_node(CLASS_OF(rb_cProc), #{intern_num :new});
|
99
|
-
"
|
100
|
-
|
101
|
-
@common_func = common_func
|
102
|
-
if common_func
|
103
|
-
extra_code << "static VALUE _rb_gvar_set(void* ge,VALUE value) {
|
104
|
-
rb_gvar_set((struct global_entry*)ge,value);
|
105
|
-
return value;
|
106
|
-
}
|
107
|
-
"
|
108
|
-
|
109
|
-
extra_code << "static VALUE re_yield(int argc, VALUE* argv, VALUE param, VALUE _parent_frame) {
|
110
|
-
VALUE yield_args = rb_ary_new4(argc,argv);
|
111
|
-
VALUE* yield_args_p = &yield_args;
|
112
|
-
|
113
|
-
#{@frame_struct}* pframe;
|
114
|
-
pframe = (typeof(pframe))_parent_frame;
|
115
|
-
|
116
|
-
return #{protected_block("rb_yield_splat(*(VALUE*)yield_args_p)",true,"yield_args_p",true)};
|
117
|
-
}"
|
118
|
-
|
119
|
-
extra_code << "static VALUE _rb_ivar_set(VALUE recv,ID idvar, VALUE value) {
|
120
|
-
rb_ivar_set(recv,idvar,value);
|
121
|
-
return value;
|
122
|
-
}
|
123
|
-
"
|
124
|
-
|
125
|
-
extra_code << "static VALUE __rb_cvar_set(VALUE recv,ID idvar, VALUE value, int warn) {
|
126
|
-
rb_cvar_set(recv,idvar,value,warn);
|
127
|
-
return value;
|
128
|
-
}
|
129
|
-
"
|
130
|
-
|
131
|
-
extra_code << "static VALUE _lvar_assing(VALUE* destination,VALUE value) {
|
132
|
-
*destination = value;
|
133
|
-
return value;
|
134
|
-
}
|
135
|
-
|
136
|
-
/*
|
137
|
-
#{caller.join("\n")}
|
138
|
-
*/
|
139
|
-
|
140
|
-
"
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
def to_c(tree)
|
145
|
-
return "Qnil" unless tree
|
146
|
-
send("to_c_" + tree[0].to_s, tree);
|
147
|
-
end
|
148
|
-
|
149
|
-
def anonymous_function
|
150
|
-
|
151
|
-
name = "anonymous" + rand(10000000).to_s
|
152
|
-
extra_code << yield(name)
|
153
|
-
|
154
|
-
name
|
155
|
-
end
|
156
|
-
|
157
|
-
def to_c_dot2(tree)
|
158
|
-
"rb_range_new(#{to_c tree[1]}, #{to_c tree[2]},0)"
|
159
|
-
end
|
160
|
-
|
161
|
-
def to_c_attrasgn(tree)
|
162
|
-
to_c_call(tree)
|
163
|
-
end
|
164
|
-
|
165
|
-
def to_c_iter(tree)
|
166
|
-
|
167
|
-
call_tree = tree[1]
|
168
|
-
args_tree = tree[2]
|
169
|
-
recv_tree = call_tree[1]
|
170
|
-
|
171
|
-
directive_code = directive(call_tree)
|
172
|
-
if directive_code
|
173
|
-
return directive_code
|
174
|
-
end
|
175
|
-
|
176
|
-
other_call_tree = call_tree.dup
|
177
|
-
other_call_tree[1] = s(:lvar, :arg)
|
178
|
-
|
179
|
-
mname = call_tree[2]
|
180
|
-
|
181
|
-
call_args_tree = call_tree[3]
|
182
|
-
|
183
|
-
caller_code = nil
|
184
|
-
|
185
|
-
recvtype = infer_type(recv_tree || s(:self))
|
186
|
-
|
187
|
-
address = nil
|
188
|
-
mobject = nil
|
189
|
-
len = nil
|
190
|
-
|
191
|
-
extra_inference = {}
|
192
|
-
|
193
|
-
if recvtype
|
194
|
-
|
195
|
-
inference_complete = true
|
196
|
-
signature = [recvtype]
|
197
|
-
|
198
|
-
call_args_tree[1..-1].each do |arg|
|
199
|
-
argtype = infer_type(arg)
|
200
|
-
if argtype
|
201
|
-
signature << argtype
|
202
|
-
else
|
203
|
-
inference_complete = false
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
if recvtype.respond_to? :fastruby_method and inference_complete
|
208
|
-
method_tree = nil
|
209
|
-
begin
|
210
|
-
method_tree = recvtype.instance_method(call_tree[2]).fastruby.tree
|
211
|
-
rescue NoMethodError
|
212
|
-
end
|
213
|
-
|
214
|
-
if method_tree
|
215
|
-
mobject = recvtype.build(signature, call_tree[2])
|
216
|
-
yield_signature = mobject.yield_signature
|
217
|
-
|
218
|
-
if not args_tree
|
219
|
-
elsif args_tree.first == :lasgn
|
220
|
-
if yield_signature[0]
|
221
|
-
extra_inference[args_tree.last] = yield_signature[0]
|
222
|
-
end
|
223
|
-
elsif args_tree.first == :masgn
|
224
|
-
yield_args = args_tree[1][1..-1].map(&:last)
|
225
|
-
(0...yield_signature.size-1).each do |i|
|
226
|
-
extra_inference[yield_args[i]] = yield_signature[i]
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
anonymous_impl = tree[3]
|
234
|
-
|
235
|
-
str_lvar_initialization = "#{@frame_struct} *pframe;
|
236
|
-
#{@locals_struct} *plocals;
|
237
|
-
pframe = (void*)param;
|
238
|
-
plocals = (void*)pframe->plocals;
|
239
|
-
"
|
240
|
-
|
241
|
-
str_arg_initialization = ""
|
242
|
-
|
243
|
-
str_impl = ""
|
244
|
-
|
245
|
-
with_extra_inference(extra_inference) do
|
246
|
-
|
247
|
-
on_block do
|
248
|
-
# if impl_tree is a block, implement the last node with a return
|
249
|
-
if anonymous_impl
|
250
|
-
if anonymous_impl[0] == :block
|
251
|
-
str_impl = anonymous_impl[1..-2].map{ |subtree|
|
252
|
-
to_c(subtree)
|
253
|
-
}.join(";")
|
254
|
-
|
255
|
-
if anonymous_impl[-1][0] != :return and anonymous_impl[-1][0] != :break and anonymous_impl[-1][0] != :next
|
256
|
-
str_impl = str_impl + ";last_expression = (#{to_c(anonymous_impl[-1])});"
|
257
|
-
else
|
258
|
-
str_impl = str_impl + ";#{to_c(anonymous_impl[-1])};"
|
259
|
-
end
|
260
|
-
else
|
261
|
-
if anonymous_impl[0] != :return and anonymous_impl[0] != :break and anonymous_impl[0] != :next
|
262
|
-
str_impl = str_impl + ";last_expression = (#{to_c(anonymous_impl)});"
|
263
|
-
else
|
264
|
-
str_impl = str_impl + ";#{to_c(anonymous_impl)};"
|
265
|
-
end
|
266
|
-
end
|
267
|
-
else
|
268
|
-
str_impl = "last_expression = Qnil;"
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
|
274
|
-
if not args_tree
|
275
|
-
str_arg_initialization = ""
|
276
|
-
elsif args_tree.first == :lasgn
|
277
|
-
str_arg_initialization = "plocals->#{args_tree[1]} = arg;"
|
278
|
-
elsif args_tree.first == :masgn
|
279
|
-
arguments = args_tree[1][1..-1].map(&:last)
|
280
|
-
|
281
|
-
(0..arguments.size-1).each do |i|
|
282
|
-
str_arg_initialization << "plocals->#{arguments[i]} = rb_ary_entry(arg,#{i});\n"
|
283
|
-
end
|
284
|
-
end
|
285
|
-
rb_funcall_caller_code = nil
|
286
|
-
|
287
|
-
if call_args_tree.size > 1
|
288
|
-
|
289
|
-
str_called_code_args = call_args_tree[1..-1].map{ |subtree| to_c subtree }.join(",")
|
290
|
-
str_recv = "pframe->next_recv"
|
291
|
-
|
292
|
-
str_recv = "plocals->self" unless recv_tree
|
293
|
-
|
294
|
-
rb_funcall_caller_code = proc { |name| "
|
295
|
-
static VALUE #{name}(VALUE param) {
|
296
|
-
// call to #{call_tree[2]}
|
297
|
-
|
298
|
-
#{str_lvar_initialization}
|
299
|
-
return rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, #{call_args_tree.size-1}, #{str_called_code_args});
|
300
|
-
}
|
301
|
-
"
|
302
|
-
}
|
303
|
-
|
304
|
-
rb_funcall_caller_code_with_lambda = rb_funcall_caller_code
|
305
|
-
else
|
306
|
-
str_recv = "pframe->next_recv"
|
307
|
-
str_recv = "plocals->self" unless recv_tree
|
308
|
-
|
309
|
-
rb_funcall_caller_code = proc { |name| "
|
310
|
-
static VALUE #{name}(VALUE param) {
|
311
|
-
// call to #{call_tree[2]}
|
312
|
-
#{str_lvar_initialization}
|
313
|
-
return rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, 0);
|
314
|
-
}
|
315
|
-
"
|
316
|
-
}
|
317
|
-
|
318
|
-
rb_funcall_caller_code_with_lambda = proc { |name| "
|
319
|
-
static VALUE #{name}(VALUE param) {
|
320
|
-
// call to #{call_tree[2]}
|
321
|
-
#{str_lvar_initialization}
|
322
|
-
VALUE ret = rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, 0);
|
323
|
-
|
324
|
-
// freeze all stacks
|
325
|
-
struct FASTRUBYTHREADDATA* thread_data = rb_current_thread_data();
|
326
|
-
|
327
|
-
if (thread_data != 0) {
|
328
|
-
VALUE rb_stack_chunk = thread_data->rb_stack_chunk;
|
329
|
-
|
330
|
-
// add reference to stack chunk to lambda object
|
331
|
-
rb_ivar_set(ret,#{intern_num :_fastruby_stack_chunk},rb_stack_chunk);
|
332
|
-
|
333
|
-
// freeze the complete chain of stack chunks
|
334
|
-
while (rb_stack_chunk != Qnil) {
|
335
|
-
struct STACKCHUNK* stack_chunk;
|
336
|
-
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
337
|
-
|
338
|
-
stack_chunk_freeze(stack_chunk);
|
339
|
-
|
340
|
-
rb_stack_chunk = rb_ivar_get(rb_stack_chunk,#{intern_num :_parent_stack_chunk});
|
341
|
-
}
|
342
|
-
}
|
343
|
-
|
344
|
-
return ret;
|
345
|
-
}
|
346
|
-
"
|
347
|
-
}
|
348
|
-
|
349
|
-
end
|
350
|
-
|
351
|
-
rb_funcall_block_code_with_lambda = proc { |name| "
|
352
|
-
static VALUE #{name}(VALUE arg, VALUE _plocals) {
|
353
|
-
// block for call to #{call_tree[2]}
|
354
|
-
VALUE last_expression = Qnil;
|
355
|
-
|
356
|
-
#{@frame_struct} frame;
|
357
|
-
#{@frame_struct} *pframe = (void*)&frame;
|
358
|
-
#{@locals_struct} *plocals = (void*)_plocals;
|
359
|
-
|
360
|
-
frame.plocals = plocals;
|
361
|
-
frame.parent_frame = 0;
|
362
|
-
frame.return_value = Qnil;
|
363
|
-
frame.rescue = 0;
|
364
|
-
frame.targetted = 0;
|
365
|
-
frame.thread_data = rb_current_thread_data();
|
366
|
-
|
367
|
-
// create a fake parent frame representing the lambda method frame and a fake locals scope
|
368
|
-
VALUE old_call_frame = ((typeof(plocals))(pframe->plocals))->call_frame;
|
369
|
-
((typeof(plocals))(pframe->plocals))->call_frame = LONG2FIX(pframe);
|
370
|
-
|
371
|
-
int aux = setjmp(frame.jmp);
|
372
|
-
if (aux != 0) {
|
373
|
-
if (aux == FASTRUBY_TAG_BREAK) {
|
374
|
-
return frame.return_value;
|
375
|
-
} else if (aux == FASTRUBY_TAG_NEXT) {
|
376
|
-
return pframe->thread_data->accumulator;
|
377
|
-
} else if (aux == FASTRUBY_TAG_REDO) {
|
378
|
-
// do nothing and let execute the block again
|
379
|
-
} else if (aux == FASTRUBY_TAG_RAISE) {
|
380
|
-
rb_funcall(((typeof(plocals))(pframe->plocals))->self, #{intern_num :raise}, 1, frame.thread_data->exception);
|
381
|
-
return Qnil;
|
382
|
-
} else {
|
383
|
-
if (aux == FASTRUBY_TAG_RETURN) {
|
384
|
-
if (((typeof(pframe))(FIX2LONG(plocals->pframe)))->targetted == 1) {
|
385
|
-
((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
|
386
|
-
return ((typeof(plocals))(pframe->plocals))->return_value;
|
387
|
-
} else {
|
388
|
-
rb_raise(rb_eLocalJumpError, \"unexpected return\");
|
389
|
-
}
|
390
|
-
} else {
|
391
|
-
rb_raise(rb_eLocalJumpError, \"unexpected return\");
|
392
|
-
}
|
393
|
-
|
394
|
-
((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
|
395
|
-
return frame.return_value;
|
396
|
-
|
397
|
-
}
|
398
|
-
}
|
399
|
-
|
400
|
-
#{str_arg_initialization}
|
401
|
-
#{str_impl}
|
402
|
-
|
403
|
-
((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
|
404
|
-
return last_expression;
|
405
|
-
}
|
406
|
-
"
|
407
|
-
}
|
408
|
-
|
409
|
-
rb_funcall_block_code_proc_new = proc { |name| "
|
410
|
-
static VALUE #{name}(VALUE arg, VALUE _plocals) {
|
411
|
-
// block for call to #{call_tree[2]}
|
412
|
-
VALUE last_expression = Qnil;
|
413
|
-
|
414
|
-
#{@frame_struct} frame;
|
415
|
-
#{@frame_struct} *pframe = (void*)&frame;
|
416
|
-
#{@locals_struct} *plocals = (void*)_plocals;
|
417
|
-
|
418
|
-
frame.plocals = plocals;
|
419
|
-
frame.parent_frame = 0;
|
420
|
-
frame.return_value = Qnil;
|
421
|
-
frame.rescue = 0;
|
422
|
-
frame.targetted = 0;
|
423
|
-
frame.thread_data = rb_current_thread_data();
|
424
|
-
|
425
|
-
// create a fake parent frame representing the lambda method frame and a fake locals scope
|
426
|
-
VALUE old_call_frame = ((typeof(plocals))(pframe->plocals))->call_frame;
|
427
|
-
((typeof(plocals))(pframe->plocals))->call_frame = LONG2FIX(pframe);
|
428
|
-
|
429
|
-
int aux = setjmp(frame.jmp);
|
430
|
-
if (aux != 0) {
|
431
|
-
if (aux == FASTRUBY_TAG_NEXT) {
|
432
|
-
return pframe->thread_data->accumulator;
|
433
|
-
} else if (aux == FASTRUBY_TAG_REDO) {
|
434
|
-
// do nothing and let execute the block again
|
435
|
-
} else if (aux == FASTRUBY_TAG_RAISE) {
|
436
|
-
rb_funcall(((typeof(plocals))(pframe->plocals))->self, #{intern_num :raise}, 1, frame.thread_data->exception);
|
437
|
-
return Qnil;
|
438
|
-
} else {
|
439
|
-
if (((typeof(pframe))(FIX2LONG(plocals->pframe)))->targetted == 1) {
|
440
|
-
|
441
|
-
if (plocals->active == Qfalse) {
|
442
|
-
rb_raise(rb_eLocalJumpError,\"return from proc-closure\");
|
443
|
-
} else {
|
444
|
-
((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
|
445
|
-
rb_jump_tag(aux);
|
446
|
-
}
|
447
|
-
} else {
|
448
|
-
rb_raise(rb_eLocalJumpError, \"unexpected return\");
|
449
|
-
}
|
450
|
-
}
|
451
|
-
}
|
452
|
-
|
453
|
-
#{str_arg_initialization}
|
454
|
-
#{str_impl}
|
455
|
-
|
456
|
-
((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
|
457
|
-
|
458
|
-
return last_expression;
|
459
|
-
}
|
460
|
-
"
|
461
|
-
}
|
462
|
-
|
463
|
-
|
464
|
-
rb_funcall_block_code = proc { |name| "
|
465
|
-
static VALUE #{name}(VALUE arg, VALUE _plocals) {
|
466
|
-
// block for call to #{call_tree[2]}
|
467
|
-
VALUE last_expression = Qnil;
|
468
|
-
|
469
|
-
#{@frame_struct} frame;
|
470
|
-
#{@frame_struct} *pframe = (void*)&frame;
|
471
|
-
#{@locals_struct} *plocals = (void*)_plocals;
|
472
|
-
|
473
|
-
frame.plocals = plocals;
|
474
|
-
frame.parent_frame = 0;
|
475
|
-
frame.return_value = Qnil;
|
476
|
-
frame.rescue = 0;
|
477
|
-
frame.targetted = 0;
|
478
|
-
frame.thread_data = rb_current_thread_data();
|
479
|
-
|
480
|
-
int aux = setjmp(frame.jmp);
|
481
|
-
if (aux != 0) {
|
482
|
-
|
483
|
-
if (aux == FASTRUBY_TAG_NEXT) {
|
484
|
-
return pframe->thread_data->accumulator;
|
485
|
-
} else if (aux == FASTRUBY_TAG_REDO) {
|
486
|
-
// do nothing and let execute the block again
|
487
|
-
} else {
|
488
|
-
rb_jump_tag(aux);
|
489
|
-
return frame.return_value;
|
490
|
-
}
|
491
|
-
}
|
492
|
-
|
493
|
-
|
494
|
-
#{str_arg_initialization}
|
495
|
-
#{str_impl}
|
496
|
-
|
497
|
-
return last_expression;
|
498
|
-
}
|
499
|
-
"
|
500
|
-
}
|
501
|
-
|
502
|
-
|
503
|
-
fastruby_str_arg_initialization = ""
|
504
|
-
|
505
|
-
if not args_tree
|
506
|
-
fastruby_str_arg_initialization = ""
|
507
|
-
elsif args_tree.first == :lasgn
|
508
|
-
fastruby_str_arg_initialization = "plocals->#{args_tree[1]} = argv[0];"
|
509
|
-
elsif args_tree.first == :masgn
|
510
|
-
arguments = args_tree[1][1..-1].map(&:last)
|
511
|
-
|
512
|
-
(0..arguments.size-1).each do |i|
|
513
|
-
fastruby_str_arg_initialization << "plocals->#{arguments[i]} = #{i} < argc ? argv[#{i}] : Qnil;\n"
|
514
|
-
end
|
515
|
-
end
|
516
|
-
|
517
|
-
block_code = proc { |name| "
|
518
|
-
static VALUE #{name}(int argc, VALUE* argv, VALUE _locals, VALUE _parent_frame) {
|
519
|
-
// block for call to #{call_tree[2]}
|
520
|
-
VALUE last_expression = Qnil;
|
521
|
-
#{@frame_struct} frame;
|
522
|
-
#{@frame_struct} *pframe = (void*)&frame;
|
523
|
-
#{@frame_struct} *parent_frame = (void*)_parent_frame;
|
524
|
-
#{@locals_struct} *plocals;
|
525
|
-
|
526
|
-
frame.plocals = (void*)_locals;
|
527
|
-
frame.parent_frame = parent_frame;
|
528
|
-
frame.return_value = Qnil;
|
529
|
-
frame.rescue = 0;
|
530
|
-
frame.targetted = 0;
|
531
|
-
frame.thread_data = parent_frame->thread_data;
|
532
|
-
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
533
|
-
|
534
|
-
plocals = frame.plocals;
|
535
|
-
|
536
|
-
int aux = setjmp(frame.jmp);
|
537
|
-
if (aux != 0) {
|
538
|
-
if (pframe->targetted == 0) {
|
539
|
-
if (aux == FASTRUBY_TAG_NEXT) {
|
540
|
-
return pframe->thread_data->accumulator;
|
541
|
-
} else if (aux == FASTRUBY_TAG_REDO) {
|
542
|
-
// do nothing and let execute the block again
|
543
|
-
} else {
|
544
|
-
longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
|
545
|
-
}
|
546
|
-
}
|
547
|
-
|
548
|
-
}
|
549
|
-
|
550
|
-
#{fastruby_str_arg_initialization}
|
551
|
-
#{str_impl}
|
552
|
-
|
553
|
-
return last_expression;
|
554
|
-
}
|
555
|
-
"
|
556
|
-
}
|
557
|
-
|
558
|
-
str_recv = "plocals->self"
|
559
|
-
|
560
|
-
if recv_tree
|
561
|
-
str_recv = to_c recv_tree
|
562
|
-
end
|
563
|
-
|
564
|
-
caller_code = nil
|
565
|
-
convention_global_name = add_global_name("int",0)
|
566
|
-
|
567
|
-
call_frame_struct_code = "
|
568
|
-
#{@block_struct} block;
|
569
|
-
#{@locals_struct} *plocals = (void*)param;
|
570
|
-
|
571
|
-
block.block_function_address = (void*)#{anonymous_function(&block_code)};
|
572
|
-
block.block_function_param = (void*)param;
|
573
|
-
|
574
|
-
// create a call_frame
|
575
|
-
#{@frame_struct} call_frame;
|
576
|
-
|
577
|
-
call_frame.parent_frame = (void*)pframe;
|
578
|
-
call_frame.plocals = plocals;
|
579
|
-
call_frame.return_value = Qnil;
|
580
|
-
call_frame.targetted = 0;
|
581
|
-
call_frame.thread_data = rb_current_thread_data();
|
582
|
-
|
583
|
-
VALUE old_call_frame = plocals->call_frame;
|
584
|
-
plocals->call_frame = LONG2FIX(&call_frame);
|
585
|
-
|
586
|
-
int aux = setjmp(call_frame.jmp);
|
587
|
-
if (aux != 0) {
|
588
|
-
#{@frame_struct}* pframe_ = (void*)pframe;
|
589
|
-
|
590
|
-
if (aux == FASTRUBY_TAG_RETRY ) {
|
591
|
-
// do nothing and let the call execute again
|
592
|
-
} else {
|
593
|
-
if (call_frame.targetted == 0) {
|
594
|
-
longjmp(pframe_->jmp,aux);
|
595
|
-
}
|
596
|
-
|
597
|
-
plocals->call_frame = old_call_frame;
|
598
|
-
return call_frame.return_value;
|
599
|
-
}
|
600
|
-
}
|
601
|
-
"
|
602
|
-
|
603
|
-
if call_args_tree.size > 1
|
604
|
-
value_cast = ( ["VALUE"]*(call_tree[3].size) ).join(",") + ", VALUE, VALUE"
|
605
|
-
|
606
|
-
str_called_code_args = call_tree[3][1..-1].map{|subtree| to_c subtree}.join(",")
|
607
|
-
|
608
|
-
caller_code = proc { |name| "
|
609
|
-
static VALUE #{name}(VALUE param, VALUE pframe) {
|
610
|
-
// call to #{call_tree[2]}
|
611
|
-
#{call_frame_struct_code}
|
612
|
-
|
613
|
-
VALUE ret = ((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name)})(#{str_recv}, (VALUE)&block, (VALUE)&call_frame, #{str_called_code_args});
|
614
|
-
plocals->call_frame = old_call_frame;
|
615
|
-
return ret;
|
616
|
-
}
|
617
|
-
"
|
618
|
-
}
|
619
|
-
|
620
|
-
else
|
621
|
-
caller_code = proc { |name| "
|
622
|
-
static VALUE #{name}(VALUE param, VALUE pframe) {
|
623
|
-
#{call_frame_struct_code}
|
624
|
-
|
625
|
-
// call to #{call_tree[2]}
|
626
|
-
VALUE ret = ((VALUE(*)(VALUE,VALUE,VALUE))#{encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name)})(#{str_recv}, (VALUE)&block, (VALUE)&call_frame);
|
627
|
-
plocals->call_frame = old_call_frame;
|
628
|
-
return ret;
|
629
|
-
}
|
630
|
-
"
|
631
|
-
}
|
632
|
-
end
|
633
|
-
|
634
|
-
inline_block "
|
635
|
-
if (#{convention_global_name}) {
|
636
|
-
return #{anonymous_function(&caller_code)}((VALUE)plocals, (VALUE)pframe);
|
637
|
-
} else {
|
638
|
-
return #{
|
639
|
-
frame_call(
|
640
|
-
protected_block(inline_block("
|
641
|
-
|
642
|
-
pframe->next_recv = #{recv_tree ? to_c(recv_tree) : "plocals->self"};
|
643
|
-
|
644
|
-
NODE* node = rb_method_node(CLASS_OF(pframe->next_recv), #{intern_num mname});
|
645
|
-
void* caller_func;
|
646
|
-
void* block_func;
|
647
|
-
|
648
|
-
if (
|
649
|
-
node == #{@proc_node_gvar} ||
|
650
|
-
node == #{@lambda_node_gvar}
|
651
|
-
) {
|
652
|
-
|
653
|
-
caller_func = #{anonymous_function(&rb_funcall_caller_code_with_lambda)};
|
654
|
-
block_func = #{anonymous_function(&rb_funcall_block_code_with_lambda)};
|
655
|
-
} else if (node == #{@procnew_node_gvar} && pframe->next_recv == rb_cProc) {
|
656
|
-
caller_func = #{anonymous_function(&rb_funcall_caller_code_with_lambda)};
|
657
|
-
block_func = #{anonymous_function(&rb_funcall_block_code_proc_new)};
|
658
|
-
} else {
|
659
|
-
caller_func = #{anonymous_function(&rb_funcall_caller_code)};
|
660
|
-
block_func = #{anonymous_function(&rb_funcall_block_code)};
|
661
|
-
}
|
662
|
-
|
663
|
-
return rb_iterate(
|
664
|
-
caller_func,
|
665
|
-
(VALUE)pframe,
|
666
|
-
block_func,
|
667
|
-
(VALUE)plocals);
|
668
|
-
|
669
|
-
"), true)
|
670
|
-
)
|
671
|
-
};
|
672
|
-
}
|
673
|
-
"
|
674
|
-
end
|
675
|
-
|
676
|
-
def frame_call(inner_code)
|
677
|
-
inline_block "
|
678
|
-
|
679
|
-
|
680
|
-
// create a call_frame
|
681
|
-
#{@frame_struct} call_frame;
|
682
|
-
typeof(call_frame)* old_pframe = (void*)pframe;
|
683
|
-
|
684
|
-
pframe = (typeof(pframe))&call_frame;
|
685
|
-
|
686
|
-
call_frame.parent_frame = (void*)pframe;
|
687
|
-
call_frame.plocals = plocals;
|
688
|
-
call_frame.return_value = Qnil;
|
689
|
-
call_frame.targetted = 0;
|
690
|
-
call_frame.thread_data = old_pframe->thread_data;
|
691
|
-
if (call_frame.thread_data == 0) call_frame.thread_data = rb_current_thread_data();
|
692
|
-
|
693
|
-
VALUE old_call_frame = plocals->call_frame;
|
694
|
-
plocals->call_frame = LONG2FIX(&call_frame);
|
695
|
-
|
696
|
-
int aux = setjmp(call_frame.jmp);
|
697
|
-
if (aux != 0) {
|
698
|
-
if (call_frame.targetted == 0) {
|
699
|
-
longjmp(old_pframe->jmp,aux);
|
700
|
-
}
|
701
|
-
|
702
|
-
if (aux == FASTRUBY_TAG_BREAK) {
|
703
|
-
plocals->call_frame = old_call_frame;
|
704
|
-
return call_frame.return_value;
|
705
|
-
} else if (aux == FASTRUBY_TAG_RETRY ) {
|
706
|
-
// do nothing and let the call execute again
|
707
|
-
} else {
|
708
|
-
plocals->call_frame = old_call_frame;
|
709
|
-
return call_frame.return_value;
|
710
|
-
}
|
711
|
-
}
|
712
|
-
|
713
|
-
VALUE ret = #{inner_code};
|
714
|
-
plocals->call_frame = old_call_frame;
|
715
|
-
return ret;
|
716
|
-
"
|
717
|
-
end
|
718
|
-
|
719
|
-
def to_c_yield(tree)
|
720
|
-
|
721
|
-
block_code = proc { |name| "
|
722
|
-
static VALUE #{name}(VALUE frame_param, VALUE* block_args) {
|
723
|
-
|
724
|
-
#{@locals_struct} *plocals;
|
725
|
-
#{@frame_struct} *pframe;
|
726
|
-
pframe = (void*)frame_param;
|
727
|
-
plocals = (void*)pframe->plocals;
|
728
|
-
|
729
|
-
if (FIX2LONG(plocals->block_function_address) == 0) {
|
730
|
-
#{_raise("rb_eLocalJumpError", "no block given")};
|
731
|
-
} else {
|
732
|
-
return ((VALUE(*)(int,VALUE*,VALUE,VALUE))FIX2LONG(plocals->block_function_address))(#{tree.size-1}, block_args, FIX2LONG(plocals->block_function_param), (VALUE)pframe);
|
733
|
-
}
|
734
|
-
}
|
735
|
-
"
|
736
|
-
}
|
737
|
-
|
738
|
-
new_yield_signature = tree[1..-1].map{|subtree| infer_type subtree}
|
739
|
-
# merge the new_yield_signature with the new
|
740
|
-
if @yield_signature
|
741
|
-
if new_yield_signature.size == @yield_signature.size
|
742
|
-
(0..new_yield_signature.size-1).each do |i|
|
743
|
-
if @yield_signature[i] != new_yield_signature[i]
|
744
|
-
@yield_signature[i] = nil
|
745
|
-
end
|
746
|
-
end
|
747
|
-
else
|
748
|
-
@yield_signature = new_yield_signature.map{|x| nil}
|
749
|
-
end
|
750
|
-
else
|
751
|
-
@yield_signature = new_yield_signature
|
752
|
-
end
|
753
|
-
|
754
|
-
ret = if tree.size > 1
|
755
|
-
anonymous_function(&block_code)+"((VALUE)pframe, (VALUE[]){#{tree[1..-1].map{|subtree| to_c subtree}.join(",")}})"
|
756
|
-
else
|
757
|
-
anonymous_function(&block_code)+"((VALUE)pframe, (VALUE[]){})"
|
758
|
-
end
|
759
|
-
|
760
|
-
protected_block(ret, false)
|
761
|
-
end
|
762
|
-
|
763
|
-
def to_c_block(tree)
|
764
|
-
|
765
|
-
str = ""
|
766
|
-
str = tree[1..-2].map{ |subtree|
|
767
|
-
to_c(subtree)
|
768
|
-
}.join(";")
|
769
|
-
|
770
|
-
if tree[-1]
|
771
|
-
|
772
|
-
if tree[-1][0] != :return
|
773
|
-
str = str + ";last_expression = #{to_c(tree[-1])};"
|
774
|
-
else
|
775
|
-
str = str + ";#{to_c(tree[-1])};"
|
776
|
-
end
|
777
|
-
end
|
778
|
-
|
779
|
-
str << "return last_expression;"
|
780
|
-
|
781
|
-
inline_block str
|
782
|
-
end
|
783
|
-
|
784
|
-
def to_c_cvar(tree)
|
785
|
-
"rb_cvar_get(CLASS_OF(plocals->self) != rb_cClass ? CLASS_OF(plocals->self) : plocals->self,#{intern_num tree[1]})"
|
786
|
-
end
|
787
|
-
|
788
|
-
def to_c_cvasgn(tree)
|
789
|
-
"__rb_cvar_set(CLASS_OF(plocals->self) != rb_cClass ? CLASS_OF(plocals->self) : plocals->self,#{intern_num tree[1]},#{to_c tree[2]},Qfalse)"
|
790
|
-
end
|
791
|
-
|
792
|
-
def to_c_return(tree)
|
793
|
-
inline_block "
|
794
|
-
plocals->return_value = #{to_c(tree[1])};
|
795
|
-
((typeof(pframe))FIX2LONG(plocals->pframe))->targetted = 1;
|
796
|
-
longjmp(pframe->jmp, FASTRUBY_TAG_RETURN);
|
797
|
-
return Qnil;
|
798
|
-
"
|
799
|
-
end
|
800
|
-
|
801
|
-
def to_c_break(tree)
|
802
|
-
inline_block(
|
803
|
-
"
|
804
|
-
|
805
|
-
VALUE value = #{tree[1] ? to_c(tree[1]) : "Qnil"};
|
806
|
-
|
807
|
-
typeof(pframe) target_frame_;
|
808
|
-
target_frame_ = (void*)FIX2LONG(plocals->call_frame);
|
809
|
-
|
810
|
-
if (target_frame_ == 0) {
|
811
|
-
#{_raise("rb_eLocalJumpError","illegal break")};
|
812
|
-
}
|
813
|
-
|
814
|
-
plocals->call_frame = LONG2FIX(0);
|
815
|
-
|
816
|
-
target_frame_->return_value = value;
|
817
|
-
target_frame_->targetted = 1;
|
818
|
-
pframe->thread_data->exception = Qnil;
|
819
|
-
longjmp(pframe->jmp,FASTRUBY_TAG_BREAK);"
|
820
|
-
)
|
821
|
-
end
|
822
|
-
|
823
|
-
def to_c_retry(tree)
|
824
|
-
inline_block(
|
825
|
-
"
|
826
|
-
typeof(pframe) target_frame_;
|
827
|
-
target_frame_ = (void*)FIX2LONG(plocals->call_frame);
|
828
|
-
|
829
|
-
if (target_frame_ == 0) {
|
830
|
-
#{_raise("rb_eLocalJumpError","illegal retry")};
|
831
|
-
}
|
832
|
-
|
833
|
-
target_frame_->targetted = 1;
|
834
|
-
longjmp(pframe->jmp,FASTRUBY_TAG_RETRY);"
|
835
|
-
)
|
836
|
-
end
|
837
|
-
|
838
|
-
def to_c_redo(tree)
|
839
|
-
if @on_block
|
840
|
-
inline_block "
|
841
|
-
longjmp(pframe->jmp,FASTRUBY_TAG_REDO);
|
842
|
-
return Qnil;
|
843
|
-
"
|
844
|
-
else
|
845
|
-
_raise("rb_eLocalJumpError","illegal redo");
|
846
|
-
end
|
847
|
-
end
|
848
|
-
|
849
|
-
def to_c_next(tree)
|
850
|
-
if @on_block
|
851
|
-
inline_block "
|
852
|
-
pframe->thread_data->accumulator = #{tree[1] ? to_c(tree[1]) : "Qnil"};
|
853
|
-
longjmp(pframe->jmp,FASTRUBY_TAG_NEXT);
|
854
|
-
return Qnil;
|
855
|
-
"
|
856
|
-
else
|
857
|
-
_raise("rb_eLocalJumpError","illegal next");
|
858
|
-
end
|
859
|
-
end
|
860
|
-
|
861
|
-
def to_c_lit(tree)
|
862
|
-
literal_value tree[1]
|
863
|
-
end
|
864
|
-
|
865
|
-
def to_c_nil(tree)
|
866
|
-
"Qnil"
|
867
|
-
end
|
868
|
-
|
869
|
-
def to_c_str(tree)
|
870
|
-
literal_value tree[1]
|
871
|
-
end
|
872
|
-
|
873
|
-
def to_c_hash(tree)
|
874
|
-
|
875
|
-
hash_aset_code = ""
|
876
|
-
(0..(tree.size-3)/2).each do |i|
|
877
|
-
strkey = to_c tree[1 + i * 2]
|
878
|
-
strvalue = to_c tree[2 + i * 2]
|
879
|
-
hash_aset_code << "rb_hash_aset(hash, #{strkey}, #{strvalue});"
|
880
|
-
end
|
881
|
-
|
882
|
-
anonymous_function{ |name| "
|
883
|
-
static VALUE #{name}(VALUE value_params) {
|
884
|
-
#{@frame_struct} *pframe;
|
885
|
-
#{@locals_struct} *plocals;
|
886
|
-
pframe = (void*)value_params;
|
887
|
-
plocals = (void*)pframe->plocals;
|
888
|
-
|
889
|
-
VALUE hash = rb_hash_new();
|
890
|
-
#{hash_aset_code}
|
891
|
-
return hash;
|
892
|
-
}
|
893
|
-
" } + "((VALUE)pframe)"
|
894
|
-
end
|
895
|
-
|
896
|
-
def to_c_array(tree)
|
897
|
-
if tree.size > 1
|
898
|
-
strargs = tree[1..-1].map{|subtree| to_c subtree}.join(",")
|
899
|
-
"rb_ary_new3(#{tree.size-1}, #{strargs})"
|
900
|
-
else
|
901
|
-
"rb_ary_new3(0)"
|
902
|
-
end
|
903
|
-
end
|
904
|
-
|
905
|
-
def to_c_scope(tree)
|
906
|
-
if tree[1]
|
907
|
-
to_c(tree[1])
|
908
|
-
else
|
909
|
-
"Qnil"
|
910
|
-
end
|
911
|
-
end
|
912
|
-
|
913
|
-
def to_c_cdecl(tree)
|
914
|
-
if tree[1].instance_of? Symbol
|
915
|
-
inline_block "
|
916
|
-
// set constant #{tree[1].to_s}
|
917
|
-
VALUE val = #{to_c tree[2]};
|
918
|
-
rb_const_set(rb_cObject, #{intern_num tree[1]}, val);
|
919
|
-
return val;
|
920
|
-
"
|
921
|
-
elsif tree[1].instance_of? FastRuby::FastRubySexp
|
922
|
-
|
923
|
-
if tree[1].node_type == :colon2
|
924
|
-
inline_block "
|
925
|
-
// set constant #{tree[1].to_s}
|
926
|
-
VALUE val = #{to_c tree[2]};
|
927
|
-
VALUE klass = #{to_c tree[1][1]};
|
928
|
-
rb_const_set(klass, #{intern_num tree[1][2]}, val);
|
929
|
-
return val;
|
930
|
-
"
|
931
|
-
elsif tree[1].node_type == :colon3
|
932
|
-
inline_block "
|
933
|
-
// set constant #{tree[1].to_s}
|
934
|
-
VALUE val = #{to_c tree[2]};
|
935
|
-
rb_const_set(rb_cObject, #{intern_num tree[1][1]}, val);
|
936
|
-
return val;
|
937
|
-
"
|
938
|
-
end
|
939
|
-
end
|
940
|
-
end
|
941
|
-
|
942
|
-
def to_c_case(tree)
|
943
|
-
|
944
|
-
tmpvarname = "tmp" + rand(1000000).to_s;
|
945
|
-
|
946
|
-
code = tree[2..-2].map{|subtree|
|
947
|
-
|
948
|
-
# this subtree is a when
|
949
|
-
subtree[1][1..-1].map{|subsubtree|
|
950
|
-
c_calltree = s(:call, nil, :inline_c, s(:arglist, s(:str, tmpvarname), s(:false)))
|
951
|
-
calltree = s(:call, subsubtree, :===, s(:arglist, c_calltree))
|
952
|
-
"
|
953
|
-
if (RTEST(#{to_c_call(calltree, tmpvarname)})) {
|
954
|
-
return #{to_c(subtree[2])};
|
955
|
-
}
|
956
|
-
|
957
|
-
"
|
958
|
-
}.join("\n")
|
959
|
-
|
960
|
-
}.join("\n")
|
961
|
-
|
962
|
-
inline_block "
|
963
|
-
|
964
|
-
VALUE #{tmpvarname} = #{to_c tree[1]};
|
965
|
-
|
966
|
-
#{code};
|
967
|
-
|
968
|
-
return #{to_c tree[-1]};
|
969
|
-
"
|
970
|
-
end
|
971
|
-
|
972
|
-
def to_c_const(tree)
|
973
|
-
"rb_const_get(CLASS_OF(plocals->self), #{intern_num(tree[1])})"
|
974
|
-
end
|
975
|
-
|
976
|
-
def to_c_defn(tree)
|
977
|
-
|
978
|
-
method_name = tree[1]
|
979
|
-
args_tree = tree[2]
|
980
|
-
|
981
|
-
global_klass_variable = add_global_name("VALUE", "Qnil");
|
982
|
-
|
983
|
-
hash = Hash.new
|
984
|
-
value_cast = ( ["VALUE"]*(args_tree.size+2) ).join(",")
|
985
|
-
|
986
|
-
strmethodargs = ""
|
987
|
-
strmethodargs_class = (["self"] + args_tree[1..-1]).map{|arg| "CLASS_OF(#{arg.to_s})"}.join(",")
|
988
|
-
|
989
|
-
if args_tree.size > 1
|
990
|
-
strmethodargs = "self,block,(VALUE)&frame,#{args_tree[1..-1].map(&:to_s).join(",") }"
|
991
|
-
else
|
992
|
-
strmethodargs = "self,block,(VALUE)&frame"
|
993
|
-
end
|
994
|
-
|
995
|
-
strmethod_signature = (["self"] + args_tree[1..-1]).map { |arg|
|
996
|
-
"sprintf(method_name+strlen(method_name), \"%lu\", FIX2LONG(rb_obj_id(CLASS_OF(#{arg}))));\n"
|
997
|
-
}.join
|
998
|
-
|
999
|
-
anonymous_method_name = anonymous_function{ |anonymous_method_name| "VALUE #{anonymous_method_name}(#{(["self"]+args_tree[1..-1]).map{|arg| "VALUE #{arg}" }.join(",")}) {
|
1000
|
-
|
1001
|
-
VALUE klass = #{global_klass_variable};
|
1002
|
-
char method_name[0x100];
|
1003
|
-
|
1004
|
-
method_name[0] = '_';
|
1005
|
-
method_name[1] = 0;
|
1006
|
-
|
1007
|
-
sprintf(method_name+1, \"#{method_name}\");
|
1008
|
-
#{strmethod_signature}
|
1009
|
-
|
1010
|
-
NODE* body;
|
1011
|
-
ID id;
|
1012
|
-
|
1013
|
-
id = rb_intern(method_name);
|
1014
|
-
body = rb_method_node(klass,id);
|
1015
|
-
|
1016
|
-
if (body == 0) {
|
1017
|
-
VALUE argv_class[] = {#{strmethodargs_class} };
|
1018
|
-
VALUE signature = rb_ary_new4(#{args_tree.size},argv_class);
|
1019
|
-
|
1020
|
-
VALUE mobject = rb_funcall(#{global_klass_variable}, #{intern_num :build}, 2, signature,rb_str_new2(#{method_name.to_s.inspect}));
|
1021
|
-
|
1022
|
-
struct METHOD {
|
1023
|
-
VALUE klass, rklass;
|
1024
|
-
VALUE recv;
|
1025
|
-
ID id, oid;
|
1026
|
-
int safe_level;
|
1027
|
-
NODE *body;
|
1028
|
-
};
|
1029
|
-
|
1030
|
-
struct METHOD *data;
|
1031
|
-
Data_Get_Struct(mobject, struct METHOD, data);
|
1032
|
-
body = data->body;
|
1033
|
-
|
1034
|
-
if (body == 0) {
|
1035
|
-
rb_raise(rb_eRuntimeError,\"method not found after build: '%s'\", method_name);
|
1036
|
-
}
|
1037
|
-
}
|
1038
|
-
|
1039
|
-
if (nd_type(body) == NODE_CFUNC) {
|
1040
|
-
struct {
|
1041
|
-
void* parent_frame;
|
1042
|
-
void* plocals;
|
1043
|
-
jmp_buf jmp;
|
1044
|
-
VALUE return_value;
|
1045
|
-
int rescue;
|
1046
|
-
VALUE last_error;
|
1047
|
-
VALUE next_recv;
|
1048
|
-
int targetted;
|
1049
|
-
struct FASTRUBYTHREADDATA* thread_data;
|
1050
|
-
} frame;
|
1051
|
-
|
1052
|
-
frame.parent_frame = 0;
|
1053
|
-
frame.rescue = 0;
|
1054
|
-
frame.return_value = Qnil;
|
1055
|
-
frame.thread_data = rb_current_thread_data();
|
1056
|
-
frame.targetted = 0;
|
1057
|
-
|
1058
|
-
int argc = body->nd_argc;
|
1059
|
-
|
1060
|
-
VALUE block = Qfalse;
|
1061
|
-
|
1062
|
-
if (rb_block_given_p()) {
|
1063
|
-
struct {
|
1064
|
-
void *block_function_address;
|
1065
|
-
void *block_function_param;
|
1066
|
-
} block_struct;
|
1067
|
-
|
1068
|
-
block_struct.block_function_address = re_yield;
|
1069
|
-
block_struct.block_function_param = 0;
|
1070
|
-
|
1071
|
-
block = (VALUE)&block_struct;
|
1072
|
-
}
|
1073
|
-
|
1074
|
-
int aux = setjmp(frame.jmp);
|
1075
|
-
if (aux != 0) {
|
1076
|
-
if (aux == FASTRUBY_TAG_RAISE) {
|
1077
|
-
rb_funcall(self, #{intern_num :raise}, 1, frame.thread_data->exception);
|
1078
|
-
}
|
1079
|
-
|
1080
|
-
if (frame.targetted == 0) {
|
1081
|
-
rb_jump_tag(aux);
|
1082
|
-
}
|
1083
|
-
|
1084
|
-
return Qnil;
|
1085
|
-
}
|
1086
|
-
|
1087
|
-
if (argc == #{args_tree.size+1}) {
|
1088
|
-
return ((VALUE(*)(#{value_cast}))body->nd_cfnc)(#{strmethodargs});
|
1089
|
-
} else if (argc == -1) {
|
1090
|
-
VALUE argv[] = {#{(["block,(VALUE)&frame"]+args_tree[1..-1]).map(&:to_s).join(",")} };
|
1091
|
-
return ((VALUE(*)(int,VALUE*,VALUE))body->nd_cfnc)(#{args_tree.size},argv,self);
|
1092
|
-
} else if (argc == -2) {
|
1093
|
-
VALUE argv[] = {#{(["block,(VALUE)&frame"]+args_tree[1..-1]).map(&:to_s).join(",")} };
|
1094
|
-
return ((VALUE(*)(VALUE,VALUE))body->nd_cfnc)(self, rb_ary_new4(#{args_tree.size},argv));
|
1095
|
-
} else {
|
1096
|
-
rb_raise(rb_eArgError, \"wrong number of arguments (#{args_tree.size-1} for %d)\", argc);
|
1097
|
-
}
|
1098
|
-
}
|
1099
|
-
|
1100
|
-
return Qnil;
|
1101
|
-
}"
|
1102
|
-
}
|
1103
|
-
|
1104
|
-
alt_options = options.dup
|
1105
|
-
|
1106
|
-
alt_options.delete(:self)
|
1107
|
-
alt_options.delete(:main)
|
1108
|
-
|
1109
|
-
inline_block "
|
1110
|
-
#{global_klass_variable} = plocals->self;
|
1111
|
-
|
1112
|
-
// set tree
|
1113
|
-
rb_funcall(#{literal_value FastRuby}, #{intern_num :set_tree}, 5,
|
1114
|
-
#{global_klass_variable},
|
1115
|
-
rb_str_new2(#{method_name.to_s.inspect}),
|
1116
|
-
#{literal_value tree},
|
1117
|
-
#{literal_value snippet_hash},
|
1118
|
-
#{literal_value alt_options}
|
1119
|
-
|
1120
|
-
);
|
1121
|
-
|
1122
|
-
rb_define_method(plocals->self, #{method_name.to_s.inspect}, #{anonymous_method_name}, #{args_tree.size-1} );
|
1123
|
-
"
|
1124
|
-
|
1125
|
-
end
|
1126
|
-
|
1127
|
-
def to_c_defs(tree)
|
1128
|
-
args_tree = tree[3];
|
1129
|
-
|
1130
|
-
tmp = FastRuby.build_defs(tree)
|
1131
|
-
|
1132
|
-
extra_code << tmp[0]
|
1133
|
-
@init_extra = @init_extra + tmp[2]
|
1134
|
-
|
1135
|
-
inline_block "
|
1136
|
-
rb_define_singleton_method(#{to_c tree[1]}, \"#{tree[2].to_s}\", (void*)#{tmp[1]}, #{args_tree.size-1});
|
1137
|
-
return Qnil;
|
1138
|
-
"
|
1139
|
-
end
|
1140
|
-
|
1141
|
-
def to_c_defined(tree)
|
1142
|
-
nt = tree[1].node_type
|
1143
|
-
|
1144
|
-
if nt == :self
|
1145
|
-
'rb_str_new2("self")'
|
1146
|
-
elsif nt == :true
|
1147
|
-
'rb_str_new2("true")'
|
1148
|
-
elsif nt == :false
|
1149
|
-
'rb_str_new2("false")'
|
1150
|
-
elsif nt == :nil
|
1151
|
-
'rb_str_new2("nil")'
|
1152
|
-
elsif nt == :lvar
|
1153
|
-
'rb_str_new2("local-variable")'
|
1154
|
-
elsif nt == :gvar
|
1155
|
-
"rb_gvar_defined((struct global_entry*)#{global_entry(tree[1][1])}) ? #{literal_value "global-variable"} : Qnil"
|
1156
|
-
elsif nt == :const
|
1157
|
-
"rb_const_defined(rb_cObject, #{intern_num tree[1][1]}) ? #{literal_value "constant"} : Qnil"
|
1158
|
-
elsif nt == :call
|
1159
|
-
"rb_method_node(CLASS_OF(#{to_c tree[1][1]}), #{intern_num tree[1][2]}) ? #{literal_value "method"} : Qnil"
|
1160
|
-
elsif nt == :yield
|
1161
|
-
"rb_block_given_p() ? #{literal_value "yield"} : Qnil"
|
1162
|
-
elsif nt == :ivar
|
1163
|
-
"rb_ivar_defined(plocals->self,#{intern_num tree[1][1]}) ? #{literal_value "instance-variable"} : Qnil"
|
1164
|
-
elsif nt == :attrset or
|
1165
|
-
nt == :op_asgn1 or
|
1166
|
-
nt == :op_asgn2 or
|
1167
|
-
nt == :op_asgn_or or
|
1168
|
-
nt == :op_asgn_and or
|
1169
|
-
nt == :op_asgn_masgn or
|
1170
|
-
nt == :masgn or
|
1171
|
-
nt == :lasgn or
|
1172
|
-
nt == :dasgn or
|
1173
|
-
nt == :dasgn_curr or
|
1174
|
-
nt == :gasgn or
|
1175
|
-
nt == :iasgn or
|
1176
|
-
nt == :cdecl or
|
1177
|
-
nt == :cvdecl or
|
1178
|
-
nt == :cvasgn
|
1179
|
-
literal_value "assignment"
|
1180
|
-
else
|
1181
|
-
literal_value "expression"
|
1182
|
-
end
|
1183
|
-
end
|
1184
|
-
|
1185
|
-
def initialize_method_structs(args_tree)
|
1186
|
-
@locals_struct = "struct {
|
1187
|
-
VALUE return_value;
|
1188
|
-
VALUE pframe;
|
1189
|
-
VALUE block_function_address;
|
1190
|
-
VALUE block_function_param;
|
1191
|
-
VALUE call_frame;
|
1192
|
-
VALUE active;
|
1193
|
-
#{@locals.map{|l| "VALUE #{l};\n"}.join}
|
1194
|
-
#{args_tree[1..-1].map{|arg| "VALUE #{arg};\n"}.join};
|
1195
|
-
}"
|
1196
|
-
|
1197
|
-
end
|
1198
|
-
|
1199
|
-
def to_c_method_defs(tree)
|
1200
|
-
|
1201
|
-
method_name = tree[2]
|
1202
|
-
args_tree = tree[3]
|
1203
|
-
|
1204
|
-
impl_tree = tree[4][1]
|
1205
|
-
|
1206
|
-
initialize_method_structs(args_tree)
|
1207
|
-
|
1208
|
-
strargs = if args_tree.size > 1
|
1209
|
-
"VALUE self, void* block_address, VALUE block_param, void* _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
|
1210
|
-
else
|
1211
|
-
"VALUE self, void* block_address, VALUE block_param, void* _parent_frame"
|
1212
|
-
end
|
1213
|
-
|
1214
|
-
extra_code << "static VALUE #{@alt_method_name + "_real"}(#{strargs}) {
|
1215
|
-
#{func_frame}
|
1216
|
-
|
1217
|
-
#{args_tree[1..-1].map { |arg|
|
1218
|
-
"plocals->#{arg} = #{arg};\n"
|
1219
|
-
}.join("") }
|
1220
|
-
|
1221
|
-
plocals->block_function_address = LONG2FIX(block_address);
|
1222
|
-
plocals->block_function_param = LONG2FIX(block_param);
|
1223
|
-
|
1224
|
-
return #{to_c impl_tree};
|
1225
|
-
}"
|
1226
|
-
|
1227
|
-
strargs2 = if args_tree.size > 1
|
1228
|
-
"VALUE self, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
|
1229
|
-
else
|
1230
|
-
"VALUE self"
|
1231
|
-
end
|
1232
|
-
|
1233
|
-
value_cast = ( ["VALUE"]*(args_tree.size+1) ).join(",")
|
1234
|
-
strmethodargs = ""
|
1235
|
-
|
1236
|
-
if args_tree.size > 1
|
1237
|
-
strmethodargs = "self,block_address,block_param,&frame,#{args_tree[1..-1].map(&:to_s).join(",") }"
|
1238
|
-
else
|
1239
|
-
strmethodargs = "self,block_address,block_param,&frame"
|
1240
|
-
end
|
1241
|
-
|
1242
|
-
"
|
1243
|
-
VALUE #{@alt_method_name}(#{strargs2}) {
|
1244
|
-
#{@frame_struct} frame;
|
1245
|
-
int argc = #{args_tree.size};
|
1246
|
-
void* block_address = 0;
|
1247
|
-
VALUE block_param = Qnil;
|
1248
|
-
|
1249
|
-
frame.plocals = 0;
|
1250
|
-
frame.parent_frame = 0;
|
1251
|
-
frame.return_value = Qnil;
|
1252
|
-
frame.rescue = 0;
|
1253
|
-
frame.targetted = 0;
|
1254
|
-
frame.thread_data = rb_current_thread_data();
|
1255
|
-
|
1256
|
-
if (rb_block_given_p()) {
|
1257
|
-
block_address = #{
|
1258
|
-
anonymous_function{|name|
|
1259
|
-
"static VALUE #{name}(int argc, VALUE* argv, VALUE param) {
|
1260
|
-
return rb_yield_splat(rb_ary_new4(argc,argv));
|
1261
|
-
}"
|
1262
|
-
}
|
1263
|
-
};
|
1264
|
-
|
1265
|
-
block_param = 0;
|
1266
|
-
}
|
1267
|
-
|
1268
|
-
int aux = setjmp(frame.jmp);
|
1269
|
-
if (aux != 0) {
|
1270
|
-
rb_funcall(self, #{intern_num :raise}, 1, frame.thread_data->exception);
|
1271
|
-
}
|
1272
|
-
|
1273
|
-
|
1274
|
-
return #{@alt_method_name + "_real"}(#{strmethodargs});
|
1275
|
-
}
|
1276
|
-
"
|
1277
|
-
end
|
1278
|
-
|
1279
|
-
def add_main
|
1280
|
-
if options[:main]
|
1281
|
-
|
1282
|
-
extra_code << "
|
1283
|
-
static VALUE #{@alt_method_name}(VALUE self__);
|
1284
|
-
static VALUE main_proc_call(VALUE self__, VALUE class_self_) {
|
1285
|
-
#{@alt_method_name}(class_self_);
|
1286
|
-
return Qnil;
|
1287
|
-
}
|
1288
|
-
|
1289
|
-
"
|
1290
|
-
|
1291
|
-
init_extra << "
|
1292
|
-
{
|
1293
|
-
VALUE newproc = rb_funcall(rb_cObject,#{intern_num :new},0);
|
1294
|
-
rb_define_singleton_method(newproc, \"call\", main_proc_call, 1);
|
1295
|
-
rb_gv_set(\"$last_obj_proc\", newproc);
|
1296
|
-
|
1297
|
-
}
|
1298
|
-
"
|
1299
|
-
end
|
1300
|
-
end
|
1301
|
-
|
1302
|
-
def define_method_at_init(klass,method_name, size, signature)
|
1303
|
-
init_extra << "
|
1304
|
-
{
|
1305
|
-
VALUE method_name = rb_funcall(
|
1306
|
-
#{literal_value FastRuby},
|
1307
|
-
#{intern_num :make_str_signature},
|
1308
|
-
2,
|
1309
|
-
#{literal_value method_name},
|
1310
|
-
#{literal_value signature}
|
1311
|
-
);
|
1312
|
-
|
1313
|
-
rb_define_method(#{literal_value klass}, RSTRING(method_name)->ptr, #{alt_method_name}, #{size});
|
1314
|
-
}
|
1315
|
-
"
|
1316
|
-
end
|
1317
|
-
|
1318
|
-
def to_c_method(tree)
|
1319
|
-
method_name = tree[1]
|
1320
|
-
args_tree = tree[2]
|
1321
|
-
impl_tree = tree[3][1]
|
1322
|
-
|
1323
|
-
if (options[:main])
|
1324
|
-
initialize_method_structs(args_tree)
|
1325
|
-
|
1326
|
-
strargs = if args_tree.size > 1
|
1327
|
-
"VALUE block, VALUE _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
|
1328
|
-
else
|
1329
|
-
"VALUE block, VALUE _parent_frame"
|
1330
|
-
end
|
1331
|
-
|
1332
|
-
ret = "VALUE #{@alt_method_name || method_name}() {
|
1333
|
-
|
1334
|
-
#{@locals_struct} *plocals;
|
1335
|
-
#{@frame_struct} frame;
|
1336
|
-
#{@frame_struct} *pframe;
|
1337
|
-
|
1338
|
-
frame.parent_frame = 0;
|
1339
|
-
frame.return_value = Qnil;
|
1340
|
-
frame.rescue = 0;
|
1341
|
-
frame.targetted = 0;
|
1342
|
-
frame.thread_data = rb_current_thread_data();
|
1343
|
-
|
1344
|
-
|
1345
|
-
int stack_chunk_instantiated = 0;
|
1346
|
-
VALUE rb_previous_stack_chunk = Qnil;
|
1347
|
-
VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
|
1348
|
-
struct STACKCHUNK* stack_chunk = 0;
|
1349
|
-
|
1350
|
-
if (rb_stack_chunk != Qnil) {
|
1351
|
-
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
1352
|
-
}
|
1353
|
-
|
1354
|
-
if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
|
1355
|
-
rb_previous_stack_chunk = rb_stack_chunk;
|
1356
|
-
rb_gc_register_address(&rb_stack_chunk);
|
1357
|
-
stack_chunk_instantiated = 1;
|
1358
|
-
|
1359
|
-
rb_stack_chunk = rb_stack_chunk_create(Qnil);
|
1360
|
-
frame.thread_data->rb_stack_chunk = rb_stack_chunk;
|
1361
|
-
|
1362
|
-
rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
|
1363
|
-
|
1364
|
-
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
1365
|
-
}
|
1366
|
-
|
1367
|
-
int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
|
1368
|
-
|
1369
|
-
plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
|
1370
|
-
plocals->active = Qtrue;
|
1371
|
-
plocals->pframe = LONG2FIX(&frame);
|
1372
|
-
frame.plocals = plocals;
|
1373
|
-
|
1374
|
-
pframe = (void*)&frame;
|
1375
|
-
|
1376
|
-
VALUE last_expression = Qnil;
|
1377
|
-
|
1378
|
-
int aux = setjmp(pframe->jmp);
|
1379
|
-
if (aux != 0) {
|
1380
|
-
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
1381
|
-
|
1382
|
-
if (stack_chunk_instantiated) {
|
1383
|
-
rb_gc_unregister_address(&rb_stack_chunk);
|
1384
|
-
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
1385
|
-
}
|
1386
|
-
|
1387
|
-
plocals->active = Qfalse;
|
1388
|
-
return plocals->return_value;
|
1389
|
-
}
|
1390
|
-
|
1391
|
-
plocals->self = self;
|
1392
|
-
|
1393
|
-
#{args_tree[1..-1].map { |arg|
|
1394
|
-
"plocals->#{arg} = #{arg};\n"
|
1395
|
-
}.join("") }
|
1396
|
-
|
1397
|
-
plocals->block_function_address = LONG2FIX(0);
|
1398
|
-
plocals->block_function_param = LONG2FIX(Qnil);
|
1399
|
-
plocals->call_frame = LONG2FIX(0);
|
1400
|
-
|
1401
|
-
VALUE ret = #{to_c impl_tree};
|
1402
|
-
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
1403
|
-
|
1404
|
-
if (stack_chunk_instantiated) {
|
1405
|
-
rb_gc_unregister_address(&rb_stack_chunk);
|
1406
|
-
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
1407
|
-
}
|
1408
|
-
|
1409
|
-
plocals->active = Qfalse;
|
1410
|
-
return ret;
|
1411
|
-
|
1412
|
-
}"
|
1413
|
-
|
1414
|
-
add_main
|
1415
|
-
ret
|
1416
|
-
else
|
1417
|
-
|
1418
|
-
initialize_method_structs(args_tree)
|
1419
|
-
|
1420
|
-
strargs = if args_tree.size > 1
|
1421
|
-
"VALUE block, VALUE _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
|
1422
|
-
else
|
1423
|
-
"VALUE block, VALUE _parent_frame"
|
1424
|
-
end
|
1425
|
-
|
1426
|
-
ret = "VALUE #{@alt_method_name || method_name}(#{strargs}) {
|
1427
|
-
|
1428
|
-
#{@frame_struct} frame;
|
1429
|
-
#{@frame_struct} *pframe;
|
1430
|
-
|
1431
|
-
frame.parent_frame = (void*)_parent_frame;
|
1432
|
-
frame.return_value = Qnil;
|
1433
|
-
frame.rescue = 0;
|
1434
|
-
frame.targetted = 0;
|
1435
|
-
frame.thread_data = ((typeof(pframe))_parent_frame)->thread_data;
|
1436
|
-
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
1437
|
-
|
1438
|
-
int stack_chunk_instantiated = 0;
|
1439
|
-
VALUE rb_previous_stack_chunk = Qnil;
|
1440
|
-
VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
|
1441
|
-
struct STACKCHUNK* stack_chunk = 0;
|
1442
|
-
|
1443
|
-
if (rb_stack_chunk != Qnil) {
|
1444
|
-
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
1445
|
-
}
|
1446
|
-
|
1447
|
-
if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
|
1448
|
-
rb_previous_stack_chunk = rb_stack_chunk;
|
1449
|
-
rb_gc_register_address(&rb_stack_chunk);
|
1450
|
-
stack_chunk_instantiated = 1;
|
1451
|
-
|
1452
|
-
rb_stack_chunk = rb_stack_chunk_create(Qnil);
|
1453
|
-
frame.thread_data->rb_stack_chunk = rb_stack_chunk;
|
1454
|
-
|
1455
|
-
rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
|
1456
|
-
|
1457
|
-
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
1458
|
-
}
|
1459
|
-
|
1460
|
-
|
1461
|
-
#{@locals_struct} *plocals;
|
1462
|
-
|
1463
|
-
int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
|
1464
|
-
|
1465
|
-
plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
|
1466
|
-
frame.plocals = plocals;
|
1467
|
-
plocals->active = Qtrue;
|
1468
|
-
plocals->pframe = LONG2FIX(&frame);
|
1469
|
-
plocals->call_frame = LONG2FIX(0);
|
1470
|
-
|
1471
|
-
pframe = (void*)&frame;
|
1472
|
-
|
1473
|
-
#{@block_struct} *pblock;
|
1474
|
-
VALUE last_expression = Qnil;
|
1475
|
-
|
1476
|
-
int aux = setjmp(pframe->jmp);
|
1477
|
-
if (aux != 0) {
|
1478
|
-
plocals->active = Qfalse;
|
1479
|
-
|
1480
|
-
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
1481
|
-
|
1482
|
-
if (stack_chunk_instantiated) {
|
1483
|
-
rb_gc_unregister_address(&rb_stack_chunk);
|
1484
|
-
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
1485
|
-
}
|
1486
|
-
|
1487
|
-
if (pframe->targetted == 0) {
|
1488
|
-
longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
|
1489
|
-
}
|
1490
|
-
|
1491
|
-
return plocals->return_value;
|
1492
|
-
}
|
1493
|
-
|
1494
|
-
plocals->self = self;
|
1495
|
-
|
1496
|
-
#{args_tree[1..-1].map { |arg|
|
1497
|
-
"plocals->#{arg} = #{arg};\n"
|
1498
|
-
}.join("") }
|
1499
|
-
|
1500
|
-
pblock = (void*)block;
|
1501
|
-
if (pblock) {
|
1502
|
-
plocals->block_function_address = LONG2FIX(pblock->block_function_address);
|
1503
|
-
plocals->block_function_param = LONG2FIX(pblock->block_function_param);
|
1504
|
-
} else {
|
1505
|
-
plocals->block_function_address = LONG2FIX(0);
|
1506
|
-
plocals->block_function_param = LONG2FIX(Qnil);
|
1507
|
-
}
|
1508
|
-
|
1509
|
-
VALUE __ret = #{to_c impl_tree};
|
1510
|
-
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
1511
|
-
|
1512
|
-
if (stack_chunk_instantiated) {
|
1513
|
-
rb_gc_unregister_address(&rb_stack_chunk);
|
1514
|
-
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
1515
|
-
}
|
1516
|
-
|
1517
|
-
plocals->active = Qfalse;
|
1518
|
-
return __ret;
|
1519
|
-
}"
|
1520
|
-
|
1521
|
-
add_main
|
1522
|
-
ret
|
1523
|
-
end
|
1524
|
-
end
|
1525
|
-
|
1526
|
-
def locals_accessor
|
1527
|
-
"plocals->"
|
1528
|
-
end
|
1529
|
-
|
1530
|
-
def to_c_gvar(tree)
|
1531
|
-
if (tree[1] == :$!)
|
1532
|
-
"pframe->thread_data->exception"
|
1533
|
-
else
|
1534
|
-
"rb_gvar_get((struct global_entry*)#{global_entry(tree[1])})"
|
1535
|
-
end
|
1536
|
-
end
|
1537
|
-
|
1538
|
-
def to_c_gasgn(tree)
|
1539
|
-
"_rb_gvar_set((void*)#{global_entry(tree[1])}, #{to_c tree[2]})"
|
1540
|
-
end
|
1541
|
-
|
1542
|
-
def to_c_ivar(tree)
|
1543
|
-
"rb_ivar_get(#{locals_accessor}self,#{intern_num tree[1]})"
|
1544
|
-
end
|
1545
|
-
|
1546
|
-
def to_c_iasgn(tree)
|
1547
|
-
"_rb_ivar_set(#{locals_accessor}self,#{intern_num tree[1]},#{to_c tree[2]})"
|
1548
|
-
end
|
1549
|
-
|
1550
|
-
def to_c_colon3(tree)
|
1551
|
-
"rb_const_get_from(rb_cObject, #{intern_num tree[1]})"
|
1552
|
-
end
|
1553
|
-
def to_c_colon2(tree)
|
1554
|
-
inline_block "
|
1555
|
-
VALUE klass = #{to_c tree[1]};
|
1556
|
-
|
1557
|
-
if (rb_is_const_id(#{intern_num tree[2]})) {
|
1558
|
-
switch (TYPE(klass)) {
|
1559
|
-
case T_CLASS:
|
1560
|
-
case T_MODULE:
|
1561
|
-
return rb_const_get_from(klass, #{intern_num tree[2]});
|
1562
|
-
break;
|
1563
|
-
default:
|
1564
|
-
#{_raise("rb_eTypeError","not a class/module")};
|
1565
|
-
break;
|
1566
|
-
}
|
1567
|
-
}
|
1568
|
-
else {
|
1569
|
-
return rb_funcall(klass, #{intern_num tree[2]}, 0, 0);
|
1570
|
-
}
|
1571
|
-
|
1572
|
-
return Qnil;
|
1573
|
-
"
|
1574
|
-
end
|
1575
|
-
|
1576
|
-
def to_c_lasgn(tree)
|
1577
|
-
if options[:validate_lvar_types]
|
1578
|
-
klass = @infer_lvar_map[tree[1]]
|
1579
|
-
if klass
|
1580
|
-
|
1581
|
-
verify_type_function = proc { |name| "
|
1582
|
-
static VALUE #{name}(VALUE arg, void* pframe ) {
|
1583
|
-
if (CLASS_OF(arg)!=#{literal_value klass}) {
|
1584
|
-
#{_raise(literal_value(FastRuby::TypeMismatchAssignmentException), "Illegal assignment at runtime (type mismatch)")};
|
1585
|
-
}
|
1586
|
-
return arg;
|
1587
|
-
}
|
1588
|
-
"
|
1589
|
-
}
|
1590
|
-
|
1591
|
-
|
1592
|
-
"_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(&verify_type_function)}(#{to_c tree[2]},pframe))"
|
1593
|
-
else
|
1594
|
-
"_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
|
1595
|
-
end
|
1596
|
-
else
|
1597
|
-
"_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
|
1598
|
-
end
|
1599
|
-
end
|
1600
|
-
|
1601
|
-
def to_c_lvar(tree)
|
1602
|
-
locals_accessor + tree[1].to_s
|
1603
|
-
end
|
1604
|
-
|
1605
|
-
def to_c_self(tree)
|
1606
|
-
locals_accessor + "self"
|
1607
|
-
end
|
1608
|
-
|
1609
|
-
def to_c_false(tree)
|
1610
|
-
"Qfalse"
|
1611
|
-
end
|
1612
|
-
|
1613
|
-
def to_c_true(tree)
|
1614
|
-
"Qtrue"
|
1615
|
-
end
|
1616
|
-
|
1617
|
-
def to_c_and(tree)
|
1618
|
-
"(RTEST(#{to_c tree[1]}) && RTEST(#{to_c tree[2]})) ? Qtrue : Qfalse"
|
1619
|
-
end
|
1620
|
-
|
1621
|
-
def to_c_or(tree)
|
1622
|
-
"(RTEST(#{to_c tree[1]}) || RTEST(#{to_c tree[2]})) ? Qtrue : Qfalse"
|
1623
|
-
end
|
1624
|
-
|
1625
|
-
def to_c_not(tree)
|
1626
|
-
"RTEST(#{to_c tree[1]}) ? Qfalse : Qtrue"
|
1627
|
-
end
|
1628
|
-
|
1629
|
-
def to_c_if(tree)
|
1630
|
-
condition_tree = tree[1]
|
1631
|
-
impl_tree = tree[2]
|
1632
|
-
else_tree = tree[3]
|
1633
|
-
|
1634
|
-
inline_block "
|
1635
|
-
if (RTEST(#{to_c condition_tree})) {
|
1636
|
-
last_expression = #{to_c impl_tree};
|
1637
|
-
}#{else_tree ?
|
1638
|
-
" else {
|
1639
|
-
last_expression = #{to_c else_tree};
|
1640
|
-
}
|
1641
|
-
" : ""
|
1642
|
-
}
|
1643
|
-
|
1644
|
-
return last_expression;
|
1645
|
-
"
|
1646
|
-
end
|
1647
|
-
|
1648
|
-
def to_c_rescue(tree)
|
1649
|
-
if tree[1][0] == :resbody
|
1650
|
-
else_tree = tree[2]
|
1651
|
-
|
1652
|
-
if else_tree
|
1653
|
-
to_c else_tree
|
1654
|
-
else
|
1655
|
-
"Qnil"
|
1656
|
-
end
|
1657
|
-
else
|
1658
|
-
resbody_tree = tree[2]
|
1659
|
-
else_tree = nil
|
1660
|
-
if tree[-1]
|
1661
|
-
if tree[-1][0] != :resbody
|
1662
|
-
else_tree = tree[-1]
|
1663
|
-
end
|
1664
|
-
end
|
1665
|
-
|
1666
|
-
catch_condition_array = []
|
1667
|
-
lasgn_code = ""
|
1668
|
-
resbody_code = to_c(resbody_tree[2])
|
1669
|
-
|
1670
|
-
rescue_code = ""
|
1671
|
-
|
1672
|
-
tree[1..-1].each do |resbody_tree|
|
1673
|
-
next if resbody_tree[0] != :resbody
|
1674
|
-
|
1675
|
-
if resbody_tree[1].size == 1
|
1676
|
-
resbody_tree[1][1] = [:const, :Exception]
|
1677
|
-
end
|
1678
|
-
|
1679
|
-
if resbody_tree[1].last[0] == :lasgn
|
1680
|
-
lasgn_code = to_c(resbody_tree[1].last)
|
1681
|
-
end
|
1682
|
-
|
1683
|
-
resbody_tree[1][1..-1].each do |xtree|
|
1684
|
-
if xtree[0] != :lasgn
|
1685
|
-
trapcode = "rb_eException";
|
1686
|
-
|
1687
|
-
if xtree
|
1688
|
-
trapcode = to_c(xtree)
|
1689
|
-
end
|
1690
|
-
|
1691
|
-
catch_condition_array << "(rb_obj_is_kind_of(frame.thread_data->exception,#{trapcode}) == Qtrue)"
|
1692
|
-
end
|
1693
|
-
end
|
1694
|
-
|
1695
|
-
rescue_code << "
|
1696
|
-
if (aux == FASTRUBY_TAG_RAISE) {
|
1697
|
-
if (#{catch_condition_array.join(" || ")})
|
1698
|
-
{
|
1699
|
-
// trap exception
|
1700
|
-
frame.targetted = 1;
|
1701
|
-
|
1702
|
-
#{lasgn_code};
|
1703
|
-
|
1704
|
-
#{resbody_code};
|
1705
|
-
}
|
1706
|
-
}
|
1707
|
-
"
|
1708
|
-
end
|
1709
|
-
|
1710
|
-
frame_call(
|
1711
|
-
frame(to_c(tree[1])+";","
|
1712
|
-
#{rescue_code}
|
1713
|
-
", else_tree ? to_c(else_tree) : nil, 1)
|
1714
|
-
|
1715
|
-
)
|
1716
|
-
end
|
1717
|
-
end
|
1718
|
-
|
1719
|
-
def to_c_ensure(tree)
|
1720
|
-
if tree.size == 2
|
1721
|
-
to_c tree[1]
|
1722
|
-
else
|
1723
|
-
ensured_code = to_c tree[2]
|
1724
|
-
inline_block "
|
1725
|
-
#{frame(to_c(tree[1]),ensured_code,ensured_code,1)};
|
1726
|
-
"
|
1727
|
-
end
|
1728
|
-
end
|
1729
|
-
|
1730
|
-
def _raise(class_tree, message_tree = nil)
|
1731
|
-
class_tree = to_c class_tree unless class_tree.instance_of? String
|
1732
|
-
|
1733
|
-
if message_tree.instance_of? String
|
1734
|
-
message_tree = "rb_str_new2(#{message_tree.inspect})"
|
1735
|
-
else
|
1736
|
-
message_tree = to_c message_tree
|
1737
|
-
end
|
1738
|
-
|
1739
|
-
if message_tree
|
1740
|
-
return inline_block("
|
1741
|
-
pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},1,#{message_tree});
|
1742
|
-
longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
|
1743
|
-
return Qnil;
|
1744
|
-
")
|
1745
|
-
else
|
1746
|
-
return inline_block("
|
1747
|
-
pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},0);
|
1748
|
-
longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
|
1749
|
-
return Qnil;
|
1750
|
-
")
|
1751
|
-
end
|
1752
|
-
|
1753
|
-
end
|
1754
|
-
|
1755
|
-
def to_c_call(tree, repass_var = nil)
|
1756
|
-
directive_code = directive(tree)
|
1757
|
-
if directive_code
|
1758
|
-
return directive_code
|
1759
|
-
end
|
1760
|
-
|
1761
|
-
if tree[2] == :require
|
1762
|
-
tree[2] = :fastruby_require
|
1763
|
-
elsif tree[2] == :raise
|
1764
|
-
# raise code
|
1765
|
-
args = tree[3]
|
1766
|
-
return _raise(args[1],args[2])
|
1767
|
-
end
|
1768
|
-
|
1769
|
-
recv = tree[1]
|
1770
|
-
mname = tree[2]
|
1771
|
-
args = tree[3]
|
1772
|
-
|
1773
|
-
mname = :require_fastruby if mname == :require
|
1774
|
-
|
1775
|
-
strargs = args[1..-1].map{|arg| to_c arg}.join(",")
|
1776
|
-
|
1777
|
-
argnum = args.size - 1
|
1778
|
-
|
1779
|
-
recv = recv || s(:self)
|
1780
|
-
|
1781
|
-
recvtype = infer_type(recv)
|
1782
|
-
|
1783
|
-
if recvtype
|
1784
|
-
|
1785
|
-
address = nil
|
1786
|
-
mobject = nil
|
1787
|
-
|
1788
|
-
inference_complete = true
|
1789
|
-
signature = [recvtype]
|
1790
|
-
|
1791
|
-
args[1..-1].each do |arg|
|
1792
|
-
argtype = infer_type(arg)
|
1793
|
-
if argtype
|
1794
|
-
signature << argtype
|
1795
|
-
else
|
1796
|
-
inference_complete = false
|
1797
|
-
end
|
1798
|
-
end
|
1799
|
-
|
1800
|
-
if repass_var
|
1801
|
-
extraargs = ","+repass_var
|
1802
|
-
extraargs_signature = ",VALUE " + repass_var
|
1803
|
-
else
|
1804
|
-
extraargs = ""
|
1805
|
-
extraargs_signature = ""
|
1806
|
-
end
|
1807
|
-
|
1808
|
-
if argnum == 0
|
1809
|
-
value_cast = "VALUE,VALUE,VALUE"
|
1810
|
-
"((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(#{to_c recv}, Qfalse, (VALUE)pframe)"
|
1811
|
-
else
|
1812
|
-
value_cast = ( ["VALUE"]*(args.size) ).join(",") + ",VALUE,VALUE"
|
1813
|
-
"((VALUE(*)(#{value_cast}))#{encode_address(recvtype,signature,mname,tree,inference_complete)})(#{to_c recv}, Qfalse, (VALUE)pframe, #{strargs})"
|
1814
|
-
end
|
1815
|
-
|
1816
|
-
else # else recvtype
|
1817
|
-
if argnum == 0
|
1818
|
-
protected_block("rb_funcall(#{to_c recv}, #{intern_num tree[2]}, 0)", true, repass_var)
|
1819
|
-
else
|
1820
|
-
protected_block("rb_funcall(#{to_c recv}, #{intern_num tree[2]}, #{argnum}, #{strargs} )", true, repass_var)
|
1821
|
-
end
|
1822
|
-
end # if recvtype
|
1823
|
-
end
|
1824
|
-
|
1825
|
-
def get_class_name(argument)
|
1826
|
-
if argument.instance_of? Symbol
|
1827
|
-
argument.to_s
|
1828
|
-
elsif argument.instance_of? FastRuby::FastRubySexp
|
1829
|
-
if argument[0] == :colon3
|
1830
|
-
get_class_name(argument[1])
|
1831
|
-
elsif argument[0] == :colon2
|
1832
|
-
get_class_name(argument[2])
|
1833
|
-
end
|
1834
|
-
end
|
1835
|
-
end
|
1836
|
-
|
1837
|
-
def get_container_tree(argument)
|
1838
|
-
if argument.instance_of? Symbol
|
1839
|
-
s(:self)
|
1840
|
-
elsif argument.instance_of? FastRuby::FastRubySexp
|
1841
|
-
if argument[0] == :colon3
|
1842
|
-
s(:const, :Object)
|
1843
|
-
elsif argument[0] == :colon2
|
1844
|
-
argument[1]
|
1845
|
-
end
|
1846
|
-
end
|
1847
|
-
end
|
1848
|
-
|
1849
|
-
def locals_scope(locals)
|
1850
|
-
old_locals = @locals
|
1851
|
-
old_locals_struct = @locals_struct
|
1852
|
-
|
1853
|
-
@locals = locals
|
1854
|
-
@locals_struct = "struct {
|
1855
|
-
VALUE return_value;
|
1856
|
-
VALUE pframe;
|
1857
|
-
VALUE block_function_address;
|
1858
|
-
VALUE block_function_param;
|
1859
|
-
VALUE call_frame;
|
1860
|
-
VALUE active;
|
1861
|
-
#{@locals.map{|l| "VALUE #{l};\n"}.join}
|
1862
|
-
}"
|
1863
|
-
|
1864
|
-
begin
|
1865
|
-
yield
|
1866
|
-
ensure
|
1867
|
-
@locals = old_locals
|
1868
|
-
@locals_struct = old_locals_struct
|
1869
|
-
end
|
1870
|
-
end
|
1871
|
-
|
1872
|
-
def method_group(init_code, tree)
|
1873
|
-
|
1874
|
-
alt_locals = Set.new
|
1875
|
-
alt_locals << :self
|
1876
|
-
|
1877
|
-
FastRuby::GetLocalsProcessor.get_locals(tree).each do |local|
|
1878
|
-
alt_locals << local
|
1879
|
-
end
|
1880
|
-
|
1881
|
-
fun = nil
|
1882
|
-
|
1883
|
-
locals_scope(alt_locals) do
|
1884
|
-
fun = anonymous_function { |method_name| "static VALUE #{method_name}(VALUE self) {
|
1885
|
-
|
1886
|
-
#{@frame_struct} frame;
|
1887
|
-
typeof(&frame) pframe = &frame;
|
1888
|
-
#{@locals_struct} *plocals;
|
1889
|
-
|
1890
|
-
frame.parent_frame = 0;
|
1891
|
-
frame.return_value = Qnil;
|
1892
|
-
frame.rescue = 0;
|
1893
|
-
frame.targetted = 0;
|
1894
|
-
frame.thread_data = rb_current_thread_data();
|
1895
|
-
|
1896
|
-
int stack_chunk_instantiated = 0;
|
1897
|
-
VALUE rb_previous_stack_chunk = Qnil;
|
1898
|
-
VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
|
1899
|
-
struct STACKCHUNK* stack_chunk = 0;
|
1900
|
-
|
1901
|
-
if (rb_stack_chunk != Qnil) {
|
1902
|
-
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
1903
|
-
}
|
1904
|
-
|
1905
|
-
if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
|
1906
|
-
rb_previous_stack_chunk = rb_stack_chunk;
|
1907
|
-
rb_gc_register_address(&rb_stack_chunk);
|
1908
|
-
stack_chunk_instantiated = 1;
|
1909
|
-
|
1910
|
-
rb_stack_chunk = rb_stack_chunk_create(Qnil);
|
1911
|
-
frame.thread_data->rb_stack_chunk = rb_stack_chunk;
|
1912
|
-
|
1913
|
-
rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
|
1914
|
-
|
1915
|
-
Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
|
1916
|
-
}
|
1917
|
-
|
1918
|
-
int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
|
1919
|
-
|
1920
|
-
plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
|
1921
|
-
|
1922
|
-
frame.plocals = plocals;
|
1923
|
-
plocals->active = Qtrue;
|
1924
|
-
plocals->self = self;
|
1925
|
-
plocals->call_frame = LONG2FIX(0);
|
1926
|
-
|
1927
|
-
#{to_c tree};
|
1928
|
-
|
1929
|
-
stack_chunk_set_current_position(stack_chunk, previous_stack_position);
|
1930
|
-
|
1931
|
-
if (stack_chunk_instantiated) {
|
1932
|
-
rb_gc_unregister_address(&rb_stack_chunk);
|
1933
|
-
frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
|
1934
|
-
}
|
1935
|
-
|
1936
|
-
plocals->active = Qfalse;
|
1937
|
-
return Qnil;
|
1938
|
-
}
|
1939
|
-
"
|
1940
|
-
}
|
1941
|
-
end
|
1942
|
-
|
1943
|
-
inline_block("
|
1944
|
-
#{init_code}
|
1945
|
-
|
1946
|
-
rb_funcall(tmpklass, #{intern_num :__id__},0);
|
1947
|
-
|
1948
|
-
#{fun}(tmpklass);
|
1949
|
-
return Qnil;
|
1950
|
-
|
1951
|
-
|
1952
|
-
")
|
1953
|
-
|
1954
|
-
end
|
1955
|
-
|
1956
|
-
|
1957
|
-
|
1958
|
-
def to_c_class(tree)
|
1959
|
-
str_class_name = get_class_name(tree[1])
|
1960
|
-
container_tree = get_container_tree(tree[1])
|
1961
|
-
|
1962
|
-
if container_tree == s(:self)
|
1963
|
-
method_group("
|
1964
|
-
VALUE tmpklass = rb_define_class(
|
1965
|
-
#{str_class_name.inspect},
|
1966
|
-
#{tree[2] ? to_c(tree[2]) : "rb_cObject"}
|
1967
|
-
);
|
1968
|
-
", tree[3])
|
1969
|
-
else
|
1970
|
-
method_group("
|
1971
|
-
VALUE container_klass = #{to_c(container_tree)};
|
1972
|
-
VALUE tmpklass = rb_define_class_under(
|
1973
|
-
container_klass,
|
1974
|
-
#{str_class_name.inspect},
|
1975
|
-
#{tree[2] ? to_c(tree[2]) : "rb_cObject"}
|
1976
|
-
);
|
1977
|
-
", tree[3])
|
1978
|
-
end
|
1979
|
-
end
|
1980
|
-
|
1981
|
-
def to_c_module(tree)
|
1982
|
-
str_class_name = get_class_name(tree[1])
|
1983
|
-
container_tree = get_container_tree(tree[1])
|
1984
|
-
|
1985
|
-
if container_tree == s(:self)
|
1986
|
-
method_group("
|
1987
|
-
VALUE tmpklass = rb_define_module(#{str_class_name.inspect});
|
1988
|
-
", tree[2])
|
1989
|
-
else
|
1990
|
-
method_group("
|
1991
|
-
VALUE container_klass = #{to_c(container_tree)};
|
1992
|
-
VALUE tmpklass = rb_define_module_under(container_klass,#{str_class_name.inspect});
|
1993
|
-
", tree[2])
|
1994
|
-
end
|
1995
|
-
end
|
1996
|
-
|
1997
|
-
def to_c_for(tree)
|
1998
|
-
alter_tree = tree.dup
|
1999
|
-
alter_tree[0] = :iter
|
2000
|
-
alter_tree[1] = [:call, alter_tree[1], :each, [:arglist]]
|
2001
|
-
to_c alter_tree
|
2002
|
-
end
|
2003
|
-
|
2004
|
-
def to_c_while(tree)
|
2005
|
-
inline_block("
|
2006
|
-
while (#{to_c tree[1]}) {
|
2007
|
-
#{to_c tree[2]};
|
2008
|
-
}
|
2009
|
-
return Qnil;
|
2010
|
-
")
|
2011
|
-
end
|
2012
|
-
|
2013
|
-
def infer_type(recv)
|
2014
|
-
if recv[0] == :call
|
2015
|
-
if recv[2] == :infer
|
2016
|
-
eval(recv[3].last.last.to_s)
|
2017
|
-
end
|
2018
|
-
elsif recv[0] == :lvar
|
2019
|
-
@infer_lvar_map[recv[1]]
|
2020
|
-
elsif recv[0] == :self
|
2021
|
-
@infer_self
|
2022
|
-
elsif recv[0] == :str or recv[0] == :lit
|
2023
|
-
recv[1].class
|
2024
|
-
else
|
2025
|
-
nil
|
2026
|
-
end
|
2027
|
-
end
|
2028
|
-
|
2029
|
-
def on_block
|
2030
|
-
old_on_block = @on_block
|
2031
|
-
@on_block = true
|
2032
|
-
return yield
|
2033
|
-
ensure
|
2034
|
-
@on_block = old_on_block
|
2035
|
-
end
|
2036
|
-
|
2037
|
-
def with_extra_inference(extra_inference)
|
2038
|
-
previous_infer_lvar_map = @infer_lvar_map
|
2039
|
-
begin
|
2040
|
-
@infer_lvar_map = @infer_lvar_map.merge(extra_inference)
|
2041
|
-
yield
|
2042
|
-
ensure
|
2043
|
-
@infer_lvar_map = previous_infer_lvar_map
|
2044
|
-
end
|
2045
|
-
end
|
2046
|
-
|
2047
|
-
def directive(tree)
|
2048
|
-
recv = tree[1]
|
2049
|
-
mname = tree[2]
|
2050
|
-
args = tree[3]
|
2051
|
-
|
2052
|
-
if mname == :infer
|
2053
|
-
return to_c(recv)
|
2054
|
-
elsif mname == :lvar_type
|
2055
|
-
lvar_name = args[1][1] || args[1][2]
|
2056
|
-
lvar_type = eval(args[2][1].to_s)
|
2057
|
-
|
2058
|
-
@infer_lvar_map[lvar_name] = lvar_type
|
2059
|
-
return ""
|
2060
|
-
elsif mname == :block_given?
|
2061
|
-
return "FIX2LONG(plocals->block_function_address) == 0 ? Qfalse : Qtrue"
|
2062
|
-
elsif mname == :inline_c
|
2063
|
-
|
2064
|
-
code = args[1][1]
|
2065
|
-
|
2066
|
-
unless (args[2] == s(:false))
|
2067
|
-
return anonymous_function{ |name| "
|
2068
|
-
static VALUE #{name}(VALUE param) {
|
2069
|
-
#{@frame_struct} *pframe = (void*)param;
|
2070
|
-
#{@locals_struct} *plocals = (void*)pframe->plocals;
|
2071
|
-
#{code};
|
2072
|
-
return Qnil;
|
2073
|
-
}
|
2074
|
-
"
|
2075
|
-
}+"((VALUE)pframe)"
|
2076
|
-
else
|
2077
|
-
code
|
2078
|
-
end
|
2079
|
-
|
2080
|
-
else
|
2081
|
-
nil
|
2082
|
-
end
|
2083
|
-
end
|
2084
|
-
|
2085
|
-
def inline_block_reference(arg, nolocals = false)
|
2086
|
-
code = nil
|
2087
|
-
|
2088
|
-
if arg.instance_of? FastRuby::FastRubySexp
|
2089
|
-
code = to_c(arg);
|
2090
|
-
else
|
2091
|
-
code = arg
|
2092
|
-
end
|
2093
|
-
|
2094
|
-
anonymous_function{ |name| "
|
2095
|
-
static VALUE #{name}(VALUE param) {
|
2096
|
-
#{@frame_struct} *pframe = (void*)param;
|
2097
|
-
|
2098
|
-
#{nolocals ? "" : "#{@locals_struct} *plocals = (void*)pframe->plocals;"}
|
2099
|
-
VALUE last_expression = Qnil;
|
2100
|
-
|
2101
|
-
#{code};
|
2102
|
-
return last_expression;
|
2103
|
-
}
|
2104
|
-
"
|
2105
|
-
}
|
2106
|
-
end
|
2107
|
-
|
2108
|
-
def inline_block(code, repass_var = nil, nolocals = false)
|
2109
|
-
anonymous_function{ |name| "
|
2110
|
-
static VALUE #{name}(VALUE param#{repass_var ? ",void* " + repass_var : "" }) {
|
2111
|
-
#{@frame_struct} *pframe = (void*)param;
|
2112
|
-
|
2113
|
-
#{nolocals ? "" : "#{@locals_struct} *plocals = (void*)pframe->plocals;"}
|
2114
|
-
VALUE last_expression = Qnil;
|
2115
|
-
|
2116
|
-
#{code}
|
2117
|
-
}
|
2118
|
-
"
|
2119
|
-
} + "((VALUE)pframe#{repass_var ? ", " + repass_var : "" })"
|
2120
|
-
end
|
2121
|
-
|
2122
|
-
def inline_ruby(proced, parameter)
|
2123
|
-
"rb_funcall(#{proced.__id__}, #{intern_num :call}, 1, #{parameter})"
|
2124
|
-
end
|
2125
|
-
|
2126
|
-
def protected_block(inner_code, always_rescue = false,repass_var = nil, nolocals = false)
|
2127
|
-
body = nil
|
2128
|
-
rescue_args = nil
|
2129
|
-
if repass_var
|
2130
|
-
body = anonymous_function{ |name| "
|
2131
|
-
static VALUE #{name}(VALUE param) {
|
2132
|
-
|
2133
|
-
#{@frame_struct} frame;
|
2134
|
-
|
2135
|
-
typeof(frame)* pframe;
|
2136
|
-
typeof(frame)* parent_frame = ((typeof(pframe))((void**)param)[0]);
|
2137
|
-
|
2138
|
-
frame.parent_frame = 0;
|
2139
|
-
frame.return_value = Qnil;
|
2140
|
-
frame.rescue = 0;
|
2141
|
-
frame.last_error = Qnil;
|
2142
|
-
frame.targetted = 0;
|
2143
|
-
frame.thread_data = parent_frame->thread_data;
|
2144
|
-
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
2145
|
-
|
2146
|
-
pframe = &frame;
|
2147
|
-
|
2148
|
-
#{
|
2149
|
-
nolocals ? "frame.plocals = 0;" : "#{@locals_struct}* plocals = parent_frame->plocals;
|
2150
|
-
frame.plocals = plocals;
|
2151
|
-
"
|
2152
|
-
}
|
2153
|
-
|
2154
|
-
int aux = setjmp(frame.jmp);
|
2155
|
-
if (aux != 0) {
|
2156
|
-
|
2157
|
-
if (frame.targetted == 1) {
|
2158
|
-
return frame.return_value;
|
2159
|
-
} else {
|
2160
|
-
rb_jump_tag(aux);
|
2161
|
-
}
|
2162
|
-
}
|
2163
|
-
|
2164
|
-
VALUE #{repass_var} = (VALUE)((void**)param)[1];
|
2165
|
-
return #{inner_code};
|
2166
|
-
}
|
2167
|
-
"
|
2168
|
-
}
|
2169
|
-
|
2170
|
-
rescue_args = ""
|
2171
|
-
rescue_args = "(VALUE)(VALUE[]){(VALUE)pframe,(VALUE)#{repass_var}}"
|
2172
|
-
else
|
2173
|
-
|
2174
|
-
body = anonymous_function{ |name| "
|
2175
|
-
static VALUE #{name}(VALUE param) {
|
2176
|
-
#{@frame_struct} frame;
|
2177
|
-
|
2178
|
-
typeof(frame)* pframe;
|
2179
|
-
typeof(frame)* parent_frame = (typeof(pframe))param;
|
2180
|
-
|
2181
|
-
frame.parent_frame = 0;
|
2182
|
-
frame.return_value = Qnil;
|
2183
|
-
frame.rescue = 0;
|
2184
|
-
frame.last_error = Qnil;
|
2185
|
-
frame.targetted = 0;
|
2186
|
-
frame.thread_data = parent_frame->thread_data;
|
2187
|
-
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
2188
|
-
|
2189
|
-
pframe = &frame;
|
2190
|
-
|
2191
|
-
#{
|
2192
|
-
nolocals ? "frame.plocals = 0;" : "#{@locals_struct}* plocals = parent_frame->plocals;
|
2193
|
-
frame.plocals = plocals;
|
2194
|
-
"
|
2195
|
-
}
|
2196
|
-
|
2197
|
-
int aux = setjmp(frame.jmp);
|
2198
|
-
if (aux != 0) {
|
2199
|
-
|
2200
|
-
if (frame.targetted == 1) {
|
2201
|
-
return frame.return_value;
|
2202
|
-
} else {
|
2203
|
-
rb_jump_tag(aux);
|
2204
|
-
}
|
2205
|
-
}
|
2206
|
-
|
2207
|
-
return #{inner_code};
|
2208
|
-
}
|
2209
|
-
"
|
2210
|
-
}
|
2211
|
-
|
2212
|
-
rescue_args = "(VALUE)pframe"
|
2213
|
-
end
|
2214
|
-
|
2215
|
-
wrapper_code = " if (state != 0) {
|
2216
|
-
if (state < 0x80) {
|
2217
|
-
|
2218
|
-
if (state == TAG_RAISE) {
|
2219
|
-
// raise emulation
|
2220
|
-
pframe->thread_data->exception = rb_eval_string(\"$!\");
|
2221
|
-
longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
|
2222
|
-
return Qnil;
|
2223
|
-
} else {
|
2224
|
-
rb_jump_tag(state);
|
2225
|
-
}
|
2226
|
-
} else {
|
2227
|
-
longjmp(pframe->jmp, state);
|
2228
|
-
}
|
2229
|
-
|
2230
|
-
}
|
2231
|
-
"
|
2232
|
-
|
2233
|
-
rescue_code = "rb_protect(#{body},#{rescue_args},&state)"
|
2234
|
-
|
2235
|
-
if always_rescue
|
2236
|
-
inline_block "
|
2237
|
-
int state;
|
2238
|
-
pframe->last_error = Qnil;
|
2239
|
-
VALUE result = #{rescue_code};
|
2240
|
-
|
2241
|
-
#{wrapper_code}
|
2242
|
-
|
2243
|
-
return result;
|
2244
|
-
", repass_var, nolocals
|
2245
|
-
else
|
2246
|
-
inline_block "
|
2247
|
-
VALUE result;
|
2248
|
-
int state;
|
2249
|
-
pframe->last_error = Qnil;
|
2250
|
-
|
2251
|
-
if (pframe->rescue) {
|
2252
|
-
result = #{rescue_code};
|
2253
|
-
#{wrapper_code}
|
2254
|
-
} else {
|
2255
|
-
return #{inner_code};
|
2256
|
-
}
|
2257
|
-
|
2258
|
-
return result;
|
2259
|
-
", repass_var, nolocals
|
2260
|
-
end
|
2261
|
-
end
|
2262
|
-
|
2263
|
-
def func_frame
|
2264
|
-
"
|
2265
|
-
#{@locals_struct} *plocals = malloc(sizeof(typeof(*plocals)));
|
2266
|
-
#{@frame_struct} frame;
|
2267
|
-
#{@frame_struct} *pframe;
|
2268
|
-
|
2269
|
-
frame.plocals = plocals;
|
2270
|
-
frame.parent_frame = (void*)_parent_frame;
|
2271
|
-
frame.return_value = Qnil;
|
2272
|
-
frame.rescue = 0;
|
2273
|
-
frame.targetted = 0;
|
2274
|
-
frame.thread_data = ((typeof(pframe))_parent_frame)->thread_data;
|
2275
|
-
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
2276
|
-
|
2277
|
-
plocals->pframe = LONG2FIX(&frame);
|
2278
|
-
|
2279
|
-
pframe = (void*)&frame;
|
2280
|
-
|
2281
|
-
#{@block_struct} *pblock;
|
2282
|
-
VALUE last_expression = Qnil;
|
2283
|
-
|
2284
|
-
int aux = setjmp(pframe->jmp);
|
2285
|
-
if (aux != 0) {
|
2286
|
-
|
2287
|
-
if (pframe->targetted == 0) {
|
2288
|
-
longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
|
2289
|
-
}
|
2290
|
-
|
2291
|
-
return plocals->return_value;
|
2292
|
-
}
|
2293
|
-
|
2294
|
-
plocals->self = self;
|
2295
|
-
"
|
2296
|
-
end
|
2297
|
-
|
2298
|
-
def c_escape(str)
|
2299
|
-
str.inspect
|
2300
|
-
end
|
2301
|
-
|
2302
|
-
def literal_value(value)
|
2303
|
-
@literal_value_hash = Hash.new unless @literal_value_hash
|
2304
|
-
return @literal_value_hash[value] if @literal_value_hash[value]
|
2305
|
-
|
2306
|
-
name = self.add_global_name("VALUE", "Qnil");
|
2307
|
-
|
2308
|
-
begin
|
2309
|
-
|
2310
|
-
str = Marshal.dump(value)
|
2311
|
-
|
2312
|
-
|
2313
|
-
if value.instance_of? Module
|
2314
|
-
|
2315
|
-
container_str = value.to_s.split("::")[0..-2].join("::")
|
2316
|
-
|
2317
|
-
init_extra << "
|
2318
|
-
#{name} = rb_define_module_under(
|
2319
|
-
#{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
|
2320
|
-
,\"#{value.to_s.split("::").last}\");
|
2321
|
-
|
2322
|
-
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
2323
|
-
"
|
2324
|
-
elsif value.instance_of? Class
|
2325
|
-
container_str = value.to_s.split("::")[0..-2].join("::")
|
2326
|
-
|
2327
|
-
init_extra << "
|
2328
|
-
#{name} = rb_define_class_under(
|
2329
|
-
#{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
|
2330
|
-
,\"#{value.to_s.split("::").last}\"
|
2331
|
-
,#{value.superclass == Object ? "rb_cObject" : literal_value(value.superclass)});
|
2332
|
-
|
2333
|
-
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
2334
|
-
"
|
2335
|
-
elsif value.instance_of? Array
|
2336
|
-
init_extra << "
|
2337
|
-
#{name} = rb_ary_new3(#{value.size}, #{value.map{|x| literal_value x}.join(",")} );
|
2338
|
-
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
2339
|
-
"
|
2340
|
-
else
|
2341
|
-
|
2342
|
-
init_extra << "
|
2343
|
-
#{name} = rb_marshal_load(rb_str_new(#{c_escape str}, #{str.size}));
|
2344
|
-
rb_funcall(#{name},#{intern_num :gc_register_object},0);
|
2345
|
-
|
2346
|
-
"
|
2347
|
-
end
|
2348
|
-
rescue TypeError => e
|
2349
|
-
@no_cache = true
|
2350
|
-
FastRuby.logger.info "#{value} disabling cache for extension"
|
2351
|
-
init_extra << "
|
2352
|
-
#{name} = rb_funcall(rb_const_get(rb_cObject, #{intern_num :ObjectSpace}), #{intern_num :_id2ref}, 1, INT2FIX(#{value.__id__}));
|
2353
|
-
"
|
2354
|
-
|
2355
|
-
end
|
2356
|
-
@literal_value_hash[value] = name
|
2357
|
-
|
2358
|
-
name
|
2359
|
-
end
|
2360
|
-
|
2361
|
-
def encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name = nil)
|
2362
|
-
name = self.add_global_name("void*", 0);
|
2363
|
-
cruby_name = self.add_global_name("void*", 0);
|
2364
|
-
cruby_len = self.add_global_name("int", 0);
|
2365
|
-
args_tree = call_tree[3]
|
2366
|
-
method_tree = nil
|
2367
|
-
|
2368
|
-
begin
|
2369
|
-
method_tree = recvtype.instance_method(@method_name.to_sym).fastruby.tree
|
2370
|
-
rescue NoMethodError
|
2371
|
-
end
|
2372
|
-
|
2373
|
-
|
2374
|
-
strargs_signature = (0..args_tree.size-2).map{|x| "VALUE arg#{x}"}.join(",")
|
2375
|
-
strargs = (0..args_tree.size-2).map{|x| "arg#{x}"}.join(",")
|
2376
|
-
inprocstrargs = (1..args_tree.size-1).map{|x| "((VALUE*)method_arguments)[#{x}]"}.join(",")
|
2377
|
-
|
2378
|
-
if args_tree.size > 1
|
2379
|
-
strargs_signature = "," + strargs_signature
|
2380
|
-
toprocstrargs = "self,"+strargs
|
2381
|
-
strargs = "," + strargs
|
2382
|
-
inprocstrargs = ","+inprocstrargs
|
2383
|
-
else
|
2384
|
-
toprocstrargs = "self"
|
2385
|
-
end
|
2386
|
-
|
2387
|
-
ruby_wrapper = anonymous_function{ |funcname| "
|
2388
|
-
static VALUE #{funcname}(VALUE self,void* block,void* frame#{strargs_signature}){
|
2389
|
-
#{@frame_struct}* pframe = frame;
|
2390
|
-
|
2391
|
-
VALUE method_arguments[#{args_tree.size}] = {#{toprocstrargs}};
|
2392
|
-
|
2393
|
-
return #{
|
2394
|
-
protected_block "rb_funcall(((VALUE*)method_arguments)[0], #{intern_num mname.to_sym}, #{args_tree.size-1}#{inprocstrargs});", false, "method_arguments"
|
2395
|
-
};
|
2396
|
-
}
|
2397
|
-
"
|
2398
|
-
}
|
2399
|
-
|
2400
|
-
value_cast = ( ["VALUE"]*(args_tree.size) ).join(",")
|
2401
|
-
|
2402
|
-
cruby_wrapper = anonymous_function{ |funcname| "
|
2403
|
-
static VALUE #{funcname}(VALUE self,void* block,void* frame#{strargs_signature}){
|
2404
|
-
#{@frame_struct}* pframe = frame;
|
2405
|
-
|
2406
|
-
VALUE method_arguments[#{args_tree.size}] = {#{toprocstrargs}};
|
2407
|
-
|
2408
|
-
// call to #{recvtype}::#{mname}
|
2409
|
-
|
2410
|
-
if (#{cruby_len} == -1) {
|
2411
|
-
return #{
|
2412
|
-
protected_block "((VALUE(*)(int,VALUE*,VALUE))#{cruby_name})(#{args_tree.size-1}, ((VALUE*)method_arguments)+1,*((VALUE*)method_arguments));", false, "method_arguments"
|
2413
|
-
};
|
2414
|
-
|
2415
|
-
} else if (#{cruby_len} == -2) {
|
2416
|
-
return #{
|
2417
|
-
protected_block "((VALUE(*)(VALUE,VALUE))#{cruby_name})(*((VALUE*)method_arguments), rb_ary_new4(#{args_tree.size-1},((VALUE*)method_arguments)+1) );", false, "method_arguments"
|
2418
|
-
};
|
2419
|
-
|
2420
|
-
} else {
|
2421
|
-
return #{
|
2422
|
-
protected_block "((VALUE(*)(#{value_cast}))#{cruby_name})(((VALUE*)method_arguments)[0] #{inprocstrargs});", false, "method_arguments"
|
2423
|
-
};
|
2424
|
-
}
|
2425
|
-
}
|
2426
|
-
"
|
2427
|
-
}
|
2428
|
-
|
2429
|
-
recvdump = nil
|
2430
|
-
|
2431
|
-
begin
|
2432
|
-
recvdump = literal_value recvtype
|
2433
|
-
rescue
|
2434
|
-
end
|
2435
|
-
|
2436
|
-
if recvdump and recvtype
|
2437
|
-
init_extra << "
|
2438
|
-
{
|
2439
|
-
VALUE recvtype = #{recvdump};
|
2440
|
-
rb_funcall(#{literal_value FastRuby}, #{intern_num :set_builder_module}, 1, recvtype);
|
2441
|
-
VALUE signature = #{literal_value signature};
|
2442
|
-
VALUE mname = #{literal_value mname};
|
2443
|
-
VALUE tree = #{literal_value method_tree};
|
2444
|
-
VALUE convention = rb_funcall(recvtype, #{intern_num :convention}, 3,signature,mname,#{inference_complete ? "Qtrue" : "Qfalse"});
|
2445
|
-
VALUE mobject = rb_funcall(recvtype, #{intern_num :method_from_signature},3,signature,mname,#{inference_complete ? "Qtrue" : "Qfalse"});
|
2446
|
-
|
2447
|
-
struct METHOD {
|
2448
|
-
VALUE klass, rklass;
|
2449
|
-
VALUE recv;
|
2450
|
-
ID id, oid;
|
2451
|
-
int safe_level;
|
2452
|
-
NODE *body;
|
2453
|
-
};
|
2454
|
-
|
2455
|
-
int len = 0;
|
2456
|
-
void* address = 0;
|
2457
|
-
|
2458
|
-
if (mobject != Qnil) {
|
2459
|
-
|
2460
|
-
struct METHOD *data;
|
2461
|
-
Data_Get_Struct(mobject, struct METHOD, data);
|
2462
|
-
|
2463
|
-
if (nd_type(data->body) == NODE_CFUNC) {
|
2464
|
-
address = data->body->nd_cfnc;
|
2465
|
-
len = data->body->nd_argc;
|
2466
|
-
}
|
2467
|
-
}
|
2468
|
-
|
2469
|
-
if (address==0) convention = #{literal_value :ruby};
|
2470
|
-
|
2471
|
-
#{convention_global_name ? convention_global_name + " = 0;" : ""}
|
2472
|
-
if (recvtype != Qnil) {
|
2473
|
-
|
2474
|
-
if (convention == #{literal_value :fastruby}) {
|
2475
|
-
#{convention_global_name ? convention_global_name + " = 1;" : ""}
|
2476
|
-
#{name} = address;
|
2477
|
-
} else if (convention == #{literal_value :cruby}) {
|
2478
|
-
// cruby, wrap direct call
|
2479
|
-
#{cruby_name} = address;
|
2480
|
-
|
2481
|
-
if (#{cruby_name} == 0) {
|
2482
|
-
#{name} = (void*)#{ruby_wrapper};
|
2483
|
-
} else {
|
2484
|
-
#{cruby_len} = len;
|
2485
|
-
#{name} = (void*)#{cruby_wrapper};
|
2486
|
-
}
|
2487
|
-
} else {
|
2488
|
-
// ruby, wrap rb_funcall
|
2489
|
-
#{name} = (void*)#{ruby_wrapper};
|
2490
|
-
}
|
2491
|
-
} else {
|
2492
|
-
// ruby, wrap rb_funcall
|
2493
|
-
#{name} = (void*)#{ruby_wrapper};
|
2494
|
-
}
|
2495
|
-
|
2496
|
-
}
|
2497
|
-
"
|
2498
|
-
else
|
2499
|
-
init_extra << "
|
2500
|
-
// ruby, wrap rb_funcall
|
2501
|
-
#{name} = (void*)#{ruby_wrapper};
|
2502
|
-
"
|
2503
|
-
end
|
2504
|
-
|
2505
|
-
name
|
2506
|
-
end
|
2507
|
-
|
2508
|
-
def intern_num(symbol)
|
2509
|
-
@intern_num_hash = Hash.new unless @intern_num_hash
|
2510
|
-
return @intern_num_hash[symbol] if @intern_num_hash[symbol]
|
2511
|
-
|
2512
|
-
name = self.add_global_name("ID", 0);
|
2513
|
-
|
2514
|
-
init_extra << "
|
2515
|
-
#{name} = rb_intern(\"#{symbol.to_s}\");
|
2516
|
-
"
|
2517
|
-
|
2518
|
-
@intern_num_hash[symbol] = name
|
2519
|
-
|
2520
|
-
name
|
2521
|
-
end
|
2522
|
-
|
2523
|
-
def add_global_name(ctype, default)
|
2524
|
-
name = "glb" + rand(1000000000).to_s
|
2525
|
-
|
2526
|
-
extra_code << "
|
2527
|
-
static #{ctype} #{name} = #{default};
|
2528
|
-
"
|
2529
|
-
name
|
2530
|
-
end
|
2531
|
-
|
2532
|
-
def global_entry(glbname)
|
2533
|
-
name = add_global_name("struct global_entry*", 0);
|
2534
|
-
|
2535
|
-
init_extra << "
|
2536
|
-
#{name} = rb_global_entry(SYM2ID(#{literal_value glbname}));
|
2537
|
-
"
|
2538
|
-
|
2539
|
-
name
|
2540
|
-
end
|
2541
|
-
|
2542
|
-
|
2543
|
-
def frame(code, jmp_code, not_jmp_code = "", rescued = nil)
|
2544
|
-
|
2545
|
-
anonymous_function{ |name| "
|
2546
|
-
static VALUE #{name}(VALUE param) {
|
2547
|
-
VALUE last_expression;
|
2548
|
-
#{@frame_struct} frame, *pframe, *parent_frame;
|
2549
|
-
#{@locals_struct} *plocals;
|
2550
|
-
|
2551
|
-
parent_frame = (void*)param;
|
2552
|
-
|
2553
|
-
frame.parent_frame = (void*)param;
|
2554
|
-
frame.plocals = parent_frame->plocals;
|
2555
|
-
frame.rescue = #{rescued ? rescued : "parent_frame->rescue"};
|
2556
|
-
frame.targetted = 0;
|
2557
|
-
frame.thread_data = parent_frame->thread_data;
|
2558
|
-
if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
|
2559
|
-
|
2560
|
-
plocals = frame.plocals;
|
2561
|
-
pframe = &frame;
|
2562
|
-
|
2563
|
-
int aux = setjmp(frame.jmp);
|
2564
|
-
if (aux != 0) {
|
2565
|
-
last_expression = pframe->return_value;
|
2566
|
-
|
2567
|
-
// restore previous frame
|
2568
|
-
typeof(pframe) original_frame = pframe;
|
2569
|
-
pframe = parent_frame;
|
2570
|
-
|
2571
|
-
#{jmp_code};
|
2572
|
-
|
2573
|
-
if (original_frame->targetted == 0) {
|
2574
|
-
longjmp(pframe->jmp,aux);
|
2575
|
-
}
|
2576
|
-
|
2577
|
-
return last_expression;
|
2578
|
-
}
|
2579
|
-
|
2580
|
-
#{code};
|
2581
|
-
|
2582
|
-
// restore previous frame
|
2583
|
-
typeof(pframe) original_frame = pframe;
|
2584
|
-
pframe = parent_frame;
|
2585
|
-
#{not_jmp_code};
|
2586
|
-
|
2587
|
-
return last_expression;
|
2588
|
-
|
2589
|
-
}
|
2590
|
-
"
|
2591
|
-
} + "((VALUE)pframe)"
|
2592
|
-
end
|
2593
|
-
end
|
2594
|
-
end
|