1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <atomic>
6 #include <iostream>
7 #include <memory>
8
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
11 #include "third_party/blink/renderer/platform/heap/persistent.h"
12 #include "third_party/blink/renderer/platform/heap/visitor.h"
13 #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
14
15 namespace blink {
16
17 namespace {
18
19 class WeaknessMarkingTest : public TestSupportingGC {};
20
21 } // namespace
22
23 enum class ObjectLiveness { Alive = 0, Dead };
24
25 template <typename Map,
26 template <typename T>
27 class KeyHolder,
28 template <typename T>
29 class ValueHolder>
TestMapImpl(ObjectLiveness expected_key_liveness,ObjectLiveness expected_value_liveness)30 void TestMapImpl(ObjectLiveness expected_key_liveness,
31 ObjectLiveness expected_value_liveness) {
32 Persistent<Map> map = MakeGarbageCollected<Map>();
33 KeyHolder<IntegerObject> int_key = MakeGarbageCollected<IntegerObject>(1);
34 ValueHolder<IntegerObject> int_value = MakeGarbageCollected<IntegerObject>(2);
35 map->insert(int_key.Get(), int_value.Get());
36 TestSupportingGC::PreciselyCollectGarbage();
37 if (expected_key_liveness == ObjectLiveness::Alive) {
38 EXPECT_TRUE(int_key.Get());
39 } else {
40 EXPECT_FALSE(int_key.Get());
41 }
42 if (expected_value_liveness == ObjectLiveness::Alive) {
43 EXPECT_TRUE(int_value.Get());
44 } else {
45 EXPECT_FALSE(int_value.Get());
46 }
47 EXPECT_EQ(((expected_key_liveness == ObjectLiveness::Alive) &&
48 (expected_value_liveness == ObjectLiveness::Alive))
49 ? 1u
50 : 0u,
51 map->size());
52 }
53
TEST_F(WeaknessMarkingTest,WeakToWeakMap)54 TEST_F(WeaknessMarkingTest, WeakToWeakMap) {
55 using Map = HeapHashMap<WeakMember<IntegerObject>, WeakMember<IntegerObject>>;
56 TestMapImpl<Map, Persistent, Persistent>(ObjectLiveness::Alive,
57 ObjectLiveness::Alive);
58 TestMapImpl<Map, WeakPersistent, Persistent>(ObjectLiveness::Dead,
59 ObjectLiveness::Alive);
60 TestMapImpl<Map, Persistent, WeakPersistent>(ObjectLiveness::Alive,
61 ObjectLiveness::Dead);
62 TestMapImpl<Map, WeakPersistent, WeakPersistent>(ObjectLiveness::Dead,
63 ObjectLiveness::Dead);
64 }
65
TEST_F(WeaknessMarkingTest,WeakToStrongMap)66 TEST_F(WeaknessMarkingTest, WeakToStrongMap) {
67 using Map = HeapHashMap<WeakMember<IntegerObject>, Member<IntegerObject>>;
68 TestMapImpl<Map, Persistent, Persistent>(ObjectLiveness::Alive,
69 ObjectLiveness::Alive);
70 TestMapImpl<Map, WeakPersistent, Persistent>(ObjectLiveness::Dead,
71 ObjectLiveness::Alive);
72 TestMapImpl<Map, Persistent, WeakPersistent>(ObjectLiveness::Alive,
73 ObjectLiveness::Alive);
74 TestMapImpl<Map, WeakPersistent, WeakPersistent>(ObjectLiveness::Dead,
75 ObjectLiveness::Dead);
76 }
77
TEST_F(WeaknessMarkingTest,StrongToWeakMap)78 TEST_F(WeaknessMarkingTest, StrongToWeakMap) {
79 using Map = HeapHashMap<Member<IntegerObject>, WeakMember<IntegerObject>>;
80 TestMapImpl<Map, Persistent, Persistent>(ObjectLiveness::Alive,
81 ObjectLiveness::Alive);
82 TestMapImpl<Map, WeakPersistent, Persistent>(ObjectLiveness::Alive,
83 ObjectLiveness::Alive);
84 TestMapImpl<Map, Persistent, WeakPersistent>(ObjectLiveness::Alive,
85 ObjectLiveness::Dead);
86 TestMapImpl<Map, WeakPersistent, WeakPersistent>(ObjectLiveness::Dead,
87 ObjectLiveness::Dead);
88 }
89
TEST_F(WeaknessMarkingTest,StrongToStrongMap)90 TEST_F(WeaknessMarkingTest, StrongToStrongMap) {
91 using Map = HeapHashMap<Member<IntegerObject>, Member<IntegerObject>>;
92 TestMapImpl<Map, Persistent, Persistent>(ObjectLiveness::Alive,
93 ObjectLiveness::Alive);
94 TestMapImpl<Map, WeakPersistent, Persistent>(ObjectLiveness::Alive,
95 ObjectLiveness::Alive);
96 TestMapImpl<Map, Persistent, WeakPersistent>(ObjectLiveness::Alive,
97 ObjectLiveness::Alive);
98 TestMapImpl<Map, WeakPersistent, WeakPersistent>(ObjectLiveness::Alive,
99 ObjectLiveness::Alive);
100 }
101
102 template <typename Set, template <typename T> class Type>
TestSetImpl(ObjectLiveness object_liveness)103 void TestSetImpl(ObjectLiveness object_liveness) {
104 Persistent<Set> set = MakeGarbageCollected<Set>();
105 Type<IntegerObject> object = MakeGarbageCollected<IntegerObject>(1);
106 set->insert(object.Get());
107 TestSupportingGC::PreciselyCollectGarbage();
108 if (object_liveness == ObjectLiveness::Alive) {
109 EXPECT_TRUE(object.Get());
110 } else {
111 EXPECT_FALSE(object.Get());
112 }
113 EXPECT_EQ((object_liveness == ObjectLiveness::Alive) ? 1u : 0u, set->size());
114 }
115
TEST_F(WeaknessMarkingTest,WeakSet)116 TEST_F(WeaknessMarkingTest, WeakSet) {
117 using Set = HeapHashSet<WeakMember<IntegerObject>>;
118 TestSetImpl<Set, Persistent>(ObjectLiveness::Alive);
119 TestSetImpl<Set, WeakPersistent>(ObjectLiveness::Dead);
120 }
121
TEST_F(WeaknessMarkingTest,StrongSet)122 TEST_F(WeaknessMarkingTest, StrongSet) {
123 using Set = HeapHashSet<Member<IntegerObject>>;
124 TestSetImpl<Set, Persistent>(ObjectLiveness::Alive);
125 TestSetImpl<Set, WeakPersistent>(ObjectLiveness::Alive);
126 }
127
TEST_F(WeaknessMarkingTest,DeadValueInReverseEphemeron)128 TEST_F(WeaknessMarkingTest, DeadValueInReverseEphemeron) {
129 using Map = HeapHashMap<Member<IntegerObject>, WeakMember<IntegerObject>>;
130 Persistent<Map> map = MakeGarbageCollected<Map>();
131 Persistent<IntegerObject> key = MakeGarbageCollected<IntegerObject>(1);
132 map->insert(key.Get(), MakeGarbageCollected<IntegerObject>(2));
133 EXPECT_EQ(1u, map->size());
134 TestSupportingGC::PreciselyCollectGarbage();
135 // Entries with dead values are removed.
136 EXPECT_EQ(0u, map->size());
137 }
138
TEST_F(WeaknessMarkingTest,NullValueInReverseEphemeron)139 TEST_F(WeaknessMarkingTest, NullValueInReverseEphemeron) {
140 using Map = HeapHashMap<Member<IntegerObject>, WeakMember<IntegerObject>>;
141 Persistent<Map> map = MakeGarbageCollected<Map>();
142 Persistent<IntegerObject> key = MakeGarbageCollected<IntegerObject>(1);
143 map->insert(key.Get(), nullptr);
144 EXPECT_EQ(1u, map->size());
145 TestSupportingGC::PreciselyCollectGarbage();
146 // Entries with null values are kept.
147 EXPECT_EQ(1u, map->size());
148 }
149
150 namespace weakness_marking_test {
151
152 class EphemeronCallbacksCounter
153 : public GarbageCollected<EphemeronCallbacksCounter> {
154 public:
EphemeronCallbacksCounter(size_t * count_holder)155 EphemeronCallbacksCounter(size_t* count_holder)
156 : count_holder_(count_holder) {}
157
Trace(Visitor * visitor)158 void Trace(Visitor* visitor) {
159 visitor->RegisterWeakCallbackMethod<EphemeronCallbacksCounter,
160 &EphemeronCallbacksCounter::Callback>(
161 this);
162 }
163
Callback(const WeakCallbackInfo & info)164 void Callback(const WeakCallbackInfo& info) {
165 *count_holder_ = ThreadState::Current()->Heap().ephemeron_callbacks_.size();
166 }
167
168 private:
169 size_t* count_holder_;
170 };
171
TEST_F(WeaknessMarkingTest,UntracableEphemeronIsNotRegsitered)172 TEST_F(WeaknessMarkingTest, UntracableEphemeronIsNotRegsitered) {
173 size_t ephemeron_count;
174 Persistent<EphemeronCallbacksCounter> ephemeron_callbacks_counter =
175 MakeGarbageCollected<EphemeronCallbacksCounter>(&ephemeron_count);
176 TestSupportingGC::PreciselyCollectGarbage();
177 size_t old_ephemeron_count = ephemeron_count;
178 using Map = HeapHashMap<WeakMember<IntegerObject>, int>;
179 Persistent<Map> map = MakeGarbageCollected<Map>();
180 map->insert(MakeGarbageCollected<IntegerObject>(1), 2);
181 TestSupportingGC::PreciselyCollectGarbage();
182 // Ephemeron value is not traceable, thus the map shouldn't be treated as an
183 // ephemeron.
184 EXPECT_EQ(old_ephemeron_count, ephemeron_count);
185 }
186
TEST_F(WeaknessMarkingTest,TracableEphemeronIsRegsitered)187 TEST_F(WeaknessMarkingTest, TracableEphemeronIsRegsitered) {
188 size_t ephemeron_count;
189 Persistent<EphemeronCallbacksCounter> ephemeron_callbacks_counter =
190 MakeGarbageCollected<EphemeronCallbacksCounter>(&ephemeron_count);
191 TestSupportingGC::PreciselyCollectGarbage();
192 size_t old_ephemeron_count = ephemeron_count;
193 using Map = HeapHashMap<WeakMember<IntegerObject>, Member<IntegerObject>>;
194 Persistent<Map> map = MakeGarbageCollected<Map>();
195 map->insert(MakeGarbageCollected<IntegerObject>(1),
196 MakeGarbageCollected<IntegerObject>(2));
197 TestSupportingGC::PreciselyCollectGarbage();
198 EXPECT_NE(old_ephemeron_count, ephemeron_count);
199 }
200
201 // TODO(keinakashima): add tests for NewLinkedHashSet after supporting
202 // WeakMember
TEST_F(WeaknessMarkingTest,SwapIntoAlreadyProcessedWeakSet)203 TEST_F(WeaknessMarkingTest, SwapIntoAlreadyProcessedWeakSet) {
204 // Regression test: https://crbug.com/1038623
205 //
206 // Test ensures that an empty weak set that has already been marked sets up
207 // weakness callbacks. This is important as another backing may be swapped in
208 // at some point after marking it initially.
209 using WeakLinkedSet = HeapLinkedHashSet<WeakMember<IntegerObject>>;
210 Persistent<WeakLinkedSet> holder1(MakeGarbageCollected<WeakLinkedSet>());
211 Persistent<WeakLinkedSet> holder2(MakeGarbageCollected<WeakLinkedSet>());
212 holder1->insert(MakeGarbageCollected<IntegerObject>(1));
213 IncrementalMarkingTestDriver driver(ThreadState::Current());
214 driver.Start();
215 driver.FinishSteps();
216 holder1->Swap(*holder2.Get());
217 driver.FinishGC();
218 }
219
TEST_F(WeaknessMarkingTest,EmptyEphemeronCollection)220 TEST_F(WeaknessMarkingTest, EmptyEphemeronCollection) {
221 // Tests that an empty ephemeron collection does not crash in the GC when
222 // processing a non-existent backing store.
223 using Map = HeapHashMap<Member<IntegerObject>, WeakMember<IntegerObject>>;
224 Persistent<Map> map = MakeGarbageCollected<Map>();
225 TestSupportingGC::PreciselyCollectGarbage();
226 }
227
TEST_F(WeaknessMarkingTest,ClearWeakHashTableAfterMarking)228 TEST_F(WeaknessMarkingTest, ClearWeakHashTableAfterMarking) {
229 // Regression test: https://crbug.com/1054363
230 //
231 // Test ensures that no marked backing with weak pointers to dead object is
232 // left behind after marking. The test creates a backing that is floating
233 // garbage. The marking verifier ensures that all buckets are properly
234 // deleted.
235 using Set = HeapHashSet<WeakMember<IntegerObject>>;
236 Persistent<Set> holder(MakeGarbageCollected<Set>());
237 holder->insert(MakeGarbageCollected<IntegerObject>(1));
238 IncrementalMarkingTestDriver driver(ThreadState::Current());
239 driver.Start();
240 driver.FinishSteps();
241 holder->clear();
242 driver.FinishGC();
243 }
244
245 } // namespace weakness_marking_test
246
247 } // namespace blink
248