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.
@@ -127,20 +127,20 @@ Currently, CastOff doesn't support object, which cannot marshal dump (e.g. STDIN
127
127
  end
128
128
 
129
129
  def add(klass, mid, strong_p)
130
- # TODO include で継承関係が変わったのを検出
131
130
  bug() unless klass.instance_of?(ClassWrapper)
132
131
  targets = [klass]
133
- if not klass.singleton?
134
- klass.each_method_search_target(mid) do |cm|
135
- next if cm == klass.contain_class
136
- case cm
137
- when Class
138
- targets << ClassWrapper.new(cm, true)
139
- when Module
140
- targets << ModuleWrapper.new(cm)
141
- else
142
- bug()
143
- end
132
+ klass.each_method_search_target(mid) do |cm|
133
+ next if klass.singleton? ? (cm == klass) : (cm == klass.contain_class)
134
+ case cm
135
+ when Class
136
+ targets << ClassWrapper.new(cm, true)
137
+ when Module
138
+ targets << ModuleWrapper.new(cm)
139
+ when ClassWrapper
140
+ bug() unless cm.singleton?
141
+ targets << cm
142
+ else
143
+ bug()
144
144
  end
145
145
  end
146
146
  targets.each do |t|
@@ -162,6 +162,27 @@ Currently, CastOff doesn't support object, which cannot marshal dump (e.g. STDIN
162
162
  end
163
163
  end
164
164
 
165
+ def self.copy(dst, src, singleton_p)
166
+ bug() unless dst.is_a?(Module)
167
+ dst = ModuleWrapper.new(dst)
168
+ deps = singleton_p ? @@singleton_method_dependency : @@instance_method_dependency
169
+ funcs = singleton_p ? @@singleton_method_dependency_initializers : @@instance_method_dependency_initializers
170
+ (deps[src] || []).each do |mid|
171
+ finits = funcs[[src, mid]]
172
+ if finits && !finits.empty?
173
+ finits.each{|f| instance_method_depend(dst, mid, f)}
174
+ else
175
+ bug() unless singleton_p
176
+ case mid
177
+ when :singleton_method_added, :method_added, :include, :extend
178
+ # nothing to do
179
+ else
180
+ bug()
181
+ end
182
+ end
183
+ end
184
+ end
185
+
165
186
  def self.hook(o)
166
187
  s = class << o
167
188
  self
@@ -193,13 +214,39 @@ Currently, CastOff doesn't support object, which cannot marshal dump (e.g. STDIN
193
214
  end
194
215
  end
195
216
 
217
+ # include のフックまで入れると読み込み時間が結構遅くなるので注意
218
+ begin
219
+ m_include = o.method(:include).unbind
220
+ m_extend = o.method(:extend).unbind
221
+ rescue NameError
222
+ raise(ExecutionError.new("#{o}: include or extend not defined"))
223
+ end
224
+ define_method(:include) do |*mods|
225
+ extend_p = Dependency.extend?
226
+ CastOff.dlog("#{self} #{extend_p ? 'extends' : 'includes'} #{mods}")
227
+ bug() unless m_include && m_extend
228
+ m = extend_p ? m_extend : m_include
229
+ # include, extend の対象は self なので、self 以外が include, extend することはない。
230
+ m.bind(self).call(*mods)
231
+ return unless o == self
232
+ mods.each do |mod|
233
+ next unless mod.is_a?(Module)
234
+ Dependency.copy(mod, self, extend_p)
235
+ Dependency.hook(mod) unless mod.singleton_methods(false).include?(:override_singleton_method)
236
+ methods = mod.instance_methods(false) + mod.private_instance_methods(false)
237
+ override_callback = extend_p ? :override_singleton_method : :override_method
238
+ methods.each{|mid| o.__send__(override_callback, o, mid, extend_p ? :extend : :include)}
239
+ end
240
+ end
241
+ alias extend include
242
+
196
243
  begin
197
- singleton_method_added = o.method(:singleton_method_added)
244
+ singleton_method_added = o.method(:singleton_method_added).unbind
198
245
  rescue NameError
