fastruby 0.0.21 → 0.0.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/Rakefile +1 -1
  2. data/benchmarks/benchmark.rb +3 -0
  3. data/benchmarks/benchmark.rb~ +3 -12
  4. data/benchmarks/benchmark8.rb +48 -0
  5. data/benchmarks/benchmark8.rb~ +46 -0
  6. data/lib/fastruby.rb +2 -1
  7. data/lib/fastruby.rb~ +2 -1
  8. data/lib/fastruby/builder.rb +18 -1
  9. data/lib/fastruby/builder.rb~ +18 -5
  10. data/lib/fastruby/modules/lvar_type/lasgn.rb~ +41 -0
  11. data/lib/fastruby/modules/translator/block.rb +1 -1
  12. data/lib/fastruby/modules/translator/block.rb~ +128 -0
  13. data/lib/fastruby/modules/translator/call.rb +62 -139
  14. data/lib/fastruby/modules/translator/call.rb~ +61 -140
  15. data/lib/fastruby/modules/translator/defn.rb +49 -105
  16. data/lib/fastruby/modules/translator/defn.rb~ +211 -0
  17. data/lib/fastruby/modules/translator/exceptions.rb +1 -0
  18. data/lib/fastruby/modules/translator/exceptions.rb~ +120 -0
  19. data/lib/fastruby/modules/translator/iter.rb +13 -20
  20. data/lib/fastruby/modules/translator/iter.rb~ +738 -0
  21. data/lib/fastruby/modules/translator/literal.rb +8 -1
  22. data/lib/fastruby/modules/translator/literal.rb~ +157 -0
  23. data/lib/fastruby/modules/translator/nonlocal.rb +7 -0
  24. data/lib/fastruby/modules/translator/nonlocal.rb~ +304 -0
  25. data/lib/fastruby/modules/translator/static.rb +1 -0
  26. data/lib/fastruby/modules/translator/static.rb~ +290 -0
  27. data/lib/fastruby/modules/translator/variable.rb +24 -6
  28. data/lib/fastruby/modules/translator/variable.rb~ +298 -0
  29. data/lib/fastruby/translator/translator.rb +411 -284
  30. data/lib/fastruby/translator/translator.rb~ +1728 -0
  31. data/spec/fastruby_only/base_spec.rb~ +74 -0
  32. data/spec/ruby/base_spec.rb~ +1 -338
  33. data/spec/ruby/block/break_spec.rb~ +21 -0
  34. data/spec/ruby/block/callcc_spec.rb~ +236 -0
  35. data/spec/ruby/block/lambda_spec.rb~ +1 -178
  36. data/spec/ruby/block/next_spec.rb~ +85 -0
  37. data/spec/ruby/block/proc_spec.rb~ +22 -0
  38. data/spec/ruby/block/redo_spec.rb~ +133 -0
  39. data/spec/ruby/block/retry_spec.rb~ +135 -0
  40. data/spec/ruby/block_spec.rb~ +494 -2
  41. data/spec/ruby/call/base_call_spec.rb~ +60 -2
  42. data/spec/ruby/defn/default_args_spec.rb~ +303 -0
  43. data/spec/ruby/defn/multiple_args_spec.rb~ +317 -0
  44. data/spec/ruby/defn/replacement_spec.rb +29 -1
  45. data/spec/ruby/defn/replacement_spec.rb~ +52 -21
  46. data/spec/ruby/exception/internal_ex_spec.rb~ +2 -2
  47. data/spec/ruby/variable_spec.rb~ +46 -23
  48. data/spec/static/flow_spec.rb~ +48 -0
  49. metadata +34 -12
@@ -23,6 +23,7 @@ module FastRuby
23
23
 
24
24
  define_translator_for(:rescue, :method => :to_c_rescue, :arity => 1)
25
25
  def to_c_rescue(tree)
26
+ @has_inline_block = true
26
27
  catch_on_throw do
27
28
  if tree[1][0] == :resbody
28
29
  else_tree = tree[2]
