Skip to content

Commit 22dfb29

Browse files
committed
[GR-15739] Add the necessary write barriers for Array and Hash.
PullRequest: truffleruby/865
2 parents 8728a65 + 9dfbd58 commit 22dfb29

37 files changed

+671
-152
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Bug fixes:
1414
* Implemented `FFI::Pointer#clear` (#1687).
1515
* Procs will now yield to the block in their declaration context even when called with a block argument (#1657).
1616
* Fixed problems with calling POSIX methods if `Symbol#[]` is redefined (#1665).
17+
* Fixed sharing of `Array` and `Hash` elements for thread-safety of objects (#1601).
1718

1819
Compatibility
1920

lib/truffle/objspace.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,12 @@ def dump_all(output: :file)
154154
def memsize_of(object)
155155
size = Truffle::ObjSpace.memsize_of(object)
156156

157-
size + Truffle::ObjSpace.sizer(object).call unless Truffle::ObjSpace.sizer(object).nil?
157+
memsizer = Truffle::CExt.hidden_variable_get object, :data_memsizer
158+
if memsizer
159+
size + memsizer.call
160+
else
161+
size
162+
end
158163
end
159164
module_function :memsize_of
160165

lib/truffle/truffle/cext.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1449,8 +1449,10 @@ def rb_data_typed_object_wrap(ruby_class, data, data_type, mark, free, size)
14491449
data_holder = DataHolder.new(data)
14501450
hidden_variable_set object, :data_type, data_type
14511451
hidden_variable_set object, :data_holder, data_holder
1452+
hidden_variable_set object, :data_memsizer, data_sizer(size, data_holder) unless size.nil?
1453+
14521454
ObjectSpace.define_finalizer object, data_finalizer(free, data_holder) unless free.nil?
1453-
Truffle::ObjSpace.define_sizer object, data_sizer(size, data_holder) unless size.nil?
1455+
14541456
define_marker object, data_marker(mark, data_holder) unless mark.nil?
14551457
object
14561458
end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
require_relative '../../spec_helper'
2+
require 'objspace'
3+
4+
describe "ObjectSpace.memsize_of" do
5+
it "returns 0 for true, false and nil" do
6+
ObjectSpace.memsize_of(true).should == 0
7+
ObjectSpace.memsize_of(false).should == 0
8+
ObjectSpace.memsize_of(nil).should == 0
9+
end
10+
11+
it "returns 0 for small Integers" do
12+
ObjectSpace.memsize_of(42).should == 0
13+
end
14+
15+
it "returns an Integer for an Object" do
16+
obj = Object.new
17+
ObjectSpace.memsize_of(obj).should be_kind_of(Integer)
18+
ObjectSpace.memsize_of(obj).should > 0
19+
end
20+
21+
it "is larger if the Object has more instance variables" do
22+
obj = Object.new
23+
before = ObjectSpace.memsize_of(obj)
24+
100.times do |i|
25+
obj.instance_variable_set(:"@foo#{i}", nil)
26+
end
27+
after = ObjectSpace.memsize_of(obj)
28+
after.should > before
29+
end
30+
end
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
require_relative '../../spec_helper'
2+
require 'objspace'
3+
4+
describe "ObjectSpace.reachable_objects_from" do
5+
it "returns nil for true and false" do
6+
ObjectSpace.reachable_objects_from(true).should == nil
7+
ObjectSpace.reachable_objects_from(false).should == nil
8+
end
9+
10+
it "returns nil for nil" do
11+
ObjectSpace.reachable_objects_from(nil).should == nil
12+
end
13+
14+
it "returns nil for small Integers" do
15+
ObjectSpace.reachable_objects_from(42).should == nil
16+
end
17+
18+
it "enumerates objects directly reachable from a given object" do
19+
ObjectSpace.reachable_objects_from(['a', 'b', 'c']).should include(Array, 'a', 'b', 'c')
20+
ObjectSpace.reachable_objects_from(Object.new).should == [Object]
21+
end
22+
23+
it "finds an object stored in an Array" do
24+
obj = Object.new
25+
ary = [obj]
26+
reachable = ObjectSpace.reachable_objects_from(ary)
27+
reachable.should include(obj)
28+
end
29+
30+
it "finds an object stored in a copy-on-write Array" do
31+
removed = Object.new
32+
obj = Object.new
33+
ary = [removed, obj]
34+
ary.shift
35+
reachable = ObjectSpace.reachable_objects_from(ary)
36+
reachable.should include(obj)
37+
reachable.should_not include(removed)
38+
end
39+
40+
it "finds an object stored in a Queue" do
41+
require 'thread'
42+
o = Object.new
43+
q = Queue.new
44+
q << o
45+
46+
reachable = ObjectSpace.reachable_objects_from(q)
47+
reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) }
48+
reachable.should include(o)
49+
end
50+
51+
it "finds an object stored in a SizedQueue" do
52+
require 'thread'
53+
o = Object.new
54+
q = SizedQueue.new(3)
55+
q << o
56+
57+
reachable = ObjectSpace.reachable_objects_from(q)
58+
reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) }
59+
reachable.should include(o)
60+
end
61+
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fails:ObjectSpace.reachable_objects_from returns nil for nil

spec/truffle/objspace/reachable_objects_from_spec.rb

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@
1212

1313
describe "ObjectSpace.reachable_objects_from" do
1414

15-
# This is a standard method, but our implementation returns more objects so we keep this spec here
15+
# This is a standard method, but our implementation returns more objects so we add extra specs here
1616

17-
it "enumerates objects directly reachable from a given object" do
17+
it "returns [NilClass] for nil" do
1818
ObjectSpace.reachable_objects_from(nil).should == [NilClass]
19-
ObjectSpace.reachable_objects_from(['a', 'b', 'c']).should include(Array, 'a', 'b', 'c')
20-
ObjectSpace.reachable_objects_from(Object.new).should == [Object]
2119
end
2220

2321
it "finds the superclass and included/prepended modules of a class" do
@@ -46,26 +44,6 @@
4644
reachable.should include(captured)
4745
end
4846

49-
it "finds an object stored in a Queue" do
50-
require 'thread'
51-
o = Object.new
52-
q = Queue.new
53-
q << o
54-
55-
reachable = ObjectSpace.reachable_objects_from(q)
56-
reachable.should include(o)
57-
end
58-
59-
it "finds an object stored in a SizedQueue" do
60-
require 'thread'
61-
o = Object.new
62-
q = SizedQueue.new(3)
63-
q << o
64-
65-
reachable = ObjectSpace.reachable_objects_from(q)
66-
reachable.should include(o)
67-
end
68-
6947
it "finds finalizers" do
7048
object = Object.new
7149
finalizer = proc { }

0 commit comments

Comments
 (0)