mirror of
https://github.com/ruby/ruby.git
synced 2025-08-27 23:16:42 +02:00
Revert "Revert "This commit implements the Object Shapes technique in CRuby.""
This reverts commit 9a6803c90b
.
This commit is contained in:
parent
5ffbb2be18
commit
ad63b668e2
41 changed files with 2311 additions and 893 deletions
|
@ -831,7 +831,7 @@ class TestMJIT < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_inlined_exivar
|
||||
assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "aaa", success_count: 3, recompile_count: 1, min_calls: 2)
|
||||
assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "aaa", success_count: 4, recompile_count: 2, min_calls: 2)
|
||||
begin;
|
||||
class Foo < Hash
|
||||
def initialize
|
||||
|
@ -850,7 +850,7 @@ class TestMJIT < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_inlined_undefined_ivar
|
||||
assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "bbb", success_count: 3, min_calls: 3)
|
||||
assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "bbb", success_count: 2, min_calls: 2)
|
||||
begin;
|
||||
class Foo
|
||||
def initialize
|
||||
|
|
|
@ -993,4 +993,13 @@ class TestObject < Test::Unit::TestCase
|
|||
end
|
||||
EOS
|
||||
end
|
||||
|
||||
def test_frozen_inspect
|
||||
obj = Object.new
|
||||
obj.instance_variable_set(:@a, "a")
|
||||
ins = obj.inspect
|
||||
obj.freeze
|
||||
|
||||
assert_equal(ins, obj.inspect)
|
||||
end
|
||||
end
|
||||
|
|
173
test/ruby/test_shapes.rb
Normal file
173
test/ruby/test_shapes.rb
Normal file
|
@ -0,0 +1,173 @@
|
|||
# frozen_string_literal: false
|
||||
require 'test/unit'
|
||||
|
||||
# These test the functionality of object shapes
|
||||
class TestShapes < Test::Unit::TestCase
|
||||
class Example
|
||||
def initialize
|
||||
@a = 1
|
||||
end
|
||||
end
|
||||
|
||||
class RemoveAndAdd
|
||||
def add_foo
|
||||
@foo = 1
|
||||
end
|
||||
|
||||
def remove
|
||||
remove_instance_variable(:@foo)
|
||||
end
|
||||
|
||||
def add_bar
|
||||
@bar = 1
|
||||
end
|
||||
end
|
||||
|
||||
# RubyVM.debug_shape returns new instances of shape objects for
|
||||
# each call. This helper method allows us to define equality for
|
||||
# shapes
|
||||
def assert_shape_equal(shape1, shape2)
|
||||
assert_equal(shape1.id, shape2.id)
|
||||
assert_equal(shape1.parent_id, shape2.parent_id)
|
||||
assert_equal(shape1.depth, shape2.depth)
|
||||
assert_equal(shape1.type, shape2.type)
|
||||
end
|
||||
|
||||
def refute_shape_equal(shape1, shape2)
|
||||
refute_equal(shape1.id, shape2.id)
|
||||
end
|
||||
|
||||
def test_iv_index
|
||||
example = RemoveAndAdd.new
|
||||
shape = RubyVM.debug_shape(example)
|
||||
assert_equal 0, shape.iv_count
|
||||
|
||||
example.add_foo # makes a transition
|
||||
new_shape = RubyVM.debug_shape(example)
|
||||
assert_equal([:@foo], example.instance_variables)
|
||||
assert_equal(shape.id, new_shape.parent.id)
|
||||
assert_equal(1, new_shape.iv_count)
|
||||
|
||||
example.remove # makes a transition
|
||||
remove_shape = RubyVM.debug_shape(example)
|
||||
assert_equal([], example.instance_variables)
|
||||
assert_equal(new_shape.id, remove_shape.parent.id)
|
||||
assert_equal(1, remove_shape.iv_count)
|
||||
|
||||
example.add_bar # makes a transition
|
||||
bar_shape = RubyVM.debug_shape(example)
|
||||
assert_equal([:@bar], example.instance_variables)
|
||||
assert_equal(remove_shape.id, bar_shape.parent.id)
|
||||
assert_equal(2, bar_shape.iv_count)
|
||||
end
|
||||
|
||||
def test_new_obj_has_root_shape
|
||||
assert_shape_equal(RubyVM.debug_root_shape, RubyVM.debug_shape(Object.new))
|
||||
end
|
||||
|
||||
def test_frozen_new_obj_has_frozen_root_shape
|
||||
assert_shape_equal(
|
||||
RubyVM.debug_frozen_root_shape,
|
||||
RubyVM.debug_shape(Object.new.freeze)
|
||||
)
|
||||
end
|
||||
|
||||
def test_str_has_root_shape
|
||||
assert_shape_equal(RubyVM.debug_root_shape, RubyVM.debug_shape(""))
|
||||
end
|
||||
|
||||
def test_array_has_root_shape
|
||||
assert_shape_equal(RubyVM.debug_root_shape, RubyVM.debug_shape([]))
|
||||
end
|
||||
|
||||
def test_hash_has_root_shape
|
||||
assert_shape_equal(RubyVM.debug_root_shape, RubyVM.debug_shape({}))
|
||||
end
|
||||
|
||||
def test_true_has_frozen_root_shape
|
||||
assert_shape_equal(RubyVM.debug_frozen_root_shape, RubyVM.debug_shape(true))
|
||||
end
|
||||
|
||||
def test_nil_has_frozen_root_shape
|
||||
assert_shape_equal(RubyVM.debug_frozen_root_shape, RubyVM.debug_shape(nil))
|
||||
end
|
||||
|
||||
def test_basic_shape_transition
|
||||
obj = Example.new
|
||||
refute_equal(RubyVM.debug_root_shape, RubyVM.debug_shape(obj))
|
||||
assert_shape_equal(RubyVM.debug_root_shape.edges[:@a], RubyVM.debug_shape(obj))
|
||||
assert_equal(obj.instance_variable_get(:@a), 1)
|
||||
end
|
||||
|
||||
def test_different_objects_make_same_transition
|
||||
obj = Example.new
|
||||
obj2 = ""
|
||||
obj2.instance_variable_set(:@a, 1)
|
||||
assert_shape_equal(RubyVM.debug_shape(obj), RubyVM.debug_shape(obj2))
|
||||
end
|
||||
|
||||
def test_duplicating_objects
|
||||
obj = Example.new
|
||||
obj2 = obj.dup
|
||||
assert_shape_equal(RubyVM.debug_shape(obj), RubyVM.debug_shape(obj2))
|
||||
end
|
||||
|
||||
def test_freezing_and_duplicating_object
|
||||
obj = Object.new.freeze
|
||||
obj2 = obj.dup
|
||||
refute_predicate(obj2, :frozen?)
|
||||
# dup'd objects shouldn't be frozen, and the shape should be the
|
||||
# parent shape of the copied object
|
||||
assert_equal(RubyVM.debug_shape(obj).parent.id, RubyVM.debug_shape(obj2).id)
|
||||
end
|
||||
|
||||
def test_freezing_and_duplicating_object_with_ivars
|
||||
obj = Example.new.freeze
|
||||
obj2 = obj.dup
|
||||
refute_predicate(obj2, :frozen?)
|
||||
refute_shape_equal(RubyVM.debug_shape(obj), RubyVM.debug_shape(obj2))
|
||||
assert_equal(obj2.instance_variable_get(:@a), 1)
|
||||
end
|
||||
|
||||
def test_freezing_and_duplicating_string_with_ivars
|
||||
str = "str"
|
||||
str.instance_variable_set(:@a, 1)
|
||||
str.freeze
|
||||
str2 = str.dup
|
||||
refute_predicate(str2, :frozen?)
|
||||
refute_equal(RubyVM.debug_shape(str).id, RubyVM.debug_shape(str2).id)
|
||||
assert_equal(str2.instance_variable_get(:@a), 1)
|
||||
end
|
||||
|
||||
def test_freezing_and_cloning_objects
|
||||
obj = Object.new.freeze
|
||||
obj2 = obj.clone(freeze: true)
|
||||
assert_predicate(obj2, :frozen?)
|
||||
assert_shape_equal(RubyVM.debug_shape(obj), RubyVM.debug_shape(obj2))
|
||||
end
|
||||
|
||||
def test_freezing_and_cloning_object_with_ivars
|
||||
obj = Example.new.freeze
|
||||
obj2 = obj.clone(freeze: true)
|
||||
assert_predicate(obj2, :frozen?)
|
||||
assert_shape_equal(RubyVM.debug_shape(obj), RubyVM.debug_shape(obj2))
|
||||
assert_equal(obj2.instance_variable_get(:@a), 1)
|
||||
end
|
||||
|
||||
def test_freezing_and_cloning_string
|
||||
str = "str".freeze
|
||||
str2 = str.clone(freeze: true)
|
||||
assert_predicate(str2, :frozen?)
|
||||
assert_shape_equal(RubyVM.debug_shape(str), RubyVM.debug_shape(str2))
|
||||
end
|
||||
|
||||
def test_freezing_and_cloning_string_with_ivars
|
||||
str = "str"
|
||||
str.instance_variable_set(:@a, 1)
|
||||
str.freeze
|
||||
str2 = str.clone(freeze: true)
|
||||
assert_predicate(str2, :frozen?)
|
||||
assert_shape_equal(RubyVM.debug_shape(str), RubyVM.debug_shape(str2))
|
||||
assert_equal(str2.instance_variable_get(:@a), 1)
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue