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