199
246
  singleton_method_added = nil
200
247
  end
201
248
  begin
202
- method_added = o.method(:method_added)
249
+ method_added = o.method(:method_added).unbind
203
250
  rescue NameError
204
251
  method_added = nil
205
252
  end
@@ -209,15 +256,15 @@ Currently, CastOff doesn't support object, which cannot marshal dump (e.g. STDIN
209
256
  CastOff.dlog("singleton method added #{o}.#{mid}")
210
257
  CastOff.delete_original_singleton_method_iseq(self, mid)
211
258
  override_singleton_method(o, mid, :added)
212
- singleton_method_added.call(mid) if singleton_method_added
259
+ singleton_method_added.bind(self).call(mid) if singleton_method_added
213
260
  else
214
261
  CastOff.dlog("method added #{o}##{mid}")
215
262
  CastOff.delete_original_instance_method_iseq(self, mid)
216
263
  override_method(o, mid, :added)
217
- method_added.call(mid) if method_added
264
+ method_added.bind(self).call(mid) if method_added
218
265
  end
219
266
  elsif o == BasicObject && method_added && !Dependency.singleton_method_added?
220
- method_added.call(mid)
267
+ method_added.bind(self).call(mid)
221
268
  end
222
269
  super(mid) rescue NoMethodError
223
270
  end
@@ -225,10 +272,11 @@ Currently, CastOff doesn't support object, which cannot marshal dump (e.g. STDIN
225
272
  CastOff.dlog("hook #{o}")
226
273
  end
227
274
  @@singleton_method_dependency[o] ||= []
228
- @@singleton_method_dependency[o] |= [:method_added, :singleton_method_added]
275
+ @@singleton_method_dependency[o] |= [:method_added, :singleton_method_added, :include]
229
276
  @@singleton_method_strong_dependency[o] ||= []
230
277
  @@singleton_method_strong_dependency[o] |= [:method_added]
231
278
  @@singleton_method_strong_dependency[o] |= [:singleton_method_added]
279
+ @@singleton_method_strong_dependency[o] |= [:include]
232
280
  end
233
281
 
234
282
  def hook(function_pointer_initializer)
@@ -165,6 +165,20 @@ module CastOff::Compiler
165
165
  @undefs
166
166
  end
167
167
 
168
+ def get_variables(var)
169
+ check_initialize()
170
+ ds = @definition.select{|d| var == d.result_variable }
171
+ bug() if ds.empty?
172
+ ds.map{|d| d.result_variable}
173
+ end
174
+
175
+ def get_variable(var)
176
+ vars = get_variables(var)
177
+ boxed_p = vars.first.boxed?
178
+ bug() if boxed_p ? vars.find{|v| v.unboxed?} : vars.find{|v| v.boxed?}
179
+ vars.first
180
+ end
181
+
168
182
  def mark(var)
169
183
  check_initialize()
170
184
  ds = @definition.select {|d| var == d.result_variable }
@@ -221,55 +235,13 @@ module CastOff::Compiler
221
235
  end
222
236
 
223
237
  ### unboxing begin ###
224
- def can_not_unbox_variable_resolve_forward(var)
238
+ def propergate_boxed_value_forward(var)
225
239
  check_initialize()
226
- return false if var.can_not_unbox?
227
- ds = @definition.select {|d| var == d.result_variable }
228
- if ds.empty?
229
- case var
230
- when TmpBuffer, Pointer, Argument, Self, ConstWrapper, Literal
231
- return false
232
- else
233
- bug(var)
234
- end
235
- end
236
- ds.each do |d|
237
- if d.result_variable.can_not_unbox?
238
- var.can_not_unbox()
239
- return true
240
- end
241
- end
242
- return false
243
- end
244
-
245
- def can_not_unbox_variable_resolve_backward(var)
246
- check_initialize()
247
- bug() unless var.can_not_unbox?
248
- ds = @definition.select {|d| var == d.result_variable }
249
- if ds.empty?
250
- case var
251
- when TmpBuffer, Pointer, Argument, Self, ConstWrapper, Literal
252
- return false
253
- else
254
- bug(var)
255
- end
256
- end
257
- ds.inject(false){|change, d| d.result_variable.can_not_unbox() || change}
258
- end
259
-
260
- def box_value_resolve_forward(var)
261
- check_initialize()
262
- bug() if !var.unboxed? && !var.boxed?
263
240
  return false if var.boxed?
