crystalizer 0.2.2
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 +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
|