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,68 @@
|
|
1
|
+
# this one inlines [trivial] ruby methods, like #nil?
|
2
|
+
|
3
|
+
module Ruby2CExtension::Plugins
|
4
|
+
|
5
|
+
class InlineMethods < Ruby2CExtension::Plugin
|
6
|
+
|
7
|
+
METHODS = {
|
8
|
+
[:nil?, 0] => proc { |cfun, recv, args|
|
9
|
+
"(Qnil == (#{recv}) ? Qtrue : Qfalse)"
|
10
|
+
},
|
11
|
+
[:equal?, 1] => proc { |cfun, recv, args|
|
12
|
+
cfun.instance_eval {
|
13
|
+
c_scope_res {
|
14
|
+
l "VALUE recv = #{recv};"
|
15
|
+
"(recv == (#{comp(args[0])}) ? Qtrue : Qfalse)"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
},
|
19
|
+
:__send__ => proc { |cfun, recv, args|
|
20
|
+
unless args
|
21
|
+
raise Ruby2CExtension::Ruby2CExtError, "inlining #__send__ without arguments is not allowed"
|
22
|
+
end
|
23
|
+
cfun.instance_eval {
|
24
|
+
add_helper <<-EOC
|
25
|
+
static void inline_method_send_no_method_name() {
|
26
|
+
rb_raise(rb_eArgError, "no method name given");
|
27
|
+
}
|
28
|
+
EOC
|
29
|
+
c_scope_res {
|
30
|
+
l "VALUE recv = #{recv};"
|
31
|
+
build_args(args)
|
32
|
+
l "if (argc == 0) inline_method_send_no_method_name();"
|
33
|
+
"rb_funcall2(recv, rb_to_id(argv[0]), argc - 1, (&(argv[0])) + 1)"
|
34
|
+
}
|
35
|
+
}
|
36
|
+
},
|
37
|
+
}
|
38
|
+
|
39
|
+
def initialize(compiler)
|
40
|
+
super
|
41
|
+
self_node = [:self, {}]
|
42
|
+
compiler.add_preprocessor(:vcall) { |cfun, node|
|
43
|
+
handle(cfun, node.last[:mid], self_node, false) || node
|
44
|
+
}
|
45
|
+
compiler.add_preprocessor(:fcall) { |cfun, node|
|
46
|
+
handle(cfun, node.last[:mid], self_node, node.last[:args]) || node
|
47
|
+
}
|
48
|
+
compiler.add_preprocessor(:call) { |cfun, node|
|
49
|
+
handle(cfun, node.last[:mid], node.last[:recv], node.last[:args]) || node
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def handle(cfun, method, recv, args)
|
54
|
+
if (pr = METHODS[method])
|
55
|
+
pr.call(cfun, cfun.comp(recv), args)
|
56
|
+
else
|
57
|
+
args ||= [:array, []]
|
58
|
+
if args.first == :array && (pr = METHODS[[method, args.last.size]])
|
59
|
+
pr.call(cfun, cfun.comp(recv), args.last)
|
60
|
+
else
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# this one makes for faster
|
2
|
+
# @a = 3
|
3
|
+
# @b = 4
|
4
|
+
# by doing the lookups locally, in C, instead of having ruby do it for us by a rb_ivar_set call.
|
5
|
+
|
6
|
+
module Ruby2CExtension::Plugins
|
7
|
+
|
8
|
+
class IVarCache < Ruby2CExtension::Plugin
|
9
|
+
|
10
|
+
include Util
|
11
|
+
|
12
|
+
def initialize(compiler)
|
13
|
+
super(compiler)
|
14
|
+
@cache_index = Hash.new { |h,k| h[k] = h.size }
|
15
|
+
compiler.add_preprocessor(:ivar) { |cfun, node|
|
16
|
+
hash = node.last
|
17
|
+
vid = hash[:vid]
|
18
|
+
key = [vid, cfun.__id__]
|
19
|
+
index = @cache_index[key]
|
20
|
+
entry = "ivar_cache[#{index}]"
|
21
|
+
"cache_ivar_get(&#{entry}, #{cfun.get_self}, #{cfun.sym(vid)})"
|
22
|
+
}
|
23
|
+
compiler.add_preprocessor(:iasgn) { |cfun, node|
|
24
|
+
hash = node.last
|
25
|
+
vid = hash[:vid]
|
26
|
+
key = [vid, cfun.__id__]
|
27
|
+
index = @cache_index[key]
|
28
|
+
entry = "ivar_cache[#{index}]"
|
29
|
+
"cache_ivar_set(&#{entry}, #{cfun.get_self}, #{cfun.sym(vid)}, #{cfun.comp(hash[:value])})"
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def global_c_code
|
34
|
+
code = %{
|
35
|
+
typedef struct {
|
36
|
+
unsigned num_bins;
|
37
|
+
unsigned bin_pos;
|
38
|
+
} ivar_cache_entry;
|
39
|
+
static ivar_cache_entry ivar_cache[#{@cache_index.size}];
|
40
|
+
static void init_ivar_cache() {
|
41
|
+
ivar_cache_entry* entry;
|
42
|
+
for (entry = &ivar_cache[#{@cache_index.size-1}]; entry >= ivar_cache; --entry) {
|
43
|
+
entry->num_bins = 0;
|
44
|
+
entry->bin_pos = 0;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
typedef struct st_table_entry st_table_entry;
|
48
|
+
struct st_table_entry {
|
49
|
+
unsigned int hash;
|
50
|
+
st_data_t key;
|
51
|
+
st_data_t record;
|
52
|
+
st_table_entry *next;
|
53
|
+
};
|
54
|
+
static st_table_entry *st_find_collided(st_table_entry **prev, ID id) {
|
55
|
+
st_table_entry *cur = *prev;
|
56
|
+
while (cur = cur->next) {
|
57
|
+
if (cur->hash == id) {
|
58
|
+
(*prev)->next = cur->next;
|
59
|
+
cur->next = *prev;
|
60
|
+
*prev = cur;
|
61
|
+
return cur;
|
62
|
+
}
|
63
|
+
prev = &(*prev)->next;
|
64
|
+
}
|
65
|
+
return 0;
|
66
|
+
}
|
67
|
+
static VALUE cache_ivar_get(ivar_cache_entry* entry,
|
68
|
+
VALUE obj, ID id)
|
69
|
+
{
|
70
|
+
st_table* table = ROBJECT(obj)->iv_tbl;
|
71
|
+
unsigned bin_pos;
|
72
|
+
st_table_entry *cur;
|
73
|
+
switch (TYPE(obj)) {
|
74
|
+
case T_OBJECT:
|
75
|
+
case T_CLASS:
|
76
|
+
case T_MODULE:
|
77
|
+
break;
|
78
|
+
default:
|
79
|
+
return rb_ivar_get(obj, id);
|
80
|
+
}
|
81
|
+
if (!table) return Qnil;
|
82
|
+
if (entry->num_bins==table->num_bins) {
|
83
|
+
bin_pos = entry->bin_pos;
|
84
|
+
} else {
|
85
|
+
entry->num_bins = table->num_bins;
|
86
|
+
bin_pos = entry->bin_pos = id % table->num_bins;
|
87
|
+
}
|
88
|
+
cur = table->bins[bin_pos];
|
89
|
+
if (!cur) return Qnil;
|
90
|
+
if (cur->hash == id) return cur->record;
|
91
|
+
cur = st_find_collided(&table->bins[bin_pos], id);
|
92
|
+
return cur ? cur->record : Qnil;
|
93
|
+
}
|
94
|
+
static VALUE cache_ivar_set(ivar_cache_entry* entry,
|
95
|
+
VALUE obj, ID id, VALUE val)
|
96
|
+
{
|
97
|
+
st_table* table;
|
98
|
+
unsigned bin_pos;
|
99
|
+
st_table_entry *cur;
|
100
|
+
if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4 || OBJ_FROZEN(obj))
|
101
|
+
return rb_ivar_set(obj, id, val);
|
102
|
+
switch (TYPE(obj)) {
|
103
|
+
case T_OBJECT:
|
104
|
+
case T_CLASS:
|
105
|
+
case T_MODULE:
|
106
|
+
break;
|
107
|
+
default:
|
108
|
+
return rb_ivar_set(obj, id, val);
|
109
|
+
}
|
110
|
+
table = ROBJECT(obj)->iv_tbl;
|
111
|
+
if (!table) {
|
112
|
+
table = ROBJECT(obj)->iv_tbl = st_init_numtable();
|
113
|
+
}
|
114
|
+
if (entry->num_bins==table->num_bins) {
|
115
|
+
bin_pos = entry->bin_pos;
|
116
|
+
} else {
|
117
|
+
entry->num_bins = table->num_bins;
|
118
|
+
bin_pos = entry->bin_pos = id % table->num_bins;
|
119
|
+
}
|
120
|
+
cur = table->bins[bin_pos];
|
121
|
+
if (!cur) {
|
122
|
+
st_add_direct(table, id, val);
|
123
|
+
return val;
|
124
|
+
}
|
125
|
+
if (cur->hash == id) return (cur->record = val);
|
126
|
+
cur = st_find_collided(&table->bins[bin_pos], id);
|
127
|
+
if (cur) {
|
128
|
+
return (cur->record = val);
|
129
|
+
} else {
|
130
|
+
st_add_direct(table, id, val);
|
131
|
+
return val;
|
132
|
+
}
|
133
|
+
}
|
134
|
+
}
|
135
|
+
code
|
136
|
+
end
|
137
|
+
|
138
|
+
def init_c_code
|
139
|
+
%{
|
140
|
+
init_ivar_cache();
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
module Ruby2CExtension::Plugins
|
3
|
+
|
4
|
+
class RequireInclude < Ruby2CExtension::Plugin
|
5
|
+
|
6
|
+
attr_reader :include_paths
|
7
|
+
|
8
|
+
def initialize(compiler, include_paths, ignore_files = nil)
|
9
|
+
super(compiler)
|
10
|
+
@include_paths = include_paths
|
11
|
+
done = {}
|
12
|
+
if ignore_files
|
13
|
+
ignore_files.each { |file|
|
14
|
+
done[File.expand_path(file)] = true
|
15
|
+
}
|
16
|
+
end
|
17
|
+
compiler.add_preprocessor(:fcall) { |cfun, node|
|
18
|
+
hash = node.last
|
19
|
+
if hash[:mid] == :require &&
|
20
|
+
(args = hash[:args]) &&
|
21
|
+
args.first == :array &&
|
22
|
+
(args = args.last).size == 1 &&
|
23
|
+
Array === args[0] &&
|
24
|
+
args[0].first == :str &&
|
25
|
+
(file = search_file(args[0].last[:lit]))
|
26
|
+
unless done[File.expand_path(file)]
|
27
|
+
done[File.expand_path(file)] = true
|
28
|
+
cfun.compiler.log "including require'd file: #{file}"
|
29
|
+
cfun.instance_eval {
|
30
|
+
add_helper <<-EOC
|
31
|
+
static NODE * find_top_cref(NODE *cref) {
|
32
|
+
while (cref && cref->nd_next) cref = cref->nd_next;
|
33
|
+
return cref;
|
34
|
+
}
|
35
|
+
EOC
|
36
|
+
c_scope {
|
37
|
+
l "NODE *top_cref = find_top_cref(#{get_cref});"
|
38
|
+
l "static int done = 0;"
|
39
|
+
c_if("!done") {
|
40
|
+
l "done = 1;"
|
41
|
+
compiler.rb_file_to_toplevel_functions(IO.read(file), file).each { |tlfn|
|
42
|
+
l "#{tlfn}(org_ruby_top_self, top_cref);"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
"Qtrue"
|
49
|
+
else
|
50
|
+
node
|
51
|
+
end
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def search_file(req_str)
|
56
|
+
req_str = req_str.dup
|
57
|
+
unless req_str =~ /\.rb\z/
|
58
|
+
req_str << ".rb"
|
59
|
+
end
|
60
|
+
res = false
|
61
|
+
include_paths.map { |path|
|
62
|
+
File.join(path, req_str)
|
63
|
+
}.find { |file|
|
64
|
+
File.exists? file
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
|
2
|
+
module Ruby2CExtension::Plugins
|
3
|
+
|
4
|
+
module Util
|
5
|
+
|
6
|
+
def deduce_type(node)
|
7
|
+
while true
|
8
|
+
Array === node or return
|
9
|
+
case node.first
|
10
|
+
when :lit
|
11
|
+
return Kernel.const_get(node.last[:lit].class.name)
|
12
|
+
when :nil
|
13
|
+
return NilClass
|
14
|
+
when :false
|
15
|
+
return FalseClass
|
16
|
+
when :true
|
17
|
+
return TrueClass
|
18
|
+
when :str, :dstr
|
19
|
+
return String
|
20
|
+
when :dsym
|
21
|
+
return Symbol
|
22
|
+
when :array, :zarray, :masgn
|
23
|
+
return Array
|
24
|
+
when :hash
|
25
|
+
return Hash
|
26
|
+
when :dregx, :dregx_once
|
27
|
+
return Regexp
|
28
|
+
when :dasn_curr, :iasgn, :cvdecl, :gasgn, :cdecl
|
29
|
+
node = node.last[:value]
|
30
|
+
when :attrasgn
|
31
|
+
args = node.last[:args]
|
32
|
+
Array === args or return
|
33
|
+
case args.first
|
34
|
+
when :array
|
35
|
+
node = args.last.last
|
36
|
+
when :argspush
|
37
|
+
node = args.last[:body]
|
38
|
+
else
|
39
|
+
return
|
40
|
+
end
|
41
|
+
else
|
42
|
+
return
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def values(cfun, nreused, *rvalues) # :yield: *vals
|
48
|
+
header = "{"
|
49
|
+
cfun.l(header)
|
50
|
+
res = 0
|
51
|
+
reuse = 0
|
52
|
+
vals = []
|
53
|
+
res_assign = ""
|
54
|
+
res_val = ""
|
55
|
+
direct = /\A\s*(\w+(\s*\[\s*\d+\s*\])?|\d+)\s*\Z/
|
56
|
+
rvalues.each { |rvalue|
|
57
|
+
nreused -= 1
|
58
|
+
val = rvalue && cfun.comp(rvalue)
|
59
|
+
if val == "res"
|
60
|
+
if res_assign
|
61
|
+
header.concat("VALUE res#{res};")
|
62
|
+
res += 1
|
63
|
+
end
|
64
|
+
var = "res#{res}"
|
65
|
+
cfun.l(res_assign = "#{var} = #{val};")
|
66
|
+
res_val = val = var
|
67
|
+
elsif nreused >= 0 and val and val !~ direct
|
68
|
+
var = "reuse#{reuse}"
|
69
|
+
header.concat("VALUE #{var};")
|
70
|
+
cfun.l("#{var} = #{val};")
|
71
|
+
val = var
|
72
|
+
end
|
73
|
+
vals << val
|
74
|
+
}
|
75
|
+
res_assign.replace("")
|
76
|
+
res_val.replace("res")
|
77
|
+
if header.size == 1
|
78
|
+
header.replace("")
|
79
|
+
yield(*vals)
|
80
|
+
else
|
81
|
+
res_rvalue = yield(*vals)
|
82
|
+
cfun.assign_res(res_rvalue)
|
83
|
+
cfun.l "}"
|
84
|
+
"res"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def split_args(arity, args, extra_allowed=nil)
|
89
|
+
if arity<0
|
90
|
+
extra_allowed = true
|
91
|
+
arity = -arity -1
|
92
|
+
end
|
93
|
+
data = args.last
|
94
|
+
required = []
|
95
|
+
remaining = nil
|
96
|
+
case args.first
|
97
|
+
when :array
|
98
|
+
if data.size>arity
|
99
|
+
required = data[0, arity]
|
100
|
+
remaining = [:array, data[arity, data.size-arity]]
|
101
|
+
else
|
102
|
+
required = data
|
103
|
+
end
|
104
|
+
when :splat
|
105
|
+
remaining = args
|
106
|
+
when :argscat
|
107
|
+
required = split_args(arity, data[:head], true) or return nil
|
108
|
+
remaining = [:argscat, {:head => required.pop, :body => data[:body]}]
|
109
|
+
when :argspush
|
110
|
+
if extra_allowed
|
111
|
+
required = split_args(arity, data[:head], true) or return nil
|
112
|
+
remaining = [:argspush, {:head => required.pop, :body => data[:body]}]
|
113
|
+
else
|
114
|
+
required = split_args(arity-1, data[:head], false) or return nil
|
115
|
+
required << data[:body]
|
116
|
+
end
|
117
|
+
else
|
118
|
+
return nil
|
119
|
+
end
|
120
|
+
if required.size<arity
|
121
|
+
nil
|
122
|
+
elsif extra_allowed
|
123
|
+
remaining ||= [:array, []]
|
124
|
+
required << remaining
|
125
|
+
elsif remaining
|
126
|
+
nil
|
127
|
+
else
|
128
|
+
required
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def args_arity(args)
|
133
|
+
data = args.last
|
134
|
+
case args.first
|
135
|
+
when :array
|
136
|
+
data.size
|
137
|
+
when :splat
|
138
|
+
-1
|
139
|
+
when :argscat
|
140
|
+
arity = args_arity(data[:head])
|
141
|
+
(arity<0) ? arity : -arity - 1
|
142
|
+
when :argspush
|
143
|
+
arity = args_arity(data[:head])
|
144
|
+
(arity<0) ? arity : arity + 1
|
145
|
+
else
|
146
|
+
-1
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
|
@@ -0,0 +1,121 @@
|
|
1
|
+
|
2
|
+
module Ruby2CExtension::Plugins
|
3
|
+
|
4
|
+
# TODO: Module.nesting, Module.constants, Kernel#autoload and Kernel#autoload?
|
5
|
+
|
6
|
+
class Warnings < Ruby2CExtension::Plugin
|
7
|
+
|
8
|
+
CALL_TYPES = [:vcall, :fcall, :call]
|
9
|
+
|
10
|
+
exp = "might not behave as expected"
|
11
|
+
exp2 = "will not behave as expected"
|
12
|
+
vis_exp = "visibility of the defined %s might not be as expected"
|
13
|
+
|
14
|
+
VCALL_WARNINGS = {
|
15
|
+
:binding => exp2,
|
16
|
+
:local_variables => exp2,
|
17
|
+
:callcc => exp,
|
18
|
+
}
|
19
|
+
|
20
|
+
FCALL_WARNINGS = {
|
21
|
+
:set_trace_func => exp,
|
22
|
+
:eval => exp,
|
23
|
+
:define_method => vis_exp % "method",
|
24
|
+
:attr => vis_exp % "attribute",
|
25
|
+
:attr_reader => vis_exp % "attribute(s)",
|
26
|
+
:attr_writer => vis_exp % "attribute(s)",
|
27
|
+
:attr_accessor => vis_exp % "attribute(s)",
|
28
|
+
:instance_eval => exp,
|
29
|
+
:module_eval => exp,
|
30
|
+
:class_eval => exp,
|
31
|
+
}
|
32
|
+
|
33
|
+
CALL_WARNINGS = {
|
34
|
+
:arity => "will return -1 for all methods defined in compiled Ruby code",
|
35
|
+
:instance_eval => exp,
|
36
|
+
:module_eval => exp,
|
37
|
+
:class_eval => exp,
|
38
|
+
}
|
39
|
+
|
40
|
+
BLOCK_PASS_WARNINGS = {
|
41
|
+
:define_method => true,
|
42
|
+
:instance_eval => true,
|
43
|
+
:module_eval => true,
|
44
|
+
:class_eval => true,
|
45
|
+
}
|
46
|
+
|
47
|
+
NO_WARNING_WITH_ITER = {
|
48
|
+
:instance_eval => true,
|
49
|
+
:module_eval => true,
|
50
|
+
:class_eval => true,
|
51
|
+
}
|
52
|
+
|
53
|
+
def initialize(compiler)
|
54
|
+
super
|
55
|
+
CALL_TYPES.each { |ct|
|
56
|
+
ct_sym = "check_#{ct}".to_sym
|
57
|
+
compiler.add_preprocessor(ct) { |cfun, node|
|
58
|
+
send(ct_sym, node.last)
|
59
|
+
node
|
60
|
+
}
|
61
|
+
}
|
62
|
+
[:iter, :block_pass].each { |it|
|
63
|
+
it_sym = "check_#{it}".to_sym
|
64
|
+
compiler.add_preprocessor(it) { |cfun, node|
|
65
|
+
if node.last[:iter] && CALL_TYPES.include?(node.last[:iter].first)
|
66
|
+
send(it_sym, node.last[:iter])
|
67
|
+
end
|
68
|
+
node
|
69
|
+
}
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def warn(str, node_hash = {})
|
74
|
+
lstr = ""
|
75
|
+
if (n = node_hash[:node])
|
76
|
+
lstr << "#{n.file}:#{n.line}: "
|
77
|
+
end
|
78
|
+
lstr << "warning: " << str
|
79
|
+
compiler.log(lstr, true)
|
80
|
+
end
|
81
|
+
|
82
|
+
def check_vcall(hash)
|
83
|
+
if (m = VCALL_WARNINGS[hash[:mid]])
|
84
|
+
warn("#{hash[:mid]}: #{m}", hash)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def check_fcall(hash)
|
89
|
+
if (m = FCALL_WARNINGS[hash[:mid]])
|
90
|
+
warn("#{hash[:mid]}: #{m}", hash)
|
91
|
+
else
|
92
|
+
unless hash[:args]
|
93
|
+
check_vcall(hash)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def check_call(hash)
|
99
|
+
if (m = CALL_WARNINGS[hash[:mid]])
|
100
|
+
warn("#{hash[:mid]}: #{m}", hash)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def check_iter(iter_node)
|
105
|
+
mid = iter_node.last[:mid]
|
106
|
+
unless NO_WARNING_WITH_ITER[mid]
|
107
|
+
send("check_#{iter_node.first}", iter_node.last)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def check_block_pass(iter_node)
|
112
|
+
mid = iter_node.last[:mid]
|
113
|
+
if BLOCK_PASS_WARNINGS[mid]
|
114
|
+
warn("#{mid} with block_pass: might not behave as expected", iter_node.last)
|
115
|
+
else
|
116
|
+
send("check_#{iter_node.first}", iter_node.last)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|