264
241
  ds = @definition.select {|d| var == d.result_variable }
265
242
  if ds.empty?
266
- case var
267
- when TmpBuffer, Pointer, Argument, Self, ConstWrapper, Literal
268
- #bug(var)
269
- return false
270
- else
271
- bug(var)
272
- end
243
+ bug(var) unless var.is_a?(Literal) # should be boxed => TmpBuffer, Pointer, Argument, Self, ConstWrapper
244
+ return false
273
245
  end
274
246
  ds.each do |d|
275
247
  if d.result_variable.boxed?
@@ -280,7 +252,7 @@ module CastOff::Compiler
280
252
  return false
281
253
  end
282
254
 
283
- def box_value_resolve_backward(var)
255
+ def propergate_boxed_value_backward(var)
284
256
  check_initialize()
285
257
  bug() unless var.boxed?
286
258
  ds = @definition.select {|d| var == d.result_variable }
@@ -294,35 +266,6 @@ module CastOff::Compiler
294
266
  end
295
267
  ds.inject(false){|change, d| d.result_variable.box() || change}
296
268
  end
297
-
298
- def unbox_value_resolve(var)
299
- check_initialize()
300
- bug() if var.can_not_unbox?
301
- return false if var.unboxed?
302
- ds = @definition.select {|d| var == d.result_variable }
303
- if ds.empty?
304
- case var
305
- when TmpBuffer, Pointer, Argument, Self, ConstWrapper, Literal
306
- return false
307
- else
308
- bug(var)
309
- end
310
- end
311
- c = nil
312
- ds.each do |d|
313
- v = d.result_variable
314
- return false unless v.unboxed?
315
- bug() if v.dynamic?
316
- bug() unless v.types.size == 1
317
- if c
318
- bug() unless c == v.types[0]
319
- else
320
- c = v.types[0]
321
- end
322
- end
323
- var.unbox()
324
- true
325
- end
326
269
  ### unboxing end ###
327
270
 
328
271
  private
@@ -431,6 +374,7 @@ module CastOff::Compiler
431
374
  other.condition.each do |(v, p)|
432
375
  tmp.delete(v) if !tmp[v] || (tmp[v] && tmp[v] != p)
433
376
  end
377
+ (tmp.keys - other.condition.keys).each{|v| tmp.delete(v)}
434
378
  else
435
379
  tmp = other.condition.dup
436
380
  end
@@ -36,27 +36,15 @@ module CastOff
36
36
  can_not_unbox()
37
37
  end
38
38
 
39
- def propergate_value_which_can_not_unbox(defs)
39
+ def propergate_boxed_value(defs)
40
40
  # nothing to do
41
41
  false
42
42
  end
43
43
 
44
- def propergate_box_value(defs)
45
- # nothing to do
46
- false
47
- end
48
-
49
- def propergate_unbox_value(defs)
50
- return false if @return_value.can_not_unbox?
51
- @return_value.unbox()
52
- end
53
-
54
- #private
55
-
56
44
  def can_not_unbox()
57
45
  params = param_variables()
58
- params.each{|p| p.can_not_unbox()}
59
- @return_value.can_not_unbox()
46
+ params.each{|p| p.box()}
47
+ @return_value.box()
60
48
  end
61
49
  ### unboxing end ###
62
50
 
@@ -261,8 +249,8 @@ module CastOff
261
249
  ### unboxing begin ###
262
250
  def unboxing_prelude()
263
251
  params = param_variables()
264
- params.each{|p| p.can_not_unbox()}
265
- @return_value.can_unbox()
252
+ params.each{|p| p.box()}
253
+ @return_value.box() unless @return_value.can_unbox?
266
254
  end
267
255
  ### unboxing end ###
268
256
 
