crystalizer 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +27 -0
- data/README +79 -0
- data/Rakefile +24 -0
- data/TODO +14 -0
- data/VERSION +1 -0
- data/benchmarks/bench.rb +129 -0
- data/benchmarks/concretize_test.rb +26 -0
- data/benchmarks/extconf.rb +10 -0
- data/benchmarks/tak_rb.rb +7 -0
- data/benchmarks/tak_so.rb +7 -0
- data/benchmarks/tak_source.rb +16 -0
- data/bin/rb2cx +162 -0
- data/doc/eval2c.txt +246 -0
- data/doc/gen_html.rb +26 -0
- data/doc/html_template +10 -0
- data/doc/index.txt +169 -0
- data/doc/limitations.txt +529 -0
- data/doc/optimizations.txt +185 -0
- data/doc/rb2cx.txt +130 -0
- data/doc/style.css +27 -0
- data/lib/concretizer.rb +3 -0
- data/lib/ruby2cext/c_function.rb +617 -0
- data/lib/ruby2cext/common_node_comp.rb +1412 -0
- data/lib/ruby2cext/compiler.rb +311 -0
- data/lib/ruby2cext/concretize.rb +269 -0
- data/lib/ruby2cext/error.rb +15 -0
- data/lib/ruby2cext/eval2c.rb +126 -0
- data/lib/ruby2cext/parser.rb +36 -0
- data/lib/ruby2cext/plugin.rb +24 -0
- data/lib/ruby2cext/plugins/builtin_methods.rb +817 -0
- data/lib/ruby2cext/plugins/cache_call.rb +293 -0
- data/lib/ruby2cext/plugins/case_optimize.rb +102 -0
- data/lib/ruby2cext/plugins/const_cache.rb +36 -0
- data/lib/ruby2cext/plugins/direct_self_call.rb +70 -0
- data/lib/ruby2cext/plugins/inline_builtin.rb +797 -0
- data/lib/ruby2cext/plugins/inline_methods.rb +68 -0
- data/lib/ruby2cext/plugins/ivar_cache.rb +147 -0
- data/lib/ruby2cext/plugins/require_include.rb +69 -0
- data/lib/ruby2cext/plugins/util.rb +154 -0
- data/lib/ruby2cext/plugins/warnings.rb +121 -0
- data/lib/ruby2cext/scopes.rb +225 -0
- data/lib/ruby2cext/str_to_c_strlit.rb +12 -0
- data/lib/ruby2cext/tools.rb +80 -0
- data/lib/ruby2cext/version.rb +22 -0
- data/results +68 -0
- data/setup.rb +1585 -0
- data/stuff/builtin_methods.rb +69 -0
- data/stuff/builtin_methods_test.rb +37 -0
- data/test/bootstrap.rb +10 -0
- data/test/causes_crash_all_opts.rb +1165 -0
- data/test/eval2c/test_eval2c.rb +37 -0
- data/test/temp_17.rb +16 -0
- data/test/temp_18.rb +8 -0
- data/test/temp_19.rb +8 -0
- data/test/temp_2.rb +7 -0
- data/test/temp_20.rb +5 -0
- data/test/temp_21.rb +161 -0
- data/test/temp_22.rb +7 -0
- data/test/temp_23.rb +7 -0
- data/test/temp_24.rb +219 -0
- data/test/temp_25.rb +7 -0
- data/test/temp_26.rb +11 -0
- data/test/temp_27.rb +11 -0
- data/test/temp_28.rb +9 -0
- data/test/temp_29.rb +9 -0
- data/test/temp_3.rb +0 -0
- data/test/temp_30.rb +0 -0
- data/test/temp_31.rb +10 -0
- data/test/temp_32.rb +10 -0
- data/test/temp_33.rb +15 -0
- data/test/temp_34.rb +15 -0
- data/test/temp_35.rb +7 -0
- data/test/temp_36.rb +7 -0
- data/test/temp_37.rb +10 -0
- data/test/temp_38.rb +10 -0
- data/test/temp_39.rb +0 -0
- data/test/temp_4.rb +7 -0
- data/test/temp_40.rb +50 -0
- data/test/temp_41.rb +50 -0
- data/test/temp_42.rb +8 -0
- data/test/temp_43.rb +8 -0
- data/test/temp_44.rb +0 -0
- data/test/temp_48.rb +7 -0
- data/test/temp_49.rb +7 -0
- data/test/temp_5.rb +7 -0
- data/test/temp_59.rb +7 -0
- data/test/temp_6.rb +7 -0
- data/test/temp_60.rb +7 -0
- data/test/temp_68.rb +239 -0
- data/test/temp_7.rb +7 -0
- data/test/temp_70.rb +7 -0
- data/test/temp_71.rb +7 -0
- data/test/temp_72.rb +13 -0
- data/test/temp_73.rb +7 -0
- data/test/temp_74.rb +7 -0
- data/test/temp_76.rb +7 -0
- data/test/temp_77.rb +13 -0
- data/test/temp_79.rb +7 -0
- data/test/temp_8.rb +14 -0
- data/test/temp_81.rb +14 -0
- data/test/temp_83.rb +0 -0
- data/test/temp_84.rb +7 -0
- data/test/temp_85.rb +7 -0
- data/test/temp_86.rb +14 -0
- data/test/temp_87.rb +7 -0
- data/test/temp_88.rb +7 -0
- data/test/temp_89.rb +7 -0
- data/test/temp_9.rb +14 -0
- data/test/temp_90.rb +0 -0
- data/test/temp_91.rb +7 -0
- data/test/temp_92.rb +7 -0
- data/test/temp_93.rb +7 -0
- data/test/temp_94.rb +7 -0
- data/test/temp_95.rb +7 -0
- data/test/temp_96.rb +0 -0
- data/test/temp_97.rb +0 -0
- data/test/temp_98.rb +7 -0
- data/test/temp_99.rb +7 -0
- data/test/test_concretize.rb +132 -0
- data/test/test_concretize_all.rb +15 -0
- data/test/test_crystalize_block.rb +73 -0
- data/test/test_files/test.rb +615 -0
- data/test/test_files/vmode_test.rb +73 -0
- data/test/test_files/warn_test.rb +35 -0
- data/test/test_syntax.rb +25 -0
- metadata +268 -0
@@ -0,0 +1,293 @@
|
|
1
|
+
# this one does something like...
|
2
|
+
# @ location X
|
3
|
+
# there is a call of method y on z
|
4
|
+
# if z has the same class as last time
|
5
|
+
# then do something of a pseudo-ruby-call into that method, since
|
6
|
+
# we have a pointer saved to it from the previous time.
|
7
|
+
# the pseudo-ruby call being necessary so that we can pass in arguments in ruby like fashion
|
8
|
+
# to the C method, etc.
|
9
|
+
# what are the limitations?
|
10
|
+
#
|
11
|
+
# this one also conflicts with builtin_extensions
|
12
|
+
# which...might be faster?
|
13
|
+
# TODOR make the order matter
|
14
|
+
# TODOR various
|
15
|
+
|
16
|
+
module Ruby2CExtension::Plugins
|
17
|
+
|
18
|
+
class CacheCall < Ruby2CExtension::Plugin
|
19
|
+
|
20
|
+
include Util
|
21
|
+
|
22
|
+
def initialize(compiler, need_frame=true)
|
23
|
+
super(compiler)
|
24
|
+
@need_frame = need_frame || nil
|
25
|
+
@cache_index = Hash.new { |h,k| h[k] = h.size }
|
26
|
+
@argcs = {}
|
27
|
+
compiler.add_preprocessor(:call, &method(:handle_call))
|
28
|
+
compiler.add_preprocessor(:vcall, &method(:handle_call))
|
29
|
+
compiler.add_preprocessor(:fcall, &method(:handle_call))
|
30
|
+
compiler.add_preprocessor(:attrasgn, &method(:handle_call))
|
31
|
+
end
|
32
|
+
|
33
|
+
def handle_call(cfun, node)
|
34
|
+
ntype = node.first
|
35
|
+
hash = node.last
|
36
|
+
mid = hash[:mid]
|
37
|
+
args = hash[:args] || [:array, []]
|
38
|
+
argc = if args.first == :array
|
39
|
+
args = args.last
|
40
|
+
args.size
|
41
|
+
else
|
42
|
+
-1
|
43
|
+
end
|
44
|
+
@argcs[argc] = true
|
45
|
+
recv = hash[:recv]
|
46
|
+
allow_private = case ntype
|
47
|
+
when :fcall, :vcall
|
48
|
+
1
|
49
|
+
else
|
50
|
+
recv.equal?(0) ? 1 : 0
|
51
|
+
end
|
52
|
+
recv = nil if recv.equal?(0)
|
53
|
+
recv ||= [:self, {}]
|
54
|
+
key = [mid, argc, allow_private]
|
55
|
+
if type=deduce_type(recv)
|
56
|
+
key << type
|
57
|
+
else
|
58
|
+
key << cfun.__id__ << recv.inspect
|
59
|
+
end
|
60
|
+
index = @cache_index[key]
|
61
|
+
entry = "method_cache[#{index}]"
|
62
|
+
assign = node.first.equal?(:attrasgn)
|
63
|
+
if argc >= 0
|
64
|
+
last = assign && args.pop
|
65
|
+
values(cfun, 1, last, recv, *args) { |last, recv, *args|
|
66
|
+
args << last if assign
|
67
|
+
args = args.inject("") { |s, arg| s.concat(", #{arg}") }
|
68
|
+
# cache_call1 means "one argument"
|
69
|
+
# delta == 0 means "they accept exactly as many args as I want to pass them"
|
70
|
+
# delta == 1 means "it accepts -1"
|
71
|
+
# it appears to
|
72
|
+
call = "cache_call#{argc}(#{allow_private}, &#{entry}, #{recv}, #{cfun.sym(mid)}#{args})"
|
73
|
+
if assign
|
74
|
+
cfun.l("#{call};")
|
75
|
+
last
|
76
|
+
else
|
77
|
+
call
|
78
|
+
end
|
79
|
+
}
|
80
|
+
else
|
81
|
+
recv = cfun.comp(recv)
|
82
|
+
cfun.c_scope_res {
|
83
|
+
cfun.l "VALUE recv = #{recv};"
|
84
|
+
cfun.build_args(args)
|
85
|
+
call = "cache_call(#{allow_private}, &#{entry}, recv, #{cfun.sym(mid)}, argc, argv)"
|
86
|
+
if assign
|
87
|
+
cfun.l("#{call};")
|
88
|
+
"argv[argc-1]"
|
89
|
+
else
|
90
|
+
call
|
91
|
+
end
|
92
|
+
}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def global_c_code
|
97
|
+
begin
|
98
|
+
#TODO: try handling NOEX_PROTECTED
|
99
|
+
code = %{
|
100
|
+
typedef struct {
|
101
|
+
VALUE klass;
|
102
|
+
VALUE (*func)(ANYARGS);
|
103
|
+
#{@need_frame && 'VALUE origin;'}
|
104
|
+
#{@need_frame && 'ID mid0;'}
|
105
|
+
} method_cache_entry;
|
106
|
+
static method_cache_entry method_cache[#{@cache_index.size}];
|
107
|
+
static void init_method_cache() {
|
108
|
+
method_cache_entry* entry;
|
109
|
+
for (entry = method_cache + #{@cache_index.size-1}; entry >= method_cache; --entry) {
|
110
|
+
entry->klass = 0;
|
111
|
+
entry->func = 0;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
static VALUE recache(
|
115
|
+
int allow_private, method_cache_entry *entry,
|
116
|
+
VALUE recv, ID mid, int argc
|
117
|
+
) {
|
118
|
+
VALUE klass = CLASS_OF(recv);
|
119
|
+
entry->klass = klass;
|
120
|
+
NODE* body;
|
121
|
+
while (!st_lookup(RCLASS(klass)->m_tbl, mid,
|
122
|
+
(st_data_t *)&body))
|
123
|
+
{
|
124
|
+
klass = RCLASS(klass)->super;
|
125
|
+
if (!klass) {
|
126
|
+
entry->klass += 2;
|
127
|
+
return;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
if (!allow_private &&
|
131
|
+
(body->nd_noex & (NOEX_PRIVATE|NOEX_PROTECTED)))
|
132
|
+
{
|
133
|
+
entry->klass += 2;
|
134
|
+
return;
|
135
|
+
}
|
136
|
+
body = body->nd_body;
|
137
|
+
if (nd_type(body) == NODE_FBODY) {
|
138
|
+
#{@need_frame && 'entry->origin = body->nd_orig;'}
|
139
|
+
#{@need_frame && 'entry->mid0 = body->nd_mid;'}
|
140
|
+
body = body->nd_head;
|
141
|
+
} else {
|
142
|
+
#{@need_frame && 'entry->origin = klass;'}
|
143
|
+
#{@need_frame && 'entry->mid0 = mid;'}
|
144
|
+
}
|
145
|
+
if (nd_type(body) == NODE_CFUNC) {
|
146
|
+
entry->func = body->nd_cfnc;
|
147
|
+
if (body->nd_argc == -1) {
|
148
|
+
entry->klass += 1;
|
149
|
+
return;
|
150
|
+
} else if (body->nd_argc == argc) {
|
151
|
+
return;
|
152
|
+
}
|
153
|
+
}
|
154
|
+
entry->klass += 2;
|
155
|
+
return;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
end
|
159
|
+
@argcs.keys.sort.each { |argc|
|
160
|
+
args = (0...argc).inject("") { |s, i|
|
161
|
+
s.concat(", arg#{i}")
|
162
|
+
}
|
163
|
+
args_declare = (0...argc).inject("") { |s, i|
|
164
|
+
s.concat(", VALUE arg#{i}")
|
165
|
+
}
|
166
|
+
argv_init = (0...argc).inject("") { |s, i|
|
167
|
+
s.concat("argv[#{i}]=arg#{i}; ")
|
168
|
+
}
|
169
|
+
argv = case argc
|
170
|
+
when 0
|
171
|
+
"0"
|
172
|
+
when 1
|
173
|
+
"&arg0"
|
174
|
+
else
|
175
|
+
"argv"
|
176
|
+
end
|
177
|
+
if @need_frame
|
178
|
+
# NOTE: uniq=(long)&_frame should be frame_unique++
|
179
|
+
pre_call = %({
|
180
|
+
VALUE res;
|
181
|
+
struct FRAME _frame = {
|
182
|
+
.self = recv,
|
183
|
+
.argc = #{(argc < 0) ? 'argc' : argc},
|
184
|
+
.last_func = mid,
|
185
|
+
.orig_func = entry->mid0,
|
186
|
+
.last_class = entry->origin,
|
187
|
+
.prev = ruby_frame,
|
188
|
+
.tmp = 0,
|
189
|
+
.node = ruby_current_node,
|
190
|
+
.iter = 0,
|
191
|
+
.flags = 0,
|
192
|
+
.uniq = (long)&_frame
|
193
|
+
};
|
194
|
+
ruby_frame = &_frame;
|
195
|
+
res = )
|
196
|
+
post_call = %(
|
197
|
+
ruby_frame = _frame.prev;
|
198
|
+
return res;
|
199
|
+
})
|
200
|
+
else
|
201
|
+
pre_call = "return "
|
202
|
+
post_call = ""
|
203
|
+
end
|
204
|
+
code.concat((argc < 0) ? %{
|
205
|
+
static inline VALUE cache_call(
|
206
|
+
int allow_private, method_cache_entry *entry,
|
207
|
+
VALUE recv, ID mid, int argc, VALUE *argv
|
208
|
+
) {
|
209
|
+
while (1) {
|
210
|
+
VALUE klass = CLASS_OF(recv);
|
211
|
+
switch (entry->klass - klass) {
|
212
|
+
case 1:
|
213
|
+
#{pre_call}
|
214
|
+
(*entry->func)(argc, argv, recv);
|
215
|
+
#{post_call}
|
216
|
+
case 0:
|
217
|
+
case 2:
|
218
|
+
return (*(allow_private ? rb_funcall2 : rb_funcall3))(
|
219
|
+
recv, mid, argc, argv
|
220
|
+
);
|
221
|
+
default:
|
222
|
+
recache(allow_private, entry, recv, mid, argc);
|
223
|
+
}
|
224
|
+
}
|
225
|
+
}
|
226
|
+
} : (argc<=1) ? %{
|
227
|
+
static inline VALUE cache_call#{argc}(
|
228
|
+
int allow_private, method_cache_entry *entry,
|
229
|
+
VALUE recv, ID mid#{args_declare}
|
230
|
+
) {
|
231
|
+
while (1) {
|
232
|
+
VALUE klass = CLASS_OF(recv);
|
233
|
+
VALUE delta = entry->klass - klass;
|
234
|
+
// here1
|
235
|
+
switch (delta) {
|
236
|
+
case 0:
|
237
|
+
case 1:
|
238
|
+
#{pre_call}
|
239
|
+
delta ? (*entry->func)(#{argc}, #{argv}, recv) :
|
240
|
+
(*entry->func)(recv#{args});
|
241
|
+
#{post_call}
|
242
|
+
case 2:
|
243
|
+
return (*(allow_private ? rb_funcall2 : rb_funcall3))(
|
244
|
+
recv, mid, #{argc}, #{argv}
|
245
|
+
);
|
246
|
+
default:
|
247
|
+
recache(allow_private, entry, recv, mid, #{argc});
|
248
|
+
}
|
249
|
+
}
|
250
|
+
}
|
251
|
+
} : %{
|
252
|
+
static inline VALUE cache_call#{argc}(
|
253
|
+
int allow_private, method_cache_entry *entry,
|
254
|
+
VALUE recv, ID mid#{args_declare}
|
255
|
+
) {
|
256
|
+
while (1) {
|
257
|
+
VALUE klass = CLASS_OF(recv);
|
258
|
+
VALUE delta = entry->klass - klass;
|
259
|
+
if (delta==0) {
|
260
|
+
#{pre_call}
|
261
|
+
(*entry->func)(recv#{args});
|
262
|
+
#{post_call}
|
263
|
+
} else {
|
264
|
+
VALUE argv[#{argc}];
|
265
|
+
#{argv_init}
|
266
|
+
if (delta == 1) {
|
267
|
+
#{pre_call}
|
268
|
+
(*entry->func)(#{argc}, #{argv}, recv);
|
269
|
+
#{post_call}
|
270
|
+
} else if (delta == 2) {
|
271
|
+
return (*(allow_private ? rb_funcall2 : rb_funcall3))(
|
272
|
+
recv, mid, #{argc}, #{argv}
|
273
|
+
);
|
274
|
+
} else {
|
275
|
+
recache(allow_private, entry, recv, mid, #{argc});
|
276
|
+
}
|
277
|
+
}
|
278
|
+
}
|
279
|
+
}
|
280
|
+
})
|
281
|
+
}
|
282
|
+
code
|
283
|
+
end
|
284
|
+
|
285
|
+
def init_c_code
|
286
|
+
%{
|
287
|
+
init_method_cache();
|
288
|
+
}
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
|
2
|
+
module Ruby2CExtension::Plugins
|
3
|
+
|
4
|
+
class CaseOptimize < Ruby2CExtension::Plugin
|
5
|
+
|
6
|
+
include Ruby2CExtension::Tools::EnsureNodeTypeMixin
|
7
|
+
|
8
|
+
def initialize(compiler)
|
9
|
+
super
|
10
|
+
compiler.add_preprocessor(:case) { |cfun, node|
|
11
|
+
handle_case(cfun, node.last) || node
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def fixnum?(node)
|
16
|
+
Array === node && node.first == :lit && Fixnum === node.last[:lit]
|
17
|
+
end
|
18
|
+
|
19
|
+
def fixed_immediate?(node)
|
20
|
+
# checks if the node is optimizable and if yes returns the equivalent C value
|
21
|
+
if fixnum?(node)
|
22
|
+
"LONG2FIX(#{node.last[:lit].inspect})"
|
23
|
+
elsif Array === node
|
24
|
+
case node.first
|
25
|
+
when :nil
|
26
|
+
"Qnil"
|
27
|
+
when :true
|
28
|
+
"Qtrue"
|
29
|
+
when :false
|
30
|
+
"Qfalse"
|
31
|
+
else
|
32
|
+
false
|
33
|
+
end
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def handle_case(cfun, hash)
|
40
|
+
cur_when = hash[:body]
|
41
|
+
fallback_whens = []
|
42
|
+
opt_cases = []
|
43
|
+
while cur_when.first == :when
|
44
|
+
ensure_node_type(head = cur_when.last[:head], :array)
|
45
|
+
cases = head.last.map { |wn| fixed_immediate?(wn) }
|
46
|
+
break unless cases.all?
|
47
|
+
case_c_code = cases.map { |c| "case #{c}:" }.join("\n")
|
48
|
+
fixnum_whens = head.last.select { |wn| fixnum?(wn) }
|
49
|
+
unless fixnum_whens.empty?
|
50
|
+
goto_label = compiler.un("case_opt_label")
|
51
|
+
case_c_code << "\n#{goto_label}:"
|
52
|
+
fallback_whens << [:when, {
|
53
|
+
:body => "Qnil;\ngoto #{goto_label}", # TODO: evil, depends on impl. details of comp_case/handle_when
|
54
|
+
:head => [:array, fixnum_whens]
|
55
|
+
}]
|
56
|
+
end
|
57
|
+
opt_cases << [case_c_code, cur_when.last[:body]]
|
58
|
+
cur_when = cur_when.last[:next] || [:nil, {}]
|
59
|
+
end
|
60
|
+
return nil if opt_cases.empty? # nothing to optimize
|
61
|
+
rest = cur_when
|
62
|
+
if rest.first == :when # some whens are left construct a complete new case node
|
63
|
+
rest = [:case, {:head => "case_opt_val", :body => rest}]
|
64
|
+
end
|
65
|
+
cfun.instance_eval {
|
66
|
+
c_scope_res {
|
67
|
+
l "VALUE case_opt_val;"
|
68
|
+
l "case_opt_val = #{comp(hash[:head])};"
|
69
|
+
l "switch (case_opt_val) {"
|
70
|
+
opt_cases.each { |(case_code, body_node)|
|
71
|
+
l case_code
|
72
|
+
assign_res(comp(body_node))
|
73
|
+
l "break;"
|
74
|
+
}
|
75
|
+
l "default:"
|
76
|
+
if fallback_whens.empty?
|
77
|
+
assign_res(comp(rest))
|
78
|
+
else
|
79
|
+
# link the fallback_whens
|
80
|
+
fallback_whens.each_with_index { |wn, i|
|
81
|
+
fallback_whens[i - 1].last[:next] = wn if i > 0
|
82
|
+
}
|
83
|
+
fallback_whens.last.last[:next] = "Qundef"
|
84
|
+
c_if("!FIXNUM_P(case_opt_val)") {
|
85
|
+
assign_res(comp_case({:head => "case_opt_val", :body => fallback_whens.first}))
|
86
|
+
}
|
87
|
+
c_else {
|
88
|
+
assign_res("Qundef")
|
89
|
+
}
|
90
|
+
c_if("res == Qundef") {
|
91
|
+
assign_res(comp(rest))
|
92
|
+
}
|
93
|
+
end
|
94
|
+
l "}"
|
95
|
+
"res"
|
96
|
+
}
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
module Ruby2CExtension::Plugins
|
3
|
+
|
4
|
+
class ConstCache < Ruby2CExtension::Plugin
|
5
|
+
def initialize(compiler)
|
6
|
+
super
|
7
|
+
compiler.add_preprocessor(:const) { |cfun, node|
|
8
|
+
cfun.instance_eval {
|
9
|
+
c_static_once {
|
10
|
+
comp_const(node.last)
|
11
|
+
}
|
12
|
+
}
|
13
|
+
}
|
14
|
+
compiler.add_preprocessor(:colon2) { |cfun, node|
|
15
|
+
mid = node.last[:mid]
|
16
|
+
if mid.to_s[0,1].downcase != mid.to_s[0,1] # then it is a constant
|
17
|
+
cfun.instance_eval {
|
18
|
+
c_static_once {
|
19
|
+
comp_colon2(node.last)
|
20
|
+
}
|
21
|
+
}
|
22
|
+
else
|
23
|
+
node
|
24
|
+
end
|
25
|
+
}
|
26
|
+
compiler.add_preprocessor(:colon3) { |cfun, node|
|
27
|
+
cfun.instance_eval {
|
28
|
+
c_static_once {
|
29
|
+
comp_colon3(node.last)
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# appears to only optimize calls
|
2
|
+
# to self that have no parameters?
|
3
|
+
# or possibly matching parameters?
|
4
|
+
|
5
|
+
module Ruby2CExtension::Plugins
|
6
|
+
|
7
|
+
class DirectSelfCall < Ruby2CExtension::Plugin
|
8
|
+
|
9
|
+
include Util
|
10
|
+
@@only_private = true
|
11
|
+
def DirectSelfCall.allow_public_methods
|
12
|
+
@@only_private = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(cfun, node)
|
16
|
+
hash = node.last
|
17
|
+
recv = hash[:recv]
|
18
|
+
return node if recv && (!(Array === recv) || !recv.first.equal?(:self))
|
19
|
+
mid = hash[:mid]
|
20
|
+
name = @ruby2c_method[[@scope,mid]]
|
21
|
+
return node unless name
|
22
|
+
args = hash[:args] || [:array, []]
|
23
|
+
if Array == args and args.first.equal?(:array) and args.last.empty?
|
24
|
+
"#{name}(0, 0, #{cfun.get_self})"
|
25
|
+
else
|
26
|
+
cfun.c_scope_res {
|
27
|
+
cfun.build_args(args)
|
28
|
+
"#{name}(argc, argv, #{cfun.get_self})"
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(compiler)
|
34
|
+
super
|
35
|
+
@ruby2c_method = {}
|
36
|
+
@scope = nil
|
37
|
+
compiler.add_preprocessor(:defn) { |cfun, node|
|
38
|
+
scope0 = @scope
|
39
|
+
hash = node.last
|
40
|
+
mid = hash[:mid]
|
41
|
+
@scope = cfun
|
42
|
+
name0 = "\0#{cfun.__id__}\0#{mid}\0"
|
43
|
+
name = name0.clone
|
44
|
+
@ruby2c_method[[cfun,mid]] = name
|
45
|
+
_add_fun = compiler.method(:add_fun)
|
46
|
+
klass = (class << compiler;self;end)
|
47
|
+
klass.send(:define_method, :add_fun) { |code, base_name|
|
48
|
+
name.replace(_add_fun[code, base_name])
|
49
|
+
code.gsub!(name0, name)
|
50
|
+
name.clone
|
51
|
+
}
|
52
|
+
ret = cfun.comp_defn(hash)
|
53
|
+
if @@only_private
|
54
|
+
unless cfun.scope.vmode.equal?(:private)
|
55
|
+
@ruby2c_method.delete([cfun,mid]) # pretend we never even saw this method...
|
56
|
+
end
|
57
|
+
end
|
58
|
+
@scope = scope0
|
59
|
+
klass.send(:define_method, :add_fun, _add_fun.unbind)
|
60
|
+
ret
|
61
|
+
}
|
62
|
+
compiler.add_preprocessor(:call, &method(:call))
|
63
|
+
compiler.add_preprocessor(:vcall, &method(:call))
|
64
|
+
compiler.add_preprocessor(:fcall, &method(:call))
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|