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.
Files changed (58) hide show
  1. data/README +578 -0
  2. data/README.en +256 -0
  3. data/bin/CastOff +145 -0
  4. data/cast_off.gemspec +25 -0
  5. data/ext/cast_off/cast_off.c.rb +1386 -0
  6. data/ext/cast_off/cast_off.h +24 -0
  7. data/ext/cast_off/depend +70 -0
  8. data/ext/cast_off/extconf.rb +19 -0
  9. data/ext/cast_off/generated_c_include/inline_api.h +507 -0
  10. data/ext/cast_off/generated_c_include/iter_api.h +595 -0
  11. data/ext/cast_off/generated_c_include/unbox_api.h.rb +76 -0
  12. data/ext/cast_off/generated_c_include/vm_api.h +751 -0
  13. data/ext/cast_off/ruby_source/atomic.h +56 -0
  14. data/ext/cast_off/ruby_source/constant.h +34 -0
  15. data/ext/cast_off/ruby_source/debug.h +41 -0
  16. data/ext/cast_off/ruby_source/eval_intern.h +234 -0
  17. data/ext/cast_off/ruby_source/gc.h +98 -0
  18. data/ext/cast_off/ruby_source/id.h +175 -0
  19. data/ext/cast_off/ruby_source/insns.inc +179 -0
  20. data/ext/cast_off/ruby_source/insns_info.inc +695 -0
  21. data/ext/cast_off/ruby_source/internal.h +227 -0
  22. data/ext/cast_off/ruby_source/iseq.h +125 -0
  23. data/ext/cast_off/ruby_source/manual_update.h +135 -0
  24. data/ext/cast_off/ruby_source/method.h +105 -0
  25. data/ext/cast_off/ruby_source/node.h +503 -0
  26. data/ext/cast_off/ruby_source/thread_pthread.h +51 -0
  27. data/ext/cast_off/ruby_source/thread_win32.h +40 -0
  28. data/ext/cast_off/ruby_source/vm_core.h +756 -0
  29. data/ext/cast_off/ruby_source/vm_exec.h +184 -0
  30. data/ext/cast_off/ruby_source/vm_insnhelper.c +1748 -0
  31. data/ext/cast_off/ruby_source/vm_insnhelper.h +220 -0
  32. data/ext/cast_off/ruby_source/vm_opts.h +51 -0
  33. data/lib/cast_off.rb +15 -0
  34. data/lib/cast_off/compile.rb +629 -0
  35. data/lib/cast_off/compile/basicblock.rb +144 -0
  36. data/lib/cast_off/compile/cfg.rb +391 -0
  37. data/lib/cast_off/compile/code_manager.rb +284 -0
  38. data/lib/cast_off/compile/configuration.rb +2368 -0
  39. data/lib/cast_off/compile/dependency.rb +240 -0
  40. data/lib/cast_off/compile/information.rb +775 -0
  41. data/lib/cast_off/compile/instruction.rb +446 -0
  42. data/lib/cast_off/compile/ir/call_ir.rb +2348 -0
  43. data/lib/cast_off/compile/ir/guard_ir.rb +423 -0
  44. data/lib/cast_off/compile/ir/jump_ir.rb +223 -0
  45. data/lib/cast_off/compile/ir/operand.rb +934 -0
  46. data/lib/cast_off/compile/ir/param_ir.rb +98 -0
  47. data/lib/cast_off/compile/ir/return_ir.rb +92 -0
  48. data/lib/cast_off/compile/ir/simple_ir.rb +808 -0
  49. data/lib/cast_off/compile/ir/sub_ir.rb +212 -0
  50. data/lib/cast_off/compile/iseq.rb +454 -0
  51. data/lib/cast_off/compile/method_information.rb +1384 -0
  52. data/lib/cast_off/compile/namespace/namespace.rb +556 -0
  53. data/lib/cast_off/compile/namespace/uuid.rb +323 -0
  54. data/lib/cast_off/compile/stack.rb +65 -0
  55. data/lib/cast_off/compile/translator.rb +1562 -0
  56. data/lib/cast_off/suggestion.rb +98 -0
  57. data/lib/cast_off/util.rb +58 -0
  58. 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
+