@@ -1728,7 +1716,7 @@ You should not use #{@method_id} method in compilation target of CastOff.
1728
1716
  [MethodWrapper.new(ArrayWrapper, :first), 1] => [['first', [], nil, nil, false, false]],
1729
1717
  [MethodWrapper.new(FixnumWrapper, :+), 2] => [['fixnum_plus', [Fixnum], Fixnum, nil, true, true], ['float_plus', [Float], nil, Float, true, true]], # FIXME
1730
1718
  [MethodWrapper.new(FixnumWrapper, :-), 2] => [['fixnum_minus', [Fixnum], Fixnum, nil, true, true], ['float_minus', [Float], nil, Float, true, true]], # FIXME
1731
- [MethodWrapper.new(FixnumWrapper, :*), 2] => [['fixnum_mult', [Fixnum], Fixnum, nil, true, true], ['float_mult', [Float], nil, Float, true, true]], # FIXME
1719
+ [MethodWrapper.new(FixnumWrapper, :*), 2] => [['fixnum_mult', [Fixnum], Fixnum, nil, true, true], ['float_mult', [Float], nil, Float, true, true]], # FIXME
1732
1720
  [MethodWrapper.new(FixnumWrapper, :<=), 2] => [['le', [Fixnum], nil, [TrueClass, FalseClass], false, false]],
1733
1721
  [MethodWrapper.new(FixnumWrapper, :<), 2] => [['lt', [Fixnum], nil, [TrueClass, FalseClass], false, false]],
1734
1722
  [MethodWrapper.new(FixnumWrapper, :>=), 2] => [['ge', [Fixnum], nil, [TrueClass, FalseClass], false, false]],
@@ -1741,7 +1729,23 @@ You should not use #{@method_id} method in compilation target of CastOff.
1741
1729
  [MethodWrapper.new(FloatWrapper, :-), 2] => [['float_minus', [Float], nil, Float, true, true], ['fixnum_minus', [Fixnum], nil, Float, true, true]],
1742
1730
  [MethodWrapper.new(FloatWrapper, :*), 2] => [['float_mult', [Float], nil, Float, true, true], ['fixnum_mult', [Fixnum], nil, Float, true, true]],
1743
1731
  [MethodWrapper.new(FloatWrapper, :/), 2] => [['float_div', [Float], nil, Float, true, true], ['fixnum_div', [Fixnum], nil, Float, true, true]],
1744
- [MethodWrapper.new(FloatWrapper, :>), 2] => [['float_gt', [Float], nil, [TrueClass, FalseClass], false, true]],
1732
+ [MethodWrapper.new(FloatWrapper, :<=), 2] => [['float_le', [Float], nil, [TrueClass, FalseClass], false, true],
1733
+ ['fixnum_le', [Fixnum], nil, [TrueClass, FalseClass], false, true]],
1734
+ [MethodWrapper.new(FloatWrapper, :<), 2] => [['float_lt', [Float], nil, [TrueClass, FalseClass], false, true],
1735
+ ['fixnum_lt', [Fixnum], nil, [TrueClass, FalseClass], false, true]],
1736
+ [MethodWrapper.new(FloatWrapper, :>=), 2] => [['float_ge', [Float], nil, [TrueClass, FalseClass], false, true],
1737
+ ['fixnum_ge', [Fixnum], nil, [TrueClass, FalseClass], false, true]],
1738
+ [MethodWrapper.new(FloatWrapper, :>), 2] => [['float_gt', [Float], nil, [TrueClass, FalseClass], false, true],
1739
+ ['fixnum_gt', [Fixnum], nil, [TrueClass, FalseClass], false, true]],
1740
+ [MethodWrapper.new(FloatWrapper, :==), 2] => [['float_eq', [Float], nil, [TrueClass, FalseClass], false, true],
1741
+ ['fixnum_eq', [Fixnum], nil, [TrueClass, FalseClass], false, true]],
1742
+ [MethodWrapper.new(FloatWrapper, :===), 2] => [['float_eqq', [Float], nil, [TrueClass, FalseClass], false, true],
1743
+ ['fixnum_eqq', [Fixnum], nil, [TrueClass, FalseClass], false, true]],
1744
+ [MethodWrapper.new(FixnumWrapper, :-@), 1] => [['uminus', [], Fixnum, nil, true, true]],
1745
+ [MethodWrapper.new(FloatWrapper, :-@), 1] => [['uminus', [], nil, Float, true, true]],
1746
+ [MethodWrapper.new(FixnumWrapper, :to_f), 1] => [['to_f', [], nil, Float, true, true]],
1747
+ [MethodWrapper.new(FloatWrapper, :to_f), 1] => [['to_f', [], nil, Float, true, false]],
1748
+ [MethodWrapper.new(FloatWrapper, :to_i), 1] => [['to_i', [], nil, Float, false, true]],
1745
1749
  }
