cast_off 0.2.0
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 +578 -0
- data/README.en +256 -0
- data/bin/CastOff +145 -0
- data/cast_off.gemspec +25 -0
- data/ext/cast_off/cast_off.c.rb +1386 -0
- data/ext/cast_off/cast_off.h +24 -0
- data/ext/cast_off/depend +70 -0
- data/ext/cast_off/extconf.rb +19 -0
- data/ext/cast_off/generated_c_include/inline_api.h +507 -0
- data/ext/cast_off/generated_c_include/iter_api.h +595 -0
- data/ext/cast_off/generated_c_include/unbox_api.h.rb +76 -0
- data/ext/cast_off/generated_c_include/vm_api.h +751 -0
- data/ext/cast_off/ruby_source/atomic.h +56 -0
- data/ext/cast_off/ruby_source/constant.h +34 -0
- data/ext/cast_off/ruby_source/debug.h +41 -0
- data/ext/cast_off/ruby_source/eval_intern.h +234 -0
- data/ext/cast_off/ruby_source/gc.h +98 -0
- data/ext/cast_off/ruby_source/id.h +175 -0
- data/ext/cast_off/ruby_source/insns.inc +179 -0
- data/ext/cast_off/ruby_source/insns_info.inc +695 -0
- data/ext/cast_off/ruby_source/internal.h +227 -0
- data/ext/cast_off/ruby_source/iseq.h +125 -0
- data/ext/cast_off/ruby_source/manual_update.h +135 -0
- data/ext/cast_off/ruby_source/method.h +105 -0
- data/ext/cast_off/ruby_source/node.h +503 -0
- data/ext/cast_off/ruby_source/thread_pthread.h +51 -0
- data/ext/cast_off/ruby_source/thread_win32.h +40 -0
- data/ext/cast_off/ruby_source/vm_core.h +756 -0
- data/ext/cast_off/ruby_source/vm_exec.h +184 -0
- data/ext/cast_off/ruby_source/vm_insnhelper.c +1748 -0
- data/ext/cast_off/ruby_source/vm_insnhelper.h +220 -0
- data/ext/cast_off/ruby_source/vm_opts.h +51 -0
- data/lib/cast_off.rb +15 -0
- data/lib/cast_off/compile.rb +629 -0
- data/lib/cast_off/compile/basicblock.rb +144 -0
- data/lib/cast_off/compile/cfg.rb +391 -0
- data/lib/cast_off/compile/code_manager.rb +284 -0
- data/lib/cast_off/compile/configuration.rb +2368 -0
- data/lib/cast_off/compile/dependency.rb +240 -0
- data/lib/cast_off/compile/information.rb +775 -0
- data/lib/cast_off/compile/instruction.rb +446 -0
- data/lib/cast_off/compile/ir/call_ir.rb +2348 -0
- data/lib/cast_off/compile/ir/guard_ir.rb +423 -0
- data/lib/cast_off/compile/ir/jump_ir.rb +223 -0
- data/lib/cast_off/compile/ir/operand.rb +934 -0
- data/lib/cast_off/compile/ir/param_ir.rb +98 -0
- data/lib/cast_off/compile/ir/return_ir.rb +92 -0
- data/lib/cast_off/compile/ir/simple_ir.rb +808 -0
- data/lib/cast_off/compile/ir/sub_ir.rb +212 -0
- data/lib/cast_off/compile/iseq.rb +454 -0
- data/lib/cast_off/compile/method_information.rb +1384 -0
- data/lib/cast_off/compile/namespace/namespace.rb +556 -0
- data/lib/cast_off/compile/namespace/uuid.rb +323 -0
- data/lib/cast_off/compile/stack.rb +65 -0
- data/lib/cast_off/compile/translator.rb +1562 -0
- data/lib/cast_off/suggestion.rb +98 -0
- data/lib/cast_off/util.rb +58 -0
- metadata +107 -0
@@ -0,0 +1,240 @@
|
|
1
|
+
module CastOff
|
2
|
+
module Compiler
|
3
|
+
class Dependency
|
4
|
+
extend CastOff::Util
|
5
|
+
include CastOff::Util
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@dependency = {}
|
9
|
+
@strong_dependency = []
|
10
|
+
end
|
11
|
+
|
12
|
+
@@instance_method_dependency = {}
|
13
|
+
@@instance_method_dependency_initializers = {}
|
14
|
+
@@singleton_method_dependency = {}
|
15
|
+
@@singleton_method_dependency_initializers = {}
|
16
|
+
@@instance_method_strong_dependency = {}
|
17
|
+
@@singleton_method_strong_dependency = {}
|
18
|
+
|
19
|
+
def self.get_class_or_module(km)
|
20
|
+
case km
|
21
|
+
when ClassWrapper
|
22
|
+
bug() if km.singleton?
|
23
|
+
return km.contain_class
|
24
|
+
when ModuleWrapper
|
25
|
+
return km.contain_module
|
26
|
+
end
|
27
|
+
bug()
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.instance_method_depend(klass, mid, function_pointer_initializer)
|
31
|
+
c = get_class_or_module(klass)
|
32
|
+
a = (@@instance_method_dependency[c] ||= [])
|
33
|
+
a << mid unless a.include?(mid)
|
34
|
+
b = (@@instance_method_dependency_initializers[[c, mid]] ||= [])
|
35
|
+
b << function_pointer_initializer unless b.include?(function_pointer_initializer)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.instance_method_strongly_depend(klass, mid)
|
39
|
+
c = get_class_or_module(klass)
|
40
|
+
@@instance_method_strong_dependency[c] ||= []
|
41
|
+
a = @@instance_method_strong_dependency[c]
|
42
|
+
a << mid unless a.include?(mid)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.instance_method_depend?(klass, mid)
|
46
|
+
bug() unless klass.instance_of?(Class) || klass.instance_of?(Module)
|
47
|
+
dep = @@instance_method_dependency[klass]
|
48
|
+
return false unless dep
|
49
|
+
return false unless dep.include?(mid)
|
50
|
+
bug() unless @@instance_method_dependency_initializers[[klass, mid]]
|
51
|
+
@@instance_method_dependency_initializers[[klass, mid]]
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.instance_method_strongly_depend?(obj, mid)
|
55
|
+
bug() unless obj.instance_of?(Class) || obj.instance_of?(Module)
|
56
|
+
dep = @@instance_method_strong_dependency[obj]
|
57
|
+
dep.instance_of?(Array) ? dep.include?(mid) : false
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.singleton_method_depend(klass, mid, function_pointer_initializer)
|
61
|
+
bug() unless klass.instance_of?(ClassWrapper)
|
62
|
+
bug() unless klass.singleton?
|
63
|
+
o = klass.contain_object
|
64
|
+
a = (@@singleton_method_dependency[o] ||= [])
|
65
|
+
a << mid unless a.include?(mid)
|
66
|
+
b = (@@singleton_method_dependency_initializers[[o, mid]] ||= [])
|
67
|
+
b << function_pointer_initializer unless b.include?(function_pointer_initializer)
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.singleton_method_strongly_depend(klass, mid)
|
71
|
+
bug() unless klass.instance_of?(ClassWrapper)
|
72
|
+
bug() unless klass.singleton?
|
73
|
+
o = klass.contain_object
|
74
|
+
@@singleton_method_strong_dependency[o] ||= []
|
75
|
+
a = @@singleton_method_strong_dependency[o]
|
76
|
+
a << mid unless a.include?(mid)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.singleton_method_depend?(obj, mid)
|
80
|
+
bug() unless obj.instance_of?(Class) || obj.instance_of?(Module)
|
81
|
+
dep = @@singleton_method_dependency[obj]
|
82
|
+
return false unless dep
|
83
|
+
return false unless dep.include?(mid)
|
84
|
+
bug() unless @@singleton_method_dependency_initializers[[obj, mid]]
|
85
|
+
@@singleton_method_dependency_initializers[[obj, mid]]
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.singleton_method_strongly_depend?(obj, mid)
|
89
|
+
bug() unless obj.instance_of?(Class) || obj.instance_of?(Module)
|
90
|
+
dep = @@singleton_method_strong_dependency[obj]
|
91
|
+
dep.instance_of?(Array) ? dep.include?(mid) : false
|
92
|
+
end
|
93
|
+
|
94
|
+
def dump(io)
|
95
|
+
begin
|
96
|
+
Marshal.dump(self, io)
|
97
|
+
rescue TypeError => e
|
98
|
+
raise(UnsupportedError.new(<<-EOS))
|
99
|
+
|
100
|
+
Failed to marshal dump method dependency.
|
101
|
+
Dependency object should be able to marshal dump.
|
102
|
+
Currently, CastOff doesn't support object, which cannot marshal dump (e.g. STDIN).
|
103
|
+
--- Marshal.dump error message ---
|
104
|
+
#{e.message}
|
105
|
+
EOS
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.load(str)
|
110
|
+
dep = Marshal.load(str)
|
111
|
+
bug() unless dep.instance_of?(Dependency)
|
112
|
+
dep
|
113
|
+
end
|
114
|
+
|
115
|
+
def marshal_dump()
|
116
|
+
[@dependency, @strong_dependency]
|
117
|
+
end
|
118
|
+
|
119
|
+
def marshal_load(obj)
|
120
|
+
@dependency, @strong_dependency = obj
|
121
|
+
end
|
122
|
+
|
123
|
+
def add(klass, mid, strong_p)
|
124
|
+
# TODO klass から、対象メソッドを定義しているクラスまでのメソッドの検索対象を全てフック
|
125
|
+
bug() unless klass.instance_of?(ClassWrapper)
|
126
|
+
targets = [klass]
|
127
|
+
if not klass.singleton?
|
128
|
+
c = klass.contain_class
|
129
|
+
cm = CastOff.override_target(c, mid)
|
130
|
+
case cm
|
131
|
+
when Class
|
132
|
+
targets << ClassWrapper.new(cm, true) if cm != c
|
133
|
+
when Module
|
134
|
+
targets << ModuleWrapper.new(cm)
|
135
|
+
else
|
136
|
+
bug()
|
137
|
+
end
|
138
|
+
end
|
139
|
+
targets.each do |t|
|
140
|
+
@dependency[t] ||= []
|
141
|
+
@dependency[t] |= [mid]
|
142
|
+
@strong_dependency |= [[t, mid]] if strong_p
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def check_failed(msg = '')
|
147
|
+
raise(LoadError.new("failed to check method dependency: #{msg}"))
|
148
|
+
end
|
149
|
+
|
150
|
+
def check(configuration)
|
151
|
+
@dependency.each do |(klass, mids)|
|
152
|
+
bug() unless klass.instance_of?(ClassWrapper) || klass.instance_of?(ModuleWrapper)
|
153
|
+
# TODO ブロックインライニングしたメソッドに対して
|
154
|
+
# コンパイル時のメソッドと等しいものかどうかをチェック
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.hook(o)
|
159
|
+
s = class << o
|
160
|
+
self
|
161
|
+
end
|
162
|
+
s.class_eval do
|
163
|
+
def override_singleton_method(obj, mid, flag)
|
164
|
+
if initializers = Dependency.singleton_method_depend?(obj, mid)
|
165
|
+
if Dependency.singleton_method_strongly_depend?(obj, mid)
|
166
|
+
raise(ExecutionError.new("Should not be override #{obj}.#{mid}"))
|
167
|
+
end
|
168
|
+
# TODO Array.each の上書きチェック
|
169
|
+
initializers.each do |init|
|
170
|
+
CastOff.dlog("update function pointer #{obj}.#{mid}")
|
171
|
+
CastOff.__send__(init)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def override_method(obj, mid, flag)
|
177
|
+
if initializers = Dependency.instance_method_depend?(obj, mid)
|
178
|
+
if Dependency.instance_method_strongly_depend?(obj, mid)
|
179
|
+
raise(ExecutionError.new("Should not be override #{obj}##{mid}"))
|
180
|
+
end
|
181
|
+
# TODO Array.each の上書きチェック
|
182
|
+
initializers.each do |init|
|
183
|
+
CastOff.dlog("update function pointer #{obj}##{mid}")
|
184
|
+
CastOff.__send__(init)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
define_method(:method_added) do |mid|
|
190
|
+
if self == o && !Dependency.ignore_overridden?(self, mid)
|
191
|
+
if Dependency.singleton_method_added?
|
192
|
+
CastOff.dlog("singleton method added #{o}.#{mid}")
|
193
|
+
CastOff.delete_original_singleton_method_iseq(self, mid)
|
194
|
+
override_singleton_method(o, mid, :added)
|
195
|
+
else
|
196
|
+
CastOff.dlog("method added #{o}##{mid}")
|
197
|
+
CastOff.delete_original_instance_method_iseq(self, mid)
|
198
|
+
override_method(o, mid, :added)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
super(mid) rescue NoMethodError
|
202
|
+
end
|
203
|
+
alias singleton_method_added method_added
|
204
|
+
CastOff.dlog("hook #{o}")
|
205
|
+
end
|
206
|
+
@@singleton_method_dependency[o] ||= []
|
207
|
+
@@singleton_method_dependency[o] |= [:method_added, :singleton_method_added]
|
208
|
+
@@singleton_method_strong_dependency[o] ||= []
|
209
|
+
@@singleton_method_strong_dependency[o] |= [:method_added]
|
210
|
+
@@singleton_method_strong_dependency[o] |= [:singleton_method_added]
|
211
|
+
end
|
212
|
+
|
213
|
+
def hook(function_pointer_initializer)
|
214
|
+
@dependency.keys.each do |klass|
|
215
|
+
m = @dependency[klass]
|
216
|
+
if klass.instance_of?(ClassWrapper) && klass.singleton?
|
217
|
+
m.each{|mid| self.class.singleton_method_depend(klass, mid, function_pointer_initializer)}
|
218
|
+
m.each{|mid| self.class.singleton_method_strongly_depend(klass, mid) if @strong_dependency.include?([klass, mid])}
|
219
|
+
o = klass.contain_object
|
220
|
+
bug() unless o.instance_of?(Class) || o.instance_of?(Module)
|
221
|
+
else
|
222
|
+
m.each{|mid| self.class.instance_method_depend(klass, mid, function_pointer_initializer)}
|
223
|
+
m.each{|mid| self.class.instance_method_strongly_depend(klass, mid) if @strong_dependency.include?([klass, mid])}
|
224
|
+
case klass
|
225
|
+
when ClassWrapper
|
226
|
+
o = klass.contain_class
|
227
|
+
when ModuleWrapper
|
228
|
+
o = klass.contain_module
|
229
|
+
else
|
230
|
+
bug()
|
231
|
+
end
|
232
|
+
end
|
233
|
+
next if o.singleton_methods(false).include?(:override_singleton_method)
|
234
|
+
Dependency.hook(o)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
@@ -0,0 +1,775 @@
|
|
1
|
+
# coding=utf-8
|
2
|
+
|
3
|
+
module CastOff::Compiler
|
4
|
+
class Translator::CFG
|
5
|
+
class Information
|
6
|
+
include CastOff::Util
|
7
|
+
include SimpleIR
|
8
|
+
|
9
|
+
attr_reader :variable_definition, :undefs, :block, :alias
|
10
|
+
attr_reader :variable_condition
|
11
|
+
|
12
|
+
def initialize(block, vars, a, defs, undefs, ptr_defs, ptrs)
|
13
|
+
@block = block
|
14
|
+
@alias = a.instance_of?(Alias) ? a : Alias.new(@block, a, vars, ptrs)
|
15
|
+
@variable_definition = defs
|
16
|
+
@ptr_defs = ptr_defs
|
17
|
+
@undefs = undefs
|
18
|
+
@ptrs = ptrs
|
19
|
+
@vars = vars
|
20
|
+
@variable_condition = VariableCondition.new(@block, @ptrs, @alias)
|
21
|
+
check_initialize()
|
22
|
+
end
|
23
|
+
|
24
|
+
def freeze()
|
25
|
+
super()
|
26
|
+
check_initialize()
|
27
|
+
@alias.freeze()
|
28
|
+
@variable_definition.freeze()
|
29
|
+
@ptr_defs.freeze()
|
30
|
+
@undefs.freeze()
|
31
|
+
@ptrs.freeze()
|
32
|
+
@vars.freeze()
|
33
|
+
@variable_condition.freeze()
|
34
|
+
end
|
35
|
+
|
36
|
+
def final_state()
|
37
|
+
# variable_condition までは final_state にならないので注意
|
38
|
+
check_initialize()
|
39
|
+
final_alias = @alias.final_state()
|
40
|
+
final_defs = (@variable_definition - @block.ekill) | @block.egen
|
41
|
+
final_undefs = @undefs + @block.ekill.map{|ir| ir.result_variable} - @block.egen.map{|ir| ir.result_variable}
|
42
|
+
Information.new(@block, @vars, final_alias, final_defs, final_undefs, @ptr_defs, @ptrs)
|
43
|
+
end
|
44
|
+
|
45
|
+
def find_same_variables(var)
|
46
|
+
check_initialize()
|
47
|
+
@alias.find_set(var)
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate()
|
51
|
+
check_initialize()
|
52
|
+
@alias.validate()
|
53
|
+
bug() unless @alias.final_state() == @block.information.alias.final_state()
|
54
|
+
defs = @variable_definition.map{|d| d.result_variable}.compact()
|
55
|
+
bug() unless (defs & @undefs).empty?
|
56
|
+
bug() unless (@vars - (defs | @undefs)).empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate_final()
|
60
|
+
check_initialize()
|
61
|
+
@alias.validate()
|
62
|
+
bug() unless @alias == @block.information.alias.final_state()
|
63
|
+
defs = @variable_definition.map{|d| d.result_variable}.compact()
|
64
|
+
bug() unless (defs & @undefs).empty?
|
65
|
+
bug() unless (@vars - (defs | @undefs)).empty?
|
66
|
+
end
|
67
|
+
|
68
|
+
def step(ir)
|
69
|
+
check_initialize()
|
70
|
+
@alias.step(ir)
|
71
|
+
@variable_condition.step(ir)
|
72
|
+
delete(ir)
|
73
|
+
add(ir)
|
74
|
+
end
|
75
|
+
|
76
|
+
def |(other)
|
77
|
+
check_initialize()
|
78
|
+
bug() unless other.instance_of?(Information)
|
79
|
+
Information.new(@block, @vars, @alias.union(other.alias), @variable_definition | other.variable_definition, @undefs | other.undefs, @ptr_defs, @ptrs)
|
80
|
+
end
|
81
|
+
|
82
|
+
def kill_definition(other)
|
83
|
+
@variable_definition.delete_if do |d0|
|
84
|
+
next unless d0.result_variable
|
85
|
+
not other.variable_definition.find{|d1| d0.result_variable == d1.result_variable}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def eql?(other)
|
90
|
+
check_initialize()
|
91
|
+
bug() unless other.instance_of?(Information)
|
92
|
+
bug() unless @block == other.block
|
93
|
+
return false unless (@variable_definition - other.variable_definition).empty? && (other.variable_definition - @variable_definition).empty?
|
94
|
+
return false unless (@undefs - other.undefs).empty? && (other.undefs - @undefs).empty?
|
95
|
+
@alias == other.alias
|
96
|
+
end
|
97
|
+
|
98
|
+
def ==(other)
|
99
|
+
check_initialize()
|
100
|
+
eql?(other)
|
101
|
+
end
|
102
|
+
|
103
|
+
def size()
|
104
|
+
check_initialize()
|
105
|
+
@variable_definition.size()
|
106
|
+
end
|
107
|
+
|
108
|
+
def replace_entry(ir)
|
109
|
+
check_initialize()
|
110
|
+
i = @variable_definition.index(ir)
|
111
|
+
@variable_definition[i] = ir if i
|
112
|
+
end
|
113
|
+
|
114
|
+
def reject!(&b)
|
115
|
+
check_initialize()
|
116
|
+
@variable_definition.reject!{|ir| yield ir}
|
117
|
+
end
|
118
|
+
|
119
|
+
def flatten!
|
120
|
+
check_initialize()
|
121
|
+
@variable_definition.flatten!
|
122
|
+
end
|
123
|
+
|
124
|
+
def hash()
|
125
|
+
bug()
|
126
|
+
end
|
127
|
+
|
128
|
+
def dup()
|
129
|
+
check_initialize()
|
130
|
+
Information.new(@block, @vars, @alias.dup(), @variable_definition.dup(), @undefs.dup(), @ptr_defs, @ptrs)
|
131
|
+
end
|
132
|
+
|
133
|
+
def to_s()
|
134
|
+
@variable_definition.join("\n")
|
135
|
+
end
|
136
|
+
|
137
|
+
def variable_definition_of(var)
|
138
|
+
check_initialize()
|
139
|
+
@variable_definition.select{|d| d.result_variable == var}
|
140
|
+
end
|
141
|
+
|
142
|
+
def undefined_variables()
|
143
|
+
check_initialize()
|
144
|
+
@undefs
|
145
|
+
end
|
146
|
+
|
147
|
+
def mark(var)
|
148
|
+
check_initialize()
|
149
|
+
ds = @variable_definition.select {|d| var == d.result_variable }
|
150
|
+
ds.inject(false){|change, d| d.alive() || change}
|
151
|
+
end
|
152
|
+
|
153
|
+
def type_resolve(var)
|
154
|
+
check_initialize()
|
155
|
+
#return false if var.dynamic? || var.static?
|
156
|
+
return false unless var.is_a?(Variable)
|
157
|
+
ret = false
|
158
|
+
|
159
|
+
bug() unless @variable_condition
|
160
|
+
ret |= @variable_condition.use(var)
|
161
|
+
ds = @variable_definition.select {|d| var == d.result_variable }
|
162
|
+
if @undefs.include?(var) || ds.empty?
|
163
|
+
case var
|
164
|
+
when TmpBuffer
|
165
|
+
ret |= var.is_dynamic()
|
166
|
+
when Pointer, Argument
|
167
|
+
ret |= var.is_dynamic()
|
168
|
+
else
|
169
|
+
bug(var)
|
170
|
+
end
|
171
|
+
else
|
172
|
+
ds.each { |d| ret = true if var.union(d.result_variable) }
|
173
|
+
end
|
174
|
+
ret
|
175
|
+
end
|
176
|
+
|
177
|
+
def exact_class_resolve(var)
|
178
|
+
check_initialize()
|
179
|
+
return false if !var.is_a?(Variable) || var.class_exact?
|
180
|
+
|
181
|
+
ds = @variable_definition.select{|d| var == d.result_variable }
|
182
|
+
if @undefs.include?(var) || ds.empty?
|
183
|
+
case var
|
184
|
+
when TmpBuffer, Pointer, Argument
|
185
|
+
return false
|
186
|
+
else
|
187
|
+
bug(var)
|
188
|
+
end
|
189
|
+
else
|
190
|
+
ds.each do |d|
|
191
|
+
r = d.result_variable
|
192
|
+
return false unless r.class_exact?
|
193
|
+
end
|
194
|
+
var.is_class_exact()
|
195
|
+
return true
|
196
|
+
end
|
197
|
+
bug()
|
198
|
+
end
|
199
|
+
|
200
|
+
### unboxing begin ###
|
201
|
+
def can_not_unbox_variable_resolve_forward(var)
|
202
|
+
check_initialize()
|
203
|
+
return false if var.can_not_unbox?
|
204
|
+
ds = @variable_definition.select {|d| var == d.result_variable }
|
205
|
+
if ds.empty?
|
206
|
+
case var
|
207
|
+
when TmpBuffer, Pointer, Argument, Self, ConstWrapper, Literal
|
208
|
+
return false
|
209
|
+
else
|
210
|
+
bug(var)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
ds.each do |d|
|
214
|
+
if d.result_variable.can_not_unbox?
|
215
|
+
var.can_not_unbox()
|
216
|
+
return true
|
217
|
+
end
|
218
|
+
end
|
219
|
+
return false
|
220
|
+
end
|
221
|
+
|
222
|
+
def can_not_unbox_variable_resolve_backward(var)
|
223
|
+
check_initialize()
|
224
|
+
bug() unless var.can_not_unbox?
|
225
|
+
ds = @variable_definition.select {|d| var == d.result_variable }
|
226
|
+
if ds.empty?
|
227
|
+
case var
|
228
|
+
when TmpBuffer, Pointer, Argument, Self, ConstWrapper, Literal
|
229
|
+
return false
|
230
|
+
else
|
231
|
+
bug(var)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
ds.inject(false){|change, d| d.result_variable.can_not_unbox() || change}
|
235
|
+
end
|
236
|
+
|
237
|
+
def box_value_resolve_forward(var)
|
238
|
+
check_initialize()
|
239
|
+
bug() if !var.unboxed? && !var.boxed?
|
240
|
+
return false if var.boxed?
|
241
|
+
ds = @variable_definition.select {|d| var == d.result_variable }
|
242
|
+
if ds.empty?
|
243
|
+
case var
|
244
|
+
when TmpBuffer, Pointer, Argument, Self, ConstWrapper, Literal
|
245
|
+
#bug(var)
|
246
|
+
return false
|
247
|
+
else
|
248
|
+
bug(var)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
ds.each do |d|
|
252
|
+
if d.result_variable.boxed?
|
253
|
+
var.box()
|
254
|
+
return true
|
255
|
+
end
|
256
|
+
end
|
257
|
+
return false
|
258
|
+
end
|
259
|
+
|
260
|
+
def box_value_resolve_backward(var)
|
261
|
+
check_initialize()
|
262
|
+
bug() unless var.boxed?
|
263
|
+
ds = @variable_definition.select {|d| var == d.result_variable }
|
264
|
+
if ds.empty?
|
265
|
+
case var
|
266
|
+
when TmpBuffer, Pointer, Argument, Self, ConstWrapper, Literal
|
267
|
+
return false
|
268
|
+
else
|
269
|
+
bug(var)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
ds.inject(false){|change, d| d.result_variable.box() || change}
|
273
|
+
end
|
274
|
+
|
275
|
+
def unbox_value_resolve(var)
|
276
|
+
check_initialize()
|
277
|
+
bug() if var.can_not_unbox?
|
278
|
+
return false if var.unboxed?
|
279
|
+
ds = @variable_definition.select {|d| var == d.result_variable }
|
280
|
+
if ds.empty?
|
281
|
+
case var
|
282
|
+
when TmpBuffer, Pointer, Argument, Self, ConstWrapper, Literal
|
283
|
+
return false
|
284
|
+
else
|
285
|
+
bug(var)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
c = nil
|
289
|
+
ds.each do |d|
|
290
|
+
v = d.result_variable
|
291
|
+
return false unless v.unboxed?
|
292
|
+
bug() if v.dynamic?
|
293
|
+
bug() unless v.types.size == 1
|
294
|
+
if c
|
295
|
+
bug() unless c == v.types[0]
|
296
|
+
else
|
297
|
+
c = v.types[0]
|
298
|
+
end
|
299
|
+
end
|
300
|
+
var.unbox()
|
301
|
+
true
|
302
|
+
end
|
303
|
+
### unboxing end ###
|
304
|
+
|
305
|
+
private
|
306
|
+
|
307
|
+
def check_initialize()
|
308
|
+
bug() unless @block.instance_of?(BasicBlock)
|
309
|
+
bug() unless @variable_definition.instance_of?(Array)
|
310
|
+
bug() unless @ptr_defs.instance_of?(Array)
|
311
|
+
bug() unless @undefs.instance_of?(Array)
|
312
|
+
bug() unless @ptrs.instance_of?(Array)
|
313
|
+
bug() unless @vars.instance_of?(Array)
|
314
|
+
bug() unless @alias.instance_of?(Alias)
|
315
|
+
bug() unless @variable_condition.instance_of?(VariableCondition)
|
316
|
+
end
|
317
|
+
|
318
|
+
def delete(ir)
|
319
|
+
check_initialize()
|
320
|
+
@variable_definition.reject!{|d| d.result_variable == ir.result_variable}
|
321
|
+
if ir.dispatch_method?
|
322
|
+
@variable_definition -= @ptr_defs
|
323
|
+
@undefs |= @ptrs
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
def add(ir)
|
328
|
+
check_initialize()
|
329
|
+
@variable_definition << ir
|
330
|
+
result_variable = ir.result_variable
|
331
|
+
@undefs -= [result_variable] if result_variable
|
332
|
+
end
|
333
|
+
|
334
|
+
class Alias
|
335
|
+
include CastOff::Compiler::SimpleIR
|
336
|
+
include CastOff::Util
|
337
|
+
attr_reader :set
|
338
|
+
|
339
|
+
def initialize(b, a, all, ptrs)
|
340
|
+
bug() unless b.instance_of?(BasicBlock)
|
341
|
+
@block = b
|
342
|
+
@all = all
|
343
|
+
@ptrs = ptrs
|
344
|
+
case a
|
345
|
+
when NilClass
|
346
|
+
a = all.dup()
|
347
|
+
bug() if a.find{|v| not v.is_a?(Variable)}
|
348
|
+
@set = [a]
|
349
|
+
when Array
|
350
|
+
bug() if a.find{|v| not v.is_a?(Variable)}
|
351
|
+
@set = a.map{|v| [v]}
|
352
|
+
when Alias
|
353
|
+
@set = a.set.map{|s| s.dup()}
|
354
|
+
else
|
355
|
+
bug()
|
356
|
+
end
|
357
|
+
validate()
|
358
|
+
end
|
359
|
+
|
360
|
+
def freeze()
|
361
|
+
super()
|
362
|
+
@all.freeze()
|
363
|
+
@set.freeze()
|
364
|
+
@ptrs.freeze()
|
365
|
+
end
|
366
|
+
|
367
|
+
def final_state()
|
368
|
+
a = dup()
|
369
|
+
@block.irs.each{|ir| a.step(ir)}
|
370
|
+
a
|
371
|
+
end
|
372
|
+
|
373
|
+
def step(ir)
|
374
|
+
case ir
|
375
|
+
when SubIR
|
376
|
+
src = ir.src
|
377
|
+
dst = ir.dst
|
378
|
+
src.is_a?(Variable) ? sub(src, dst) : isolate(dst)
|
379
|
+
when CallIR
|
380
|
+
return_value = ir.return_value
|
381
|
+
bug() unless return_value.is_a?(Variable)
|
382
|
+
isolate(return_value)
|
383
|
+
@ptrs.each{|p| isolate(p)} if ir.dispatch_method?
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
def dup()
|
388
|
+
Alias.new(@block, self, @all, @ptrs)
|
389
|
+
end
|
390
|
+
|
391
|
+
def find_set(var)
|
392
|
+
bug() unless var.is_a?(Variable)
|
393
|
+
set.each{|s| return s if s.include?(var)}
|
394
|
+
bug("set = #{set}, var = #{var}, #{var.class}")
|
395
|
+
end
|
396
|
+
|
397
|
+
def validate()
|
398
|
+
a = @set.inject([]) do |ary, s|
|
399
|
+
bug() unless (ary & s).empty?
|
400
|
+
ary + s
|
401
|
+
end
|
402
|
+
size = @all.size()
|
403
|
+
bug() unless a.size() == size && (a & @all).size() == size
|
404
|
+
end
|
405
|
+
|
406
|
+
def eql?(other)
|
407
|
+
other_set = other.set.dup()
|
408
|
+
@set.each{|s| other_set.delete(s){return false}}
|
409
|
+
bug() unless other_set.empty?
|
410
|
+
return true
|
411
|
+
end
|
412
|
+
|
413
|
+
def ==(other)
|
414
|
+
eql?(other)
|
415
|
+
end
|
416
|
+
|
417
|
+
def union(other)
|
418
|
+
a = @all.dup()
|
419
|
+
new_set = []
|
420
|
+
until a.empty?
|
421
|
+
var = a.pop()
|
422
|
+
s0 = find_set(var)
|
423
|
+
s1 = other.find_set(var)
|
424
|
+
s = s0 & s1
|
425
|
+
new_set << s
|
426
|
+
a -= s
|
427
|
+
end
|
428
|
+
@set = new_set
|
429
|
+
validate()
|
430
|
+
dup()
|
431
|
+
end
|
432
|
+
|
433
|
+
private
|
434
|
+
|
435
|
+
def sub(arg0, result)
|
436
|
+
return if arg0 == result
|
437
|
+
reject(result)
|
438
|
+
s = find_set(arg0)
|
439
|
+
bug() if s.include?(result)
|
440
|
+
s << result
|
441
|
+
end
|
442
|
+
|
443
|
+
def isolate(var)
|
444
|
+
reject(var)
|
445
|
+
@set << [var]
|
446
|
+
end
|
447
|
+
|
448
|
+
def reject(var)
|
449
|
+
s = find_set(var)
|
450
|
+
s.delete(var){bug()}
|
451
|
+
@set.delete(s){bug()} if s.empty?
|
452
|
+
end
|
453
|
+
end # Alias
|
454
|
+
|
455
|
+
class VariableCondition
|
456
|
+
include CastOff::Util
|
457
|
+
include SimpleIR
|
458
|
+
|
459
|
+
attr_reader :block, :condition
|
460
|
+
|
461
|
+
def initialize(b, ptrs, a)
|
462
|
+
@block = b
|
463
|
+
@ptrs = ptrs
|
464
|
+
@condition = initialize_condition_from_block(a)
|
465
|
+
end
|
466
|
+
|
467
|
+
def use(v)
|
468
|
+
p = @condition[v]
|
469
|
+
p ? p.call(v) : false
|
470
|
+
end
|
471
|
+
|
472
|
+
def step(ir)
|
473
|
+
unless ir.result_variable
|
474
|
+
bug() if ir.dispatch_method?
|
475
|
+
return
|
476
|
+
end
|
477
|
+
@condition.delete(ir.result_variable)
|
478
|
+
@ptrs.each{|p| @condition.delete(p)} if ir.dispatch_method?
|
479
|
+
end
|
480
|
+
|
481
|
+
def eql?(other)
|
482
|
+
#@condition == other.condition && @block == other.block
|
483
|
+
bug()
|
484
|
+
end
|
485
|
+
|
486
|
+
def ==(other)
|
487
|
+
eql?(other)
|
488
|
+
end
|
489
|
+
|
490
|
+
def hash
|
491
|
+
bug()
|
492
|
+
end
|
493
|
+
|
494
|
+
def freeze()
|
495
|
+
super()
|
496
|
+
@ptrs.freeze()
|
497
|
+
@condition.freeze()
|
498
|
+
end
|
499
|
+
|
500
|
+
private
|
501
|
+
|
502
|
+
NilWrapper = ClassWrapper.new(NilClass, true)
|
503
|
+
FalseWrapper = ClassWrapper.new(FalseClass, true)
|
504
|
+
def initialize_condition_from_block(a)
|
505
|
+
cond = {}
|
506
|
+
bug() unless a.instance_of?(Alias)
|
507
|
+
return cond unless @block.pre.size == 1
|
508
|
+
b = @block.pre[0]
|
509
|
+
ir = b.irs.last
|
510
|
+
return cond unless ir.is_a?(JumpIR)
|
511
|
+
fallthrough = (ir.jump_targets & @block.labels).empty?
|
512
|
+
p = nil
|
513
|
+
case ir.jump_type
|
514
|
+
when :branchif
|
515
|
+
if fallthrough
|
516
|
+
p = proc{|v| v.is_negative_cond_value; v.is_static([NilWrapper, FalseWrapper])}
|
517
|
+
else
|
518
|
+
p = proc{|v| v.is_not([NilWrapper, FalseWrapper])}
|
519
|
+
end
|
520
|
+
when :branchunless
|
521
|
+
if fallthrough
|
522
|
+
p = proc{|v| v.is_not([NilWrapper, FalseWrapper])}
|
523
|
+
else
|
524
|
+
p = proc{|v| v.is_negative_cond_value; v.is_static([NilWrapper, FalseWrapper])}
|
525
|
+
end
|
526
|
+
end
|
527
|
+
if p
|
528
|
+
set = a.find_set(ir.cond_value)
|
529
|
+
bug() if set.empty?
|
530
|
+
set.each{|s| cond[s] = p}
|
531
|
+
end
|
532
|
+
cond
|
533
|
+
end
|
534
|
+
end #VariableCondition
|
535
|
+
end # Information
|
536
|
+
|
537
|
+
def calc_egen_ekill
|
538
|
+
all = all_ir()
|
539
|
+
@blocks.each { |b| b.calc_egen() }
|
540
|
+
@blocks.each { |b| b.calc_ekill(all) }
|
541
|
+
end
|
542
|
+
|
543
|
+
class BasicBlock
|
544
|
+
attr_reader :egen, :ekill
|
545
|
+
attr_accessor :information, :out_undefined, :in_undefined
|
546
|
+
attr_accessor :in_guards
|
547
|
+
|
548
|
+
def calc_egen()
|
549
|
+
egen = []
|
550
|
+
kill = []
|
551
|
+
@irs.reverse.each do |ir|
|
552
|
+
next unless ir.result_variable
|
553
|
+
gen = [ir]
|
554
|
+
egen |= (gen - kill)
|
555
|
+
kill |= @irs.select{|i| i.result_variable == ir.result_variable && i != ir }
|
556
|
+
kill |= @irs.select{|i| i.result_variable.is_a?(Pointer) && i != ir } if ir.dispatch_method?
|
557
|
+
end
|
558
|
+
@egen = egen
|
559
|
+
@egen.freeze()
|
560
|
+
end
|
561
|
+
|
562
|
+
def calc_ekill(all)
|
563
|
+
kill = []
|
564
|
+
@irs.each do |ir|
|
565
|
+
next unless ir.result_variable
|
566
|
+
kill |= all.select{|i| i.result_variable == ir.result_variable && i != ir }
|
567
|
+
kill |= all.select{|i| i.result_variable.is_a?(Pointer) && i != ir } if ir.dispatch_method?
|
568
|
+
end
|
569
|
+
@ekill = kill
|
570
|
+
@ekill.freeze()
|
571
|
+
end
|
572
|
+
end # BasicBlock
|
573
|
+
|
574
|
+
def calc_undefined_variables()
|
575
|
+
vars = all_variable()
|
576
|
+
change = true
|
577
|
+
entry = @blocks[0]
|
578
|
+
bug() if @blocks.find{|b| b != entry && b.pre.empty? }
|
579
|
+
bug() unless entry.pre.empty?
|
580
|
+
entry.in_undefined = vars
|
581
|
+
@blocks.each{|b| b.out_undefined = []}
|
582
|
+
entry.out_undefined = entry.in_undefined - entry.egen.map{|ir| ir.result_variable}
|
583
|
+
while change
|
584
|
+
change = false
|
585
|
+
@blocks.each do |b0|
|
586
|
+
if b0 != entry
|
587
|
+
b0.in_undefined = b0.pre.inject([]){|in_undefined, b1| in_undefined | b1.out_undefined }
|
588
|
+
out_undefined = b0.in_undefined + b0.ekill.map{|ir| ir.result_variable} - b0.egen.map{|ir| ir.result_variable}
|
589
|
+
if !(out_undefined - b0.out_undefined).empty?
|
590
|
+
b0.out_undefined |= out_undefined
|
591
|
+
change = true
|
592
|
+
end
|
593
|
+
end
|
594
|
+
end
|
595
|
+
end
|
596
|
+
@blocks.each do |b|
|
597
|
+
b.in_undefined.freeze()
|
598
|
+
b.out_undefined.freeze()
|
599
|
+
end
|
600
|
+
# validation
|
601
|
+
@blocks.each do |b|
|
602
|
+
undefined = b.in_undefined.dup()
|
603
|
+
b.irs.each do |ir|
|
604
|
+
ir.variables_without_result.each do |var|
|
605
|
+
var.has_undefined_path() if undefined.include?(var)
|
606
|
+
end
|
607
|
+
result_variable = ir.result_variable
|
608
|
+
undefined -= [result_variable] if result_variable
|
609
|
+
end
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
def set_information
|
614
|
+
ptr_defs = all_pointer_definition()
|
615
|
+
ptrs = all_pointer()
|
616
|
+
vars = all_variable()
|
617
|
+
calc_egen_ekill()
|
618
|
+
calc_undefined_variables()
|
619
|
+
entry = @blocks[0]
|
620
|
+
bug() if @blocks.find{|b| (not b.in_undefined) || (not b.out_undefined)}
|
621
|
+
bug() if @blocks.find{|b| b != entry && b.pre.empty? }
|
622
|
+
bug() unless entry.pre.empty?
|
623
|
+
@blocks.each{|b| b.information = Information.new(b, vars, vars, [], [], ptr_defs, ptrs)}
|
624
|
+
entry.information = Information.new(entry, vars, vars, [], vars, ptr_defs, ptrs)
|
625
|
+
change = true
|
626
|
+
while change
|
627
|
+
change = false
|
628
|
+
@blocks.each do |b0|
|
629
|
+
next if b0 == entry
|
630
|
+
info = b0.pre.inject(Information.new(b0, vars, nil, [], [], ptr_defs, ptrs)) {|info, b1| info | b1.information.final_state()}
|
631
|
+
change = true if b0.information != info
|
632
|
+
b0.information = info
|
633
|
+
end
|
634
|
+
end
|
635
|
+
change = true
|
636
|
+
while change
|
637
|
+
change = false
|
638
|
+
@blocks.each do |b0|
|
639
|
+
next if b0 == entry
|
640
|
+
info = b0.information.dup
|
641
|
+
b0.pre.each{|b1| info.kill_definition(b1.information.final_state())}
|
642
|
+
change = true if b0.information != info
|
643
|
+
b0.information = info
|
644
|
+
end
|
645
|
+
end
|
646
|
+
@blocks.each{|b| b.information.freeze()}
|
647
|
+
# validation
|
648
|
+
@blocks.each do |b|
|
649
|
+
variable_definition = b.information.dup()
|
650
|
+
variable_definition.validate()
|
651
|
+
b.irs.each do |ir|
|
652
|
+
ir.variables_without_result.each do |var|
|
653
|
+
var.has_undefined_path() if variable_definition.undefined_variables.include?(var)
|
654
|
+
end
|
655
|
+
variable_definition.step(ir)
|
656
|
+
end
|
657
|
+
variable_definition.validate_final()
|
658
|
+
end
|
659
|
+
@blocks.each do |b|
|
660
|
+
u0 = b.in_undefined
|
661
|
+
u1 = b.information.undefined_variables
|
662
|
+
bug("u1 = #{u1}, u0 = #{u0}") unless (u0 - u1).empty? && (u1 - u0).empty?
|
663
|
+
u0 = b.out_undefined
|
664
|
+
u1 = b.information.final_state.undefined_variables
|
665
|
+
bug("u1 = #{u1}, u0 = #{u0}") unless (u0 - u1).empty? && (u1 - u0).empty?
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
class Guards
|
670
|
+
include CastOff::Util
|
671
|
+
include CastOff::Compiler::SimpleIR
|
672
|
+
|
673
|
+
attr_reader :guards, :block
|
674
|
+
|
675
|
+
def initialize(b, d, g, ptrs)
|
676
|
+
@block = b
|
677
|
+
@variable_definition = d
|
678
|
+
@guards = g
|
679
|
+
@ptrs = ptrs
|
680
|
+
end
|
681
|
+
|
682
|
+
def dup()
|
683
|
+
Guards.new(@block, @variable_definition.dup(), @guards.dup(), @ptrs)
|
684
|
+
end
|
685
|
+
|
686
|
+
def &(other)
|
687
|
+
bug() unless other.instance_of?(Guards)
|
688
|
+
Guards.new(@block, @variable_definition.dup(), @guards & other.guards, @ptrs)
|
689
|
+
end
|
690
|
+
|
691
|
+
def eql?(other)
|
692
|
+
bug() unless other.instance_of?(Guards)
|
693
|
+
bug() unless other.block == @block
|
694
|
+
@guards == other.guards
|
695
|
+
end
|
696
|
+
|
697
|
+
def ==(other)
|
698
|
+
eql?(other)
|
699
|
+
end
|
700
|
+
|
701
|
+
def final_state()
|
702
|
+
g = dup()
|
703
|
+
@block.irs.each{|ir| g.step(ir)}
|
704
|
+
g
|
705
|
+
end
|
706
|
+
|
707
|
+
def validate_final()
|
708
|
+
@variable_definition.validate_final()
|
709
|
+
end
|
710
|
+
|
711
|
+
def redundant?(ir)
|
712
|
+
ir.is_a?(StandardGuard) ? @guards.include?(ir.guard_value) : false
|
713
|
+
end
|
714
|
+
|
715
|
+
def step(ir)
|
716
|
+
case ir
|
717
|
+
when StandardGuard
|
718
|
+
guard_value = ir.guard_value
|
719
|
+
bug() unless guard_value.is_a?(Variable)
|
720
|
+
@guards | [guard_value]
|
721
|
+
@guards |= @variable_definition.find_same_variables(guard_value)
|
722
|
+
when SubIR
|
723
|
+
src = ir.src
|
724
|
+
dst = ir.dst
|
725
|
+
if @guards.include?(src)
|
726
|
+
@guards |= [dst]
|
727
|
+
else
|
728
|
+
@guards -= [dst]
|
729
|
+
end
|
730
|
+
when CallIR
|
731
|
+
@guards -= [ir.return_value]
|
732
|
+
@guards -= @ptrs if ir.dispatch_method?
|
733
|
+
end
|
734
|
+
@variable_definition.step(ir)
|
735
|
+
end
|
736
|
+
|
737
|
+
def freeze()
|
738
|
+
super()
|
739
|
+
@guards.freeze()
|
740
|
+
@variable_definition.freeze()
|
741
|
+
end
|
742
|
+
end
|
743
|
+
|
744
|
+
def inject_guards()
|
745
|
+
vars = all_variable()
|
746
|
+
ptrs = all_pointer()
|
747
|
+
guards = []
|
748
|
+
@blocks.each do |b|
|
749
|
+
b.irs.map! do |ir|
|
750
|
+
g = ir.generate_guard(vars)
|
751
|
+
guards << g
|
752
|
+
g ? [g, ir] : ir
|
753
|
+
end
|
754
|
+
b.irs.flatten!
|
755
|
+
end
|
756
|
+
guards.compact()
|
757
|
+
guards.freeze()
|
758
|
+
|
759
|
+
bug() if @blocks.find{|b| not b.information.frozen?}
|
760
|
+
@blocks.each{|b| b.in_guards = Guards.new(b, b.information, [], ptrs)}
|
761
|
+
change = true
|
762
|
+
while change
|
763
|
+
change = false
|
764
|
+
@blocks.each do |b0|
|
765
|
+
next if b0.entry_point?
|
766
|
+
in_guards = b0.pre.inject(Guards.new(b0, b0.information, guards, ptrs)){|in_g, b1| in_g & b1.in_guards.final_state()}
|
767
|
+
change = true if b0.in_guards != in_guards
|
768
|
+
b0.in_guards = in_guards
|
769
|
+
end
|
770
|
+
end
|
771
|
+
@blocks.each{|b| b.in_guards.freeze()}
|
772
|
+
end
|
773
|
+
end
|
774
|
+
end
|
775
|
+
|