cast_off 0.2.3 → 0.3.1
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/README +22 -47
- data/README.en +14 -36
- data/bin/{CastOff → cast_off} +53 -22
- data/cast_off.gemspec +2 -2
- data/lib/cast_off/compile/basicblock.rb +12 -0
- data/lib/cast_off/compile/cfg.rb +1 -1
- data/lib/cast_off/compile/code_manager.rb +3 -2
- data/lib/cast_off/compile/configuration.rb +43 -29
- data/lib/cast_off/compile/information.rb +363 -229
- data/lib/cast_off/compile/ir/guard_ir.rb +29 -9
- data/lib/cast_off/compile/ir/simple_ir.rb +2 -2
- data/lib/cast_off/compile/translator.rb +48 -10
- data/lib/cast_off/compile.rb +42 -17
- metadata +4 -4
@@ -93,19 +93,26 @@ expected <%= @guard_value.types %> but %s, %s\\n\\
|
|
93
93
|
}
|
94
94
|
EOS
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
96
|
+
GUARD_RECOMPILATION_FUNCTION_TEMPLATE = ERB.new(<<-EOS, 0, '%-', '__recompilation')
|
97
|
+
NOINLINE(static void <RECOMPILATION_FUNCTION_NAME>(VALUE obj));
|
98
|
+
static void <RECOMPILATION_FUNCTION_NAME>(VALUE obj)
|
99
|
+
{
|
99
100
|
#if 1
|
100
|
-
|
101
|
-
%
|
101
|
+
if(!sampling_table) register_sampling_table(rb_hash_new());
|
102
|
+
% count = 0
|
103
|
+
% defs = get_definition(@guard_value)
|
104
|
+
% defs.each do |defn|
|
102
105
|
% case defn
|
103
106
|
% when SubIR
|
104
107
|
% case defn.src
|
105
108
|
% when LocalVariable, DynamicVariable, InstanceVariable, ClassVariable, GlobalVariable, Self
|
106
|
-
|
107
|
-
|
109
|
+
% count += 1
|
110
|
+
sampling_variable(obj, ID2SYM(rb_intern("<%= defn.src.source %>")));
|
111
|
+
% when ConstWrapper
|
108
112
|
% # Fixme
|
113
|
+
/* <%= defn.src.path %> */
|
114
|
+
% when Literal
|
115
|
+
% # nothing to do
|
109
116
|
% else
|
110
117
|
% bug(defn.src)
|
111
118
|
% end
|
@@ -115,12 +122,25 @@ expected <%= @guard_value.types %> but %s, %s\\n\\
|
|
115
122
|
% recv.types.each do |k|
|
116
123
|
% recv_class = @translator.get_c_classname(k)
|
117
124
|
% bug() unless recv_class
|
118
|
-
|
125
|
+
% count += 1
|
126
|
+
__sampling_poscall(obj, <%= recv_class %>, ID2SYM(rb_intern("<%= defn.method_id %>")));
|
119
127
|
% end
|
120
128
|
% end
|
121
129
|
% end
|
122
|
-
|
130
|
+
% if count > 0
|
131
|
+
rb_funcall(rb_mCastOff, rb_intern("re_compile"), 2, rb_str_new2("<%= @translator.signiture() %>"), sampling_table_val);
|
132
|
+
% else
|
133
|
+
% dlog("skip recompilation: defs = \#{defs.join("\\n")}")
|
134
|
+
% end
|
123
135
|
#endif
|
136
|
+
}
|
137
|
+
EOS
|
138
|
+
|
139
|
+
GUARD_TEMPLATE = ERB.new(<<-EOS, 0, '%-', 'g0')
|
140
|
+
%bug() if @guard_value.undefined? || @guard_value.dynamic?
|
141
|
+
<%= guard_begin() %>
|
142
|
+
%func = @translator.declare_recompilation_function(GUARD_RECOMPILATION_FUNCTION_TEMPLATE.trigger(binding))
|
143
|
+
<%= func %>(<%= @guard_value %>);
|
124
144
|
%if @configuration.deoptimize?
|
125
145
|
goto <%= @insn.guard_label %>;
|
126
146
|
% @insn.iseq.inject_guard(@insn, GUARD_DEOPTIMIZATION_TEMPLATE.trigger(binding))
|
@@ -670,7 +670,7 @@ Call site is (#{insn}).
|
|
670
670
|
change = false
|
671
671
|
@cfg.blocks.each do |b|
|
672
672
|
foo = b.irs & irs
|
673
|
-
bar = b.information.
|
673
|
+
bar = b.information.definition & irs
|
674
674
|
if foo.size > 0 || bar.size > 0
|
675
675
|
vars = []
|
676
676
|
bar.each do |ir|
|
@@ -745,7 +745,7 @@ Call site is (#{insn}).
|
|
745
745
|
when Literal
|
746
746
|
return [target]
|
747
747
|
when Variable
|
748
|
-
ds = @information.
|
748
|
+
ds = @information.definition_of(target)
|
749
749
|
bug() if ds.empty?
|
750
750
|
ary = []
|
751
751
|
ds.each do |d|
|
@@ -87,6 +87,7 @@ static void sampling_variable(VALUE val, VALUE sym)
|
|
87
87
|
/* :variable => [klass0, klass1, ...] */
|
88
88
|
VALUE klass = rb_class_of(val);
|
89
89
|
VALUE hashval;
|
90
|
+
VALUE singleton_class_obj_p = Qfalse;
|
90
91
|
st_table *hash;
|
91
92
|
|
92
93
|
if (!st_lookup(sampling_table, (st_data_t)sym, (st_data_t*)&hashval)) {
|
@@ -96,11 +97,16 @@ static void sampling_variable(VALUE val, VALUE sym)
|
|
96
97
|
hash = RHASH_TBL(hashval);
|
97
98
|
|
98
99
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
99
|
-
|
100
|
+
if (rb_obj_class(val) == rb_cClass) {
|
101
|
+
klass = val;
|
102
|
+
singleton_class_obj_p = Qtrue;
|
103
|
+
} else {
|
104
|
+
klass = rb_cCastOffSingletonClass;
|
105
|
+
}
|
100
106
|
}
|
101
107
|
|
102
108
|
if (!st_lookup(hash, (st_data_t)klass, 0)) {
|
103
|
-
st_insert(hash, (st_data_t)klass, (st_data_t)
|
109
|
+
st_insert(hash, (st_data_t)klass, (st_data_t)singleton_class_obj_p);
|
104
110
|
}
|
105
111
|
|
106
112
|
return;
|
@@ -109,18 +115,30 @@ static void sampling_variable(VALUE val, VALUE sym)
|
|
109
115
|
static void __sampling_poscall(VALUE val, VALUE method_klass, VALUE method_id)
|
110
116
|
{
|
111
117
|
VALUE klass;
|
112
|
-
VALUE method_id_hashval, hashval;
|
113
|
-
|
118
|
+
VALUE mtblval, method_id_hashval, hashval;
|
119
|
+
VALUE singleton_class_obj_p = Qfalse;
|
120
|
+
VALUE class_method_p = Qfalse;
|
121
|
+
st_table *mtbl, *method_id_hash, *hash;
|
114
122
|
|
115
123
|
if (FL_TEST(method_klass, FL_SINGLETON)) {
|
116
|
-
|
124
|
+
VALUE recv = rb_ivar_get(method_klass, rb_intern("__attached__"));
|
125
|
+
if (rb_obj_class(recv) == rb_cClass && rb_class_of(recv) == method_klass) {
|
126
|
+
method_klass = recv;
|
127
|
+
class_method_p = Qtrue;
|
128
|
+
} else {
|
129
|
+
method_klass = rb_cCastOffSingletonClass;
|
130
|
+
}
|
117
131
|
}
|
118
132
|
|
119
|
-
|
133
|
+
if (!st_lookup(sampling_table, (st_data_t)class_method_p, (st_data_t*)&mtblval)) {
|
134
|
+
mtblval = rb_hash_new();
|
135
|
+
st_insert(sampling_table, (st_data_t)class_method_p, (st_data_t)mtblval);
|
136
|
+
}
|
137
|
+
mtbl = RHASH_TBL(mtblval);
|
120
138
|
|
121
|
-
if (!st_lookup(
|
139
|
+
if (!st_lookup(mtbl, (st_data_t)method_klass, (st_data_t*)&method_id_hashval)) {
|
122
140
|
method_id_hashval = rb_hash_new();
|
123
|
-
st_insert(
|
141
|
+
st_insert(mtbl, (st_data_t)method_klass, (st_data_t)method_id_hashval);
|
124
142
|
}
|
125
143
|
method_id_hash = RHASH_TBL(method_id_hashval);
|
126
144
|
if (!st_lookup(method_id_hash, (st_data_t)method_id, (st_data_t*)&hashval)) {
|
@@ -129,12 +147,18 @@ static void __sampling_poscall(VALUE val, VALUE method_klass, VALUE method_id)
|
|
129
147
|
}
|
130
148
|
hash = RHASH_TBL(hashval);
|
131
149
|
|
150
|
+
klass = rb_class_of(val);
|
132
151
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
133
|
-
|
152
|
+
if (rb_obj_class(val) == rb_cClass) {
|
153
|
+
klass = val;
|
154
|
+
singleton_class_obj_p = Qtrue;
|
155
|
+
} else {
|
156
|
+
klass = rb_cCastOffSingletonClass;
|
157
|
+
}
|
134
158
|
}
|
135
159
|
|
136
160
|
if (!st_lookup(hash, (st_data_t)klass, 0)) {
|
137
|
-
st_insert(hash, (st_data_t)klass, (st_data_t)
|
161
|
+
st_insert(hash, (st_data_t)klass, (st_data_t)singleton_class_obj_p);
|
138
162
|
}
|
139
163
|
|
140
164
|
return;
|
@@ -385,6 +409,10 @@ static inline int empty_method_table_p(VALUE klass)
|
|
385
409
|
<%= func.gsub(/<CLASS_CHECK_FUNCTION_NAME>/, name) %>
|
386
410
|
%end
|
387
411
|
|
412
|
+
%@recompilation_functions.each do |(func, name)|
|
413
|
+
<%= func.gsub(/<RECOMPILATION_FUNCTION_NAME>/, name) %>
|
414
|
+
%end
|
415
|
+
|
388
416
|
%if !inline_block?
|
389
417
|
static inline void expand_dframe(rb_thread_t *th, long size, rb_iseq_t *iseq, int root_p)
|
390
418
|
{
|
@@ -769,6 +797,7 @@ void Init_<%= signiture() %>(void)
|
|
769
797
|
@declare_constants = {}
|
770
798
|
@class_check_functions = {}
|
771
799
|
@throw_exception_functions = {}
|
800
|
+
@recompilation_functions = {}
|
772
801
|
@prefetch_constants = {}
|
773
802
|
@ivar_index = {}
|
774
803
|
@loopkey = {}
|
@@ -912,6 +941,15 @@ Source line is #{@root_iseq.source_line}.
|
|
912
941
|
name
|
913
942
|
end
|
914
943
|
|
944
|
+
def declare_recompilation_function(func)
|
945
|
+
unless name = @recompilation_functions[func]
|
946
|
+
idx = @recompilation_functions.size()
|
947
|
+
name = "recompilation_#{idx}"
|
948
|
+
@recompilation_functions[func] = name
|
949
|
+
end
|
950
|
+
name
|
951
|
+
end
|
952
|
+
|
915
953
|
def prefetch_constant(var, path, singleton_p)
|
916
954
|
if @prefetch_constants[var]
|
917
955
|
bug() unless @prefetch_constants[var] == [path, singleton_p]
|
data/lib/cast_off/compile.rb
CHANGED
@@ -546,26 +546,35 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
546
546
|
|
547
547
|
def parse_sampling_table(sampling_table)
|
548
548
|
reciever_result = {}
|
549
|
-
return_value_result = {}
|
549
|
+
return_value_result = {:instance_methods => {}, :singleton_methods => {}}
|
550
550
|
sampling_table.each do |(key0, val0)|
|
551
551
|
case key0
|
552
552
|
when Symbol
|
553
553
|
bug() unless val0.is_a?(Hash)
|
554
|
-
reciever_result[key0] = val0.
|
555
|
-
when
|
554
|
+
reciever_result[key0] = val0.to_a
|
555
|
+
when TrueClass, FalseClass
|
556
|
+
mtbl = return_value_result[(key0 ? :singleton_methods : :instance_methods)]
|
557
|
+
bug() unless mtbl.is_a?(Hash)
|
556
558
|
bug() unless val0.is_a?(Hash)
|
557
|
-
|
558
|
-
|
559
|
-
bug() unless
|
560
|
-
|
561
|
-
|
559
|
+
val0.each do |(klass, midtbl)|
|
560
|
+
bug() unless klass.is_a?(Class)
|
561
|
+
bug() unless midtbl.is_a?(Hash)
|
562
|
+
newval = {}
|
563
|
+
midtbl.each do |(key1, val1)|
|
564
|
+
bug() unless key1.is_a?(Symbol)
|
565
|
+
bug() unless val1.is_a?(Hash)
|
566
|
+
newval[key1] = val1.to_a
|
567
|
+
end
|
568
|
+
mtbl[klass] = newval
|
562
569
|
end
|
563
|
-
return_value_result[key0] = newval
|
564
570
|
else
|
565
571
|
bug("#{key0}, #{key0.class}")
|
566
572
|
end
|
567
573
|
end
|
568
|
-
|
574
|
+
k0 = reciever_result.keys
|
575
|
+
k1 = return_value_result[:instance_methods].keys
|
576
|
+
k2 = return_value_result[:singleton_methods].keys
|
577
|
+
bug() unless (k0 & k1 & k2).empty?
|
569
578
|
[reciever_result, return_value_result]
|
570
579
|
end
|
571
580
|
|
@@ -603,8 +612,13 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
603
612
|
reciever_result.each do |key0, val0|
|
604
613
|
bug() unless key0.is_a?(Symbol)
|
605
614
|
bug() unless val0.is_a?(Array)
|
606
|
-
val0.each do |
|
607
|
-
|
615
|
+
val0.each do |(klass, singleton_p)|
|
616
|
+
kstr = klass.to_s
|
617
|
+
if singleton_p
|
618
|
+
bug() unless klass.is_a?(Class)
|
619
|
+
kstr = "Class<#{kstr}>"
|
620
|
+
end
|
621
|
+
ary << [key0.to_s, kstr]
|
608
622
|
end
|
609
623
|
end
|
610
624
|
suggestion.add_suggestion(msg, ["<Variable>", "<SamplingResultClass>"], ary)
|
@@ -612,11 +626,22 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
612
626
|
if return_value_result.size > 0
|
613
627
|
msg = "These are unresolved method return values sampling results."
|
614
628
|
ary = []
|
615
|
-
return_value_result.each do |
|
616
|
-
bug() unless
|
617
|
-
bug() unless
|
618
|
-
|
619
|
-
|
629
|
+
return_value_result.each do |sym, mtbl|
|
630
|
+
bug() unless sym == :singleton_methods || sym == :instance_methods
|
631
|
+
bug() unless mtbl.is_a?(Hash)
|
632
|
+
mtbl.each do |key0, val0|
|
633
|
+
bug() unless key0.is_a?(Class)
|
634
|
+
bug() unless val0.is_a?(Hash)
|
635
|
+
val0.each do |(mid, classes)|
|
636
|
+
classes.each do |(klass, singleton_p)|
|
637
|
+
kstr = klass.to_s
|
638
|
+
if singleton_p
|
639
|
+
bug() unless klass.is_a?(Class)
|
640
|
+
kstr = "Class<#{kstr}>"
|
641
|
+
end
|
642
|
+
ary << ["#{key0}#{sym == :singleton_methods ? '.' : '#'}#{mid}", kstr]
|
643
|
+
end
|
644
|
+
end
|
620
645
|
end
|
621
646
|
end
|
622
647
|
suggestion.add_suggestion(msg, ["<Method>", "<SamplingResultClass>"], ary)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cast_off
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,14 +9,14 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-11-
|
12
|
+
date: 2011-11-18 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'CastOff is a performance improvement tool for Ruby1.9.3
|
15
15
|
|
16
16
|
'
|
17
17
|
email: shiba@rvm.jp
|
18
18
|
executables:
|
19
|
-
-
|
19
|
+
- cast_off
|
20
20
|
extensions:
|
21
21
|
- ext/cast_off/extconf.rb
|
22
22
|
extra_rdoc_files:
|
@@ -95,7 +95,7 @@ files:
|
|
95
95
|
- cast_off.gemspec
|
96
96
|
- README
|
97
97
|
- README.en
|
98
|
-
- bin/
|
98
|
+
- bin/cast_off
|
99
99
|
homepage: http://github.com/soba1104/CastOff
|
100
100
|
licenses: []
|
101
101
|
post_install_message:
|