1746
1750
  SpecializeTable1 = {
1747
1751
  [:==, 2, MethodWrapper.new(ObjectWrapper, :==)] => :specialized_object_eq,
@@ -1800,10 +1804,26 @@ You should not use #{@method_id} method in compilation target of CastOff.
1800
1804
  bug()
1801
1805
  end
1802
1806
 
1807
+ def unboxed_decl(v)
1808
+ bug() unless v.is_a?(Variable)
1809
+ bug() if v.dynamic?
1810
+ bug() unless v.types.size == 1
1811
+ c = v.types[0]
1812
+ bug() unless c.is_a?(ClassWrapper)
1813
+ case c
1814
+ when FloatWrapper
1815
+ 'double'
1816
+ when FixnumWrapper
1817
+ 'long'
1818
+ else
1819
+ bug()
1820
+ end
1821
+ end
1822
+
1803
1823
  def specialized_code(klass, mid, argc, recv, param)
1804
1824
  bug() unless klass.is_a?(ClassWrapper)
1805
1825
  return false unless @configuration.enable_inline_api?
1806
- # FIXME 関数ポインタが実行時に同一であることをチェック
1826
+ # FIXME ロード時に、関数ポインタが想定しているものと同一であることをチェック
1807
1827
  if klass.String? || klass.Array? || klass.Fixnum? || klass.Float?
1808
1828
  entries = SpecializeTable0[[MethodWrapper.new(klass, mid), argc]]
1809
1829
  return false unless entries
@@ -1816,9 +1836,6 @@ You should not use #{@method_id} method in compilation target of CastOff.
1816
1836
  (param + [@return_value]).zip(t_param + [t_result]).each do |p, t|
1817
1837
  next if t.nil?
1818
1838
  unless p.is_just?(t)
1819
- #if @source && @configuration.development?
1820
- #@translator.add_inlineapi_suggestion(["#{klass}###{mid}", "1st argument can be not #{t}", @source_line, @source])
1821
- #end
1822
1839
  fin = false
1823
1840
  break
1824
1841
  end
@@ -1832,24 +1849,12 @@ You should not use #{@method_id} method in compilation target of CastOff.
1832
1849
  name, t_param, t_result, exact_classes, can_unbox_result, can_unbox_param = entry
1833
1850
 
1834
1851
  s_param = param.empty? ? '' : ", #{param.join(", ")}"
1835
- if can_unbox_param
1836
- suffix = ([recv] + param + [@return_value]).map{|p|
1837
- if p.unboxed?
1838
- bug() if p.dynamic?
1839
- bug() unless p.types.size == 1
1840
- c = p.types[0]
1841
- case c
1842
- when FloatWrapper
1843
- 'double'
1844
- when FixnumWrapper
1845
- 'long'
1846
- else
1847
- bug()
1848
- end
1849
- else
1850
- 'VALUE'
1851
- end
1852
- }.join("_")
1852
+ if can_unbox_param || can_unbox_result
1853
+ bug() if !can_unbox_param && ([recv] + param).find{|p| p.unboxed? }
1854
+ suffix = ([recv] + param).map{|p| p.unboxed? ? unboxed_decl(p) : 'VALUE'}
1855
+ bug() if !can_unbox_result && @return_value.unboxed?
1856
+ suffix << (@return_value.unboxed? ? unboxed_decl(@return_value) : 'VALUE')
1857
+ suffix = suffix.join('_')
1853
1858
  return " #{@return_value} = cast_off_inline_#{klass.to_s.downcase}_#{name}_#{suffix}(#{recv}#{s_param});"
1854
1859
  else
1855
1860
  return " #{@return_value} = cast_off_inline_#{klass.to_s.downcase}_#{name}(#{recv}#{s_param});"
@@ -2030,7 +2035,7 @@ You should not use #{@method_id} method in compilation target of CastOff.
2030
2035
  % if funcall
2031
2036
  <%= funcall_code(nil, id, recv, param, @argc) %>
2032
2037
  % else
2033
- rb_raise(rb_eCastOffExecutionError, "type mismatch: reciever = <%= recv %>, method name = <%= id %>");
2038
+ rb_bug("type mismatch: method name = <%= @method_id %>");
2034
2039
  % end
2035
2040
  }
