mirror of
https://github.com/ruby/ruby.git
synced 2025-08-24 21:44:30 +02:00
Move object_id
in object fields.
And get rid of the `obj_to_id_tbl` It's no longer needed, the `object_id` is now stored inline in the object alongside instance variables. We still need the inverse table in case `_id2ref` is invoked, but we lazily build it by walking the heap if that happens. The `object_id` concern is also no longer a GC implementation concern, but a generic implementation. Co-Authored-By: Matt Valentine-House <matt@eightbitraptor.com>
This commit is contained in:
parent
d34c150547
commit
f48e45d1e9
Notes:
git
2025-05-08 05:58:19 +00:00
23 changed files with 1140 additions and 560 deletions
177
test/ruby/test_object_id.rb
Normal file
177
test/ruby/test_object_id.rb
Normal file
|
@ -0,0 +1,177 @@
|
|||
require 'test/unit'
|
||||
|
||||
class TestObjectId < Test::Unit::TestCase
|
||||
def setup
|
||||
@obj = Object.new
|
||||
end
|
||||
|
||||
def test_dup_new_id
|
||||
id = @obj.object_id
|
||||
refute_equal id, @obj.dup.object_id
|
||||
end
|
||||
|
||||
def test_dup_with_ivar_and_id
|
||||
id = @obj.object_id
|
||||
@obj.instance_variable_set(:@foo, 42)
|
||||
|
||||
copy = @obj.dup
|
||||
refute_equal id, copy.object_id
|
||||
assert_equal 42, copy.instance_variable_get(:@foo)
|
||||
end
|
||||
|
||||
def test_dup_with_id_and_ivar
|
||||
@obj.instance_variable_set(:@foo, 42)
|
||||
id = @obj.object_id
|
||||
|
||||
copy = @obj.dup
|
||||
refute_equal id, copy.object_id
|
||||
assert_equal 42, copy.instance_variable_get(:@foo)
|
||||
end
|
||||
|
||||
def test_dup_with_id_and_ivar_and_frozen
|
||||
@obj.instance_variable_set(:@foo, 42)
|
||||
@obj.freeze
|
||||
id = @obj.object_id
|
||||
|
||||
copy = @obj.dup
|
||||
refute_equal id, copy.object_id
|
||||
assert_equal 42, copy.instance_variable_get(:@foo)
|
||||
refute_predicate copy, :frozen?
|
||||
end
|
||||
|
||||
def test_clone_new_id
|
||||
id = @obj.object_id
|
||||
refute_equal id, @obj.clone.object_id
|
||||
end
|
||||
|
||||
def test_clone_with_ivar_and_id
|
||||
id = @obj.object_id
|
||||
@obj.instance_variable_set(:@foo, 42)
|
||||
|
||||
copy = @obj.clone
|
||||
refute_equal id, copy.object_id
|
||||
assert_equal 42, copy.instance_variable_get(:@foo)
|
||||
end
|
||||
|
||||
def test_clone_with_id_and_ivar
|
||||
@obj.instance_variable_set(:@foo, 42)
|
||||
id = @obj.object_id
|
||||
|
||||
copy = @obj.clone
|
||||
refute_equal id, copy.object_id
|
||||
assert_equal 42, copy.instance_variable_get(:@foo)
|
||||
end
|
||||
|
||||
def test_clone_with_id_and_ivar_and_frozen
|
||||
@obj.instance_variable_set(:@foo, 42)
|
||||
@obj.freeze
|
||||
id = @obj.object_id
|
||||
|
||||
copy = @obj.clone
|
||||
refute_equal id, copy.object_id
|
||||
assert_equal 42, copy.instance_variable_get(:@foo)
|
||||
assert_predicate copy, :frozen?
|
||||
end
|
||||
|
||||
def test_marshal_new_id
|
||||
return pass if @obj.is_a?(Module)
|
||||
|
||||
id = @obj.object_id
|
||||
refute_equal id, Marshal.load(Marshal.dump(@obj)).object_id
|
||||
end
|
||||
|
||||
def test_marshal_with_ivar_and_id
|
||||
return pass if @obj.is_a?(Module)
|
||||
|
||||
id = @obj.object_id
|
||||
@obj.instance_variable_set(:@foo, 42)
|
||||
|
||||
copy = Marshal.load(Marshal.dump(@obj))
|
||||
refute_equal id, copy.object_id
|
||||
assert_equal 42, copy.instance_variable_get(:@foo)
|
||||
end
|
||||
|
||||
def test_marshal_with_id_and_ivar
|
||||
return pass if @obj.is_a?(Module)
|
||||
|
||||
@obj.instance_variable_set(:@foo, 42)
|
||||
id = @obj.object_id
|
||||
|
||||
copy = Marshal.load(Marshal.dump(@obj))
|
||||
refute_equal id, copy.object_id
|
||||
assert_equal 42, copy.instance_variable_get(:@foo)
|
||||
end
|
||||
|
||||
def test_marshal_with_id_and_ivar_and_frozen
|
||||
return pass if @obj.is_a?(Module)
|
||||
|
||||
@obj.instance_variable_set(:@foo, 42)
|
||||
@obj.freeze
|
||||
id = @obj.object_id
|
||||
|
||||
copy = Marshal.load(Marshal.dump(@obj))
|
||||
refute_equal id, copy.object_id
|
||||
assert_equal 42, copy.instance_variable_get(:@foo)
|
||||
refute_predicate copy, :frozen?
|
||||
end
|
||||
end
|
||||
|
||||
class TestObjectIdClass < TestObjectId
|
||||
def setup
|
||||
@obj = Class.new
|
||||
end
|
||||
end
|
||||
|
||||
class TestObjectIdGeneric < TestObjectId
|
||||
def setup
|
||||
@obj = Array.new
|
||||
end
|
||||
end
|
||||
|
||||
class TestObjectIdTooComplex < TestObjectId
|
||||
class TooComplex
|
||||
end
|
||||
|
||||
def setup
|
||||
if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
|
||||
assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
|
||||
end
|
||||
8.times do |i|
|
||||
TooComplex.new.instance_variable_set("@a#{i}", 1)
|
||||
end
|
||||
@obj = TooComplex.new
|
||||
@obj.instance_variable_set(:@test, 1)
|
||||
end
|
||||
end
|
||||
|
||||
class TestObjectIdTooComplexClass < TestObjectId
|
||||
class TooComplex < Module
|
||||
end
|
||||
|
||||
def setup
|
||||
if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
|
||||
assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
|
||||
end
|
||||
8.times do |i|
|
||||
TooComplex.new.instance_variable_set("@a#{i}", 1)
|
||||
end
|
||||
@obj = TooComplex.new
|
||||
@obj.instance_variable_set(:@test, 1)
|
||||
end
|
||||
end
|
||||
|
||||
class TestObjectIdTooComplexGeneric < TestObjectId
|
||||
class TooComplex < Array
|
||||
end
|
||||
|
||||
def setup
|
||||
if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
|
||||
assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
|
||||
end
|
||||
8.times do |i|
|
||||
TooComplex.new.instance_variable_set("@a#{i}", 1)
|
||||
end
|
||||
@obj = TooComplex.new
|
||||
@obj.instance_variable_set(:@test, 1)
|
||||
end
|
||||
end
|
|
@ -622,6 +622,73 @@ class TestShapes < Test::Unit::TestCase
|
|||
end;
|
||||
end
|
||||
|
||||
def test_too_complex_and_frozen
|
||||
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
|
||||
begin;
|
||||
$VERBOSE = nil
|
||||
class TooComplex
|
||||
attr_reader :very_unique
|
||||
end
|
||||
|
||||
RubyVM::Shape::SHAPE_MAX_VARIATIONS.times do
|
||||
TooComplex.new.instance_variable_set(:"@unique_#{_1}", Object.new)
|
||||
end
|
||||
|
||||
tc = TooComplex.new
|
||||
tc.instance_variable_set(:"@very_unique", 3)
|
||||
|
||||
shape = RubyVM::Shape.of(tc)
|
||||
assert_predicate shape, :too_complex?
|
||||
refute_predicate shape, :shape_frozen?
|
||||
tc.freeze
|
||||
frozen_shape = RubyVM::Shape.of(tc)
|
||||
refute_equal shape.id, frozen_shape.id
|
||||
assert_predicate frozen_shape, :too_complex?
|
||||
assert_predicate frozen_shape, :shape_frozen?
|
||||
|
||||
assert_equal 3, tc.very_unique
|
||||
assert_equal 3, Ractor.make_shareable(tc).very_unique
|
||||
end;
|
||||
end
|
||||
|
||||
def test_too_complex_and_frozen_and_object_id
|
||||
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
|
||||
begin;
|
||||
$VERBOSE = nil
|
||||
class TooComplex
|
||||
attr_reader :very_unique
|
||||
end
|
||||
|
||||
RubyVM::Shape::SHAPE_MAX_VARIATIONS.times do
|
||||
TooComplex.new.instance_variable_set(:"@unique_#{_1}", Object.new)
|
||||
end
|
||||
|
||||
tc = TooComplex.new
|
||||
tc.instance_variable_set(:"@very_unique", 3)
|
||||
|
||||
shape = RubyVM::Shape.of(tc)
|
||||
assert_predicate shape, :too_complex?
|
||||
refute_predicate shape, :shape_frozen?
|
||||
tc.freeze
|
||||
frozen_shape = RubyVM::Shape.of(tc)
|
||||
refute_equal shape.id, frozen_shape.id
|
||||
assert_predicate frozen_shape, :too_complex?
|
||||
assert_predicate frozen_shape, :shape_frozen?
|
||||
refute_predicate frozen_shape, :has_object_id?
|
||||
|
||||
tc.object_id
|
||||
|
||||
id_shape = RubyVM::Shape.of(tc)
|
||||
refute_equal frozen_shape.id, id_shape.id
|
||||
assert_predicate id_shape, :too_complex?
|
||||
assert_predicate id_shape, :shape_frozen?
|
||||
assert_predicate id_shape, :has_object_id?
|
||||
|
||||
assert_equal 3, tc.very_unique
|
||||
assert_equal 3, Ractor.make_shareable(tc).very_unique
|
||||
end;
|
||||
end
|
||||
|
||||
def test_too_complex_obj_ivar_ractor_share
|
||||
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
|
||||
begin;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue