fastruby 0.0.12 → 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -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