2036
2041
  %end
@@ -2071,7 +2076,7 @@ You should not use #{@method_id} method in compilation target of CastOff.
2071
2076
  id = @translator.allocate_id(@method_id)
2072
2077
  bug() if recv.undefined?
2073
2078
  if @configuration.development? && sampling_return_value?
2074
- ret << " cast_off_tmp = #{recv};"
2079
+ ret << " sampling_tmp = #{recv};"
2075
2080
  end
2076
2081
  if blockarg?
2077
2082
  ret << funcall_code(nil, id, recv, param, @argc)
@@ -2146,7 +2151,7 @@ You should not use #{@method_id} method in compilation target of CastOff.
2146
2151
  end
2147
2152
  end
2148
2153
  if @configuration.development? && sampling_return_value?
2149
- ret << " sampling_poscall(#{@return_value}, cast_off_tmp, ID2SYM(rb_intern(#{@method_id.to_s.inspect})));"
2154
+ ret << " sampling_poscall(#{@return_value}, sampling_tmp, ID2SYM(rb_intern(#{@method_id.to_s.inspect})));"
2150
2155
  end
2151
2156
  ret.join("\n")
2152
2157
  end
@@ -2189,6 +2194,8 @@ You should not use #{@method_id} method in compilation target of CastOff.
2189
2194
  recv.types.each do |t|
2190
2195
  ok = @configuration.use_method_information(t, @method_id)
2191
2196
  return false unless ok
2197
+ # これのせいで依存するクラスなどが結構増える。読み込みが遅くなる。
2198
+ @dependency.add(t, @method_id, true)
2192
2199
  end
2193
2200
  return true
2194
2201
  end
@@ -2211,6 +2218,8 @@ You should not use #{@method_id} method in compilation target of CastOff.
2211
2218
  recv.types.each do |t|
2212
2219
  ok = @configuration.use_method_information(t, @method_id)
2213
2220
  return true unless ok
2221
+ # これのせいで依存するクラスなどが結構増える。読み込みが遅くなる。
2222
+ @dependency.add(t, @method_id, true)
2214
2223
  end
2215
2224
  end
2216
2225
  se
@@ -2286,19 +2295,8 @@ You should not use #{@method_id} method in compilation target of CastOff.
2286
2295
  return
2287
2296
  end
2288
2297
  name, t_args, t_result, exact_classes, can_unbox_result, can_unbox_param = entry
2289
- if can_unbox_param
2290
- params.each do |p|
2291
- next unless p.box_unbox_undefined? # for guard
2292
- p.can_unbox? ? p.can_unbox() : p.can_not_unbox()
2293
- end
2294
- else
2295
- params.each{|p| p.can_not_unbox()}
2296
- end
2297
- if can_unbox_result
2298
- @return_value.can_unbox()
2299
- else
2300
- @return_value.can_not_unbox()
2301
- end
2298
+ can_unbox_param ? params.each{|p| p.box() unless p.can_unbox?} : params.each{|p| p.box()}
2299
+ @return_value.box() unless can_unbox_result && @return_value.can_unbox?
2302
2300
  return
2303
2301
  end
2304
2302
  end