fastruby 0.0.18 → 0.0.19
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.
- data/CHANGELOG +10 -0
- data/Rakefile +2 -1
- data/benchmarks/benchmark.rb~ +2 -4
- data/benchmarks/benchmark3.rb~ +2 -4
- data/ext/fastruby_base/fastruby_base.inl +1 -1
- data/lib/fastruby/builder.rb +8 -7
- data/lib/fastruby/fastruby_sexp.rb +18 -0
- data/lib/fastruby/inliner/modules/call.rb +254 -67
- data/lib/fastruby/inliner/modules/recursive.rb +5 -0
- data/lib/fastruby/reductor/modules/case.rb +2 -1
- data/lib/fastruby/translator/modules/block.rb +65 -59
- data/lib/fastruby/translator/modules/call.rb +7 -4
- data/lib/fastruby/translator/modules/exceptions.rb +66 -64
- data/lib/fastruby/translator/modules/flow.rb +8 -8
- data/lib/fastruby/translator/modules/literal.rb +5 -4
- data/lib/fastruby/translator/modules/method_group.rb +6 -5
- data/lib/fastruby/translator/modules/nonlocal.rb +153 -11
- data/lib/fastruby/translator/modules/static.rb +8 -8
- data/lib/fastruby/translator/modules/variable.rb +15 -15
- data/lib/fastruby/translator/translator.rb +156 -59
- data/lib/fastruby.rb +1 -1
- data/lib/fastruby.rb~ +36 -0
- data/spec/fastruby/inliner/modules/call_spec.rb +0 -0
- data/spec/fastruby/translator/modules/nonlocal_spec.rb +0 -0
- data/spec/fastruby/translator/translator_spec.rb +0 -0
- data/spec/ruby/base_spec.rb~ +5 -5
- data/spec/ruby/block/break_spec.rb~ +236 -0
- data/spec/ruby/block/lambda_spec.rb~ +38 -0
- data/spec/ruby/block/next_spec.rb~ +85 -0
- data/spec/ruby/call/base_call_spec.rb~ +83 -0
- data/spec/ruby/defn/replacement_spec.rb +52 -2
- data/spec/ruby/defn/replacement_spec.rb~ +52 -2
- data/spec/ruby/exception/base_spec.rb +22 -1
- data/spec/ruby/return_spec.rb~ +99 -0
- metadata +30 -10
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
0.0.19 Fixed temporal variable names of case blocks to make it deterministic and allow caching
|
2
|
+
|
3
|
+
Fixed bug of duplicated entries on $LOAD_PATH, significant performance improvement saves 80% of time both with caching and without caching
|
4
|
+
|
5
|
+
Inline of methods with iter calls
|
6
|
+
|
7
|
+
Inline of iter calls
|
8
|
+
|
9
|
+
Use of observer to allow replacement of CFUNC calls (example: Fixnum#+)
|
10
|
+
|
1
11
|
0.0.18 Optimize of exising methods using "optimize" (only pure ruby methods are supported)
|
2
12
|
|
3
13
|
Implemented new cache by syntax tree, more accurate, fixing a few cache bugs and compatible with inlining
|
data/Rakefile
CHANGED
@@ -7,7 +7,7 @@ require "rspec/core/rake_task"
|
|
7
7
|
|
8
8
|
spec = Gem::Specification.new do |s|
|
9
9
|
s.name = 'fastruby'
|
10
|
-
s.version = '0.0.
|
10
|
+
s.version = '0.0.19'
|
11
11
|
s.author = 'Dario Seminara'
|
12
12
|
s.email = 'robertodarioseminara@gmail.com'
|
13
13
|
s.platform = Gem::Platform::RUBY
|
@@ -17,6 +17,7 @@ spec = Gem::Specification.new do |s|
|
|
17
17
|
s.add_dependency "ruby_parser", ">= 2.0.6"
|
18
18
|
s.add_dependency "define_method_handler", ">= 0.0.5"
|
19
19
|
s.add_dependency "method_source", ">= 0.6.7"
|
20
|
+
s.add_dependency "ruby2ruby", ">= 1.3.1"
|
20
21
|
s.has_rdoc = true
|
21
22
|
s.extra_rdoc_files = [ 'README' ]
|
22
23
|
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
data/benchmarks/benchmark.rb~
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "fastruby"
|
3
3
|
|
4
|
-
def lvar_type(*x); end
|
5
|
-
|
6
4
|
class X
|
7
5
|
def foo(a,b)
|
8
|
-
|
6
|
+
a+b
|
9
7
|
end
|
10
8
|
end
|
11
9
|
|
@@ -17,7 +15,7 @@ class Y
|
|
17
15
|
|
18
16
|
ret = 0
|
19
17
|
while i > 0
|
20
|
-
ret =
|
18
|
+
ret = (i+i)
|
21
19
|
i = i - 1
|
22
20
|
end
|
23
21
|
return ret
|
data/benchmarks/benchmark3.rb~
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "fastruby"
|
3
3
|
|
4
|
-
def lvar_type(*x); end
|
5
|
-
|
6
4
|
class X
|
7
5
|
def foo
|
8
|
-
yield(1
|
6
|
+
yield(1)
|
9
7
|
end
|
10
8
|
end
|
11
9
|
|
@@ -17,7 +15,7 @@ class Y
|
|
17
15
|
|
18
16
|
ret = 0
|
19
17
|
while i > 0
|
20
|
-
x.foo do |a
|
18
|
+
x.foo do |a|
|
21
19
|
end
|
22
20
|
i = i - 1
|
23
21
|
end
|
@@ -402,6 +402,7 @@ static VALUE fastruby_method_tree_pointer(VALUE self) {
|
|
402
402
|
|
403
403
|
if (rb_tree_pointer == Qnil) {
|
404
404
|
VALUE* tree_pointer = malloc(sizeof(VALUE*));
|
405
|
+
rb_gc_register_address(tree_pointer);
|
405
406
|
*tree_pointer = Qnil;
|
406
407
|
rb_tree_pointer = LONG2FIX(tree_pointer);
|
407
408
|
rb_ivar_set(self, rb_intern("@tree"), rb_tree_pointer);
|
@@ -412,7 +413,6 @@ static VALUE fastruby_method_tree_pointer(VALUE self) {
|
|
412
413
|
|
413
414
|
static VALUE fastruby_method_tree_eq(VALUE self, VALUE val) {
|
414
415
|
VALUE* tree_pointer = (VALUE*)FIX2LONG(fastruby_method_tree_pointer(self));
|
415
|
-
rb_ivar_set(self, rb_intern("__current_tree"), val);
|
416
416
|
*tree_pointer = val;
|
417
417
|
return Qnil;
|
418
418
|
}
|
data/lib/fastruby/builder.rb
CHANGED
@@ -23,6 +23,10 @@ require "fastruby/logging"
|
|
23
23
|
require "fastruby/getlocals"
|
24
24
|
require "fastruby_load_path"
|
25
25
|
require "fastruby/inliner/inliner"
|
26
|
+
require "fastruby/translator/translator"
|
27
|
+
require "rubygems"
|
28
|
+
require "inline"
|
29
|
+
require "fastruby/inline_extension"
|
26
30
|
|
27
31
|
require FastRuby.fastruby_load_path + "/../ext/fastruby_base/fastruby_base"
|
28
32
|
|
@@ -68,11 +72,6 @@ module FastRuby
|
|
68
72
|
def rebuild(signature, noreturn = false)
|
69
73
|
no_cache = false
|
70
74
|
mname = FastRuby.make_str_signature(@method_name, signature)
|
71
|
-
|
72
|
-
require "fastruby/translator/translator"
|
73
|
-
require "rubygems"
|
74
|
-
require "inline"
|
75
|
-
require "fastruby/inline_extension"
|
76
75
|
|
77
76
|
inliner = FastRuby::Inliner.new
|
78
77
|
|
@@ -119,13 +118,15 @@ module FastRuby
|
|
119
118
|
end
|
120
119
|
|
121
120
|
inliner.inlined_methods.each do |inlined_method|
|
122
|
-
inlined_method.observe("#{@owner}##{@method_name}") do |imethod|
|
121
|
+
inlined_method.observe("#{@owner}##{@method_name}#{mname}") do |imethod|
|
123
122
|
rebuild(signature, noreturn)
|
124
123
|
end
|
125
124
|
end
|
126
125
|
|
127
126
|
alt_options = options.dup
|
128
127
|
alt_options.delete(:self)
|
128
|
+
|
129
|
+
#require "pry"; binding.pry
|
129
130
|
code_sha1 = FastRuby.cache.hash_snippet(inlined_tree.inspect, FastRuby::VERSION + signature.map(&:to_s).join('-') + alt_options.inspect)
|
130
131
|
|
131
132
|
paths = FastRuby.cache.retrieve(code_sha1)
|
@@ -224,7 +225,7 @@ module FastRuby
|
|
224
225
|
$class_self = old_class_self
|
225
226
|
end
|
226
227
|
|
227
|
-
observe("#{@owner}##{@method_name}") do |imethod|
|
228
|
+
observe("#{@owner}##{@method_name}#{mname}") do |imethod|
|
228
229
|
if tree
|
229
230
|
rebuild(signature, noreturn)
|
230
231
|
end
|
@@ -32,6 +32,24 @@ module FastRuby
|
|
32
32
|
}
|
33
33
|
end
|
34
34
|
|
35
|
+
def to_sexp
|
36
|
+
ret = s()
|
37
|
+
each do |subtree|
|
38
|
+
if subtree.respond_to?(:to_sexp)
|
39
|
+
ret << subtree.to_sexp
|
40
|
+
else
|
41
|
+
ret << subtree
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
ret
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_ruby
|
49
|
+
require "ruby2ruby"
|
50
|
+
Ruby2Ruby.new.process(to_sexp)
|
51
|
+
end
|
52
|
+
|
35
53
|
def map
|
36
54
|
sexp = FastRubySexp.new
|
37
55
|
self.each do |subtree|
|
@@ -24,82 +24,132 @@ require "define_method_handler"
|
|
24
24
|
|
25
25
|
module FastRuby
|
26
26
|
class Inliner
|
27
|
+
|
28
|
+
class BlockProcessing
|
29
|
+
def initialize(inlined_name, break_inlined_name)
|
30
|
+
@inlined_name = inlined_name
|
31
|
+
@break_inlined_name = break_inlined_name
|
32
|
+
end
|
33
|
+
|
34
|
+
define_method_handler(:process, :priority => -100) { |tree|
|
35
|
+
tree.map &method(:process)
|
36
|
+
}
|
37
|
+
|
38
|
+
define_method_handler(:process, :priority => 1000) { |tree|
|
39
|
+
tree
|
40
|
+
}.condition{|tree| not tree.respond_to?(:node_type) }
|
41
|
+
|
42
|
+
define_method_handler(:process) { |tree|
|
43
|
+
if tree[1]
|
44
|
+
fs(:call, nil, :_throw, fs(:arglist, fs(:lit,@inlined_name.to_sym), process(tree[1])))
|
45
|
+
else
|
46
|
+
fs(:call, nil, :_throw, fs(:arglist, fs(:lit,@inlined_name.to_sym), fs(:nil)))
|
47
|
+
end
|
48
|
+
}.condition{|tree| tree.node_type == :next}
|
49
|
+
|
50
|
+
define_method_handler(:process) { |tree|
|
51
|
+
if tree[1]
|
52
|
+
fs(:call, nil, :_throw, fs(:arglist, fs(:lit,@break_inlined_name.to_sym), process(tree[1])))
|
53
|
+
else
|
54
|
+
fs(:call, nil, :_throw, fs(:arglist, fs(:lit,@break_inlined_name.to_sym), fs(:nil)))
|
55
|
+
end
|
56
|
+
}.condition{|tree| tree.node_type == :break and @break_inlined_name}
|
57
|
+
|
58
|
+
define_method_handler(:process) { |tree|
|
59
|
+
fs(:call, nil, :_loop, fs(:arglist, fs(:lit,@inlined_name.to_sym)))
|
60
|
+
}.condition{|tree| tree.node_type == :redo}
|
61
|
+
|
62
|
+
define_method_handler(:process) { |tree|
|
63
|
+
if tree[3]
|
64
|
+
fs(:iter, process(tree[1]), tree[2], tree[3].duplicate)
|
65
|
+
else
|
66
|
+
fs(:iter, process(tree[1]), tree[2])
|
67
|
+
end
|
68
|
+
}.condition{|tree| tree.node_type == :iter}
|
69
|
+
end
|
70
|
+
|
27
71
|
def inline_local_name(method_name, local_name)
|
28
72
|
"__inlined_#{method_name}_#{local_name}".to_sym
|
29
73
|
end
|
30
74
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
tree[2..-1].each do |subtree|
|
36
|
-
ret_tree << inline(subtree)
|
37
|
-
end
|
38
|
-
|
39
|
-
ret_tree
|
40
|
-
|
41
|
-
}.condition{|tree| tree.node_type == :iter}
|
75
|
+
def method_obj_or_gtfo(klass, method_name)
|
76
|
+
return nil unless klass.respond_to?(:fastruby_method)
|
77
|
+
klass.fastruby_method(method_name)
|
78
|
+
end
|
42
79
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
if method_name == :lvar_type
|
52
|
-
lvar_name = args_tree[1][1] || args_tree[1][2]
|
53
|
-
lvar_type = eval(args_tree[2][1].to_s)
|
54
|
-
|
55
|
-
@infer_lvar_map[lvar_name] = lvar_type
|
56
|
-
next tree
|
80
|
+
def add_prefix(tree, prefix)
|
81
|
+
tree = tree.duplicate
|
82
|
+
tree.walk_tree do |subtree|
|
83
|
+
if subtree.node_type == :lvar or subtree.node_type == :lasgn
|
84
|
+
subtree[1] = inline_local_name(prefix, subtree[1])
|
85
|
+
add_local subtree[1]
|
86
|
+
end
|
57
87
|
end
|
58
88
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
89
|
+
tree
|
90
|
+
end
|
91
|
+
|
92
|
+
def catch_block(name,tree)
|
93
|
+
fs(:block,fs(:iter, fs(:call, nil, :_catch, fs(:arglist, fs(:lit,name.to_sym))),nil,tree))
|
94
|
+
end
|
95
|
+
|
96
|
+
def method_tree_to_inlined_block(mobject, call_tree, method_name, block_args_tree = nil, block_tree = nil)
|
97
|
+
args_tree = call_tree[3]
|
98
|
+
recv_tree = call_tree[1] || fs(:self)
|
66
99
|
|
67
|
-
|
100
|
+
target_method_tree = mobject.tree
|
68
101
|
|
69
|
-
|
70
|
-
|
71
|
-
next tree unless target_method_tree
|
72
|
-
next tree if target_method_tree.find_tree(:iter)
|
73
|
-
target_method_tree_args = target_method_tree[2]
|
102
|
+
@method_index = (@method_index || 0) + 1
|
74
103
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
target_method_tree_block = target_method_tree.find_tree(:scope)[1].duplicate
|
104
|
+
prefix = method_name.to_s + "_" + @method_index.to_s
|
105
|
+
target_method_tree_block = add_prefix(target_method_tree.find_tree(:scope)[1], prefix)
|
79
106
|
|
80
|
-
target_method_tree_block.
|
81
|
-
|
82
|
-
|
83
|
-
|
107
|
+
if target_method_tree_block.find_tree(:return)
|
108
|
+
inlined_name = inline_local_name(method_name, "main_return_tagname")
|
109
|
+
target_method_tree_block = catch_block(inlined_name,target_method_tree_block)
|
110
|
+
|
111
|
+
target_method_tree_block.walk_tree do |subtree|
|
112
|
+
if subtree[0] == :return
|
113
|
+
if subtree[1]
|
114
|
+
subtree[0..-1] = fs(:call, nil, :_throw, fs(:arglist, fs(:lit,inlined_name.to_sym), subtree[1]))
|
115
|
+
else
|
116
|
+
subtree[0..-1] = fs(:call, nil, :_throw, fs(:arglist, fs(:lit,inlined_name.to_sym), fs(:nil)))
|
117
|
+
end
|
118
|
+
end
|
84
119
|
end
|
85
120
|
end
|
86
121
|
|
122
|
+
target_method_tree_args = target_method_tree[2]
|
123
|
+
|
87
124
|
newblock = fs(:block)
|
88
125
|
|
89
126
|
(1..args_tree.size-1).each do |i|
|
90
127
|
itype = infer_type(args_tree[i])
|
91
|
-
inlined_name = inline_local_name(
|
128
|
+
inlined_name = inline_local_name(prefix, target_method_tree_args[i])
|
92
129
|
|
93
130
|
add_local inlined_name
|
94
131
|
|
95
132
|
self.extra_inferences[inlined_name] = itype if itype
|
96
|
-
newblock << fs(:lasgn, inlined_name, args_tree[i].duplicate)
|
133
|
+
newblock << fs(:lasgn, inlined_name, recursive_inline(args_tree[i].duplicate))
|
97
134
|
end
|
98
135
|
|
99
|
-
inlined_name = inline_local_name(
|
136
|
+
inlined_name = inline_local_name(prefix, :self)
|
100
137
|
add_local inlined_name
|
101
138
|
newblock << fs(:lasgn, inlined_name, recv_tree.duplicate)
|
102
139
|
|
140
|
+
return nil if target_method_tree_block.find_tree(:return)
|
141
|
+
|
142
|
+
break_tag = nil
|
143
|
+
|
144
|
+
if block_tree
|
145
|
+
block_tree = recursive_inline(block_tree)
|
146
|
+
if block_tree.find_tree(:break) # FIXME: discard nested iter calls on finding
|
147
|
+
break_tag = inline_local_name(prefix, "__break_tag")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
block_num = 0
|
152
|
+
|
103
153
|
target_method_tree_block.walk_tree do |subtree|
|
104
154
|
if subtree.node_type == :call
|
105
155
|
if subtree[1] == nil
|
@@ -112,38 +162,175 @@ module FastRuby
|
|
112
162
|
end
|
113
163
|
if subtree.node_type == :self
|
114
164
|
subtree[0] = :lvar
|
115
|
-
subtree[1] = inline_local_name(
|
165
|
+
subtree[1] = inline_local_name(prefix, :self)
|
116
166
|
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
if
|
125
|
-
if
|
126
|
-
|
127
|
-
|
167
|
+
if subtree.node_type == :yield
|
168
|
+
if block_tree
|
169
|
+
# inline yield
|
170
|
+
yield_call_args = subtree.duplicate
|
171
|
+
|
172
|
+
subtree[0..-1] = fs(:block)
|
173
|
+
|
174
|
+
if block_args_tree
|
175
|
+
return nil if yield_call_args[1..-1].find{|x| x.node_type == :splat}
|
176
|
+
if block_args_tree.node_type == :masgn
|
177
|
+
return nil if block_args_tree[1].size != yield_call_args.size
|
178
|
+
return nil if block_args_tree[1][1..-1].find{|x| x.node_type == :splat}
|
179
|
+
|
180
|
+
(1..yield_call_args.size-1).each do |i|
|
181
|
+
inlined_name = block_args_tree[1][i][1]
|
182
|
+
add_local inlined_name
|
183
|
+
subtree << fs(:lasgn, inlined_name, yield_call_args[i])
|
128
184
|
end
|
185
|
+
else
|
186
|
+
return nil if 2 != yield_call_args.size
|
187
|
+
|
188
|
+
inlined_name = block_args_tree[1]
|
189
|
+
add_local inlined_name
|
190
|
+
subtree << fs(:lasgn, inlined_name, yield_call_args[1])
|
129
191
|
end
|
192
|
+
else
|
193
|
+
return nil if yield_call_args.size > 1
|
194
|
+
end
|
195
|
+
|
196
|
+
if block_tree.find_tree(:next) or block_tree.find_tree(:redo) or break_tag
|
197
|
+
inlined_name = inline_local_name(prefix, "block_block_#{block_num}")
|
198
|
+
block_num = block_num + 1
|
130
199
|
|
131
|
-
|
200
|
+
alt_block_tree = BlockProcessing.new(inlined_name, break_tag).process(block_tree)
|
201
|
+
alt_block_tree = catch_block(inlined_name,alt_block_tree)
|
202
|
+
else
|
203
|
+
alt_block_tree = block_tree.duplicate
|
132
204
|
end
|
205
|
+
subtree << alt_block_tree
|
133
206
|
else
|
134
|
-
|
135
|
-
next tree
|
207
|
+
subtree[0..-1] = fs(:call, fs(:nil), :raise, fs(:arglist, fs(:const, :LocalJumpError), fs(:str, "no block given")))
|
136
208
|
end
|
137
209
|
end
|
138
|
-
|
139
|
-
newblock << subtree
|
140
210
|
end
|
141
211
|
|
142
212
|
@inlined_methods << mobject
|
213
|
+
|
214
|
+
if break_tag
|
215
|
+
inner_block = fs(:block)
|
216
|
+
target_method_tree_block[1..-1].each do |subtree|
|
217
|
+
inner_block << subtree
|
218
|
+
end
|
219
|
+
|
220
|
+
newblock << catch_block(break_tag,inner_block)
|
221
|
+
else
|
222
|
+
target_method_tree_block[1..-1].each do |subtree|
|
223
|
+
newblock << subtree
|
224
|
+
end
|
225
|
+
end
|
143
226
|
newblock
|
227
|
+
end
|
228
|
+
|
229
|
+
define_method_handler(:inline) { |tree|
|
230
|
+
tree
|
231
|
+
}.condition{|tree| tree.node_type == :defs}
|
232
|
+
|
233
|
+
define_method_handler(:inline) { |tree|
|
234
|
+
ret_tree = fs(:iter)
|
235
|
+
ret_tree << tree[1].duplicate
|
236
|
+
|
237
|
+
call_tree = tree[1]
|
238
|
+
recv_tree = call_tree[1] || fs(:self)
|
239
|
+
method_name = call_tree[2]
|
240
|
+
args_tree = call_tree[3]
|
241
|
+
block_tree = tree[3] || fs(:nil)
|
242
|
+
block_args_tree = tree[2]
|
243
|
+
|
244
|
+
tree[2..-1].each do |subtree|
|
245
|
+
ret_tree << inline(subtree)
|
246
|
+
end
|
247
|
+
|
248
|
+
next ret_tree if block_tree.find_tree(:retry)
|
249
|
+
|
250
|
+
recvtype = infer_type(recv_tree)
|
251
|
+
|
252
|
+
if recvtype
|
253
|
+
# search the tree of target method
|
254
|
+
mobject = method_obj_or_gtfo(recvtype,method_name)
|
255
|
+
|
256
|
+
next tree unless mobject
|
257
|
+
next tree unless mobject.tree
|
258
|
+
|
259
|
+
exit_now = false
|
260
|
+
if block_tree.find_tree(:break) or block_tree.find_tree(:return)
|
261
|
+
mobject.tree.walk_tree do |subtree|
|
262
|
+
if subtree.node_type == :iter
|
263
|
+
if subtree.find_tree(:yield)
|
264
|
+
exit_now = true
|
265
|
+
break
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
next tree if exit_now
|
272
|
+
|
273
|
+
target_method_tree_args = mobject.tree[2]
|
274
|
+
next tree if target_method_tree_args.find{|subtree| subtree.to_s =~ /^\*/}
|
275
|
+
|
276
|
+
method_tree_to_inlined_block(mobject, call_tree, method_name, block_args_tree, block_tree) || ret_tree
|
277
|
+
|
278
|
+
else
|
279
|
+
# nothing to do, we don't know what is the method
|
280
|
+
ret_tree
|
281
|
+
end
|
282
|
+
}.condition{|tree| tree.node_type == :iter}
|
283
|
+
|
284
|
+
define_method_handler(:inline) { |tree|
|
285
|
+
|
286
|
+
next tree if tree.find_tree(:block_pass)
|
287
|
+
|
288
|
+
recv_tree = tree[1] || fs(:self)
|
289
|
+
method_name = tree[2]
|
290
|
+
args_tree = tree[3]
|
291
|
+
|
292
|
+
if method_name == :lvar_type
|
293
|
+
lvar_name = args_tree[1][1] || args_tree[1][2]
|
294
|
+
lvar_type = eval(args_tree[2][1].to_s)
|
295
|
+
|
296
|
+
@infer_lvar_map[lvar_name] = lvar_type
|
297
|
+
next recursive_inline(tree)
|
298
|
+
end
|
299
|
+
|
300
|
+
recvtype = infer_type(recv_tree)
|
301
|
+
|
302
|
+
if recvtype
|
303
|
+
# search the tree of target method
|
304
|
+
mobject = method_obj_or_gtfo(recvtype,method_name)
|
305
|
+
|
306
|
+
next recursive_inline(tree) unless mobject
|
307
|
+
next recursive_inline(tree) unless mobject.tree
|
308
|
+
|
309
|
+
exit_now = false
|
310
|
+
mobject.tree.walk_tree do |subtree|
|
311
|
+
if subtree.node_type == :iter
|
312
|
+
if subtree.find_tree(:return)
|
313
|
+
exit_now = true
|
314
|
+
break
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
next recursive_inline(tree) if exit_now
|
320
|
+
|
321
|
+
target_method_tree_args = if mobject.tree.node_type == :defn
|
322
|
+
mobject.tree[2]
|
323
|
+
else
|
324
|
+
mobject.tree[3]
|
325
|
+
end
|
326
|
+
|
327
|
+
next recursive_inline(tree) if target_method_tree_args.find{|subtree| subtree.to_s =~ /^\*/}
|
328
|
+
|
329
|
+
method_tree_to_inlined_block(mobject, tree, method_name) || recursive_inline(tree)
|
330
|
+
|
144
331
|
else
|
145
332
|
# nothing to do, we don't know what is the method
|
146
|
-
tree
|
333
|
+
recursive_inline(tree)
|
147
334
|
end
|
148
335
|
}.condition{|tree| tree.node_type == :call}
|
149
336
|
end
|
@@ -24,6 +24,11 @@ require "define_method_handler"
|
|
24
24
|
|
25
25
|
module FastRuby
|
26
26
|
class Inliner
|
27
|
+
|
28
|
+
def recursive_inline(tree)
|
29
|
+
tree.map &method(:inline)
|
30
|
+
end
|
31
|
+
|
27
32
|
define_method_handler(:inline, :priority => -100) {|tree|
|
28
33
|
tree.map &method(:inline)
|
29
34
|
}.condition{|tree| tree.respond_to?(:node_type)}
|
@@ -41,7 +41,8 @@ module FastRuby
|
|
41
41
|
end
|
42
42
|
|
43
43
|
reduce_for(:case) do |tree|
|
44
|
-
|
44
|
+
@case_index = (@case_index || 0) + 1
|
45
|
+
temporal_var_name = "temporal_case_var_#{@case_index}".to_sym
|
45
46
|
ifs = when_array_to_if(tree[2..-1], temporal_var_name)
|
46
47
|
fs(:block, fs(:lasgn, temporal_var_name, tree[1]), ifs)
|
47
48
|
end
|