cast_off 0.3.1 → 0.3.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/cast_off.gemspec +1 -1
- data/ext/cast_off/cast_off.c.rb +65 -26
- data/ext/cast_off/generated_c_include/unbox_api.h.rb +57 -3
- data/lib/cast_off/compile/cfg.rb +7 -41
- data/lib/cast_off/compile/configuration.rb +124 -13
- data/lib/cast_off/compile/dependency.rb +66 -18
- data/lib/cast_off/compile/information.rb +19 -75
- data/lib/cast_off/compile/ir/call_ir.rb +55 -57
- data/lib/cast_off/compile/ir/guard_ir.rb +96 -80
- data/lib/cast_off/compile/ir/jump_ir.rb +3 -15
- data/lib/cast_off/compile/ir/operand.rb +33 -47
- data/lib/cast_off/compile/ir/param_ir.rb +3 -24
- data/lib/cast_off/compile/ir/return_ir.rb +3 -13
- data/lib/cast_off/compile/ir/simple_ir.rb +16 -6
- data/lib/cast_off/compile/ir/sub_ir.rb +8 -66
- data/lib/cast_off/compile/iseq.rb +11 -0
- data/lib/cast_off/compile/translator.rb +14 -13
- data/lib/cast_off/compile.rb +122 -39
- data/lib/cast_off/util.rb +2 -0
- metadata +2 -2
@@ -87,7 +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
|
90
|
+
VALUE singleton_class_or_module_obj_p = Qfalse;
|
91
91
|
st_table *hash;
|
92
92
|
|
93
93
|
if (!st_lookup(sampling_table, (st_data_t)sym, (st_data_t*)&hashval)) {
|
@@ -97,16 +97,16 @@ static void sampling_variable(VALUE val, VALUE sym)
|
|
97
97
|
hash = RHASH_TBL(hashval);
|
98
98
|
|
99
99
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
100
|
-
if (rb_obj_class(val) == rb_cClass) {
|
100
|
+
if (rb_obj_class(val) == rb_cClass || rb_obj_class(val) == rb_cModule) {
|
101
101
|
klass = val;
|
102
|
-
|
102
|
+
singleton_class_or_module_obj_p = Qtrue;
|
103
103
|
} else {
|
104
104
|
klass = rb_cCastOffSingletonClass;
|
105
105
|
}
|
106
106
|
}
|
107
107
|
|
108
108
|
if (!st_lookup(hash, (st_data_t)klass, 0)) {
|
109
|
-
st_insert(hash, (st_data_t)klass, (st_data_t)
|
109
|
+
st_insert(hash, (st_data_t)klass, (st_data_t)singleton_class_or_module_obj_p);
|
110
110
|
}
|
111
111
|
|
112
112
|
return;
|
@@ -116,23 +116,23 @@ static void __sampling_poscall(VALUE val, VALUE method_klass, VALUE method_id)
|
|
116
116
|
{
|
117
117
|
VALUE klass;
|
118
118
|
VALUE mtblval, method_id_hashval, hashval;
|
119
|
-
VALUE
|
120
|
-
VALUE
|
119
|
+
VALUE singleton_class_or_module_obj_p = Qfalse;
|
120
|
+
VALUE class_method_or_module_function_p = Qfalse;
|
121
121
|
st_table *mtbl, *method_id_hash, *hash;
|
122
122
|
|
123
123
|
if (FL_TEST(method_klass, FL_SINGLETON)) {
|
124
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) {
|
125
|
+
if ((rb_obj_class(recv) == rb_cClass || rb_obj_class(recv) == rb_cModule) && rb_class_of(recv) == method_klass) {
|
126
126
|
method_klass = recv;
|
127
|
-
|
127
|
+
class_method_or_module_function_p = Qtrue;
|
128
128
|
} else {
|
129
129
|
method_klass = rb_cCastOffSingletonClass;
|
130
130
|
}
|
131
131
|
}
|
132
132
|
|
133
|
-
if (!st_lookup(sampling_table, (st_data_t)
|
133
|
+
if (!st_lookup(sampling_table, (st_data_t)class_method_or_module_function_p, (st_data_t*)&mtblval)) {
|
134
134
|
mtblval = rb_hash_new();
|
135
|
-
st_insert(sampling_table, (st_data_t)
|
135
|
+
st_insert(sampling_table, (st_data_t)class_method_or_module_function_p, (st_data_t)mtblval);
|
136
136
|
}
|
137
137
|
mtbl = RHASH_TBL(mtblval);
|
138
138
|
|
@@ -149,16 +149,16 @@ static void __sampling_poscall(VALUE val, VALUE method_klass, VALUE method_id)
|
|
149
149
|
|
150
150
|
klass = rb_class_of(val);
|
151
151
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
152
|
-
if (rb_obj_class(val) == rb_cClass) {
|
152
|
+
if (rb_obj_class(val) == rb_cClass || rb_obj_class(val) == rb_cModule) {
|
153
153
|
klass = val;
|
154
|
-
|
154
|
+
singleton_class_or_module_obj_p = Qtrue;
|
155
155
|
} else {
|
156
156
|
klass = rb_cCastOffSingletonClass;
|
157
157
|
}
|
158
158
|
}
|
159
159
|
|
160
160
|
if (!st_lookup(hash, (st_data_t)klass, 0)) {
|
161
|
-
st_insert(hash, (st_data_t)klass, (st_data_t)
|
161
|
+
st_insert(hash, (st_data_t)klass, (st_data_t)singleton_class_or_module_obj_p);
|
162
162
|
}
|
163
163
|
|
164
164
|
return;
|
@@ -571,6 +571,7 @@ static VALUE <%= this_function_name() %>(VALUE dummy, VALUE self)
|
|
571
571
|
/* decl variables */
|
572
572
|
VALUE cast_off_argv[<%= @root_iseq.all_argv_size() %>];
|
573
573
|
VALUE cast_off_tmp;
|
574
|
+
VALUE sampling_tmp;
|
574
575
|
rb_thread_t *th;
|
575
576
|
%if inline_block?
|
576
577
|
VALUE thval;
|
data/lib/cast_off/compile.rb
CHANGED
@@ -78,34 +78,33 @@ module CastOff
|
|
78
78
|
class_table = {}
|
79
79
|
bind_table = {}
|
80
80
|
location_table = {}
|
81
|
-
cinfo_table = {}
|
81
|
+
#cinfo_table = {}
|
82
82
|
compiled = []
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
return if event != 'call'
|
87
|
-
return if file =~ /\(/
|
88
|
-
|
83
|
+
#@@autocompile_proc = lambda {|file, line, mid, bind, klass, cinfo|
|
84
|
+
@@autocompile_proc = lambda {|file, line, mid, bind, klass|
|
85
|
+
# trace method invocation
|
89
86
|
# TODO should handle singleton class
|
90
87
|
|
91
|
-
|
92
|
-
method_table = class_table[klass]
|
93
|
-
unless method_table
|
94
|
-
method_table = Hash.new(0)
|
95
|
-
class_table[klass] = method_table
|
96
|
-
end
|
88
|
+
method_table = (class_table[klass] ||= Hash.new(-1))
|
97
89
|
count = (method_table[mid] += 1)
|
90
|
+
if count == 0
|
91
|
+
bug() unless bind.nil?
|
92
|
+
return true # re-call this proc with binding
|
93
|
+
end
|
98
94
|
if count == 1
|
95
|
+
#count = @@compilation_threshold if contain_loop?(klass, mid)
|
96
|
+
bug() unless bind.instance_of?(Binding) || bind.nil?
|
99
97
|
bind_table[[klass, mid]] = bind
|
100
|
-
location_table[[klass, mid]] = [File.expand_path(file), line]
|
101
|
-
end
|
102
|
-
if cinfo
|
103
|
-
table = (cinfo_table[[klass, mid]] ||= {})
|
104
|
-
table[cinfo] = true
|
98
|
+
location_table[[klass, mid]] = (file =~ /\(/) ? nil : [File.expand_path(file), line]
|
105
99
|
end
|
100
|
+
#if cinfo
|
101
|
+
#table = (cinfo_table[[klass, mid]] ||= {})
|
102
|
+
#table[cinfo] = true
|
103
|
+
#end
|
106
104
|
if count == @@compilation_threshold && @@compile_auto_incremental
|
107
105
|
compiled << __autocompile(klass, mid, bind_table, location_table, compiled.size)
|
108
106
|
end
|
107
|
+
false
|
109
108
|
}
|
110
109
|
hook_method_invocation(@@autocompile_proc)
|
111
110
|
at_exit do
|
@@ -118,7 +117,7 @@ module CastOff
|
|
118
117
|
targets << [klass, mid, count]
|
119
118
|
end
|
120
119
|
end
|
121
|
-
targets = sort_targets(targets, cinfo_table)
|
120
|
+
#targets = sort_targets(targets, cinfo_table)
|
122
121
|
targets.each_with_index do |(klass, mid, count), index|
|
123
122
|
dlog("#{count}: #{klass} #{mid}")
|
124
123
|
compiled << __autocompile(klass, mid, bind_table, location_table, index)
|
@@ -168,7 +167,7 @@ module CastOff
|
|
168
167
|
manager, configuration, suggestion = compile_iseq(iseq, mid, typemap, false, bind)
|
169
168
|
manager.compilation_target_is_a(t, mid, false)
|
170
169
|
set_direct_call(target, mid, target.instance_of?(Class) ? :class : :module, manager, configuration)
|
171
|
-
load_binary(manager, configuration, suggestion, iseq
|
170
|
+
load_binary(manager, configuration, suggestion, iseq)
|
172
171
|
t = override_target(target, mid)
|
173
172
|
dlog("override target of #{target}##{mid} is #{t}")
|
174
173
|
__send__("register_method_#{manager.signiture}", t)
|
@@ -190,7 +189,7 @@ module CastOff
|
|
190
189
|
manager, configuration, suggestion = compile_iseq(iseq, mid, typemap, false, bind)
|
191
190
|
manager.compilation_target_is_a(obj, mid, true)
|
192
191
|
set_direct_call(obj, mid, :singleton, manager, configuration)
|
193
|
-
load_binary(manager, configuration, suggestion, iseq
|
192
|
+
load_binary(manager, configuration, suggestion, iseq)
|
194
193
|
__send__("register_singleton_method_#{manager.signiture}", obj)
|
195
194
|
@@original_singleton_method_iseq[[obj, mid]] = iseq
|
196
195
|
@@manager_table[manager.signiture] = manager
|
@@ -207,7 +206,7 @@ module CastOff
|
|
207
206
|
execute_no_hook() do
|
208
207
|
bind = block.binding
|
209
208
|
manager, configuration, suggestion = compile_iseq(iseq, nil, typemap, false, bind)
|
210
|
-
load_binary(manager, configuration, suggestion, iseq
|
209
|
+
load_binary(manager, configuration, suggestion, iseq)
|
211
210
|
@@loaded_binary[key] = manager.signiture
|
212
211
|
end
|
213
212
|
end
|
@@ -321,6 +320,7 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
321
320
|
target = compilation_target.target_object
|
322
321
|
mid = compilation_target.method_id
|
323
322
|
singleton = compilation_target.singleton_method?
|
323
|
+
return false unless CastOff.use_base_configuration?
|
324
324
|
vlog("re-compile(#{target}#{singleton ? '.' : '#'}#{mid}): update_p = #{update_p}, reciever_result = #{reciever_result}, return_value_result = #{return_value_result}")
|
325
325
|
return false unless update_p
|
326
326
|
ann = manager.load_annotation() || {}
|
@@ -474,7 +474,57 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
474
474
|
end
|
475
475
|
end
|
476
476
|
|
477
|
-
def
|
477
|
+
def contain_loop?(klass, mid)
|
478
|
+
case compilation_target_type(klass, mid)
|
479
|
+
when :singleton_method
|
480
|
+
singleton_p = true
|
481
|
+
when :instance_method
|
482
|
+
singleton_p = false
|
483
|
+
when nil
|
484
|
+
return false
|
485
|
+
else
|
486
|
+
bug()
|
487
|
+
end
|
488
|
+
begin
|
489
|
+
iseq = get_iseq(klass, mid, singleton_p)
|
490
|
+
rescue UnsupportedError
|
491
|
+
return false
|
492
|
+
end
|
493
|
+
bug() unless iseq.instance_of?(RubyVM::InstructionSequence)
|
494
|
+
a = iseq.to_a
|
495
|
+
filepath, line_no = *a.slice(7, 2)
|
496
|
+
body = a.last
|
497
|
+
pc = 0
|
498
|
+
body.each do |insn|
|
499
|
+
next unless insn.instance_of?(Array)
|
500
|
+
op = insn.first
|
501
|
+
case op
|
502
|
+
when :jump, :branchif, :branchunless
|
503
|
+
dst = insn[1]
|
504
|
+
m = (/label_/).match(dst)
|
505
|
+
bug() unless m
|
506
|
+
dst = m.post_match.to_i
|
507
|
+
if dst < pc
|
508
|
+
vlog("#{klass}#{singleton_p ? '.' : '#'}#{mid} contains backedge: #{filepath}(#{line_no})")
|
509
|
+
return true
|
510
|
+
end
|
511
|
+
when :send
|
512
|
+
case insn[3] # blockiseq
|
513
|
+
when NilClass
|
514
|
+
# nothing to do
|
515
|
+
when Array
|
516
|
+
vlog("#{klass}#{singleton_p ? '.' : '#'}#{mid} has block: #{filepath}(#{line_no})")
|
517
|
+
return true
|
518
|
+
else
|
519
|
+
bug()
|
520
|
+
end
|
521
|
+
end
|
522
|
+
pc += insn.size
|
523
|
+
end
|
524
|
+
false
|
525
|
+
end
|
526
|
+
|
527
|
+
def compilation_target_type(klass, mid)
|
478
528
|
return nil unless klass.instance_of?(Class) || klass.instance_of?(Module) # FIXME
|
479
529
|
return nil if klass.name =~ /CastOff/ # ここで弾いておかないと、__compile の require で __load が走る。
|
480
530
|
# Namespace のほうはあらかじめ require しておくことで回避。
|
@@ -486,14 +536,29 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
486
536
|
return nil unless klass.singleton_methods(false).include?(mid)
|
487
537
|
singleton = true
|
488
538
|
end
|
539
|
+
singleton ? :singleton_method : :instance_method
|
540
|
+
end
|
541
|
+
|
542
|
+
def __autocompile(klass, mid, bind_table, location_table, index)
|
543
|
+
case compilation_target_type(klass, mid)
|
544
|
+
when :singleton_method
|
545
|
+
singleton = true
|
546
|
+
when :instance_method
|
547
|
+
singleton = false
|
548
|
+
when nil
|
549
|
+
return nil
|
550
|
+
else
|
551
|
+
bug()
|
552
|
+
end
|
489
553
|
begin
|
554
|
+
location = location_table[[klass, mid]]
|
555
|
+
return nil unless location
|
490
556
|
bind = bind_table[[klass, mid]]
|
491
557
|
if singleton
|
492
558
|
CastOff.compile_singleton_method(klass, mid, bind)
|
493
559
|
else
|
494
560
|
CastOff.compile(klass, mid, bind)
|
495
561
|
end
|
496
|
-
location = location_table[[klass, mid]]
|
497
562
|
begin
|
498
563
|
Marshal.dump(klass)
|
499
564
|
rescue TypeError => e
|
@@ -553,11 +618,12 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
553
618
|
bug() unless val0.is_a?(Hash)
|
554
619
|
reciever_result[key0] = val0.to_a
|
555
620
|
when TrueClass, FalseClass
|
556
|
-
|
621
|
+
sym = key0 ? :singleton_methods : :instance_methods
|
622
|
+
mtbl = return_value_result[sym]
|
557
623
|
bug() unless mtbl.is_a?(Hash)
|
558
624
|
bug() unless val0.is_a?(Hash)
|
559
625
|
val0.each do |(klass, midtbl)|
|
560
|
-
bug() unless klass.is_a?(Class)
|
626
|
+
bug() unless klass.is_a?(Class) || (klass.is_a?(Module) && sym == :singleton_methods)
|
561
627
|
bug() unless midtbl.is_a?(Hash)
|
562
628
|
newval = {}
|
563
629
|
midtbl.each do |(key1, val1)|
|
@@ -605,9 +671,10 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
605
671
|
__send__("register_sampling_table_#{manager.signiture}", h)
|
606
672
|
suggestion.add_handler do
|
607
673
|
reciever_result, return_value_result = parse_sampling_table(h)
|
608
|
-
update_base_configuration(manager, reciever_result, return_value_result)
|
674
|
+
up = update_base_configuration(manager, reciever_result, return_value_result)
|
675
|
+
vlog("update base configuration = #{up}")
|
609
676
|
if reciever_result.size > 0
|
610
|
-
msg = "These are unresolved local variables
|
677
|
+
msg = "These are profiling results of unresolved local variables."
|
611
678
|
ary = []
|
612
679
|
reciever_result.each do |key0, val0|
|
613
680
|
bug() unless key0.is_a?(Symbol)
|
@@ -615,8 +682,14 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
615
682
|
val0.each do |(klass, singleton_p)|
|
616
683
|
kstr = klass.to_s
|
617
684
|
if singleton_p
|
618
|
-
|
619
|
-
|
685
|
+
case klass # 変数名が klass だとわかりにくいので、変更すること
|
686
|
+
when Class
|
687
|
+
kstr = "Class<#{kstr}>"
|
688
|
+
when Module
|
689
|
+
kstr = "Module<#{kstr}>"
|
690
|
+
else
|
691
|
+
bug()
|
692
|
+
end
|
620
693
|
end
|
621
694
|
ary << [key0.to_s, kstr]
|
622
695
|
end
|
@@ -624,20 +697,26 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
624
697
|
suggestion.add_suggestion(msg, ["<Variable>", "<SamplingResultClass>"], ary)
|
625
698
|
end
|
626
699
|
if return_value_result.size > 0
|
627
|
-
msg = "These are unresolved method return values
|
700
|
+
msg = "These are profiling results of unresolved method return values."
|
628
701
|
ary = []
|
629
702
|
return_value_result.each do |sym, mtbl|
|
630
703
|
bug() unless sym == :singleton_methods || sym == :instance_methods
|
631
704
|
bug() unless mtbl.is_a?(Hash)
|
632
705
|
mtbl.each do |key0, val0|
|
633
|
-
bug() unless key0.is_a?(Class)
|
706
|
+
bug() unless key0.is_a?(Class) || (key0.is_a?(Module) && sym == :singleton_methods)
|
634
707
|
bug() unless val0.is_a?(Hash)
|
635
708
|
val0.each do |(mid, classes)|
|
636
709
|
classes.each do |(klass, singleton_p)|
|
637
710
|
kstr = klass.to_s
|
638
711
|
if singleton_p
|
639
|
-
|
640
|
-
|
712
|
+
case klass # 変数名が klass だとわかりにくいので、変更すること
|
713
|
+
when Class
|
714
|
+
kstr = "Class<#{kstr}>"
|
715
|
+
when Module
|
716
|
+
kstr = "Module<#{kstr}>"
|
717
|
+
else
|
718
|
+
bug()
|
719
|
+
end
|
641
720
|
end
|
642
721
|
ary << ["#{key0}#{sym == :singleton_methods ? '.' : '#'}#{mid}", kstr]
|
643
722
|
end
|
@@ -653,14 +732,15 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
653
732
|
s1 = configuration.to_s
|
654
733
|
configuration.compact()
|
655
734
|
s2 = configuration.to_s
|
735
|
+
vlog("update configuration = #{update_p}")
|
656
736
|
if update_p
|
657
|
-
|
737
|
+
update_p = false if s0 == s1 # ignore configuration が更新されたときにここに来る
|
658
738
|
else
|
659
739
|
bug() if s0 != s1
|
660
740
|
end
|
661
741
|
if update_p
|
662
|
-
suggestion.add_suggestion("You
|
663
|
-
suggestion.add_suggestion("CastOff suggests you to use following type
|
742
|
+
suggestion.add_suggestion("You specified following type information to CastOff", ["Your Annotation"], [[s0]], false)
|
743
|
+
suggestion.add_suggestion("CastOff suggests you to use following type information", ["CastOff Suggestion"], [[s2]], false)
|
664
744
|
end
|
665
745
|
end
|
666
746
|
end
|
@@ -680,7 +760,7 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
680
760
|
dep.hook(function_pointer_initializer)
|
681
761
|
end
|
682
762
|
|
683
|
-
def load_binary(manager, configuration, suggestion, iseq
|
763
|
+
def load_binary(manager, configuration, suggestion, iseq)
|
684
764
|
so = manager.compiled_binary
|
685
765
|
sign = manager.signiture
|
686
766
|
bug("#{so} is not exist") unless File.exist?(so)
|
@@ -692,7 +772,10 @@ Currently, CastOff cannot compile method which source file is not exist.
|
|
692
772
|
set_sampling_table(suggestion, manager, configuration)
|
693
773
|
suggestion.dump_at_exit()
|
694
774
|
__send__(function_pointer_initializer)
|
695
|
-
|
775
|
+
if configuration.prefetch_constant?
|
776
|
+
bug() unless configuration.bind.instance_of?(Configuration::BindingWrapper)
|
777
|
+
__send__("prefetch_constants_#{sign}", configuration.bind.bind)
|
778
|
+
end
|
696
779
|
end
|
697
780
|
|
698
781
|
def capture_instruction()
|
data/lib/cast_off/util.rb
CHANGED
@@ -43,11 +43,13 @@ module CastOff::Util
|
|
43
43
|
STDERR.puts("<<< TODO #{message} :#{caller[0]} >>>")
|
44
44
|
bt_and_bye()
|
45
45
|
end
|
46
|
+
public(:todo)
|
46
47
|
|
47
48
|
def bug(message = nil)
|
48
49
|
STDERR.puts("<<< BUG #{message} :#{caller[0]} >>>")
|
49
50
|
bt_and_bye()
|
50
51
|
end
|
52
|
+
public(:bug)
|
51
53
|
|
52
54
|
=begin
|
53
55
|
def method_missing(name, *args, &block)
|
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.3.
|
4
|
+
version: 0.3.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-11-
|
12
|
+
date: 2011-11-22 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'CastOff is a performance improvement tool for Ruby1.9.3
|
15
15
|
|