summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJemma Issroff <jemmaissroff@gmail.com>2022-10-03 11:14:32 -0400
committerAaron Patterson <tenderlove@ruby-lang.org>2022-10-11 08:40:56 -0700
commitad63b668e22e21c352b852f3119ae98a7acf99f1 (patch)
treecdaea65a9cae753a25f521c06d9d6a205085335f /test
parent5ffbb2be187681a37f2722ce1d7db4ec5c128464 (diff)
Revert "Revert "This commit implements the Object Shapes technique in CRuby.""
This reverts commit 9a6803c90b817f70389cae10d60b50ad752da48f.
Diffstat (limited to 'test')
-rw-r--r--test/-ext-/marshal/test_internal_ivar.rb1
-rw-r--r--test/ruby/test_mjit.rb4
-rw-r--r--test/ruby/test_object.rb9
-rw-r--r--test/ruby/test_shapes.rb173
4 files changed, 185 insertions, 2 deletions
diff --git a/test/-ext-/marshal/test_internal_ivar.rb b/test/-ext-/marshal/test_internal_ivar.rb
index a32138f6e8..9359c7f113 100644
--- a/test/-ext-/marshal/test_internal_ivar.rb
+++ b/test/-ext-/marshal/test_internal_ivar.rb
@@ -7,6 +7,7 @@ module Bug end
module Bug::Marshal
class TestInternalIVar < Test::Unit::TestCase
def test_marshal
+ pend "We don't support IVs with ID of 0"
v = InternalIVar.new("hello", "world", "bye")
assert_equal("hello", v.normal)
assert_equal("world", v.internal)
diff --git a/test/ruby/test_mjit.rb b/test/ruby/test_mjit.rb
index e49195f763..4c6cc6f39f 100644
--- a/test/ruby/test_mjit.rb
+++ b/test/ruby/test_mjit.rb
@@ -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
diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb
index 83208bbcdb..a9d5d4b13e 100644
--- a/test/ruby/test_object.rb
+++ b/test/ruby/test_object.rb
@@ -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
diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb
new file mode 100644
index 0000000000..807d485354
--- /dev/null
+++ b/test/ruby/test_shapes.rb
@@ -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