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.
@@ -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