fastruby 0.0.21 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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