fastruby 0.0.19 → 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/CHANGELOG +8 -0
  2. data/{README → README.rdoc} +6 -1
  3. data/Rakefile +7 -7
  4. data/benchmarks/benchmark.rb~ +14 -2
  5. data/ext/fastruby_base/fastruby_base.inl +8 -4
  6. data/lib/fastruby/builder/inference_updater.rb +76 -0
  7. data/lib/fastruby/builder/inference_updater.rb~ +76 -0
  8. data/lib/fastruby/builder/inferencer.rb +38 -0
  9. data/lib/fastruby/{inliner → builder}/inliner.rb +16 -27
  10. data/lib/fastruby/builder/inliner.rb~ +60 -0
  11. data/lib/fastruby/builder/locals_inference.rb +53 -0
  12. data/lib/fastruby/builder/lvar_type.rb +43 -0
  13. data/lib/fastruby/builder/lvar_type.rb~ +44 -0
  14. data/lib/fastruby/builder/pipeline.rb +43 -0
  15. data/lib/fastruby/builder/pipeline.rb~ +43 -0
  16. data/lib/fastruby/{reductor → builder}/reductor.rb +6 -3
  17. data/lib/fastruby/builder/reductor.rb~ +42 -0
  18. data/lib/fastruby/builder.rb +73 -25
  19. data/lib/fastruby/builder.rb~ +311 -0
  20. data/lib/fastruby/corelib/fixnum.rb +75 -0
  21. data/lib/fastruby/corelib/fixnum.rb~ +146 -0
  22. data/lib/fastruby/corelib/integer.rb +96 -0
  23. data/lib/fastruby/corelib/integer.rb~ +96 -0
  24. data/lib/fastruby/corelib.rb +23 -0
  25. data/lib/fastruby/corelib.rb~ +23 -0
  26. data/lib/fastruby/getlocals.rb +3 -1
  27. data/lib/fastruby/logging.rb +2 -2
  28. data/lib/fastruby/modules/inferencer/infer.rb +31 -0
  29. data/lib/fastruby/modules/inferencer/literal.rb +42 -0
  30. data/lib/fastruby/modules/inliner/call.rb +327 -0
  31. data/lib/fastruby/{inliner/modules/call.rb → modules/inliner/call.rb~} +14 -24
  32. data/lib/fastruby/modules/inliner/defn.rb +41 -0
  33. data/lib/fastruby/modules/inliner/defn.rb~ +29 -0
  34. data/lib/fastruby/modules/inliner/recursive.rb +40 -0
  35. data/lib/fastruby/{inliner/modules/recursive.rb → modules/inliner/recursive.rb~} +1 -1
  36. data/lib/fastruby/modules/lvar_type/call.rb +36 -0
  37. data/lib/fastruby/modules/lvar_type/call.rb~ +36 -0
  38. data/lib/fastruby/modules/lvar_type/defn.rb +42 -0
  39. data/lib/fastruby/modules/lvar_type/defn.rb~ +42 -0
  40. data/lib/fastruby/modules/lvar_type/lasgn.rb +41 -0
  41. data/lib/fastruby/modules/lvar_type/lasgn.rb~ +42 -0
  42. data/lib/fastruby/modules/lvar_type/recursive.rb +33 -0
  43. data/lib/fastruby/modules/lvar_type/recursive.rb~ +33 -0
  44. data/lib/fastruby/{reductor/modules → modules/reductor}/case.rb +0 -0
  45. data/lib/fastruby/modules/reductor/fastruby_flag.rb +33 -0
  46. data/lib/fastruby/{reductor/modules → modules/reductor}/for.rb +0 -0
  47. data/lib/fastruby/{reductor/modules → modules/reductor}/nontree.rb +0 -0
  48. data/lib/fastruby/modules/reductor/nontree.rb~ +32 -0
  49. data/lib/fastruby/{reductor/modules → modules/reductor}/recursive.rb +1 -1
  50. data/lib/fastruby/modules/reductor/recursive.rb~ +31 -0
  51. data/lib/fastruby/{translator/modules → modules/translator}/block.rb +0 -0
  52. data/lib/fastruby/modules/translator/call.rb +344 -0
  53. data/lib/fastruby/{translator/modules/call.rb → modules/translator/call.rb~} +24 -3
  54. data/lib/fastruby/{translator/modules → modules/translator}/defn.rb +10 -9
  55. data/lib/fastruby/modules/translator/defn.rb~ +267 -0
  56. data/lib/fastruby/{translator/modules → modules/translator}/directive.rb +3 -1
  57. data/lib/fastruby/modules/translator/directive.rb~ +44 -0
  58. data/lib/fastruby/{translator/modules → modules/translator}/exceptions.rb +3 -1
  59. data/lib/fastruby/modules/translator/exceptions.rb~ +120 -0
  60. data/lib/fastruby/{translator/modules → modules/translator}/flow.rb +0 -0
  61. data/lib/fastruby/modules/translator/iter.rb +745 -0
  62. data/lib/fastruby/{translator/modules/iter.rb → modules/translator/iter.rb~} +103 -48
  63. data/lib/fastruby/modules/translator/literal.rb +150 -0
  64. data/lib/fastruby/{translator/modules/literal.rb → modules/translator/literal.rb~} +3 -3
  65. data/lib/fastruby/{translator/modules → modules/translator}/logical.rb +0 -0
  66. data/lib/fastruby/{translator/modules → modules/translator}/method_group.rb +0 -0
  67. data/lib/fastruby/{translator/modules → modules/translator}/nonlocal.rb +18 -6
  68. data/lib/fastruby/modules/translator/nonlocal.rb~ +298 -0
  69. data/lib/fastruby/modules/translator/static.rb +290 -0
  70. data/lib/fastruby/{translator/modules/static.rb → modules/translator/static.rb~} +66 -17
  71. data/lib/fastruby/modules/translator/variable.rb +280 -0
  72. data/lib/fastruby/{translator/modules/variable.rb → modules/translator/variable.rb~} +14 -44
  73. data/lib/fastruby/modules.rb +30 -0
  74. data/lib/fastruby/object.rb +42 -6
  75. data/lib/fastruby/object.rb~ +159 -0
  76. data/lib/fastruby/set_tree.rb +7 -11
  77. data/lib/fastruby/set_tree.rb~ +71 -0
  78. data/lib/fastruby/sexp_extension.rb +29 -7
  79. data/lib/fastruby/sexp_extension.rb~ +262 -0
  80. data/lib/fastruby/translator/scope_mode_helper.rb~ +138 -0
  81. data/lib/fastruby/translator/translator.rb +87 -92
  82. data/lib/fastruby/translator/translator.rb~ +1600 -0
  83. data/lib/fastruby/translator/translator_modules.rb +3 -1
  84. data/lib/fastruby/translator/translator_modules.rb~ +53 -0
  85. data/lib/fastruby.rb +3 -1
  86. data/lib/fastruby.rb~ +3 -1
  87. data/lib/fastruby_only/base.rb +1 -0
  88. data/spec/corelib/numeric/fixnum_spec.rb +110 -0
  89. data/spec/corelib/numeric/fixnum_spec.rb~ +104 -0
  90. data/spec/corelib/numeric/integer_spec.rb +173 -0
  91. data/spec/corelib/numeric/integer_spec.rb~ +173 -0
  92. data/spec/fastruby_only/base_spec.rb +74 -0
  93. data/spec/graph/base_spec.rb +2 -1
  94. data/spec/graph/base_spec.rb~ +35 -0
  95. data/spec/graph/path_spec.rb +2 -2
  96. data/spec/graph/path_spec.rb~ +48 -0
  97. data/spec/graph/vertex_spec.rb +2 -1
  98. data/spec/graph/vertex_spec.rb~ +58 -0
  99. data/spec/reductor/base_spec.rb +1 -1
  100. data/spec/ruby/block/lambda_spec.rb~ +163 -0
  101. data/spec/ruby/block/proc_as_block_spec.rb~ +69 -1
  102. data/spec/ruby/block_spec.rb~ +2 -494
  103. data/spec/ruby/call/base_call_spec.rb +1 -1
  104. data/spec/ruby/call/base_call_spec.rb~ +2 -60
  105. data/spec/ruby/defn/replacement_spec.rb +26 -14
  106. data/spec/ruby/defn/replacement_spec.rb~ +13 -3
  107. data/spec/ruby/exception/internal_ex_spec.rb~ +86 -0
  108. data/spec/ruby/integrity_spec.rb~ +35 -1
  109. data/spec/ruby/variable_spec.rb~ +31 -0
  110. data/spec/scope_mode/flow_spec.rb +1 -1
  111. data/spec/scope_mode/flow_spec.rb~ +109 -0
  112. data/spec/sugar/base_spec.rb +29 -0
  113. data/spec/sugar/base_spec.rb~ +16 -0
  114. metadata +100 -43
  115. data/spec/fastruby/inliner/modules/call_spec.rb +0 -0
  116. data/spec/fastruby/translator/modules/nonlocal_spec.rb +0 -0
  117. data/spec/fastruby/translator/translator_spec.rb +0 -0
  118. data/spec/ruby/block/arguments_spec.rb~ +0 -214
  119. data/spec/ruby/block/break_spec.rb~ +0 -236
  120. data/spec/ruby/block/next_spec.rb~ +0 -85
  121. data/spec/ruby/block/retry_spec.rb~ +0 -43