@@ -0,0 +1,120 @@
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
+ module FastRuby
22
+ class Context
23
+
24
+ define_translator_for(:rescue, :method => :to_c_rescue, :arity => 1)
25
+ def to_c_rescue(tree)
26
+ catch_on_throw do
27
+ if tree[1][0] == :resbody
28
+ else_tree = tree[2]
29
+
30
+ if else_tree
31
+ to_c else_tree
32
+ else
33
+ "Qnil"
34
+ end
35
+ else
36
+ resbody_tree = tree[2]
37
+ else_tree = nil
38
+ if tree[-1]
39
+ if tree[-1][0] != :resbody
40
+ else_tree = tree[-1]
41
+ end
42
+ end
43
+
44
+ catch_condition_array = []
45
+ lasgn_code = ""
46
+ resbody_code = to_c(resbody_tree[2])
47
+
48
+ rescue_code = ""
49
+
50
+ tree[1..-1].each do |resbody_tree|
51
+ next if resbody_tree[0] != :resbody
52
+
53
+ if resbody_tree[1].size == 1
54
+ resbody_tree[1][1] = s(:const, :Exception)
55
+ end
56
+
57
+ if resbody_tree[1].last[0] == :lasgn
58
+ lasgn_code = to_c(resbody_tree[1].last)
59
+ end
60
+
61
+ resbody_tree[1][1..-1].each do |xtree|
62
+ if xtree[0] != :lasgn
63
+ trapcode = "rb_eException";
64
+
65
+ if xtree
66
+ trapcode = to_c(xtree)
67
+ end
68
+
69
+ catch_condition_array << "(rb_obj_is_kind_of(frame.thread_data->exception,#{trapcode}) == Qtrue)"
70
+ end
71
+ end
72
+
73
+ rescue_code << "
74
+ if (aux == FASTRUBY_TAG_RAISE) {
75
+ if (#{catch_condition_array.join(" || ")})
76
+ {
77
+ // trap exception
78
+ frame.targetted = 1;
79
+
80
+ #{lasgn_code};
81
+
82
+ #{resbody_code};
83
+ }
84
+ }
85
+ "
86
+ end
87
+
88
+ frame_call(
89
+ "ret = " + frame(to_c(tree[1])+";","
90
+ #{rescue_code}
91
+ ", else_tree ? to_c(else_tree) : nil, 1)
92
+
93
+ )
94
+ end
95
+ end
96
+ end
97
+
98
+ define_translator_for(:ensure, :method => :to_c_ensure, :arity => 1)
99
+ def to_c_ensure(tree)
100
+ if tree.size == 2
101
+ to_c tree[1]
102
+ else
103
+ ensured_code = to_c tree[2]
104
+ inline_block {
105
+ "#{frame(to_c(tree[1]),ensured_code,ensured_code,1)};"
106
+ }
107
+ end
108
+ end
109
+
110
+ define_translator_for(:call, :priority => 100){ |*x|
111
+ tree, result_var = x
112
+
113
+ # raise code
114
+ args = tree[3]
115
+ _raise(args[1],args[2])
116
+ }.condition{|*x|
117
+ tree = x.first; tree.node_type == :call && tree[2] == :raise
118
+ }
119
+ end
120
+ end
@@ -24,6 +24,8 @@ module FastRuby
24
24
  define_translator_for(:iter, :method => :to_c_iter)
25
25
  def to_c_iter(tree, result_var = nil)
26
26
 
27
+ @has_inline_block = true
28
+
27
29
  call_tree = tree[1]
28
30
  args_tree = tree[2]
29
31
  recv_tree = call_tree[1]
@@ -445,7 +447,8 @@ end
445
447
  frame.return_value = Qnil;
446
448
  frame.rescue = 0;
447
449
  frame.targetted = 0;
448
- frame.thread_data = parent_frame->thread_data;
450
+ frame.thread_data = 0;
451
+ if (parent_frame != 0) frame.thread_data = parent_frame->thread_data;
449
452
  if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
450
453
 
451
454
  plocals = frame.plocals;
@@ -669,8 +672,8 @@ end
669
672
  funcall_call_code
670
673
  end
671
674
  else
672
- encoded_address = encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name, true)
673
-
675
+ encoded_address = dynamic_block_call(signature,mname)
676
+
674
677
  if call_args_tree.size > 1
675
678
  strargs = (0..call_args_tree.size-2).map{|i| "arg#{i}"}.join(",")
676
679
  else
@@ -704,26 +707,16 @@ end
704
707
  end
705
708
  }
706
709
 