@@ -0,0 +1,1600 @@
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 "rubygems"
23
+ require "sexp"
24
+ require "fastruby/method_extension"
25
+ require "fastruby/set_tree"
26
+ require "fastruby/exceptions"
27
+ require "fastruby/translator/translator_modules"
28
+ require "fastruby/translator/scope_mode_helper"
29
+ require "fastruby/modules"
30
+ require "define_method_handler"
31
+ require "base64"
32
+
33
+ module FastRuby
34
+ class Context
35
+ attr_accessor :locals
36
+ attr_accessor :options
37
+ attr_reader :no_cache
38
+ attr_reader :init_extra
39
+ attr_reader :extra_code
40
+
41
+ class Value
42
+ attr_accessor :value
43
+ def initialize(v); @value = v; end
44
+ end
45
+
46
+ def self.define_translator_for(ntype, options = {}, &blk)
47
+ condition_blk = proc do |*x|
48
+ tree = x.first; tree.node_type == ntype
49
+ end
50
+
51
+ if options[:arity]
52
+ if options[:arity] == 1
53
+ condition_blk = proc do |*x|
54
+ tree = x.first; x.size == 1 and tree.node_type == ntype
55
+ end
56
+ end
57
+ end
58
+
59
+ define_method_handler(:to_c, options, &blk).condition &condition_blk
60
+ end
61
+
62
+ define_method_handler(:to_c, :priority => 10000){|*x|
63
+ "Qnil"
64
+ }.condition{|*x| x.size == 1 and (not x.first)}
65
+
66
+ define_method_handler(:to_c, :priority => 1000){|tree, result_var|
67
+ "#{result_var} = #{to_c(tree)};"
68
+ }.condition{|*x| x.size == 2 and (not x.first)}
69
+
70
+ define_method_handler(:to_c, :priority => -9000){ |tree, result_var|
71
+ "#{result_var} = #{to_c(tree)};"
72
+ }.condition{|*x| x.size == 2 }
73
+
74
+ define_method_handler(:to_c, :priority => -10000) do |*x|
75
+ tree, result_var = x
76
+
77
+ raise "undefined translator for node type :#{tree.node_type}"
78
+ end
79
+
80
+ define_method_handler(:initialize_to_c){|*x|}.condition{|*x|false}
81
+
82
+ define_translator_for(:call, :priority => 100){ |*x|
83
+ tree, result_var = x
84
+
85
+ tree[2] = :fastruby_require
86
+ to_c(tree)
87
+ }.condition{|*x|
88
+ tree = x.first; tree.node_type == :call && tree[2] == :require
89
+ }
90
+
91
+ define_method_handler(:infer_value, :priority => -1000) do |tree|
92
+ nil
93
+ end
94
+
95
+ FastRuby::Modules.load_all("translator")
96
+
97
+ def catch_block(*catchs)
98
+ old_catch_blocks = @catch_blocks.dup
99
+ begin
100
+ catchs.each &@catch_blocks.method(:<<)
101
+ return yield
102
+ ensure
103
+ @catch_blocks = old_catch_blocks
104
+ end
105
+ end
106
+
107
+ def initialize(common_func = true, inferencer = nil)
108
+ initialize_to_c
109
+
110
+ @inferencer = inferencer
111
+ @catch_blocks = []
112
+ @no_cache = false
113
+ @extra_code = ""
114
+ @options = {}
115
+ @init_extra = Array.new
116
+ @frame_struct = "struct {
117
+ void* parent_frame;
118
+ void* plocals;
119
+ jmp_buf jmp;
120
+ VALUE return_value;
121
+ int rescue;
122
+ VALUE last_error;
123
+ VALUE next_recv;
124
+ int targetted;
125
+ struct FASTRUBYTHREADDATA* thread_data;
126
+ }"
127
+
128
+ @block_struct = "struct {
129
+ void* block_function_address;
130
+ void* block_function_param;
131
+ VALUE proc;
132
+ }"
133
+
134
+ extra_code << "
135
+ static void frb_jump_tag(int state) {
136
+ VALUE exception = rb_funcall(#{literal_value FastRuby::JumpTagException}, #{intern_num :new},1,INT2FIX(state));
137
+ rb_exc_raise(exception);
138
+ }
139
+ "
140
+
141
+ extra_code << "
142
+ #define FASTRUBY_TAG_RETURN 0x80
143
+ #define FASTRUBY_TAG_NEXT 0x81
144
+ #define FASTRUBY_TAG_BREAK 0x82
145
+ #define FASTRUBY_TAG_RAISE 0x83
146
+ #define FASTRUBY_TAG_REDO 0x84
147
+ #define FASTRUBY_TAG_RETRY 0x85
148
+ #define TAG_RAISE 0x6
149
+
150
+ # define PTR2NUM(x) (ULONG2NUM((unsigned long)(x)))
151
+ # define NUM2PTR(x) ((void*)(NUM2ULONG(x)))
152
+
153
+ #ifndef __INLINE_FASTRUBY_BASE
154
+ #include \"#{FastRuby.fastruby_load_path}/../ext/fastruby_base/fastruby_base.inl\"
155
+ #define __INLINE_FASTRUBY_BASE
156
+ #endif
157
+ "
158
+
159
+ ruby_code = "
160
+ unless $LOAD_PATH.include? #{FastRuby.fastruby_load_path.inspect}
161
+ $LOAD_PATH << #{FastRuby.fastruby_load_path.inspect}
162
+ end
163
+ require #{FastRuby.fastruby_script_path.inspect}
164
+ "
165
+
166
+ init_extra << "
167
+ rb_eval_string(#{ruby_code.inspect});
168
+ "
169
+
170
+
171
+ if RUBY_VERSION =~ /^1\.8/
172
+
173
+ @lambda_node_gvar = add_global_name("NODE*", 0);
174
+ @proc_node_gvar = add_global_name("NODE*", 0);
175
+ @procnew_node_gvar = add_global_name("NODE*", 0);
176
+ @callcc_node_gvar = add_global_name("NODE*", 0);
177
+
178
+ init_extra << "
179
+ #{@lambda_node_gvar} = rb_method_node(rb_cObject, #{intern_num :lambda});
180
+ #{@proc_node_gvar} = rb_method_node(rb_cObject, #{intern_num :proc});
181
+ #{@procnew_node_gvar} = rb_method_node(CLASS_OF(rb_cProc), #{intern_num :new});
182
+ #{@callcc_node_gvar} = rb_method_node(rb_mKernel, #{intern_num :callcc});
183
+ "
184
+ elsif RUBY_VERSION =~ /^1\.9/
185
+
186
+ @lambda_node_gvar = add_global_name("void*", 0);
187
+ @proc_node_gvar = add_global_name("void*", 0);
188
+ @procnew_node_gvar = add_global_name("void*", 0);
189
+ @callcc_node_gvar = add_global_name("void*", 0);
190
+
191
+ init_extra << "
192
+ #{@lambda_node_gvar} = rb_method_entry(rb_cObject, #{intern_num :lambda});
193
+ #{@proc_node_gvar} = rb_method_entry(rb_cObject, #{intern_num :proc});
194
+ #{@procnew_node_gvar} = rb_method_entry(CLASS_OF(rb_const_get(rb_cObject, #{intern_num :Proc})), #{intern_num :new});
195
+ #{@callcc_node_gvar} = rb_method_entry(rb_mKernel, #{intern_num :callcc});
196
+ "
197
+ end
198
+
199
+ @common_func = common_func
200
+ if common_func
201
+ extra_code << "static VALUE _rb_gvar_set(void* ge,VALUE value) {
202
+ rb_gvar_set((struct global_entry*)ge,value);
203
+ return value;
204
+ }
205
+ "
206
+
207
+ extra_code << "static VALUE re_yield(int argc, VALUE* argv, VALUE param, VALUE _parent_frame) {
208
+ VALUE yield_args = rb_ary_new4(argc,argv);
209
+ VALUE* yield_args_p = &yield_args;
210
+
211
+ #{@frame_struct}* pframe;
212
+ pframe = (typeof(pframe))_parent_frame;
213
+
214
+ return #{protected_block("last_expression = rb_yield_splat(*(VALUE*)yield_args_p)",true,"yield_args_p",true)};
215
+ }"
216
+
217
+ extra_code << "static VALUE _rb_ivar_set(VALUE recv,ID idvar, VALUE value) {
218
+ rb_ivar_set(recv,idvar,value);
219
+ return value;
220
+ }
221
+ "
222
+
223
+ extra_code << "static VALUE __rb_cvar_set(VALUE recv,ID idvar, VALUE value, int warn) {
224
+ #{if RUBY_VERSION =~ /^1\.9/
225
+ "rb_cvar_set(recv,idvar,value);"
226
+ elsif RUBY_VERSION =~ /^1\.8/
227
+ "rb_cvar_set(recv,idvar,value,warn);"
228
+ else
229
+ raise RuntimeError, "unsupported ruby version #{RUBY_VERSION}"
230
+ end
231
+ }
232
+
233
+ return value;
234
+ }
235
+ "
236
+
237
+ extra_code << "static VALUE _lvar_assing(VALUE* destination,VALUE value) {
238
+ *destination = value;
239
+ return value;
240
+ }
241
+
242
+ /*
243
+ #{caller.join("\n")}
244
+ */
245
+
246
+ "
247
+
248
+ end
249
+ end
250
+
251
+
252
+ def _raise(class_tree, message_tree = nil)
253
+ class_tree = to_c class_tree unless class_tree.instance_of? String
254
+
255
+ if message_tree.instance_of? String
256
+ message_tree = "rb_str_new2(#{message_tree.inspect})"
257
+ else
258
+ message_tree = to_c message_tree
259
+ end
260
+
261
+ if message_tree
262
+ return inline_block("
263
+ pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},1,#{message_tree});
264
+ longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
265
+ return Qnil;
266
+ ")
267
+ else
268
+ return inline_block("
269
+ pframe->thread_data->exception = rb_funcall(#{class_tree}, #{intern_num :exception},0);
270
+ longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
271
+ return Qnil;
272
+ ")
273
+ end
274
+
275
+ end
276
+
277
+ def anonymous_function(*x)
278
+
279
+ name = "anonymous" + rand(10000000).to_s
280
+ extra_code << yield(name,*x)
281
+
282
+ name
283
+ end
284
+
285
+ def frame_call(inner_code, precode = "", postcode = "")
286
+ inline_block "
287
+
288
+ volatile VALUE ret = Qnil;
289
+ // create a call_frame
290
+ #{@frame_struct} call_frame;
291
+ typeof(call_frame)* volatile old_pframe = (void*)pframe;
292
+
293
+ pframe = (typeof(pframe))&call_frame;
294
+
295
+ call_frame.parent_frame = (void*)pframe;
296
+ call_frame.plocals = plocals;
297
+ call_frame.return_value = Qnil;
298
+ call_frame.targetted = 0;
299
+ call_frame.thread_data = old_pframe->thread_data;
300
+ if (call_frame.thread_data == 0) call_frame.thread_data = rb_current_thread_data();
301
+
302
+ void* volatile old_call_frame = plocals->call_frame;
303
+ plocals->call_frame = &call_frame;
304
+
305
+ #{precode}
306
+
307
+ int aux = setjmp(call_frame.jmp);
308
+ if (aux != 0) {
309
+ if (call_frame.targetted == 0) {
310
+ #{postcode}
311
+ longjmp(old_pframe->jmp,aux);
312
+ }
313
+
314
+ if (aux == FASTRUBY_TAG_BREAK) {
315
+ plocals->call_frame = old_call_frame;
316
+ #{postcode}
317
+ return call_frame.return_value;
318
+ } else if (aux == FASTRUBY_TAG_RETRY ) {
319
+ // do nothing and let the call execute again
320
+ } else {
321
+ plocals->call_frame = old_call_frame;
322
+ #{postcode}
323
+ return call_frame.return_value;
324
+ }
325
+ }
326
+
327
+
328
+ #{inner_code};
329
+
330
+ #{postcode}
331
+
332
+ plocals->call_frame = old_call_frame;
333
+ return ret;
334
+ "
335
+ end
336
+
337
+ def initialize_method_structs(args_tree)
338
+ @locals_struct = "struct {
339
+ int size;
340
+ void* call_frame;
341
+ void* parent_locals;
342
+ void* pframe;
343
+ void* block_function_address;
344
+ void* block_function_param;
345
+ VALUE active;
346
+ VALUE targetted;
347
+ VALUE return_value;
348
+ #{@locals.map{|l| "VALUE #{l};\n"}.join}
349
+ }"
350
+
351
+ end
352
+
353
+ def add_main
354
+ if options[:main]
355
+
356
+ extra_code << "
357
+ static VALUE #{@alt_method_name}(VALUE self__);
358
+ static VALUE main_proc_call(VALUE self__, VALUE signature, VALUE class_self_) {
359
+ #{@alt_method_name}(class_self_);
360
+ return Qnil;
361
+ }
362
+
363
+ "
364
+
365
+ init_extra << "
366
+ {
367
+ VALUE newproc = rb_funcall(rb_cObject,#{intern_num :new},0);
368
+ rb_define_singleton_method(newproc, \"call\", main_proc_call, 2);
369
+ rb_gv_set(\"$last_obj_proc\", newproc);
370
+ }
371
+ "
372
+ end
373
+ end
374
+
375
+ def define_method_at_init(method_name, size, signature)
376
+ extra_code << "
377
+ static VALUE main_proc_call(VALUE self__, VALUE signature, VALUE class_self_) {
378
+ VALUE method_name = rb_funcall(
379
+ #{literal_value FastRuby},
380
+ #{intern_num :make_str_signature},
381
+ 2,
382
+ #{literal_value method_name},
383
+ signature
384
+ );
385
+
386
+ ID id = rb_intern(RSTRING_PTR(method_name));
387
+
388
+ rb_funcall(
389
+ #{literal_value FastRuby},
390
+ #{intern_num :set_builder_module},
391
+ 1,
392
+ class_self_
393
+ );
394
+
395
+ VALUE rb_method_hash;
396
+ void** address = 0;
397
+ rb_method_hash = rb_funcall(class_self_, #{intern_num :method_hash},1,#{literal_value method_name});
398
+
399
+ if (rb_method_hash != Qnil) {
400
+ VALUE tmp = rb_hash_aref(rb_method_hash, PTR2NUM(id));
401
+ if (tmp != Qnil) {
402
+ address = (void*)NUM2PTR(tmp);
403
+ }
404
+ }
405
+
406
+ if (address == 0) {
407
+ address = malloc(sizeof(void*));
408
+ }
409
+ *address = #{@alt_method_name};
410
+
411
+ rb_funcall(
412
+ class_self_,
413
+ #{intern_num :register_method_value},
414
+ 3,
415
+ #{literal_value method_name},
416
+ PTR2NUM(id),
417
+ PTR2NUM(address)
418
+ );
419
+
420
+ return Qnil;
421
+ }
422
+ "
423
+
424
+ init_extra << "
425
+ {
426
+ VALUE newproc = rb_funcall(rb_cObject,#{intern_num :new},0);
427
+ rb_define_singleton_method(newproc, \"call\", main_proc_call, 2);
428
+ rb_gv_set(\"$last_obj_proc\", newproc);
429
+ }
430
+ "
431
+ end
432
+
433
+ def to_c_method(tree, signature = nil)
434
+
435
+ if tree[0] == :defn
436
+ method_name = tree[1]
437
+ original_args_tree = tree[2]
438
+ block_argument = tree[2].find{|x| x.to_s[0] == ?&}
439
+ impl_tree = tree[3][1]
440
+ elsif tree[0] == :defs
441
+ method_name = tree[2]
442
+ original_args_tree = tree[3]
443
+ block_argument = tree[3].find{|x| x.to_s[0] == ?&}
444
+ impl_tree = tree[4][1]
445
+ end
446
+
447
+ if "0".respond_to?(:ord)
448
+ @alt_method_name = "_" + method_name.to_s.gsub("_x_", "_x__x_").gsub(/\W/){|x| "_x_#{x.ord}" } + "_" + rand(10000000000).to_s
449
+ else
450
+ @alt_method_name = "_" + method_name.to_s.gsub("_x_", "_x__x_").gsub(/\W/){|x| "_x_#{x[0]}" } + "_" + rand(10000000000).to_s
451
+ end
452
+
453
+ args_tree = original_args_tree.select{|x| x.to_s[0] != ?&}
454
+
455
+ initialize_method_structs(original_args_tree)
456
+
457
+ if options[:main] then
458
+ strargs = if args_tree.size > 1
459
+ "VALUE self, VALUE block, VALUE _parent_frame, #{(0..signature.size-1).map{|x| "VALUE arg#{x}"}.join(",")}"
460
+ else
461
+ "VALUE self, VALUE block, VALUE _parent_frame"
462
+ end
463
+
464
+ else
465
+
466
+ strargs = "VALUE self, VALUE block, VALUE _parent_frame, int argc, VALUE* argv"
467
+
468
+ splat_arg = args_tree[1..-1].find{|x| x.to_s.match(/\*/) }
469
+
470
+ maxargnum = args_tree[1..-1].count{ |x|
471
+ if x.instance_of? Symbol
472
+ not x.to_s.match(/\*/) and not x.to_s.match(/\&/)
473
+ else
474
+ false
475
+ end
476
+ }
477
+
478
+ minargnum = maxargnum
479
+
480
+ args_tree[1..-1].each do |subtree|
481
+ unless subtree.instance_of? Symbol
482
+ if subtree[0] == :block
483
+ minargnum = minargnum - (subtree.size-1)
484
+ end
485
+ end
486
+ end
487
+
488
+ if args_tree[1..-1].find{|x| x.to_s.match(/\*/)}
489
+ maxargnum = 2147483647
490
+ end
491
+
492
+ read_arguments_code = ""
493
+
494
+
495
+ validate_arguments_code = if signature.size-1 < minargnum
496
+ "
497
+ rb_raise(rb_eArgError, \"wrong number of arguments (#{signature.size-1} for #{minargnum})\");
498
+ "
499
+ elsif signature.size-1 > maxargnum
500
+ "
501
+ rb_raise(rb_eArgError, \"wrong number of arguments (#{signature.size-1} for #{maxargnum})\");
502
+ "
503
+ else
504
+
505
+ default_block_tree = args_tree[1..-1].find{|subtree|
506
+ unless subtree.instance_of? Symbol
507
+ if subtree[0] == :block
508
+ next true
509
+ end
510
+ end
511
+
512
+ false
513
+ }
514
+
515
+ i = -1
516
+
517
+ normalargsnum = args_tree[1..-1].count{|subtree|
518
+ if subtree.instance_of? Symbol
519
+ unless subtree.to_s.match(/\*/) or subtree.to_s.match(/\&/)
520
+ next true
521
+ end
522
+ end
523
+
524
+ false
525
+ }
526
+
527
+ read_arguments_code = args_tree[1..-1].map { |arg_|
528
+ arg = arg_.to_s
529
+ i = i + 1
530
+
531
+ if i < normalargsnum
532
+ if i < signature.size-1
533
+ "plocals->#{arg} = argv[#{i}];\n"
534
+ else
535
+
536
+ if default_block_tree
537
+ initialize_tree = default_block_tree[1..-1].find{|subtree| subtree[1] == arg_}
538
+ if initialize_tree
539
+ to_c(initialize_tree) + ";\n"
540
+ else
541
+ ""
542
+ end
543
+ else
544
+ ";\n"
545
+ end
546
+ end
547
+ else
548
+ ""
549
+ end
550
+ }.join("")
551
+
552
+ if splat_arg
553
+ if signature.size-1 < normalargsnum then
554
+ read_arguments_code << "
555
+ plocals->#{splat_arg.to_s.gsub("*","")} = rb_ary_new3(0);
556
+ "
557
+ else
558
+ read_arguments_code << "
559
+ plocals->#{splat_arg.to_s.gsub("*","")} = rb_ary_new4(
560
+ #{(signature.size-1) - (normalargsnum)}, argv+#{normalargsnum}
561
+ );
562
+ "
563
+ end
564
+
565
+ end
566
+
567
+
568
+ ""
569
+ end
570
+
571
+ if block_argument
572
+
573
+ proc_reyield_block_tree = s(:iter, s(:call, nil, :proc, s(:arglist)), s(:masgn, s(:array, s(:splat, s(:lasgn, :__xproc_arguments)))), s(:yield, s(:splat, s(:lvar, :__xproc_arguments))))
574
+
575
+ require "fastruby/sexp_extension"
576
+
577
+ read_arguments_code << "
578
+ if (pblock ? pblock->proc != Qnil : 0) {
579
+ plocals->#{block_argument.to_s.gsub("&","")} = pblock->proc;
580
+ } else {
581
+ plocals->#{block_argument.to_s.gsub("&","")} = #{to_c FastRuby::FastRubySexp.from_sexp(proc_reyield_block_tree)};
582
+ }
583
+ "
584
+
585
+ read_arguments_code << "
586
+ if (pblock) {
587
+ rb_ivar_set(plocals->#{block_argument.to_s.gsub("&","")},
588
+ #{intern_num "__block_address"}, PTR2NUM(pblock->block_function_address));
589
+ rb_ivar_set(plocals->#{block_argument.to_s.gsub("&","")},
590
+ #{intern_num "__block_param"}, PTR2NUM(pblock->block_function_param));
591
+ }
592
+
593
+ "
594
+ end
595
+
596
+ end
597
+
598
+ require "fastruby/sexp_extension"
599
+
600
+ trs = lambda{|tree|
601
+ if not tree.respond_to? :node_type
602
+ next tree
603
+ elsif tree.node_type == :call
604
+ mmname = tree[2]
605
+ next trs.call(tree[1]) || tree[1] if mmname == :infer
606
+ next fs(:nil) if mmname == :_throw or mmname == :_loop or mmname == :_raise
607
+ next fs(:nil) if mmname == :== and infer_value(tree)
608
+ elsif tree.node_type == :iter
609
+ mmname = tree[1][2]
610
+ next fs(:nil) if mmname == :_static
611
+ next fs(:block, trs.call(tree[3]) || tree[3]) if mmname == :_catch
612
+ end
613
+
614
+ tree.map &trs
615
+ }
616
+
617
+ evaluate_tree = tree.transform &trs
618
+
619
+ scope_mode = FastRuby::ScopeModeHelper.get_scope_mode(evaluate_tree)
620
+ ret = "VALUE #{@alt_method_name || method_name}(#{options[:main] ? "VALUE self" : strargs}) {
621
+ #{validate_arguments_code}
622
+
623
+ #{@frame_struct} frame;
624
+ #{@frame_struct} * volatile pframe;
625
+
626
+ frame.parent_frame = #{options[:main] ? "0" : "(void*)_parent_frame"};
627
+ frame.return_value = Qnil;
628
+ frame.rescue = 0;
629
+ frame.targetted = 0;
630
+ frame.thread_data = #{options[:main] ? "0" : "((typeof(pframe))_parent_frame)->thread_data"};
631
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
632
+
633
+ int stack_chunk_instantiated = 0;
634
+
635
+ #{
636
+ if scope_mode == :dag
637
+ "
638
+ volatile VALUE rb_previous_stack_chunk = Qnil;
639
+ VALUE rb_stack_chunk = frame.thread_data->rb_stack_chunk;
640
+ struct STACKCHUNK* volatile stack_chunk = 0;
641
+
642
+ if (rb_stack_chunk != Qnil) {
643
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
644
+ }
645
+
646
+ if (stack_chunk == 0 || (stack_chunk == 0 ? 0 : stack_chunk_frozen(stack_chunk)) ) {
647
+ rb_previous_stack_chunk = rb_stack_chunk;
648
+ rb_gc_register_address(&rb_stack_chunk);
649
+ stack_chunk_instantiated = 1;
650
+
651
+ rb_stack_chunk = rb_stack_chunk_create(Qnil);
652
+ frame.thread_data->rb_stack_chunk = rb_stack_chunk;
653
+
654
+ rb_ivar_set(rb_stack_chunk, #{intern_num :_parent_stack_chunk}, rb_previous_stack_chunk);
655
+
656
+ Data_Get_Struct(rb_stack_chunk,struct STACKCHUNK,stack_chunk);
657
+ }
658
+
659
+ #{@locals_struct}* volatile plocals;
660
+
661
+ volatile int previous_stack_position = stack_chunk_get_current_position(stack_chunk);
662
+ plocals = (typeof(plocals))stack_chunk_alloc(stack_chunk ,sizeof(typeof(*plocals))/sizeof(void*));
663
+
664
+ "
665
+ else
666
+ "
667
+ #{@locals_struct} locals;
668
+ typeof(locals) * volatile plocals = &locals;
669
+ "
670
+ end
671
+ }
672
+
673
+ plocals->parent_locals = (frame.thread_data->last_plocals);
674
+ void* volatile old_parent_locals = frame.thread_data->last_plocals;
675
+
676
+ #{
677
+ if scope_mode == :dag
678
+ "frame.thread_data->last_plocals = plocals;\n"
679
+ end
680
+ }
681
+
682
+ frame.plocals = plocals;
683
+ plocals->active = Qtrue;
684
+ plocals->targetted = Qfalse;
685
+ plocals->pframe = (&frame);
686
+ plocals->call_frame = (0);
687
+
688
+ pframe = (void*)&frame;
689
+
690
+ #{@block_struct} * volatile pblock;
691
+ volatile VALUE last_expression = Qnil;
692
+
693
+ int aux = setjmp(pframe->jmp);
694
+ if (aux != 0) {
695
+ plocals->active = Qfalse;
696
+
697
+ #{
698
+ if scope_mode == :dag
699
+ "
700
+ stack_chunk_set_current_position(stack_chunk, previous_stack_position);
701
+
702
+ if (stack_chunk_instantiated) {
703
+ rb_gc_unregister_address(&rb_stack_chunk);
704
+ frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
705
+ }
706
+ "
707
+ end
708
+ }
709
+ #{
710
+ unless options[:main]
711
+ "
712
+ if (plocals->targetted == Qfalse || aux != FASTRUBY_TAG_RETURN) {
713
+ frame.thread_data->last_plocals = old_parent_locals;
714
+
715
+ longjmp(((typeof(pframe))_parent_frame)->jmp,aux);
716
+ }
717
+ "
718
+ end
719
+ }
720
+
721
+ frame.thread_data->last_plocals = old_parent_locals;
722
+
723
+ return plocals->return_value;
724
+ }
725
+
726
+ plocals->self = self;
727
+
728
+ #{
729
+ unless options[:main]
730
+ "
731
+ pblock = (void*)block;
732
+ if (pblock) {
733
+ plocals->block_function_address = pblock->block_function_address;
734
+ plocals->block_function_param = pblock->block_function_param;
735
+ } else {
736
+ plocals->block_function_address = (0);
737
+ plocals->block_function_param = 0;
738
+ }
739
+ "
740
+ end
741
+ }
742
+
743
+ #{read_arguments_code}
744
+
745
+ #{to_c impl_tree, "last_expression"};
746
+
747
+ local_return:
748
+ #{
749
+ if scope_mode == :dag
750
+ "
751
+ stack_chunk_set_current_position(stack_chunk, previous_stack_position);
752
+
753
+ if (stack_chunk_instantiated) {
754
+ rb_gc_unregister_address(&rb_stack_chunk);
755
+ frame.thread_data->rb_stack_chunk = rb_previous_stack_chunk;
756
+ }
757
+ "
758
+ end
759
+ }
760
+ plocals->active = Qfalse;
761
+
762
+ frame.thread_data->last_plocals = old_parent_locals;
763
+
764
+ return last_expression;
765
+ }"
766
+
767
+ add_main
768
+ extra_code << ret
769
+
770
+ "
771
+ static VALUE dummy_#{@alt_method_name}_#{rand(1000000000000000000000000000000000)}(VALUE a) {
772
+ return Qnil;
773
+ }
774
+ "
775
+ end
776
+
777
+ def locals_accessor
778
+ "plocals->"
779
+ end
780
+
781
+ def locals_scope(locals)
782
+ old_locals = @locals
783
+ old_locals_struct = @locals_struct
784
+
785
+ @locals = locals
786
+ @locals_struct = "struct {
787
+ int size;
788
+ void* call_frame;
789
+ void* parent_locals;
790
+ void* pframe;
791
+ void* block_function_address;
792
+ void* block_function_param;
793
+ VALUE active;
794
+ VALUE targetted;
795
+ VALUE return_value;
796
+ #{@locals.map{|l| "VALUE #{l};\n"}.join}
797
+ }"
798
+
799
+ begin
800
+ yield
801
+ ensure
802
+ @locals = old_locals
803
+ @locals_struct = old_locals_struct
804
+ end
805
+ end
806
+
807
+ def infer_type(recv)
808
+ array = @inferencer.infer(recv).to_a
809
+
810
+ if array.size == 1
811
+ array[0]
812
+ else
813
+ nil
814
+ end
815
+ end
816
+
817
+ def on_block
818
+ old_on_block = @on_block
819
+ @on_block = true
820
+ return yield
821
+ ensure
822
+ @on_block = old_on_block
823
+ end
824
+
825
+ def directive(tree)
826
+ recv = tree[1]
827
+ mname = tree[2]
828
+ args = tree[3]
829
+
830
+ if mname == :infer
831
+ return to_c(recv)
832
+ elsif mname == :block_given?
833
+ return "plocals->block_function_address == 0 ? Qfalse : Qtrue"
834
+ elsif mname == :inline_c
835
+
836
+ code = args[1][1]
837
+
838
+ unless (args[2] == s(:false))
839
+ return anonymous_function{ |name| "
840
+ static VALUE #{name}(VALUE param) {
841
+ #{@frame_struct} *pframe = (void*)param;
842
+ #{@locals_struct} *plocals = (void*)pframe->plocals;
843
+ #{code};
844
+
845
+ return Qnil;
846
+ }
847
+ "
848
+ }+"((VALUE)pframe)"
849
+ else
850
+ code
851
+ end
852
+
853
+ else
854
+ nil
855
+ end
856
+ end
857
+
858
+ def inline_block_reference(arg, nolocals = false)
859
+ code = nil
860
+
861
+ if arg.instance_of? FastRuby::FastRubySexp
862
+ code = to_c(arg);
863
+ else
864
+ code = arg
865
+ end
866
+
867
+ anonymous_function{ |name| "
868
+ static VALUE #{name}(VALUE param) {
869
+ #{@frame_struct} *pframe = (void*)param;
870
+
871
+ #{nolocals ? "" : "#{@locals_struct} *plocals = (void*)pframe->plocals;"}
872
+ VALUE last_expression = Qnil;
873
+
874
+ #{code};
875
+ return last_expression;
876
+ }
877
+ "
878
+ }
879
+ end
880
+
881
+ def catch_on_throw
882
+ old_catch_jmp_on_throw = @catch_jmp_on_throw || false
883
+ @catch_jmp_on_throw = true
884
+ begin
885
+ ret = yield
886
+ ensure
887
+ @catch_jmp_on_throw = old_catch_jmp_on_throw
888
+ end
889
+
890
+ ret
891
+ end
892
+
893
+ def inline_block(*args)
894
+
895
+ unless block_given?
896
+ code = args.first
897
+ return inline_block(*args[1..-1]) {
898
+ code
899
+ }
900
+ end
901
+
902
+ repass_var = args[0]
903
+ nolocals = args[1] || false
904
+
905
+ code = catch_on_throw{ yield }
906
+
907
+ anonymous_function{ |name| "
908
+ static VALUE #{name}(VALUE param#{repass_var ? ",void* " + repass_var : "" }) {
909
+ #{@frame_struct} * volatile pframe = (void*)param;
910
+
911
+ #{nolocals ? "" : "#{@locals_struct} * volatile plocals = (void*)pframe->plocals;"}
912
+ volatile VALUE last_expression = Qnil;
913
+
914
+ #{code}
915
+ return Qnil;
916
+
917
+
918
+ #{@catch_blocks.map { |cb|
919
+ "#{cb.to_s}_end:
920
+
921
+ plocals->return_value = last_expression;
922
+ plocals->targetted = 1;
923
+ longjmp(pframe->jmp, #{intern_num( cb.to_s + "_end")});
924
+
925
+ #{cb.to_s}_start:
926
+
927
+ plocals->return_value = last_expression;
928
+ plocals->targetted = 1;
929
+ longjmp(pframe->jmp, #{intern_num( cb.to_s + "_start")});
930
+
931
+ "
932
+
933
+ }.join("\n")
934
+ }
935
+ #{unless nolocals
936
+ "
937
+ local_return:
938
+ plocals->return_value = last_expression;
939
+ plocals->targetted = 1;
940
+ longjmp(pframe->jmp, FASTRUBY_TAG_RETURN);
941
+ return last_expression;
942
+ "
943
+ end
944
+ }
945
+ fastruby_local_redo:
946
+ longjmp(pframe->jmp,FASTRUBY_TAG_REDO);
947
+ return Qnil;
948
+ fastruby_local_next:
949
+ longjmp(pframe->jmp,FASTRUBY_TAG_NEXT);
950
+ return Qnil;
951
+
952
+
953
+ }
954
+ "
955
+ } + "((VALUE)pframe#{repass_var ? ", " + repass_var : "" })"
956
+ end
957
+
958
+ def inline_ruby(proced, parameter)
959
+ "rb_funcall(#{proced.__id__}, #{intern_num :call}, 1, #{parameter})"
960
+ end
961
+
962
+ def protected_block(*args)
963
+ unless block_given?
964
+ inner_code = args.first
965
+ return protected_block(*args[1..-1]) {
966
+ inner_code
967
+ }
968
+ end
969
+
970
+ repass_var = args[1]
971
+ nolocals = args[2] || false
972
+
973
+ inline_block(repass_var, nolocals) do
974
+ generate_protected_block(yield, *args)
975
+ end
976
+ end
977
+
978
+ def generate_protected_block(inner_code, always_rescue = false,repass_var = nil, nolocals = false)
979
+ body = nil
980
+ rescue_args = nil
981
+
982
+ body = anonymous_function{ |name| "
983
+ static VALUE #{name}(VALUE param) {
984
+
985
+ #{@frame_struct} frame;
986
+
987
+ typeof(frame)* volatile pframe;
988
+
989
+ #{if repass_var
990
+ "typeof(frame)* parent_frame = ((typeof(pframe))((void**)param)[0]);"
991
+ else
992
+ "typeof(frame)* parent_frame = (typeof(pframe))param;"
993
+ end
994
+ }
995
+
996
+ frame.parent_frame = 0;
997
+ frame.return_value = Qnil;
998
+ frame.rescue = 0;
999
+ frame.last_error = Qnil;
1000
+ frame.targetted = 0;
1001
+ frame.thread_data = parent_frame->thread_data;
1002
+ frame.next_recv = parent_frame->next_recv;
1003
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
1004
+
1005
+ pframe = &frame;
1006
+
1007
+ #{
1008
+ nolocals ? "frame.plocals = 0;" : "#{@locals_struct}* plocals = parent_frame->plocals;
1009
+ frame.plocals = plocals;
1010
+ "
1011
+ }
1012
+
1013
+ int aux = setjmp(frame.jmp);
1014
+ if (aux != 0) {
1015
+
1016
+ if (frame.targetted == 1) {
1017
+ return frame.return_value;
1018
+ } else {
1019
+ frb_jump_tag(aux);
1020
+ }
1021
+ }
1022
+
1023
+ #{if repass_var
1024
+ "VALUE #{repass_var} = (VALUE)((void**)param)[1];"
1025
+ end
1026
+ }
1027
+ volatile VALUE last_expression = Qnil;
1028
+ #{inner_code};
1029
+ return last_expression;
1030
+ }
1031
+ "
1032
+ }
1033
+
1034
+ if repass_var
1035
+ rescue_args = ""
1036
+ rescue_args = "(VALUE)(VALUE[]){(VALUE)pframe,(VALUE)#{repass_var}}"
1037
+ else
1038
+ rescue_args = "(VALUE)pframe"
1039
+ end
1040
+
1041
+ wrapper_code = "
1042
+ if (str.state >= 0x80) {
1043
+ longjmp(pframe->jmp, str.state);
1044
+ } else {
1045
+ if (str.last_error != Qnil) {
1046
+ // raise emulation
1047
+ pframe->thread_data->exception = str.last_error;
1048
+ longjmp(pframe->jmp, FASTRUBY_TAG_RAISE);
1049
+ return Qnil;
1050
+ }
1051
+ }
1052
+ "
1053
+
1054
+ return_err_struct = "struct {
1055
+ VALUE last_error;
1056
+ int state;
1057
+ }
1058
+ "
1059
+
1060
+ rescue_body = anonymous_function{ |name| "
1061
+ static VALUE #{name}(VALUE param, VALUE err) {
1062
+ #{return_err_struct} *pstr = (void*)param;
1063
+
1064
+ if (rb_obj_is_instance_of(err, #{literal_value FastRuby::JumpTagException})) {
1065
+ pstr->state = FIX2INT(rb_funcall(err, #{intern_num :state}, 0));
1066
+ } else {
1067
+ pstr->last_error = err;
1068
+ }
1069
+
1070
+ return Qnil;
1071
+ }
1072
+ "
1073
+ }
1074
+
1075
+ rescue_code = "rb_rescue2(#{body}, #{rescue_args}, #{rescue_body}, (VALUE)&str, rb_eException, (VALUE)0)"
1076
+
1077
+ if always_rescue
1078
+ "
1079
+ #{return_err_struct} str;
1080
+
1081
+ str.state = 0;
1082
+ str.last_error = Qnil;
1083
+
1084
+ pframe->last_error = Qnil;
1085
+ VALUE result = #{rescue_code};
1086
+
1087
+ #{wrapper_code}
1088
+
1089
+ return result;
1090
+ "
1091
+ else
1092
+ "
1093
+ VALUE result;
1094
+ #{return_err_struct} str;
1095
+
1096
+ str.state = 0;
1097
+ str.last_error = Qnil;
1098
+
1099
+ pframe->last_error = Qnil;
1100
+
1101
+ if (pframe->rescue) {
1102
+ result = #{rescue_code};
1103
+ #{wrapper_code}
1104
+ } else {
1105
+ VALUE last_expression = Qnil;
1106
+ #{inner_code};
1107
+ return last_expression;
1108
+ }
1109
+
1110
+ return result;
1111
+ "
1112
+ end
1113
+ end
1114
+
1115
+ def c_escape(str)
1116
+ str.inspect
1117
+ end
1118
+
1119
+ def literal_value(value)
1120
+ @literal_value_hash = Hash.new unless @literal_value_hash
1121
+ return @literal_value_hash[value] if @literal_value_hash[value]
1122
+
1123
+ name = self.add_global_name("VALUE", "Qnil");
1124
+
1125
+ begin
1126
+
1127
+ str = Marshal.dump(value)
1128
+
1129
+
1130
+ if value.instance_of? Module
1131
+
1132
+ container_str = value.to_s.split("::")[0..-2].join("::")
1133
+
1134
+ init_extra << "
1135
+ #{name} = rb_define_module_under(
1136
+ #{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
1137
+ ,\"#{value.to_s.split("::").last}\");
1138
+
1139
+ rb_funcall(#{name},#{intern_num :gc_register_object},0);
1140
+ "
1141
+ elsif value.instance_of? Class
1142
+ container_str = value.to_s.split("::")[0..-2].join("::")
1143
+
1144
+ str_class_name = value.to_s.split("::").last
1145
+
1146
+ if (str_class_name == "Object")
1147
+ init_extra << "
1148
+ #{name} = rb_cObject;
1149
+ "
1150
+ else
1151
+ init_extra << "
1152
+ #{name} = rb_define_class_under(
1153
+ #{container_str == "" ? "rb_cObject" : literal_value(eval(container_str))}
1154
+ ,\"#{str_class_name}\"
1155
+ ,#{value.superclass == Object ? "rb_cObject" : literal_value(value.superclass)});
1156
+
1157
+ rb_funcall(#{name},#{intern_num :gc_register_object},0);
1158
+ "
1159
+ end
1160
+ elsif value.instance_of? Array
1161
+ init_extra << "
1162
+ #{name} = rb_ary_new3(#{value.size}, #{value.map{|x| literal_value x}.join(",")} );
1163
+ rb_funcall(#{name},#{intern_num :gc_register_object},0);
1164
+ "
1165
+ else
1166
+
1167
+ init_extra << "
1168
+
1169
+ {
1170
+ VALUE encoded_str = rb_str_new2(#{Base64.encode64(str).inspect});
1171
+ VALUE str = rb_funcall(rb_cObject, #{intern_num :decode64}, 1, encoded_str);
1172
+ #{name} = rb_marshal_load(str);
1173
+
1174
+ rb_funcall(#{name},#{intern_num :gc_register_object},0);
1175
+ }
1176
+
1177
+ "
1178
+ end
1179
+ rescue TypeError => e
1180
+ @no_cache = true
1181
+ FastRuby.logger.info "#{value} disabling cache for extension"
1182
+ init_extra << "
1183
+ #{name} = rb_funcall(rb_const_get(rb_cObject, #{intern_num :ObjectSpace}), #{intern_num :_id2ref}, 1, INT2FIX(#{value.__id__}));
1184
+ "
1185
+
1186
+ end
1187
+ @literal_value_hash[value] = name
1188
+
1189
+ name
1190
+ end
1191
+
1192
+ def encode_address(recvtype,signature,mname,call_tree,inference_complete,convention_global_name = nil, is_block_call = false)
1193
+ name = self.add_global_name("void*", 0);
1194
+ address_name = self.add_global_name("void**", 0);
1195
+ @last_address_name = address_name
1196
+ cfunc_address_name = self.add_global_name("void**", 0);
1197
+ cfunc_real_address_name = self.add_global_name("void*", 0);
1198
+ tree_pointer_name = self.add_global_name("VALUE*", 0);
1199
+
1200
+ if call_tree[3].select{|st| st.respond_to?(:node_type) ? st[0] == :block_pass : false}
1201
+ is_block_call = true
1202
+ end
1203
+
1204
+ args_tree = call_tree[3].reject{|st| st.respond_to?(:node_type) ? st[0] == :block_pass : false}
1205
+ method_tree = nil
1206
+
1207
+ begin
1208
+ method_tree = recvtype.instance_method(@method_name.to_sym).fastruby.tree
1209
+ rescue NoMethodError
1210
+ end
1211
+
1212
+ strargs_signature = (0..args_tree.size-2).map{|x| "VALUE arg#{x}"}.join(",")
1213
+ strargs = (0..args_tree.size-2).map{|x| "arg#{x}"}.join(",")
1214
+ inprocstrargs = (1..args_tree.size-1).map{|x| "((VALUE*)method_arguments)[#{x}]"}.join(",")
1215
+
1216
+ if args_tree.size > 1
1217
+ strargs_signature = "," + strargs_signature
1218
+ toprocstrargs = "self,"+strargs
1219
+ strargs = "," + strargs
1220
+ inprocstrargs = ","+inprocstrargs
1221
+ else
1222
+ toprocstrargs = "self"
1223
+ end
1224
+
1225
+ value_cast = ( ["VALUE"]*(args_tree.size) ).join(",") + ",VALUE,VALUE"
1226
+
1227
+ recvdump = nil
1228
+
1229
+ begin
1230
+ recvdump = literal_value recvtype
1231
+ rescue
1232
+ end
1233
+
1234
+ pureruby_wrapper = anonymous_function{ |funcname| "
1235
+ static VALUE #{funcname}(VALUE self,void* block,void* frame, int argc, VALUE* argv){
1236
+ #{@frame_struct}* pframe = frame;
1237
+ VALUE method_arguments[3];
1238
+
1239
+ method_arguments[0] = (VALUE)argc;
1240
+ method_arguments[1] = (VALUE)argv;
1241
+ method_arguments[2] = (VALUE)self;
1242
+
1243
+ return #{
1244
+ protected_block "last_expression = rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);", false, "method_arguments"
1245
+ };
1246
+ }
1247
+ "
1248
+ }
1249
+
1250
+ generic_wrapper = anonymous_function{ |funcname| "
1251
+ static VALUE #{funcname}(VALUE self,void* block,void* frame, int argc, VALUE* argv){
1252
+ #{@frame_struct}* pframe = frame;
1253
+ VALUE method_arguments[4];
1254
+
1255
+ method_arguments[0] = (VALUE)argc;
1256
+ method_arguments[1] = (VALUE)argv;
1257
+ method_arguments[2] = (VALUE)self;
1258
+ method_arguments[3] = (VALUE)block;
1259
+
1260
+ void* fptr = 0;
1261
+
1262
+ if (*#{address_name} == 0) {
1263
+ if (#{tree_pointer_name} != 0) {
1264
+ if (*#{tree_pointer_name} != Qnil) {
1265
+ VALUE signature = #{literal_value signature};
1266
+ VALUE recvtype = #{recvdump};
1267
+ VALUE mname = #{literal_value mname};
1268
+
1269
+ rb_funcall(recvtype, #{intern_num :build}, 2, signature, mname);
1270
+ }
1271
+ }
1272
+ }
1273
+
1274
+ fptr = *#{address_name};
1275
+
1276
+ if (fptr == 0) {
1277
+ fptr = *#{cfunc_address_name};
1278
+ if (fptr != 0) {
1279
+ return ( (VALUE(*)(VALUE,VALUE,VALUE,int,VALUE*) ) (fptr) )(self,(VALUE)block,(VALUE)frame, argc, argv);
1280
+ }
1281
+ }
1282
+
1283
+ if (fptr == 0) {
1284
+ if (block==0) {
1285
+ return #{
1286
+ protected_block "last_expression = rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);", false, "method_arguments"
1287
+ };
1288
+
1289
+ } else {
1290
+ return #{
1291
+ protected_block "
1292
+ #{@block_struct} *pblock;
1293
+ pblock = (typeof(pblock))( ((VALUE*)method_arguments)[3] );
1294
+ last_expression = rb_iterate(
1295
+ #{anonymous_function{|name_|
1296
+ "
1297
+ static VALUE #{name_} (VALUE data) {
1298
+ VALUE* method_arguments = (VALUE*)data;
1299
+ return rb_funcall2(((VALUE*)method_arguments)[2], #{intern_num mname.to_sym}, ((int*)method_arguments)[0], ((VALUE**)method_arguments)[1]);
1300
+ }
1301
+ "
1302
+ }},
1303
+ (VALUE)method_arguments,
1304
+
1305
+ #{anonymous_function{|name_|
1306
+ "
1307
+ static VALUE #{name_} (VALUE arg_, VALUE param, int argc, VALUE* argv) {
1308
+
1309
+ VALUE arg;
1310
+ #{
1311
+ # TODO: access directly to argc and argv for optimal execution
1312
+ if RUBY_VERSION =~ /^1\.9/
1313
+ "
1314
+ if (TYPE(arg_) == T_ARRAY) {
1315
+ if (_RARRAY_LEN(arg_) <= 1) {
1316
+ arg = rb_ary_new4(argc,argv);
1317
+ } else {
1318
+ arg = arg_;
1319
+ }
1320
+ } else {
1321
+ arg = rb_ary_new4(argc,argv);
1322
+ }
1323
+ "
1324
+ else
1325
+ "arg = arg_;"
1326
+ end
1327
+ }
1328
+
1329
+ return rb_proc_call(param, arg);
1330
+ }
1331
+ "
1332
+ }},
1333
+ pblock->proc
1334
+ );
1335
+ ", false, "method_arguments"
1336
+ };
1337
+ }
1338
+
1339
+ } else {
1340
+ return ( (VALUE(*)(VALUE,VALUE,VALUE,int,VALUE*)) (fptr) )(self,(VALUE)block,(VALUE)frame,argc,argv);
1341
+ }
1342
+ }
1343
+ "
1344
+ }
1345
+
1346
+
1347
+ cfuncall1inprocargs = (0..args_tree.size-2).map{|x| "argv[#{x}]"}.join(",")
1348
+ cfuncall1inprocargs = ","+cfuncall1inprocargs if cfuncall1inprocargs != ""
1349
+
1350
+ cfunc_value_cast = (["VALUE"]*args_tree.size).join(",")
1351
+ cfunc_wrapper = anonymous_function{ |funcname| "
1352
+ static VALUE #{funcname}(VALUE self, void* block,void* frame, int argc, VALUE* argv){
1353
+ return rb_vm_call(ruby_current_thread, self, #{intern_num mname.to_sym}, argc, argv, #{cfunc_real_address_name});
1354
+ }
1355
+ "
1356
+ }
1357
+
1358
+ toprocstrargs = (0..25).map{|x| "arg#{x}"}.join(",")
1359
+ strargs_signature = (0..25).map{|x| "VALUE arg#{x}"}.join(",")
1360
+
1361
+ cfunc_wrapper_1 = anonymous_function{ |funcname| "
1362
+ static VALUE #{funcname}(VALUE self, void* block,void* frame, int argc, VALUE* argv){
1363
+ return ( (VALUE(*)(int, VALUE*, VALUE)) (#{cfunc_real_address_name}) )(argc,argv,self);
1364
+ }
1365
+ "
1366
+ }
1367
+
1368
+ cfunc_wrapper_2 = anonymous_function{ |funcname| "
1369
+ static VALUE #{funcname}(VALUE self, void* block,void* frame, int argc, VALUE* argv){
1370
+ VALUE args = rb_ary_new3(argc, argv);
1371
+ return ( (VALUE(*)(VALUE,VALUE)) (#{cfunc_real_address_name}) )(self,args);
1372
+ }
1373
+ "
1374
+ }
1375
+
1376
+ update_cfunc_method = anonymous_function{ |funcname| "
1377
+ static VALUE #{funcname}(){
1378
+ void** default_address = (void**)#{cfunc_address_name};
1379
+ ID default_id = rb_intern(\"default\");
1380
+ VALUE recvtype = #{recvdump};
1381
+
1382
+ if (1) {
1383
+ *default_address = 0;
1384
+
1385
+ #{
1386
+ if RUBY_VERSION == "1.9.2"
1387
+
1388
+ "
1389
+ rb_method_entry_t* me = rb_method_entry(recvtype,#{intern_num mname});
1390
+ if (me != 0) {
1391
+ rb_method_definition_t* def = me->def;
1392
+
1393
+ if (def->type == VM_METHOD_TYPE_CFUNC) {
1394
+ *default_address = #{cfunc_wrapper};
1395
+ #{cfunc_real_address_name} = (void*)me;
1396
+ }
1397
+ }
1398
+ "
1399
+ end
1400
+ }
1401
+ if (default_address != 0) {
1402
+ if (recvtype != Qnil) {
1403
+ rb_funcall(
1404
+ recvtype,
1405
+ #{intern_num :register_method_value},
1406
+ 3,
1407
+ #{literal_value mname},
1408
+ PTR2NUM(default_id),
1409
+ PTR2NUM(default_address)
1410
+ );
1411
+ }
1412
+ }
1413
+ }
1414
+ return Qnil;
1415
+ }
1416
+ "
1417
+ }
1418
+
1419
+
1420
+
1421
+ if recvdump and recvtype
1422
+ init_extra << "
1423
+ {
1424
+ VALUE recvtype = #{recvdump};
1425
+ rb_funcall(#{literal_value FastRuby}, #{intern_num :set_builder_module}, 1, recvtype);
1426
+ VALUE signature = #{literal_value signature};
1427
+ VALUE mname = #{literal_value mname};
1428
+ VALUE tree = #{literal_value method_tree};
1429
+ VALUE rb_str_signature = rb_funcall(
1430
+ #{literal_value FastRuby},
1431
+ #{intern_num :make_str_signature},
1432
+ 2,
1433
+ mname,
1434
+ signature);
1435
+
1436
+
1437
+
1438
+ VALUE fastruby_method = rb_funcall(recvtype, #{intern_num :fastruby_method}, 1, mname);
1439
+ #{tree_pointer_name} = (VALUE*)NUM2PTR(fastruby_method_tree_pointer(fastruby_method));
1440
+
1441
+ ID id;
1442
+ ID default_id = rb_intern(\"default\");
1443
+ VALUE rb_method_hash;
1444
+ void** address = 0;
1445
+ void** default_address = 0;
1446
+ id = rb_intern(RSTRING_PTR(rb_str_signature));
1447
+ rb_method_hash = rb_funcall(recvtype, #{intern_num :method_hash},1,mname);
1448
+
1449
+ if (rb_method_hash != Qnil) {
1450
+ VALUE tmp = rb_hash_aref(rb_method_hash, PTR2NUM(id));
1451
+ if (tmp != Qnil) {
1452
+ address = (void*)NUM2PTR(tmp);
1453
+ }
1454
+
1455
+ tmp = rb_hash_aref(rb_method_hash, PTR2NUM(default_id));
1456
+ if (tmp != Qnil) {
1457
+ default_address = (void*)NUM2PTR(tmp);
1458
+ }
1459
+ }
1460
+
1461
+ if (default_address==0) {
1462
+ default_address = malloc(sizeof(void*));
1463
+ *default_address = 0;
1464
+ }
1465
+ #{cfunc_address_name} = default_address;
1466
+ #{unless is_block_call
1467
+ "
1468
+ #{update_cfunc_method}();
1469
+ rb_iterate(#{anonymous_function{|funcname|
1470
+ "static VALUE #{funcname}(VALUE recv) {
1471
+ return rb_funcall(recv, #{intern_num :observe}, 1, #{literal_value(@alt_method_name + "#" + cfunc_address_name)});
1472
+ }
1473
+ "
1474
+ }},fastruby_method,#{update_cfunc_method},Qnil);
1475
+ "
1476
+ end
1477
+ }
1478
+
1479
+ if (address==0) {
1480
+ address = malloc(sizeof(void*));
1481
+
1482
+ if (recvtype != Qnil) {
1483
+ rb_funcall(
1484
+ recvtype,
1485
+ #{intern_num :register_method_value},
1486
+ 3,
1487
+ #{literal_value mname},
1488
+ PTR2NUM(id),
1489
+ PTR2NUM(address)
1490
+ );
1491
+ }
1492
+
1493
+ *address = 0; //(void*)
1494
+ }
1495
+
1496
+ #{address_name} = address;
1497
+ #{name} = (void*)#{generic_wrapper};
1498
+ }
1499
+ "
1500
+ else
1501
+ init_extra << "
1502
+ // ruby, wrap rb_funcall
1503
+ #{name} = (void*)#{pureruby_wrapper};
1504
+ "
1505
+ end
1506
+
1507
+ name
1508
+ end
1509
+
1510
+ def intern_num(symbol)
1511
+ symbol = symbol.to_sym
1512
+ @intern_num_hash = Hash.new unless @intern_num_hash
1513
+ return @intern_num_hash[symbol] if @intern_num_hash[symbol]
1514
+
1515
+ name = self.add_global_name("ID", 0);
1516
+
1517
+ init_extra << "
1518
+ #{name} = rb_intern(\"#{symbol.to_s}\");
1519
+ "
1520
+
1521
+ @intern_num_hash[symbol] = name
1522
+
1523
+ name
1524
+ end
1525
+
1526
+ def add_global_name(ctype, default)
1527
+ name = "glb" + rand(1000000000).to_s
1528
+
1529
+ extra_code << "
1530
+ static #{ctype} #{name} = #{default};
1531
+ "
1532
+ name
1533
+ end
1534
+
1535
+ def global_entry(glbname)
1536
+ name = add_global_name("struct global_entry*", 0);
1537
+
1538
+ init_extra << "
1539
+ #{name} = rb_global_entry(SYM2ID(#{literal_value glbname}));
1540
+ "
1541
+
1542
+ name
1543
+ end
1544
+
1545
+
1546
+ def frame(code, jmp_code, not_jmp_code = "", rescued = nil)
1547
+
1548
+ anonymous_function{ |name| "
1549
+ static VALUE #{name}(VALUE param) {
1550
+ volatile VALUE last_expression = Qnil;
1551
+ #{@frame_struct} frame;
1552
+
1553
+ typeof(frame)* volatile pframe;
1554
+ typeof(frame)* volatile parent_frame;
1555
+ #{@locals_struct}* volatile plocals;
1556
+
1557
+ parent_frame = (void*)param;
1558
+
1559
+ frame.parent_frame = (void*)param;
1560
+ frame.plocals = parent_frame->plocals;
1561
+ frame.rescue = #{rescued ? rescued : "parent_frame->rescue"};
1562
+ frame.targetted = 0;
1563
+ frame.thread_data = parent_frame->thread_data;
1564
+ if (frame.thread_data == 0) frame.thread_data = rb_current_thread_data();
1565
+
1566
+ plocals = frame.plocals;
1567
+ pframe = &frame;
1568
+
1569
+ int aux = setjmp(frame.jmp);
1570
+ if (aux != 0) {
1571
+ last_expression = pframe->return_value;
1572
+
1573
+ // restore previous frame
1574
+ typeof(pframe) original_frame = pframe;
1575
+ pframe = parent_frame;
1576
+
1577
+ #{jmp_code};
1578
+
1579
+ if (original_frame->targetted == 0) {
1580
+ longjmp(pframe->jmp,aux);
1581
+ }
1582
+
1583
+ return last_expression;
1584
+ }
1585
+
1586
+ #{code};
1587
+
1588
+ // restore previous frame
1589
+ volatile typeof(pframe) original_frame = pframe;
1590
+ pframe = parent_frame;
1591
+ #{not_jmp_code};
1592
+
1593
+ return last_expression;
1594
+
1595
+ }
1596
+ "
1597
+ } + "((VALUE)pframe)"
1598
+ end
1599
+ end
1600
+ end