707
- ret = ((VALUE(*)(VALUE,VALUE,VALUE,int,VALUE*))#{encoded_address})(recv, (VALUE)&block, (VALUE)&call_frame, #{call_args_tree.size-1}, (VALUE[]){#{strargs}});
710
+ int block_call = 0;
711
+ ret = ((VALUE(*)(VALUE,void*,void*,int,VALUE*,int*))#{encoded_address})(recv, &block, &call_frame, #{call_args_tree.size-1}, (VALUE[]){#{strargs}},&block_call);
712
+
713
+ if (block_call) {
714
+ ret = #{funcall_call_code};
715
+ }
708
716
  "
709
717
 
710
718
  code = "
711
- if (#{@last_address_name} == 0) {
712
- return #{funcall_call_code};
713
- } else {
714
- #{if recvtype and inference_complete
715
- "if (*#{@last_address_name} == 0) {
716
- rb_funcall(#{literal_value recvtype},#{intern_num :build}, 2, #{literal_value signature}, #{literal_value mname});
717
- }
718
- "
719
- end
720
- }
721
- if (*#{@last_address_name} == 0) {
722
- return #{funcall_call_code};
723
- } else {
724
- #{fastruby_call_code}
725
- }
726
- }
719
+ #{fastruby_call_code};
727
720
  "
728
721
 
729
722
  fastruby_precode = " #{@block_struct} block;
@@ -0,0 +1,738 @@
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
+ module FastRuby
22
+ class Context
23
+
24
+ define_translator_for(:iter, :method => :to_c_iter)
25
+ def to_c_iter(tree, result_var = nil)
26
+
27
+ @has_inline_block
28
+
29
+ call_tree = tree[1]
30
+ args_tree = tree[2]
31
+ recv_tree = call_tree[1]
32
+
33
+ directive_code = directive(call_tree)
34
+ if directive_code
35
+ if result_var
36
+ return "#{result_var} = #{directive_code};\n"
37
+ else
38
+ return directive_code
39
+ end
40
+ end
41
+
42
+ other_call_tree = call_tree.dup
43
+ other_call_tree[1] = s(:lvar, :arg)
44
+
45
+ mname = call_tree[2]
46
+
47
+ call_args_tree = call_tree[3]
48
+
49
+ caller_code = nil
50
+
51
+ recvtype = infer_type(recv_tree || s(:self))
52
+
53
+ address = nil
54
+ mobject = nil
55
+ len = nil
56
+
57
+ if recvtype
58
+
59
+ inference_complete = true
60
+ signature = [recvtype]
61
+
62
+ call_args_tree[1..-1].each do |arg|
63
+ argtype = infer_type(arg)
64
+ if argtype
65
+ signature << argtype
66
+ else
67
+ inference_complete = false
68
+ end
69
+ end
70
+ end
71
+
72
+ anonymous_impl = tree[3]
73
+
74
+ str_lvar_initialization = "#{@frame_struct} *pframe;
75
+ #{@locals_struct} *plocals;
76
+
77
+ "
78
+
79
+ str_arg_initialization = ""
80
+
81
+ str_impl = ""
82
+ on_block do
83
+ str_impl = to_c(anonymous_impl, "last_expression")
84
+ end
85
+
86
+ if not args_tree
87
+ elsif args_tree.first == :lasgn
88
+ if RUBY_VERSION =~ /^1\.8/
89
+ str_arg_initialization << "plocals->#{args_tree[1]} = arg;"
90
+ elsif RUBY_VERSION =~ /^1\.9/
91
+ str_arg_initialization << "
92
+ if (TYPE(arg) != T_ARRAY) {
93
+ plocals->#{args_tree[1]} = arg;
94
+ } else {
95
+ plocals->#{args_tree[1]} = rb_ary_entry(arg,0);
96
+ }
97
+ "
98
+ end
99
+ elsif args_tree.first == :masgn
100
+
101
+ if RUBY_VERSION =~ /^1\.8/
102
+ str_arg_initialization << "
103
+ {
104
+ if (TYPE(arg) != T_ARRAY) {
105
+ if (arg != Qnil) {
106
+ arg = rb_ary_new4(1,&arg);
107
+ } else {
108
+ arg = rb_ary_new2(0);
109
+ }
110
+ } else if (_RARRAY_LEN(arg) <= 1) {
111
+ arg = rb_ary_new4(1,&arg);
112
+ }
113
+ }
114
+ "
115
+ elsif RUBY_VERSION =~ /^1\.9/
116
+ str_arg_initialization << "
117
+ {
118
+ }
119
+ "
120
+ end
121
+
122
+ arguments = args_tree[1][1..-1]
123
+
124
+ (0..arguments.size-1).each do |i|
125
+ arg = arguments[i]
126
+ if arg[0] == :lasgn
127
+ str_arg_initialization << "plocals->#{arguments[i].last} = rb_ary_entry(arg,#{i});\n"
128
+ elsif arg[0] == :splat
129
+ str_arg_initialization << "plocals->#{arg.last.last} = rb_ary_new2(_RARRAY_LEN(arg)-#{i});\n
130
+
131
+ int i;
132
+ for (i=#{i};i<_RARRAY_LEN(arg);i++){
133
+ rb_ary_store(plocals->#{arg.last.last},i-#{i},rb_ary_entry(arg,i));
134
+ }
135
+ "
136
+ end
137
+ end
138
+ end
139
+ str_recv = "pframe->next_recv"
140
+ str_recv = "plocals->self" unless recv_tree
141
+
142
+ strargs = if call_args_tree.size > 1
143
+ "," + (0..call_args_tree.size-2).map{|i| "arg#{i}"}.join(",")
144
+ else
145
+ ""
146
+ end
147
+
148
+ str_evaluate_args = ""
149
+
150
+ rb_funcall_caller_code = proc { |name, call_type| "
151
+ static VALUE #{name}(VALUE param) {
152
+ // call to #{call_tree[2]}
153
+ VALUE last_expression = Qnil;
154
+ VALUE* args_array = (VALUE*)param;
155
+
156
+ #{str_lvar_initialization}
157
+ pframe = (void*)args_array[0];
158
+ plocals = (void*)pframe->plocals;
159
+ #{str_evaluate_args};
160
+
161
+ VALUE ret = rb_funcall(#{str_recv}, #{intern_num call_tree[2]}, #{call_args_tree.size-1} #{strargs});
162
+ #{
163
+ if call_type == :lambda
164
+ "
165
+
166
+ // freeze all stacks
167
+ struct FASTRUBYTHREADDATA* thread_data = rb_current_thread_data();
168
+
169
+ if (thread_data != 0) {
170
+ VALUE rb_stack_chunk = thread_data->rb_stack_chunk;
171
+
172
+ // add reference to stack chunk to lambda object
173
+ rb_ivar_set(ret,#{intern_num :_fastruby_stack_chunk},rb_stack_chunk);
174
+
175
+ // freeze the complete chain of stack chunks
176
+ while (rb_stack_chunk != Qnil) {
177
+ struct STACKCHUNK* stack_chunk;
178
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
179
+
180
+ stack_chunk_freeze(stack_chunk);
181
+
182
+ rb_stack_chunk = rb_ivar_get(rb_stack_chunk,#{intern_num :_parent_stack_chunk});
183
+ }
184
+ }
185
+ "
186
+ end
187
+ }
188
+ return ret;
189
+ }
190
+ "
191
+ }
192
+
193
+
194
+ if call_args_tree.size > 1
195
+ if call_args_tree.last[0] == :splat
196
+ rb_funcall_caller_code = proc { |name,call_type| "
197
+ static VALUE #{name}(VALUE param) {
198
+ // call to #{call_tree[2]}
199
+
200
+ VALUE* args_array = (VALUE*)param;
201
+ int argc = args_array[1];
202
+ VALUE* argv = (VALUE*)args_array[2];
203
+
204
+ VALUE last_expression = Qnil;
205
+ #{str_lvar_initialization}
206
+
207
+ pframe = (void*)args_array[0];
208
+ plocals = (void*)pframe->plocals;
209
+
210
+ return rb_funcall2(#{str_recv}, #{intern_num call_tree[2]}, argc, argv);
211
+ }
212
+ "
213
+ }
214
+ else
215
+ str_evaluate_args = "
216
+ #{
217
+ (0..call_args_tree.size-2).map{|i|
218
+ "VALUE arg#{i} = args_array[#{i+1}];"
219
+ }.join("\n")
220
+ }
221
+
222
+ "
223
+ end
224
+ end
225
+
226
+ argument_array_read = "
227
+ VALUE arg;
228
+ #{
229
+ # TODO: access directly to argc and argv for optimal execution
230
+ if RUBY_VERSION =~ /^1\.9/
231
+ "
232
+ if (TYPE(arg_) == T_ARRAY) {
233
+ if (_RARRAY_LEN(arg_) <= 1) {
234
+ arg = rb_ary_new4(argc,argv);
235
+ } else {
236
+ arg = arg_;
237
+ }
238
+ } else {
239
+ arg = rb_ary_new4(argc,argv);
240
+ }
241
+ "
242
+ else
243
+ "arg = arg_;"
244
+ end
245
+ }
246
+ "
247
+
248
+ rb_funcall_block_code = proc { |name,call_type| "
249
+ static VALUE #{name}(VALUE arg_, VALUE _plocals, int argc, VALUE* argv) {
250
+ // block for call to #{call_tree[2]}
251
+ #{argument_array_read}
252
+
253
+ volatile VALUE last_expression = Qnil;
254
+
255
+ #{@frame_struct} frame;
256
+ #{@frame_struct} * volatile pframe = (void*)&frame;
257
+ #{@locals_struct} * volatile plocals = (void*)_plocals;
258
+
259
+ frame.plocals = plocals;
260
+ frame.parent_frame = 0;
261
+ frame.return_value = Qnil;
262
+ frame.rescue = 0;
263
+ frame.targetted = 0;
264
+ frame.thread_data = rb_current_thread_data();
265
+
266
+ #{str_arg_initialization}
267
+
268
+ #{
269
+ if call_type == :lambda or call_type == :proc_new
270
+ "
271
+ void* volatile old_call_frame = ((typeof(plocals))(pframe->plocals))->call_frame;
272
+ ((typeof(plocals))(pframe->plocals))->call_frame = pframe;
273
+ "
274
+ end
275
+ }
276
+
277
+ int aux = setjmp(frame.jmp);
278
+ if (aux != 0) {
279
+
280
+ if (aux == FASTRUBY_TAG_NEXT) {
281
+ last_expression = pframe->thread_data->accumulator;
282
+ goto fastruby_local_next;
283
+ } else if (aux == FASTRUBY_TAG_REDO) {
284
+ // do nothing and let execute the block again
285
+ #{
286
+ if call_type == :lambda
287
+ "
288
+
289
+ } else if (aux == FASTRUBY_TAG_BREAK) {
290
+ last_expression = frame.return_value;
291
+ typeof(pframe) target_frame_ = (void*)plocals->call_frame;
292
+
293
+ if (target_frame_ == 0) {
294
+ goto fastruby_local_next;
295
+ } else {
296
+ if (target_frame_->targetted == 1) {
297
+ goto fastruby_local_next;
298
+ } else {
299
+ #{_raise("rb_eLocalJumpError","illegal break")};
300
+ }
301
+ }
302
+ "
303
+ end
304
+ }
305
+ #{
306
+ if call_type == :lambda or call_type == :proc_new
307
+ "
308
+ } else if (aux == FASTRUBY_TAG_RAISE) {
309
+ rb_funcall(((typeof(plocals))(pframe->plocals))->self, #{intern_num :raise}, 1, frame.thread_data->exception);
310
+ return Qnil;
311
+ "
312
+ end
313
+ }
314
+ } else {
315
+ #{
316
+ case call_type
317
+ when :proc_new
318
+ "
319
+ _local_return:
320
+ if (plocals->targetted == 1) {
321
+ if (plocals->active == Qfalse) {
322
+ rb_raise(rb_eLocalJumpError,\"return from proc-closure\");
323
+ } else {
324
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
325
+ frb_jump_tag(aux);
326
+ }
327
+ } else {
328
+ rb_raise(rb_eLocalJumpError, \"unexpected return\");
329
+ }
330
+ "
331
+ when :lambda
332
+ "
333
+ if (aux == FASTRUBY_TAG_RETURN) {
334
+ if (plocals->targetted == 1) {
335
+ last_expression = ((typeof(plocals))(pframe->plocals))->return_value;
336
+ goto fastruby_local_next;
337
+
338
+ } else {
339
+ rb_raise(rb_eLocalJumpError, \"unexpected return\");
340
+ }
341
+ } else {
342
+ rb_raise(rb_eLocalJumpError, \"unexpected return\");
343
+ }
344
+ "
345
+ else
346
+ "
347
+ frb_jump_tag(aux);
348
+ return frame.return_value;
349
+ "
350
+ end
351
+ }
352
+
353
+ }
354
+ }
355
+
356
+ #{
357
+ if call_type == :callcc
358
+ "
359
+ if (rb_obj_is_kind_of(arg, rb_const_get(rb_cObject, #{intern_num :Continuation}))) {
360
+ struct FASTRUBYTHREADDATA* thread_data = frame.thread_data;
361
+ rb_ivar_set(arg,#{intern_num :__stack_chunk},thread_data->rb_stack_chunk);
362
+ }
363
+ "
364
+ end
365
+ }
366
+
367
+ fastruby_local_redo:
368
+ #{str_impl};
369
+
370
+ #{
371
+ case call_type
372
+ when :proc_new
373
+ "
374
+ return last_expression;
375
+ local_return:
376
+ aux = FASTRUBY_TAG_RETURN;
377
+ plocals->return_value = last_expression;
378
+ plocals->targetted = 1;
379
+ goto _local_return;
380
+ "
381
+ when :lambda
382
+ "
383
+ local_return:
384
+ "
385
+ else
386
+ "
387
+ return last_expression;
388
+ local_return:
389
+ plocals->return_value = last_expression;
390
+ plocals->targetted = 1;
391
+ frb_jump_tag(FASTRUBY_TAG_RETURN);
392
+ "
393
+ end
394
+ }
395
+
396
+
397
+ fastruby_local_next:
398
+ #{
399
+ if call_type == :proc_new or call_type == :lambda
400
+ "
401
+ ((typeof(plocals))(pframe->plocals))->call_frame = old_call_frame;
402
+ "
403
+ end
404
+ }
405
+ return last_expression;
406
+ }
407
+ "
408
+ }
409
+
410
+ fastruby_str_arg_initialization = ""
411
+
412
+ if not args_tree
413
+ fastruby_str_arg_initialization = ""
414
+ elsif args_tree.first == :lasgn
415
+ fastruby_str_arg_initialization = "plocals->#{args_tree[1]} = argv[0];"
416
+ elsif args_tree.first == :masgn
417
+ arguments = args_tree[1][1..-1]
418
+
419
+ (0..arguments.size-1).each do |i|
420
+ arg = arguments[i]
421
+ if arg[0] == :lasgn
422
+ fastruby_str_arg_initialization << "plocals->#{arg.last} = #{i} < argc ? argv[#{i}] : Qnil;\n"
423
+ elsif arg[0] == :splat
424
+ fastruby_str_arg_initialization << "plocals->#{arg.last.last} = rb_ary_new2(#{arguments.size-1-i});\n
425
+ {
426
+ int i;
427
+ for (i=#{i};i<argc;i++){
428
+ rb_ary_store(plocals->#{arg.last.last},i-#{i},argv[i]);
429
+ }
430
+ }
431
+ "
432
+ end
433
+ end
434
+ end
435
+
436
+ block_code = proc { |name| "
437
+ static VALUE #{name}(int argc, VALUE* argv, VALUE _locals, VALUE _parent_frame) {
438
+ // block for call to #{call_tree[2]}
439
+ volatile VALUE last_expression = Qnil;
440
+ #{@frame_struct} frame;
441
+ #{@frame_struct} * volatile pframe = (void*)&frame;
442
+ #{@frame_struct} * volatile parent_frame = (void*)_parent_frame;
443
+ #{@locals_struct} * volatile plocals;
444
+
445
+ frame.plocals = (void*)_locals;
446
+ frame.parent_frame = parent_frame;
447
+ frame.return_value = Qnil;
448
+ frame.rescue = 0;
449
+ frame.targetted = 0;
450
+ frame.thread_data = 0;
451
+ if (parent_frame != 0) frame.thread_data = parent_frame->thread_data;
452
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
453
+
454
+ plocals = frame.plocals;
455
+
456
+ #{fastruby_str_arg_initialization}
457
+
458
+ int aux = setjmp(frame.jmp);
459
+ if (aux != 0) {
460
+ if (pframe->targetted == 0) {
461
+ if (aux == FASTRUBY_TAG_NEXT) {
462
+ return pframe->thread_data->accumulator;
463
+ } else if (aux == FASTRUBY_TAG_REDO) {
464
+ // do nothing and let execute the block again
465
+ } else {
466
+ longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
467
+ }
468
+ }
469
+
470
+ }
471
+
472
+ fastruby_local_redo:
473
+ #{str_impl};
474
+
475
+ return last_expression;
476
+ local_return:
477
+ plocals->return_value = last_expression;
478
+ plocals->targetted = 1;
479
+ longjmp(pframe->jmp, FASTRUBY_TAG_RETURN);
480
+ fastruby_local_next:
481
+ return last_expression; }
482
+ "
483
+ }
484
+
485
+ caller_code = nil
486
+ convention_global_name = add_global_name("int",0)
487
+
488
+ precode = "
489
+ struct FASTRUBYTHREADDATA* thread_data = 0;
490
+ VALUE saved_rb_stack_chunk = Qnil;
491
+
492
+ VALUE next_recv = plocals->self;
493
+
494
+ #{
495
+ if recv_tree
496
+ to_c recv_tree, "next_recv"
497
+ end
498
+ };
499
+
500
+ pframe->next_recv = next_recv;
501
+ #ifdef RUBY_1_8
502
+ NODE* node = rb_method_node(CLASS_OF(pframe->next_recv), #{intern_num mname});
503
+ #endif
504
+ #ifdef RUBY_1_9
505
+ void* node = rb_method_entry(CLASS_OF(pframe->next_recv), #{intern_num mname});
506
+ #endif
507
+
508
+ if (node == #{@callcc_node_gvar}) {
509
+
510
+ // freeze all stacks
511
+ thread_data = rb_current_thread_data();
512
+
513
+ if (thread_data != 0) {
514
+ VALUE rb_stack_chunk = thread_data->rb_stack_chunk;
515
+ saved_rb_stack_chunk = rb_stack_chunk;
516
+
517
+ // freeze the complete chain of stack chunks
518
+ while (rb_stack_chunk != Qnil) {
519
+ struct STACKCHUNK* stack_chunk;
520
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
521
+
522
+ stack_chunk_freeze(stack_chunk);
523
+
524
+ rb_stack_chunk = rb_ivar_get(rb_stack_chunk,#{intern_num :_parent_stack_chunk});
525
+ }
526
+ }
527
+ }
528
+ "
529
+
530
+ postcode = "
531
+ if (node == #{@callcc_node_gvar}) {
532
+ thread_data->rb_stack_chunk = saved_rb_stack_chunk;
533
+ }
534
+ "
535
+
536
+
537
+ funcall_call_code = "
538
+ #{
539
+ frame_call(
540
+ "ret = " + protected_block("
541
+
542
+ void* caller_func;
543
+ void* block_func;
544
+ typeof(plocals) current_plocals;
545
+
546
+ if (pframe->thread_data == 0) pframe->thread_data = rb_current_thread_data();
547
+ void* last_plocals = pframe->thread_data->last_plocals;
548
+
549
+ #ifdef RUBY_1_8
550
+ NODE* node = rb_method_node(CLASS_OF(pframe->next_recv), #{intern_num mname});
551
+ #endif
552
+ #ifdef RUBY_1_9
553
+ void* node = rb_method_entry(CLASS_OF(pframe->next_recv), #{intern_num mname});
554
+ #endif
555
+
556
+ if (
557
+ node == #{@proc_node_gvar} ||
558
+ node == #{@lambda_node_gvar}
559
+ ) {
560
+
561
+ caller_func = #{anonymous_function(:lambda,&rb_funcall_caller_code)};
562
+ block_func = #{anonymous_function(:lambda,&rb_funcall_block_code)};
563
+ } else if (node == #{@procnew_node_gvar} && pframe->next_recv == rb_cProc) {
564
+ caller_func = #{anonymous_function(:lambda,&rb_funcall_caller_code)};
565
+ block_func = #{anonymous_function(:proc_new,&rb_funcall_block_code)};
566
+ } else if (node == #{@callcc_node_gvar}) {
567
+ caller_func = #{anonymous_function(:normal,&rb_funcall_caller_code)};
568
+ block_func = #{anonymous_function(:callcc,&rb_funcall_block_code)};
569
+ } else {
570
+ caller_func = #{anonymous_function(:normal,&rb_funcall_caller_code)};
571
+ block_func = #{anonymous_function(:normal,&rb_funcall_block_code)};
572
+ }
573
+
574
+
575
+ #{if call_args_tree.size > 1 and call_args_tree.last[0] == :splat
576
+ "
577
+ VALUE args_array[3];
578
+ VALUE array = Qnil;
579
+
580
+ #{to_c call_args_tree.last[1], "array"};
581
+
582
+ if (TYPE(array) != T_ARRAY) {
583
+ array = rb_ary_new4(1,&array);
584
+ }
585
+
586
+ int argc = #{call_args_tree.size-2};
587
+ VALUE argv[#{call_args_tree.size} + _RARRAY_LEN(array)];
588
+
589
+ VALUE aux_ = Qnil;;
590
+ #{
591
+ i = -1
592
+ call_args_tree[1..-2].map {|arg|
593
+ i = i + 1
594
+ "
595
+ #{to_c arg, "aux_"};
596
+ argv[#{i}] = aux_;
597
+ "
598
+ }.join(";\n")
599
+ };
600
+
601
+ int array_len = _RARRAY_LEN(array);
602
+
603
+ int i;
604
+ for (i=0; i<array_len;i++) {
605
+ argv[argc] = rb_ary_entry(array,i);
606
+ argc++;
607
+ }
608
+
609
+ args_array[0] = (VALUE)pframe;
610
+ args_array[1] = (VALUE)argc;
611
+ args_array[2] = (VALUE)argv;
612
+
613
+ last_expression = rb_iterate(
614
+ caller_func,
615
+ (VALUE)args_array,
616
+ block_func,
617
+ (VALUE)plocals);
618
+
619
+ "
620
+ else
621
+ "
622
+
623
+ VALUE args_array[#{call_args_tree.size+2}];
624
+ VALUE aux___ = Qnil;
625
+ args_array[0] = (VALUE)pframe;
626
+
627
+ #{
628
+ (0..call_args_tree.size-2).map{|i|
629
+ to_c(call_args_tree[i+1], "aux___")+";"+
630
+ "args_array[#{i+1}] = aux___;"
631
+ }.join("\n")
632
+ }
633
+
634
+ last_expression = rb_iterate(
635
+ caller_func,
636
+ (VALUE)args_array,
637
+ block_func,
638
+ (VALUE)plocals);
639
+ "
640
+ end
641
+ }
642
+ if (node == #{@callcc_node_gvar}) {
643
+
644
+ // remove active flags of abandoned stack
645
+ current_plocals = pframe->thread_data->last_plocals;
646
+ while (current_plocals) {
647
+ current_plocals->active = Qfalse;
648
+ current_plocals = (typeof(current_plocals))(current_plocals->parent_locals);
649
+ }
650
+
651
+ // restore last_plocals
652
+ pframe->thread_data->last_plocals = last_plocals;
653
+
654
+ // mark all scopes as active
655
+ current_plocals = last_plocals;
656
+
657
+ while (current_plocals) {
658
+ current_plocals->active = Qtrue;
659
+ current_plocals = (typeof(current_plocals))(current_plocals->parent_locals);
660
+ }
661
+ }
662
+ ", true), precode, postcode
663
+ )
664
+ };
665
+ "
666
+
667
+ recvtype = nil if call_args_tree.size > 1 ? call_args_tree.last[0] == :splat : false
668
+ unless recvtype
669
+ if result_var
670
+ "#{result_var} = #{funcall_call_code};"
671
+ else
672
+ funcall_call_code
673
+ end
674
+ else
675
+ encoded_address = dynamic_block_call(signature,mname)
676
+
677
+ if call_args_tree.size > 1
678
+ strargs = (0..call_args_tree.size-2).map{|i| "arg#{i}"}.join(",")
679
+ else
680
+ strargs = ""
681
+ end
682
+
683
+ fastruby_call_code = "
684
+ // call to #{call_tree[2]}
685
+ #{
686
+ if call_args_tree.size > 1
687
+ " #{
688
+ (0..call_args_tree.size-2).map{|i|
689
+ "VALUE arg#{i} = Qnil;"
690
+ }.join("\n")
691
+ }
692
+
693
+ #{
694
+ (0..call_args_tree.size-2).map{|i|
695
+ to_c(call_args_tree[i+1], "arg#{i}")+";"
696
+ }.join("\n")
697
+ }
698
+ "
699
+ end
700
+ };
701
+
702
+ VALUE recv = plocals->self;
703
+
704
+ #{
705
+ if recv_tree
706
+ to_c recv_tree, "recv"
707
+ end
708
+ }
709
+
710
+ int block_call = 0;
711
+ ret = ((VALUE(*)(VALUE,void*,void*,int,VALUE*,int*))#{encoded_address})(recv, &block, &call_frame, #{call_args_tree.size-1}, (VALUE[]){#{strargs}},&block_call);
712
+
713
+ if (block_call) {
714
+ ret = #{funcall_call_code};
715
+ }
716
+ "
717
+
718
+ code = "
719
+ #{fastruby_call_code};
720
+ "
721
+
722
+ fastruby_precode = " #{@block_struct} block;
723
+
724
+ block.block_function_address = ((void*)#{anonymous_function(&block_code)});
725
+ block.block_function_param = ((void*)plocals);
726
+ block.proc = Qnil;
727
+ "
728
+
729
+ if result_var
730
+ "#{result_var} = #{frame_call(code,fastruby_precode,"")}"
731
+ else
732
+ frame_call(code,fastruby_precode,"")
733
+ end
734
+
735
+ end
736
+ end
737
+ end
738
+ end