1 // Copyright 2017 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 <initializer_list>
6 
7 #include "base/bind.h"
8 #include "base/test/scoped_feature_list.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/blink/public/common/features.h"
11 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
12 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
13 #include "third_party/blink/renderer/platform/heap/heap.h"
14 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
15 #include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
16 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
17 #include "third_party/blink/renderer/platform/heap/impl/heap_compact.h"
18 #include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
19 #include "third_party/blink/renderer/platform/heap/member.h"
20 #include "third_party/blink/renderer/platform/heap/persistent.h"
21 #include "third_party/blink/renderer/platform/heap/thread_state.h"
22 #include "third_party/blink/renderer/platform/heap/visitor.h"
23 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
24 
25 namespace blink {
26 
27 class IncrementalMarkingTest : public TestSupportingGC {};
28 
29 namespace incremental_marking_test {
30 
31 // Visitor that expects every directly reachable object from a given backing
32 // store to be in the set of provided objects.
33 class BackingVisitor : public Visitor {
34  public:
BackingVisitor(ThreadState * state,Vector<void * > * objects)35   BackingVisitor(ThreadState* state, Vector<void*>* objects)
36       : Visitor(state), objects_(objects) {}
~BackingVisitor()37   ~BackingVisitor() final {}
38 
ProcessBackingStore(HeapObjectHeader * header)39   void ProcessBackingStore(HeapObjectHeader* header) {
40     EXPECT_TRUE(header->IsMarked());
41     header->Unmark();
42 
43     GCInfo::From(header->GcInfoIndex()).trace(this, header->Payload());
44   }
45 
Visit(const void * obj,TraceDescriptor desc)46   void Visit(const void* obj, TraceDescriptor desc) final {
47     EXPECT_TRUE(obj);
48     auto** pos = std::find(objects_->begin(), objects_->end(), obj);
49     if (objects_->end() != pos)
50       objects_->erase(pos);
51     // The garbage collector will find those objects so we can mark them.
52     HeapObjectHeader* const header =
53         HeapObjectHeader::FromPayload(desc.base_object_payload);
54     if (!header->IsMarked())
55       EXPECT_TRUE(header->TryMark());
56   }
57 
VisitEphemeron(const void * key,TraceDescriptor value_desc)58   void VisitEphemeron(const void* key, TraceDescriptor value_desc) final {
59     if (!HeapObjectHeader::FromPayload(key)->IsMarked())
60       return;
61     value_desc.callback(this, value_desc.base_object_payload);
62   }
63 
64  private:
65   Vector<void*>* objects_;
66 };
67 
68 // Base class for initializing worklists.
69 class IncrementalMarkingScopeBase {
70   DISALLOW_NEW();
71 
72  public:
IncrementalMarkingScopeBase(ThreadState * thread_state)73   explicit IncrementalMarkingScopeBase(ThreadState* thread_state)
74       : thread_state_(thread_state), heap_(thread_state_->Heap()) {
75     if (thread_state_->IsMarkingInProgress() ||
76         thread_state_->IsSweepingInProgress()) {
77       TestSupportingGC::PreciselyCollectGarbage();
78     }
79     heap_.SetupWorklists(false);
80   }
81 
~IncrementalMarkingScopeBase()82   ~IncrementalMarkingScopeBase() {
83     heap_.DestroyMarkingWorklists(BlinkGC::StackState::kNoHeapPointersOnStack);
84     heap_.DestroyCompactionWorklists();
85   }
86 
heap() const87   ThreadHeap& heap() const { return heap_; }
88 
89  protected:
90   ThreadState* const thread_state_;
91   ThreadHeap& heap_;
92 };
93 
94 class IncrementalMarkingScope : public IncrementalMarkingScopeBase {
95   STACK_ALLOCATED();
96 
97  public:
IncrementalMarkingScope(ThreadState * thread_state)98   explicit IncrementalMarkingScope(ThreadState* thread_state)
99       : IncrementalMarkingScopeBase(thread_state),
100         gc_forbidden_scope_(thread_state),
101         marking_worklist_(heap_.GetMarkingWorklist()),
102         write_barrier_worklist_(heap_.GetWriteBarrierWorklist()),
103         not_fully_constructed_worklist_(
104             heap_.GetNotFullyConstructedWorklist()) {
105     thread_state_->SetGCPhase(ThreadState::GCPhase::kMarking);
106     ThreadState::AtomicPauseScope atomic_pause_scope_(thread_state_);
107     ScriptForbiddenScope script_forbidden_scope;
108     EXPECT_TRUE(marking_worklist_->IsGlobalEmpty());
109     EXPECT_TRUE(write_barrier_worklist_->IsGlobalEmpty());
110     EXPECT_TRUE(not_fully_constructed_worklist_->IsGlobalEmpty());
111     thread_state->EnableIncrementalMarkingBarrier();
112     thread_state->current_gc_data_.visitor = std::make_unique<MarkingVisitor>(
113         thread_state, MarkingVisitor::kGlobalMarking);
114   }
115 
~IncrementalMarkingScope()116   ~IncrementalMarkingScope() {
117     EXPECT_TRUE(marking_worklist_->IsGlobalEmpty());
118     EXPECT_TRUE(write_barrier_worklist_->IsGlobalEmpty());
119     EXPECT_TRUE(not_fully_constructed_worklist_->IsGlobalEmpty());
120     thread_state_->DisableIncrementalMarkingBarrier();
121     // Need to clear out unused worklists that might have been polluted during
122     // test.
123     heap_.GetWeakCallbackWorklist()->Clear();
124     thread_state_->SetGCPhase(ThreadState::GCPhase::kSweeping);
125     thread_state_->SetGCPhase(ThreadState::GCPhase::kNone);
126   }
127 
marking_worklist() const128   MarkingWorklist* marking_worklist() const { return marking_worklist_; }
write_barrier_worklist() const129   WriteBarrierWorklist* write_barrier_worklist() const {
130     return write_barrier_worklist_;
131   }
not_fully_constructed_worklist() const132   NotFullyConstructedWorklist* not_fully_constructed_worklist() const {
133     return not_fully_constructed_worklist_;
134   }
135 
136  protected:
137   ThreadState::GCForbiddenScope gc_forbidden_scope_;
138   MarkingWorklist* const marking_worklist_;
139   WriteBarrierWorklist* const write_barrier_worklist_;
140   NotFullyConstructedWorklist* const not_fully_constructed_worklist_;
141 };
142 
143 // Expects that the write barrier fires for the objects passed to the
144 // constructor. This requires that the objects are added to the marking stack
145 // as well as headers being marked.
146 class ExpectWriteBarrierFires : public IncrementalMarkingScope {
147  public:
ExpectWriteBarrierFires(ThreadState * thread_state,std::initializer_list<void * > objects)148   ExpectWriteBarrierFires(ThreadState* thread_state,
149                           std::initializer_list<void*> objects)
150       : IncrementalMarkingScope(thread_state),
151         objects_(objects),
152         backing_visitor_(thread_state_, &objects_) {
153     EXPECT_TRUE(marking_worklist_->IsGlobalEmpty());
154     EXPECT_TRUE(write_barrier_worklist_->IsGlobalEmpty());
155     for (void* object : objects_) {
156       // Ensure that the object is in the normal arena so we can ignore backing
157       // objects on the marking stack.
158       CHECK(ThreadHeap::IsNormalArenaIndex(
159           PageFromObject(object)->Arena()->ArenaIndex()));
160       headers_.push_back(HeapObjectHeader::FromPayload(object));
161       EXPECT_FALSE(headers_.back()->IsMarked());
162     }
163     EXPECT_FALSE(objects_.IsEmpty());
164   }
165 
~ExpectWriteBarrierFires()166   ~ExpectWriteBarrierFires() {
167     // All objects watched should be on the marking or write barrier worklist.
168     MarkingItem item;
169     while (marking_worklist_->Pop(WorklistTaskId::MutatorThread, &item)) {
170       // Inspect backing stores to allow specifying objects that are only
171       // reachable through a backing store.
172       if (!ThreadHeap::IsNormalArenaIndex(
173               PageFromObject(item.base_object_payload)
174                   ->Arena()
175                   ->ArenaIndex())) {
176         backing_visitor_.ProcessBackingStore(
177             HeapObjectHeader::FromPayload(item.base_object_payload));
178         continue;
179       }
180       auto** pos =
181           std::find(objects_.begin(), objects_.end(), item.base_object_payload);
182       if (objects_.end() != pos)
183         objects_.erase(pos);
184     }
185     HeapObjectHeader* header;
186     while (
187         write_barrier_worklist_->Pop(WorklistTaskId::MutatorThread, &header)) {
188       // Inspect backing stores to allow specifying objects that are only
189       // reachable through a backing store.
190       if (!ThreadHeap::IsNormalArenaIndex(
191               PageFromObject(header->Payload())->Arena()->ArenaIndex())) {
192         backing_visitor_.ProcessBackingStore(header);
193         continue;
194       }
195       auto** pos =
196           std::find(objects_.begin(), objects_.end(), header->Payload());
197       if (objects_.end() != pos)
198         objects_.erase(pos);
199     }
200     EXPECT_TRUE(objects_.IsEmpty());
201     // All headers of objects watched should be marked at this point.
202     for (HeapObjectHeader* header : headers_) {
203       EXPECT_TRUE(header->IsMarked());
204       header->Unmark();
205     }
206     EXPECT_TRUE(marking_worklist_->IsGlobalEmpty());
207     EXPECT_TRUE(write_barrier_worklist_->IsGlobalEmpty());
208   }
209 
210  private:
211   Vector<void*> objects_;
212   Vector<HeapObjectHeader*> headers_;
213   BackingVisitor backing_visitor_;
214 };
215 
216 // Expects that no write barrier fires for the objects passed to the
217 // constructor. This requires that the marking stack stays empty and the marking
218 // state of the object stays the same across the lifetime of the scope.
219 class ExpectNoWriteBarrierFires : public IncrementalMarkingScope {
220  public:
ExpectNoWriteBarrierFires(ThreadState * thread_state,std::initializer_list<void * > objects)221   ExpectNoWriteBarrierFires(ThreadState* thread_state,
222                             std::initializer_list<void*> objects)
223       : IncrementalMarkingScope(thread_state) {
224     EXPECT_TRUE(marking_worklist_->IsGlobalEmpty());
225     EXPECT_TRUE(write_barrier_worklist_->IsGlobalEmpty());
226     for (void* object : objects) {
227       HeapObjectHeader* header = HeapObjectHeader::FromPayload(object);
228       headers_.push_back(std::make_pair(header, header->IsMarked()));
229     }
230   }
231 
~ExpectNoWriteBarrierFires()232   ~ExpectNoWriteBarrierFires() {
233     EXPECT_TRUE(marking_worklist_->IsGlobalEmpty());
234     EXPECT_TRUE(write_barrier_worklist_->IsGlobalEmpty());
235     for (const auto& pair : headers_) {
236       EXPECT_EQ(pair.second, pair.first->IsMarked());
237       pair.first->Unmark();
238     }
239   }
240 
241  private:
242   Vector<std::pair<HeapObjectHeader*, bool /* was marked */>> headers_;
243 };
244 
245 class Object : public LinkedObject {
246  public:
247   Object() = default;
Object(Object * next)248   explicit Object(Object* next) : LinkedObject(next) {}
249 
IsMarked() const250   bool IsMarked() const {
251     return HeapObjectHeader::FromPayload(this)->IsMarked();
252   }
253 
Trace(Visitor * visitor) const254   void Trace(Visitor* visitor) const override { LinkedObject::Trace(visitor); }
255 };
256 
257 class ObjectWithWriteBarrier : public GarbageCollected<ObjectWithWriteBarrier> {
258  public:
Trace(Visitor * v) const259   void Trace(Visitor* v) const { v->Trace(object_); }
260 
Set(Object * object)261   void Set(Object* object) { object_ = object; }
262 
263  private:
264   Member<Object> object_;
265 };
266 
267 // =============================================================================
268 // Basic infrastructure support. ===============================================
269 // =============================================================================
270 
TEST_F(IncrementalMarkingTest,EnableDisableBarrier)271 TEST_F(IncrementalMarkingTest, EnableDisableBarrier) {
272   EXPECT_FALSE(ThreadState::Current()->IsIncrementalMarking());
273   ThreadState::Current()->EnableIncrementalMarkingBarrier();
274   EXPECT_TRUE(ThreadState::Current()->IsIncrementalMarking());
275   EXPECT_TRUE(ThreadState::IsAnyIncrementalMarking());
276   ThreadState::Current()->DisableIncrementalMarkingBarrier();
277   EXPECT_FALSE(ThreadState::Current()->IsIncrementalMarking());
278 }
279 
TEST_F(IncrementalMarkingTest,WriteBarrierTriggersWhenMarkingIsOn)280 TEST_F(IncrementalMarkingTest, WriteBarrierTriggersWhenMarkingIsOn) {
281   auto* object1 = MakeGarbageCollected<Object>();
282   auto* object2 = MakeGarbageCollected<ObjectWithWriteBarrier>();
283   {
284     ExpectWriteBarrierFires scope(ThreadState::Current(), {object1});
285     EXPECT_FALSE(object1->IsMarked());
286     object2->Set(object1);
287     EXPECT_TRUE(object1->IsMarked());
288   }
289 }
290 
TEST_F(IncrementalMarkingTest,WriteBarrierBailoutWhenMarkingIsOff)291 TEST_F(IncrementalMarkingTest, WriteBarrierBailoutWhenMarkingIsOff) {
292   auto* object1 = MakeGarbageCollected<Object>();
293   auto* object2 = MakeGarbageCollected<ObjectWithWriteBarrier>();
294   EXPECT_FALSE(object1->IsMarked());
295   object2->Set(object1);
296   EXPECT_FALSE(object1->IsMarked());
297 }
298 
299 // =============================================================================
300 // Member<T> support. ==========================================================
301 // =============================================================================
302 
TEST_F(IncrementalMarkingTest,MemberSetUnmarkedObject)303 TEST_F(IncrementalMarkingTest, MemberSetUnmarkedObject) {
304   auto* parent = MakeGarbageCollected<Object>();
305   auto* child = MakeGarbageCollected<Object>();
306   {
307     ExpectWriteBarrierFires scope(ThreadState::Current(), {child});
308     EXPECT_FALSE(child->IsMarked());
309     parent->set_next(child);
310     EXPECT_TRUE(child->IsMarked());
311   }
312 }
313 
TEST_F(IncrementalMarkingTest,MemberSetMarkedObjectNoBarrier)314 TEST_F(IncrementalMarkingTest, MemberSetMarkedObjectNoBarrier) {
315   auto* parent = MakeGarbageCollected<Object>();
316   auto* child = MakeGarbageCollected<Object>();
317   EXPECT_TRUE(HeapObjectHeader::FromPayload(child)->TryMark());
318   {
319     ExpectNoWriteBarrierFires scope(ThreadState::Current(), {child});
320     parent->set_next(child);
321   }
322 }
323 
TEST_F(IncrementalMarkingTest,MemberInitializingStoreNoBarrier)324 TEST_F(IncrementalMarkingTest, MemberInitializingStoreNoBarrier) {
325   auto* object1 = MakeGarbageCollected<Object>();
326   HeapObjectHeader* object1_header = HeapObjectHeader::FromPayload(object1);
327   {
328     IncrementalMarkingScope scope(ThreadState::Current());
329     EXPECT_FALSE(object1_header->IsMarked());
330     auto* object2 = MakeGarbageCollected<Object>(object1);
331     HeapObjectHeader* object2_header = HeapObjectHeader::FromPayload(object2);
332     EXPECT_FALSE(object1_header->IsMarked());
333     EXPECT_FALSE(object2_header->IsMarked());
334   }
335 }
336 
TEST_F(IncrementalMarkingTest,MemberReferenceAssignMember)337 TEST_F(IncrementalMarkingTest, MemberReferenceAssignMember) {
338   auto* obj = MakeGarbageCollected<LinkedObject>();
339   auto* ref_obj = MakeGarbageCollected<LinkedObject>();
340   Member<LinkedObject>& m2 = ref_obj->next_ref();
341   Member<LinkedObject> m3(obj);
342   {
343     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
344     m2 = m3;
345   }
346 }
347 
TEST_F(IncrementalMarkingTest,MemberSetDeletedValueNoBarrier)348 TEST_F(IncrementalMarkingTest, MemberSetDeletedValueNoBarrier) {
349   auto* obj = MakeGarbageCollected<LinkedObject>();
350   Member<LinkedObject>& m = obj->next_ref();
351   {
352     ExpectNoWriteBarrierFires scope(ThreadState::Current(), {});
353     m = WTF::kHashTableDeletedValue;
354   }
355 }
356 
TEST_F(IncrementalMarkingTest,MemberCopyDeletedValueNoBarrier)357 TEST_F(IncrementalMarkingTest, MemberCopyDeletedValueNoBarrier) {
358   auto* obj1 = MakeGarbageCollected<LinkedObject>();
359   Member<LinkedObject>& m1 = obj1->next_ref();
360   m1 = WTF::kHashTableDeletedValue;
361   {
362     ExpectNoWriteBarrierFires scope(ThreadState::Current(), {});
363     auto* obj2 = MakeGarbageCollected<LinkedObject>();
364     obj2->next_ref() = m1;
365   }
366 }
367 
TEST_F(IncrementalMarkingTest,MemberHashTraitConstructDeletedValueNoBarrier)368 TEST_F(IncrementalMarkingTest, MemberHashTraitConstructDeletedValueNoBarrier) {
369   auto* obj = MakeGarbageCollected<LinkedObject>();
370   Member<LinkedObject>& m = obj->next_ref();
371   {
372     ExpectNoWriteBarrierFires scope(ThreadState::Current(), {});
373     HashTraits<Member<LinkedObject>>::ConstructDeletedValue(m, false);
374   }
375 }
376 
TEST_F(IncrementalMarkingTest,MemberHashTraitIsDeletedValueNoBarrier)377 TEST_F(IncrementalMarkingTest, MemberHashTraitIsDeletedValueNoBarrier) {
378   auto* obj =
379       MakeGarbageCollected<LinkedObject>(MakeGarbageCollected<LinkedObject>());
380   Member<LinkedObject>& m = obj->next_ref();
381   {
382     ExpectNoWriteBarrierFires scope(ThreadState::Current(), {});
383     EXPECT_FALSE(HashTraits<Member<LinkedObject>>::IsDeletedValue(m));
384   }
385 }
386 
387 // =============================================================================
388 // Mixin support. ==============================================================
389 // =============================================================================
390 
391 namespace {
392 
393 class Mixin : public GarbageCollectedMixin {
394  public:
Mixin()395   Mixin() : next_(nullptr) {}
~Mixin()396   virtual ~Mixin() {}
397 
Trace(Visitor * visitor) const398   void Trace(Visitor* visitor) const override { visitor->Trace(next_); }
399 
Bar()400   virtual void Bar() {}
401 
402  protected:
403   Member<Object> next_;
404 };
405 
406 class ClassWithVirtual {
407  protected:
Foo()408   virtual void Foo() {}
409 };
410 
411 class Child : public GarbageCollected<Child>,
412               public ClassWithVirtual,
413               public Mixin {
414  public:
Child()415   Child() : ClassWithVirtual(), Mixin() {}
~Child()416   ~Child() override {}
417 
Trace(Visitor * visitor) const418   void Trace(Visitor* visitor) const override { Mixin::Trace(visitor); }
419 
Foo()420   void Foo() override {}
Bar()421   void Bar() override {}
422 };
423 
424 class ParentWithMixinPointer : public GarbageCollected<ParentWithMixinPointer> {
425  public:
ParentWithMixinPointer()426   ParentWithMixinPointer() : mixin_(nullptr) {}
427 
set_mixin(Mixin * mixin)428   void set_mixin(Mixin* mixin) { mixin_ = mixin; }
429 
Trace(Visitor * visitor) const430   virtual void Trace(Visitor* visitor) const { visitor->Trace(mixin_); }
431 
432  protected:
433   Member<Mixin> mixin_;
434 };
435 
436 }  // namespace
437 
TEST_F(IncrementalMarkingTest,WriteBarrierOnUnmarkedMixinApplication)438 TEST_F(IncrementalMarkingTest, WriteBarrierOnUnmarkedMixinApplication) {
439   ParentWithMixinPointer* parent =
440       MakeGarbageCollected<ParentWithMixinPointer>();
441   auto* child = MakeGarbageCollected<Child>();
442   Mixin* mixin = static_cast<Mixin*>(child);
443   EXPECT_NE(static_cast<void*>(child), static_cast<void*>(mixin));
444   {
445     ExpectWriteBarrierFires scope(ThreadState::Current(), {child});
446     parent->set_mixin(mixin);
447   }
448 }
449 
TEST_F(IncrementalMarkingTest,NoWriteBarrierOnMarkedMixinApplication)450 TEST_F(IncrementalMarkingTest, NoWriteBarrierOnMarkedMixinApplication) {
451   ParentWithMixinPointer* parent =
452       MakeGarbageCollected<ParentWithMixinPointer>();
453   auto* child = MakeGarbageCollected<Child>();
454   EXPECT_TRUE(HeapObjectHeader::FromPayload(child)->TryMark());
455   Mixin* mixin = static_cast<Mixin*>(child);
456   EXPECT_NE(static_cast<void*>(child), static_cast<void*>(mixin));
457   {
458     ExpectNoWriteBarrierFires scope(ThreadState::Current(), {child});
459     parent->set_mixin(mixin);
460   }
461 }
462 
463 // =============================================================================
464 // HeapVector support. =========================================================
465 // =============================================================================
466 
467 namespace {
468 
469 // HeapVector allows for insertion of container objects that can be traced but
470 // are themselves non-garbage collected.
471 class NonGarbageCollectedContainer {
472   DISALLOW_NEW();
473 
474  public:
NonGarbageCollectedContainer(Object * obj,int y)475   NonGarbageCollectedContainer(Object* obj, int y) : obj_(obj), y_(y) {}
476 
~NonGarbageCollectedContainer()477   virtual ~NonGarbageCollectedContainer() {}
Trace(Visitor * visitor) const478   virtual void Trace(Visitor* visitor) const { visitor->Trace(obj_); }
479 
480  private:
481   Member<Object> obj_;
482   int y_;
483 };
484 
485 class NonGarbageCollectedContainerRoot {
486   DISALLOW_NEW();
487 
488  public:
NonGarbageCollectedContainerRoot(Object * obj1,Object * obj2,int y)489   NonGarbageCollectedContainerRoot(Object* obj1, Object* obj2, int y)
490       : next_(obj1, y), obj_(obj2) {}
~NonGarbageCollectedContainerRoot()491   virtual ~NonGarbageCollectedContainerRoot() {}
492 
Trace(Visitor * visitor) const493   virtual void Trace(Visitor* visitor) const {
494     visitor->Trace(next_);
495     visitor->Trace(obj_);
496   }
497 
498  private:
499   NonGarbageCollectedContainer next_;
500   Member<Object> obj_;
501 };
502 
503 }  // namespace
504 
TEST_F(IncrementalMarkingTest,HeapVectorPushBackMember)505 TEST_F(IncrementalMarkingTest, HeapVectorPushBackMember) {
506   auto* obj = MakeGarbageCollected<Object>();
507   auto* vec = MakeGarbageCollected<HeapVector<Member<Object>>>();
508   {
509     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
510     vec->push_back(obj);
511   }
512 }
513 
TEST_F(IncrementalMarkingTest,HeapVectorPushBackNonGCedContainer)514 TEST_F(IncrementalMarkingTest, HeapVectorPushBackNonGCedContainer) {
515   auto* obj = MakeGarbageCollected<Object>();
516   auto* vec = MakeGarbageCollected<HeapVector<NonGarbageCollectedContainer>>();
517   {
518     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
519     vec->push_back(NonGarbageCollectedContainer(obj, 1));
520   }
521 }
522 
TEST_F(IncrementalMarkingTest,HeapVectorPushBackStdPair)523 TEST_F(IncrementalMarkingTest, HeapVectorPushBackStdPair) {
524   auto* obj1 = MakeGarbageCollected<Object>();
525   auto* obj2 = MakeGarbageCollected<Object>();
526   auto* vec = MakeGarbageCollected<
527       HeapVector<std::pair<Member<Object>, Member<Object>>>>();
528   {
529     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
530     vec->push_back(std::make_pair(Member<Object>(obj1), Member<Object>(obj2)));
531   }
532 }
533 
TEST_F(IncrementalMarkingTest,HeapVectorEmplaceBackMember)534 TEST_F(IncrementalMarkingTest, HeapVectorEmplaceBackMember) {
535   auto* obj = MakeGarbageCollected<Object>();
536   auto* vec = MakeGarbageCollected<HeapVector<Member<Object>>>();
537   {
538     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
539     vec->emplace_back(obj);
540   }
541 }
542 
TEST_F(IncrementalMarkingTest,HeapVectorEmplaceBackNonGCedContainer)543 TEST_F(IncrementalMarkingTest, HeapVectorEmplaceBackNonGCedContainer) {
544   auto* obj = MakeGarbageCollected<Object>();
545   auto* vec = MakeGarbageCollected<HeapVector<NonGarbageCollectedContainer>>();
546   {
547     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
548     vec->emplace_back(obj, 1);
549   }
550 }
551 
TEST_F(IncrementalMarkingTest,HeapVectorEmplaceBackStdPair)552 TEST_F(IncrementalMarkingTest, HeapVectorEmplaceBackStdPair) {
553   auto* obj1 = MakeGarbageCollected<Object>();
554   auto* obj2 = MakeGarbageCollected<Object>();
555   auto* vec = MakeGarbageCollected<
556       HeapVector<std::pair<Member<Object>, Member<Object>>>>();
557   {
558     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
559     vec->emplace_back(obj1, obj2);
560   }
561 }
562 
TEST_F(IncrementalMarkingTest,HeapVectorCopyMember)563 TEST_F(IncrementalMarkingTest, HeapVectorCopyMember) {
564   auto* object = MakeGarbageCollected<Object>();
565   auto* vec1 = MakeGarbageCollected<HeapVector<Member<Object>>>();
566   vec1->push_back(object);
567   {
568     ExpectWriteBarrierFires scope(ThreadState::Current(), {object});
569     MakeGarbageCollected<HeapVector<Member<Object>>>(*vec1);
570   }
571 }
572 
TEST_F(IncrementalMarkingTest,HeapVectorCopyNonGCedContainer)573 TEST_F(IncrementalMarkingTest, HeapVectorCopyNonGCedContainer) {
574   auto* obj = MakeGarbageCollected<Object>();
575   auto* vec1 = MakeGarbageCollected<HeapVector<NonGarbageCollectedContainer>>();
576   vec1->emplace_back(obj, 1);
577   {
578     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
579     MakeGarbageCollected<HeapVector<NonGarbageCollectedContainer>>(*vec1);
580   }
581 }
582 
TEST_F(IncrementalMarkingTest,HeapVectorCopyStdPair)583 TEST_F(IncrementalMarkingTest, HeapVectorCopyStdPair) {
584   using ValueType = std::pair<Member<Object>, Member<Object>>;
585   auto* obj1 = MakeGarbageCollected<Object>();
586   auto* obj2 = MakeGarbageCollected<Object>();
587   auto* vec1 = MakeGarbageCollected<HeapVector<ValueType>>();
588   vec1->emplace_back(obj1, obj2);
589   {
590     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
591     MakeGarbageCollected<HeapVector<ValueType>>(*vec1);
592   }
593 }
594 
TEST_F(IncrementalMarkingTest,HeapVectorMoveMember)595 TEST_F(IncrementalMarkingTest, HeapVectorMoveMember) {
596   auto* obj = MakeGarbageCollected<Object>();
597   auto* vec1 = MakeGarbageCollected<HeapVector<Member<Object>>>();
598   vec1->push_back(obj);
599   {
600     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
601     MakeGarbageCollected<HeapVector<Member<Object>>>(std::move(*vec1));
602   }
603 }
604 
TEST_F(IncrementalMarkingTest,HeapVectorMoveNonGCedContainer)605 TEST_F(IncrementalMarkingTest, HeapVectorMoveNonGCedContainer) {
606   auto* obj = MakeGarbageCollected<Object>();
607   auto* vec1 = MakeGarbageCollected<HeapVector<NonGarbageCollectedContainer>>();
608   vec1->emplace_back(obj, 1);
609   {
610     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
611     MakeGarbageCollected<HeapVector<NonGarbageCollectedContainer>>(
612         std::move(*vec1));
613   }
614 }
615 
TEST_F(IncrementalMarkingTest,HeapVectorMoveStdPair)616 TEST_F(IncrementalMarkingTest, HeapVectorMoveStdPair) {
617   using ValueType = std::pair<Member<Object>, Member<Object>>;
618   using VectorType = HeapVector<ValueType>;
619   auto* obj1 = MakeGarbageCollected<Object>();
620   auto* obj2 = MakeGarbageCollected<Object>();
621   auto* vec1 = MakeGarbageCollected<VectorType>();
622   vec1->emplace_back(obj1, obj2);
623   {
624     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
625     MakeGarbageCollected<VectorType>(std::move(*vec1));
626   }
627 }
628 
TEST_F(IncrementalMarkingTest,HeapVectorSwapMember)629 TEST_F(IncrementalMarkingTest, HeapVectorSwapMember) {
630   using VectorType = HeapVector<Member<Object>>;
631   auto* obj1 = MakeGarbageCollected<Object>();
632   auto* obj2 = MakeGarbageCollected<Object>();
633   auto* vec1 = MakeGarbageCollected<VectorType>();
634   vec1->push_back(obj1);
635   auto* vec2 = MakeGarbageCollected<VectorType>();
636   vec2->push_back(obj2);
637   {
638     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
639     std::swap(*vec1, *vec2);
640   }
641 }
642 
TEST_F(IncrementalMarkingTest,HeapVectorSwapNonGCedContainer)643 TEST_F(IncrementalMarkingTest, HeapVectorSwapNonGCedContainer) {
644   using VectorType = HeapVector<NonGarbageCollectedContainer>;
645   auto* obj1 = MakeGarbageCollected<Object>();
646   auto* obj2 = MakeGarbageCollected<Object>();
647   auto* vec1 = MakeGarbageCollected<VectorType>();
648   vec1->emplace_back(obj1, 1);
649   auto* vec2 = MakeGarbageCollected<VectorType>();
650   vec2->emplace_back(obj2, 2);
651   {
652     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
653     std::swap(*vec1, *vec2);
654   }
655 }
656 
TEST_F(IncrementalMarkingTest,HeapVectorSwapStdPair)657 TEST_F(IncrementalMarkingTest, HeapVectorSwapStdPair) {
658   using ValueType = std::pair<Member<Object>, Member<Object>>;
659   using VectorType = HeapVector<ValueType>;
660   auto* obj1 = MakeGarbageCollected<Object>();
661   auto* obj2 = MakeGarbageCollected<Object>();
662   auto* vec1 = MakeGarbageCollected<VectorType>();
663   vec1->emplace_back(obj1, nullptr);
664   auto* vec2 = MakeGarbageCollected<VectorType>();
665   vec2->emplace_back(nullptr, obj2);
666   {
667     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
668     std::swap(*vec1, *vec2);
669   }
670 }
671 
TEST_F(IncrementalMarkingTest,HeapVectorSubscriptOperator)672 TEST_F(IncrementalMarkingTest, HeapVectorSubscriptOperator) {
673   auto* obj1 = MakeGarbageCollected<Object>();
674   auto* obj2 = MakeGarbageCollected<Object>();
675   HeapVector<Member<Object>> vec;
676   vec.push_back(obj1);
677   {
678     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj2});
679     EXPECT_EQ(1u, vec.size());
680     EXPECT_EQ(obj1, vec[0]);
681     vec[0] = obj2;
682     EXPECT_EQ(obj2, vec[0]);
683     EXPECT_FALSE(obj1->IsMarked());
684   }
685 }
686 
TEST_F(IncrementalMarkingTest,HeapVectorEagerTracingStopsAtMember)687 TEST_F(IncrementalMarkingTest, HeapVectorEagerTracingStopsAtMember) {
688   auto* obj1 = MakeGarbageCollected<Object>();
689   auto* obj2 = MakeGarbageCollected<Object>();
690   auto* obj3 = MakeGarbageCollected<Object>();
691   obj1->set_next(obj3);
692   HeapVector<NonGarbageCollectedContainerRoot> vec;
693   {
694     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
695     vec.emplace_back(obj1, obj2, 3);
696     // |obj3| is only reachable from |obj1| which is not eagerly traced. Only
697     // objects without object headers are eagerly traced.
698     EXPECT_FALSE(obj3->IsMarked());
699   }
700 }
701 
702 // =============================================================================
703 // HeapDeque support. ==========================================================
704 // =============================================================================
705 
TEST_F(IncrementalMarkingTest,HeapDequePushBackMember)706 TEST_F(IncrementalMarkingTest, HeapDequePushBackMember) {
707   auto* obj = MakeGarbageCollected<Object>();
708   HeapDeque<Member<Object>> deq;
709   {
710     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
711     deq.push_back(obj);
712   }
713 }
714 
TEST_F(IncrementalMarkingTest,HeapDequePushFrontMember)715 TEST_F(IncrementalMarkingTest, HeapDequePushFrontMember) {
716   auto* obj = MakeGarbageCollected<Object>();
717   HeapDeque<Member<Object>> deq;
718   {
719     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
720     deq.push_front(obj);
721   }
722 }
723 
TEST_F(IncrementalMarkingTest,HeapDequeEmplaceBackMember)724 TEST_F(IncrementalMarkingTest, HeapDequeEmplaceBackMember) {
725   auto* obj = MakeGarbageCollected<Object>();
726   HeapDeque<Member<Object>> deq;
727   {
728     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
729     deq.emplace_back(obj);
730   }
731 }
732 
TEST_F(IncrementalMarkingTest,HeapDequeEmplaceFrontMember)733 TEST_F(IncrementalMarkingTest, HeapDequeEmplaceFrontMember) {
734   auto* obj = MakeGarbageCollected<Object>();
735   HeapDeque<Member<Object>> deq;
736   {
737     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
738     deq.emplace_front(obj);
739   }
740 }
741 
TEST_F(IncrementalMarkingTest,HeapDequeCopyMember)742 TEST_F(IncrementalMarkingTest, HeapDequeCopyMember) {
743   auto* object = MakeGarbageCollected<Object>();
744   HeapDeque<Member<Object>> deq1;
745   deq1.push_back(object);
746   {
747     ExpectWriteBarrierFires scope(ThreadState::Current(), {object});
748     HeapDeque<Member<Object>> deq2(deq1);
749   }
750 }
751 
TEST_F(IncrementalMarkingTest,HeapDequeMoveMember)752 TEST_F(IncrementalMarkingTest, HeapDequeMoveMember) {
753   auto* object = MakeGarbageCollected<Object>();
754   HeapDeque<Member<Object>> deq1;
755   deq1.push_back(object);
756   {
757     ExpectWriteBarrierFires scope(ThreadState::Current(), {object});
758     HeapDeque<Member<Object>> deq2(std::move(deq1));
759   }
760 }
761 
TEST_F(IncrementalMarkingTest,HeapDequeSwapMember)762 TEST_F(IncrementalMarkingTest, HeapDequeSwapMember) {
763   auto* obj1 = MakeGarbageCollected<Object>();
764   auto* obj2 = MakeGarbageCollected<Object>();
765   HeapDeque<Member<Object>> deq1;
766   deq1.push_back(obj1);
767   HeapDeque<Member<Object>> deq2;
768   deq2.push_back(obj2);
769   {
770     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
771     std::swap(deq1, deq2);
772   }
773 }
774 
775 // =============================================================================
776 // HeapHashSet support. ========================================================
777 // =============================================================================
778 
779 namespace {
780 
781 template <typename Container>
Insert()782 void Insert() {
783   auto* obj = MakeGarbageCollected<Object>();
784   Container container;
785   {
786     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
787     container.insert(obj);
788   }
789 }
790 
791 template <typename Container>
InsertNoBarrier()792 void InsertNoBarrier() {
793   auto* obj = MakeGarbageCollected<Object>();
794   Container container;
795   {
796     ExpectNoWriteBarrierFires scope(ThreadState::Current(), {obj});
797     container.insert(obj);
798   }
799 }
800 
801 template <typename Container>
Copy()802 void Copy() {
803   auto* obj = MakeGarbageCollected<Object>();
804   Container container1;
805   container1.insert(obj);
806   {
807     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
808     Container container2(container1);
809     EXPECT_TRUE(container1.Contains(obj));
810     EXPECT_TRUE(container2.Contains(obj));
811   }
812 }
813 
814 template <typename Container>
CopyNoBarrier()815 void CopyNoBarrier() {
816   auto* obj = MakeGarbageCollected<Object>();
817   Container container1;
818   container1.insert(obj);
819   {
820     ExpectNoWriteBarrierFires scope(ThreadState::Current(), {obj});
821     Container container2(container1);
822     EXPECT_TRUE(container1.Contains(obj));
823     EXPECT_TRUE(container2.Contains(obj));
824   }
825 }
826 
827 template <typename Container>
Move()828 void Move() {
829   auto* obj = MakeGarbageCollected<Object>();
830   auto* container1 = MakeGarbageCollected<Container>();
831   auto* container2 = MakeGarbageCollected<Container>();
832   container1->insert(obj);
833   {
834     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj});
835     *container2 = std::move(*container1);
836   }
837 }
838 
839 template <typename Container>
MoveNoBarrier()840 void MoveNoBarrier() {
841   auto* obj = MakeGarbageCollected<Object>();
842   auto* container1 = MakeGarbageCollected<Container>();
843   container1->insert(obj);
844   {
845     ExpectNoWriteBarrierFires scope(ThreadState::Current(), {obj});
846     auto* container2 = MakeGarbageCollected<Container>(std::move(*container1));
847   }
848 }
849 
850 template <typename Container>
Swap()851 void Swap() {
852   auto* obj1 = MakeGarbageCollected<Object>();
853   auto* obj2 = MakeGarbageCollected<Object>();
854   auto* container1 = MakeGarbageCollected<Container>();
855   container1->insert(obj1);
856   auto* container2 = MakeGarbageCollected<Container>();
857   container2->insert(obj2);
858   {
859     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
860     std::swap(*container1, *container2);
861   }
862 }
863 
864 template <typename Container>
SwapNoBarrier()865 void SwapNoBarrier() {
866   auto* obj1 = MakeGarbageCollected<Object>();
867   auto* obj2 = MakeGarbageCollected<Object>();
868   auto* container1 = MakeGarbageCollected<Container>();
869   container1->insert(obj1);
870   auto* container2 = MakeGarbageCollected<Container>();
871   container2->insert(obj2);
872   {
873     ExpectNoWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
874     std::swap(*container1, *container2);
875   }
876 }
877 
878 }  // namespace
879 
TEST_F(IncrementalMarkingTest,HeapHashSetInsert)880 TEST_F(IncrementalMarkingTest, HeapHashSetInsert) {
881   Insert<HeapHashSet<Member<Object>>>();
882   // Weak references are strongified for the current cycle.
883   Insert<HeapHashSet<WeakMember<Object>>>();
884 }
885 
TEST_F(IncrementalMarkingTest,HeapHashSetCopy)886 TEST_F(IncrementalMarkingTest, HeapHashSetCopy) {
887   Copy<HeapHashSet<Member<Object>>>();
888   // Weak references are strongified for the current cycle.
889   Copy<HeapHashSet<WeakMember<Object>>>();
890 }
891 
TEST_F(IncrementalMarkingTest,HeapHashSetMove)892 TEST_F(IncrementalMarkingTest, HeapHashSetMove) {
893   Move<HeapHashSet<Member<Object>>>();
894   // Weak references are strongified for the current cycle.
895   Move<HeapHashSet<WeakMember<Object>>>();
896 }
897 
TEST_F(IncrementalMarkingTest,HeapHashSetSwap)898 TEST_F(IncrementalMarkingTest, HeapHashSetSwap) {
899   Swap<HeapHashSet<Member<Object>>>();
900   // Weak references are strongified for the current cycle.
901   Swap<HeapHashSet<WeakMember<Object>>>();
902 }
903 
904 // =============================================================================
905 // HeapLinkedHashSet support. ==================================================
906 // =============================================================================
907 
TEST_F(IncrementalMarkingTest,HeapLinkedHashSetInsert)908 TEST_F(IncrementalMarkingTest, HeapLinkedHashSetInsert) {
909   Insert<HeapLinkedHashSet<Member<Object>>>();
910   // Weak references are strongified for the current cycle.
911   Insert<HeapLinkedHashSet<WeakMember<Object>>>();
912 }
913 
TEST_F(IncrementalMarkingTest,HeapLinkedHashSetCopy)914 TEST_F(IncrementalMarkingTest, HeapLinkedHashSetCopy) {
915   Copy<HeapLinkedHashSet<Member<Object>>>();
916   // Weak references are strongified for the current cycle.
917   Copy<HeapLinkedHashSet<WeakMember<Object>>>();
918 }
919 
TEST_F(IncrementalMarkingTest,HeapLinkedHashSetMove)920 TEST_F(IncrementalMarkingTest, HeapLinkedHashSetMove) {
921   Move<HeapLinkedHashSet<Member<Object>>>();
922   // Weak references are strongified for the current cycle.
923   Move<HeapLinkedHashSet<WeakMember<Object>>>();
924 }
925 
TEST_F(IncrementalMarkingTest,HeapLinkedHashSetSwap)926 TEST_F(IncrementalMarkingTest, HeapLinkedHashSetSwap) {
927   Swap<HeapLinkedHashSet<Member<Object>>>();
928   // Weak references are strongified for the current cycle.
929   Swap<HeapLinkedHashSet<WeakMember<Object>>>();
930 }
931 
932 // =============================================================================
933 // HeapHashCountedSet support. =================================================
934 // =============================================================================
935 
936 // HeapHashCountedSet does not support copy or move.
937 
TEST_F(IncrementalMarkingTest,HeapHashCountedSetInsert)938 TEST_F(IncrementalMarkingTest, HeapHashCountedSetInsert) {
939   Insert<HeapHashCountedSet<Member<Object>>>();
940   // Weak references are strongified for the current cycle.
941   Insert<HeapHashCountedSet<WeakMember<Object>>>();
942 }
943 
TEST_F(IncrementalMarkingTest,HeapHashCountedSetSwap)944 TEST_F(IncrementalMarkingTest, HeapHashCountedSetSwap) {
945   // HeapHashCountedSet is not move constructible so we cannot use std::swap.
946   {
947     auto* obj1 = MakeGarbageCollected<Object>();
948     auto* obj2 = MakeGarbageCollected<Object>();
949     auto* container1 =
950         MakeGarbageCollected<HeapHashCountedSet<Member<Object>>>();
951     container1->insert(obj1);
952     auto* container2 =
953         MakeGarbageCollected<HeapHashCountedSet<Member<Object>>>();
954     container2->insert(obj2);
955     {
956       ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
957       container1->swap(*container2);
958     }
959   }
960   {
961     auto* obj1 = MakeGarbageCollected<Object>();
962     auto* obj2 = MakeGarbageCollected<Object>();
963     auto* container1 =
964         MakeGarbageCollected<HeapHashCountedSet<WeakMember<Object>>>();
965     container1->insert(obj1);
966     auto* container2 =
967         MakeGarbageCollected<HeapHashCountedSet<WeakMember<Object>>>();
968     container2->insert(obj2);
969     {
970       // Weak references are strongified for the current cycle.
971       ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
972       container1->swap(*container2);
973     }
974   }
975 }
976 
977 // =============================================================================
978 // HeapHashMap support. ========================================================
979 // =============================================================================
980 
TEST_F(IncrementalMarkingTest,HeapHashMapInsertMember)981 TEST_F(IncrementalMarkingTest, HeapHashMapInsertMember) {
982   auto* obj1 = MakeGarbageCollected<Object>();
983   auto* obj2 = MakeGarbageCollected<Object>();
984   HeapHashMap<Member<Object>, Member<Object>> map;
985   {
986     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
987     map.insert(obj1, obj2);
988   }
989 }
990 
TEST_F(IncrementalMarkingTest,HeapHashMapInsertWeakMember)991 TEST_F(IncrementalMarkingTest, HeapHashMapInsertWeakMember) {
992   auto* obj1 = MakeGarbageCollected<Object>();
993   auto* obj2 = MakeGarbageCollected<Object>();
994   HeapHashMap<WeakMember<Object>, WeakMember<Object>> map;
995   {
996     // Weak references are strongified for the current cycle.
997     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
998     map.insert(obj1, obj2);
999   }
1000 }
1001 
TEST_F(IncrementalMarkingTest,HeapHashMapInsertMemberWeakMember)1002 TEST_F(IncrementalMarkingTest, HeapHashMapInsertMemberWeakMember) {
1003   auto* obj1 = MakeGarbageCollected<Object>();
1004   auto* obj2 = MakeGarbageCollected<Object>();
1005   HeapHashMap<Member<Object>, WeakMember<Object>> map;
1006   {
1007     // Weak references are strongified for the current cycle.
1008     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1009     map.insert(obj1, obj2);
1010   }
1011 }
1012 
TEST_F(IncrementalMarkingTest,HeapHashMapInsertWeakMemberMember)1013 TEST_F(IncrementalMarkingTest, HeapHashMapInsertWeakMemberMember) {
1014   auto* obj1 = MakeGarbageCollected<Object>();
1015   auto* obj2 = MakeGarbageCollected<Object>();
1016   HeapHashMap<WeakMember<Object>, Member<Object>> map;
1017   {
1018     // Weak references are strongified for the current cycle.
1019     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1020     map.insert(obj1, obj2);
1021   }
1022 }
1023 
TEST_F(IncrementalMarkingTest,HeapHashMapSetMember)1024 TEST_F(IncrementalMarkingTest, HeapHashMapSetMember) {
1025   auto* obj1 = MakeGarbageCollected<Object>();
1026   auto* obj2 = MakeGarbageCollected<Object>();
1027   HeapHashMap<Member<Object>, Member<Object>> map;
1028   {
1029     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1030     map.Set(obj1, obj2);
1031   }
1032 }
1033 
TEST_F(IncrementalMarkingTest,HeapHashMapSetMemberUpdateValue)1034 TEST_F(IncrementalMarkingTest, HeapHashMapSetMemberUpdateValue) {
1035   auto* obj1 = MakeGarbageCollected<Object>();
1036   auto* obj2 = MakeGarbageCollected<Object>();
1037   auto* obj3 = MakeGarbageCollected<Object>();
1038   HeapHashMap<Member<Object>, Member<Object>> map;
1039   map.insert(obj1, obj2);
1040   {
1041     // Only |obj3| is newly added to |map|, so we only expect the barrier to
1042     // fire on this one.
1043     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj3});
1044     map.Set(obj1, obj3);
1045     EXPECT_FALSE(HeapObjectHeader::FromPayload(obj1)->IsMarked());
1046     EXPECT_FALSE(HeapObjectHeader::FromPayload(obj2)->IsMarked());
1047   }
1048 }
1049 
TEST_F(IncrementalMarkingTest,HeapHashMapIteratorChangeKey)1050 TEST_F(IncrementalMarkingTest, HeapHashMapIteratorChangeKey) {
1051   auto* obj1 = MakeGarbageCollected<Object>();
1052   auto* obj2 = MakeGarbageCollected<Object>();
1053   auto* obj3 = MakeGarbageCollected<Object>();
1054   HeapHashMap<Member<Object>, Member<Object>> map;
1055   map.insert(obj1, obj2);
1056   {
1057     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj3});
1058     auto it = map.find(obj1);
1059     EXPECT_NE(map.end(), it);
1060     it->key = obj3;
1061   }
1062 }
1063 
TEST_F(IncrementalMarkingTest,HeapHashMapIteratorChangeValue)1064 TEST_F(IncrementalMarkingTest, HeapHashMapIteratorChangeValue) {
1065   auto* obj1 = MakeGarbageCollected<Object>();
1066   auto* obj2 = MakeGarbageCollected<Object>();
1067   auto* obj3 = MakeGarbageCollected<Object>();
1068   HeapHashMap<Member<Object>, Member<Object>> map;
1069   map.insert(obj1, obj2);
1070   {
1071     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj3});
1072     auto it = map.find(obj1);
1073     EXPECT_NE(map.end(), it);
1074     it->value = obj3;
1075   }
1076 }
1077 
TEST_F(IncrementalMarkingTest,HeapHashMapCopyMemberMember)1078 TEST_F(IncrementalMarkingTest, HeapHashMapCopyMemberMember) {
1079   auto* obj1 = MakeGarbageCollected<Object>();
1080   auto* obj2 = MakeGarbageCollected<Object>();
1081   HeapHashMap<Member<Object>, Member<Object>> map1;
1082   map1.insert(obj1, obj2);
1083   {
1084     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1085     EXPECT_TRUE(map1.Contains(obj1));
1086     HeapHashMap<Member<Object>, Member<Object>> map2(map1);
1087     EXPECT_TRUE(map1.Contains(obj1));
1088     EXPECT_TRUE(map2.Contains(obj1));
1089   }
1090 }
1091 
TEST_F(IncrementalMarkingTest,HeapHashMapCopyWeakMemberWeakMember)1092 TEST_F(IncrementalMarkingTest, HeapHashMapCopyWeakMemberWeakMember) {
1093   auto* obj1 = MakeGarbageCollected<Object>();
1094   auto* obj2 = MakeGarbageCollected<Object>();
1095   HeapHashMap<WeakMember<Object>, WeakMember<Object>> map1;
1096   map1.insert(obj1, obj2);
1097   {
1098     // Weak references are strongified for the current cycle.
1099     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1100     EXPECT_TRUE(map1.Contains(obj1));
1101     HeapHashMap<WeakMember<Object>, WeakMember<Object>> map2(map1);
1102     EXPECT_TRUE(map1.Contains(obj1));
1103     EXPECT_TRUE(map2.Contains(obj1));
1104   }
1105 }
1106 
TEST_F(IncrementalMarkingTest,HeapHashMapCopyMemberWeakMember)1107 TEST_F(IncrementalMarkingTest, HeapHashMapCopyMemberWeakMember) {
1108   auto* obj1 = MakeGarbageCollected<Object>();
1109   auto* obj2 = MakeGarbageCollected<Object>();
1110   HeapHashMap<Member<Object>, WeakMember<Object>> map1;
1111   map1.insert(obj1, obj2);
1112   {
1113     // Weak references are strongified for the current cycle.
1114     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1115     EXPECT_TRUE(map1.Contains(obj1));
1116     HeapHashMap<Member<Object>, WeakMember<Object>> map2(map1);
1117     EXPECT_TRUE(map1.Contains(obj1));
1118     EXPECT_TRUE(map2.Contains(obj1));
1119   }
1120 }
1121 
TEST_F(IncrementalMarkingTest,HeapHashMapCopyWeakMemberMember)1122 TEST_F(IncrementalMarkingTest, HeapHashMapCopyWeakMemberMember) {
1123   auto* obj1 = MakeGarbageCollected<Object>();
1124   auto* obj2 = MakeGarbageCollected<Object>();
1125   HeapHashMap<WeakMember<Object>, Member<Object>> map1;
1126   map1.insert(obj1, obj2);
1127   {
1128     // Weak references are strongified for the current cycle.
1129     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1130     EXPECT_TRUE(map1.Contains(obj1));
1131     HeapHashMap<WeakMember<Object>, Member<Object>> map2(map1);
1132     EXPECT_TRUE(map1.Contains(obj1));
1133     EXPECT_TRUE(map2.Contains(obj1));
1134   }
1135 }
1136 
TEST_F(IncrementalMarkingTest,HeapHashMapMoveMember)1137 TEST_F(IncrementalMarkingTest, HeapHashMapMoveMember) {
1138   auto* obj1 = MakeGarbageCollected<Object>();
1139   auto* obj2 = MakeGarbageCollected<Object>();
1140   auto* map1 =
1141       MakeGarbageCollected<HeapHashMap<Member<Object>, Member<Object>>>();
1142   map1->insert(obj1, obj2);
1143   {
1144     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1145     MakeGarbageCollected<HeapHashMap<Member<Object>, Member<Object>>>(
1146         std::move(*map1));
1147   }
1148 }
1149 
TEST_F(IncrementalMarkingTest,HeapHashMapMoveWeakMember)1150 TEST_F(IncrementalMarkingTest, HeapHashMapMoveWeakMember) {
1151   auto* obj1 = MakeGarbageCollected<Object>();
1152   auto* obj2 = MakeGarbageCollected<Object>();
1153   auto* map1 = MakeGarbageCollected<
1154       HeapHashMap<WeakMember<Object>, WeakMember<Object>>>();
1155   map1->insert(obj1, obj2);
1156   {
1157     // Weak references are strongified for the current cycle.
1158     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1159     MakeGarbageCollected<HeapHashMap<WeakMember<Object>, WeakMember<Object>>>(
1160         std::move(*map1));
1161   }
1162 }
1163 
TEST_F(IncrementalMarkingTest,HeapHashMapMoveMemberWeakMember)1164 TEST_F(IncrementalMarkingTest, HeapHashMapMoveMemberWeakMember) {
1165   auto* obj1 = MakeGarbageCollected<Object>();
1166   auto* obj2 = MakeGarbageCollected<Object>();
1167   auto* map1 =
1168       MakeGarbageCollected<HeapHashMap<Member<Object>, WeakMember<Object>>>();
1169   map1->insert(obj1, obj2);
1170   {
1171     // Weak references are strongified for the current cycle.
1172     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1173     MakeGarbageCollected<HeapHashMap<Member<Object>, WeakMember<Object>>>(
1174         std::move(*map1));
1175   }
1176 }
1177 
TEST_F(IncrementalMarkingTest,HeapHashMapMoveWeakMemberMember)1178 TEST_F(IncrementalMarkingTest, HeapHashMapMoveWeakMemberMember) {
1179   auto* obj1 = MakeGarbageCollected<Object>();
1180   auto* obj2 = MakeGarbageCollected<Object>();
1181   auto* map1 =
1182       MakeGarbageCollected<HeapHashMap<WeakMember<Object>, Member<Object>>>();
1183   map1->insert(obj1, obj2);
1184   {
1185     // Weak references are strongified for the current cycle.
1186     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1, obj2});
1187     MakeGarbageCollected<HeapHashMap<WeakMember<Object>, Member<Object>>>(
1188         std::move(*map1));
1189   }
1190 }
1191 
TEST_F(IncrementalMarkingTest,HeapHashMapSwapMemberMember)1192 TEST_F(IncrementalMarkingTest, HeapHashMapSwapMemberMember) {
1193   auto* obj1 = MakeGarbageCollected<Object>();
1194   auto* obj2 = MakeGarbageCollected<Object>();
1195   auto* obj3 = MakeGarbageCollected<Object>();
1196   auto* obj4 = MakeGarbageCollected<Object>();
1197   auto* map1 =
1198       MakeGarbageCollected<HeapHashMap<Member<Object>, Member<Object>>>();
1199   map1->insert(obj1, obj2);
1200   auto* map2 =
1201       MakeGarbageCollected<HeapHashMap<Member<Object>, Member<Object>>>();
1202   map2->insert(obj3, obj4);
1203   {
1204     ExpectWriteBarrierFires scope(ThreadState::Current(),
1205                                   {obj1, obj2, obj3, obj4});
1206     std::swap(*map1, *map2);
1207   }
1208 }
1209 
TEST_F(IncrementalMarkingTest,HeapHashMapSwapWeakMemberWeakMember)1210 TEST_F(IncrementalMarkingTest, HeapHashMapSwapWeakMemberWeakMember) {
1211   auto* obj1 = MakeGarbageCollected<Object>();
1212   auto* obj2 = MakeGarbageCollected<Object>();
1213   auto* obj3 = MakeGarbageCollected<Object>();
1214   auto* obj4 = MakeGarbageCollected<Object>();
1215   auto* map1 = MakeGarbageCollected<
1216       HeapHashMap<WeakMember<Object>, WeakMember<Object>>>();
1217   map1->insert(obj1, obj2);
1218   auto* map2 = MakeGarbageCollected<
1219       HeapHashMap<WeakMember<Object>, WeakMember<Object>>>();
1220   map2->insert(obj3, obj4);
1221   {
1222     // Weak references are strongified for the current cycle.
1223     ExpectWriteBarrierFires scope(ThreadState::Current(),
1224                                   {obj1, obj2, obj3, obj4});
1225     std::swap(*map1, *map2);
1226   }
1227 }
1228 
TEST_F(IncrementalMarkingTest,HeapHashMapSwapMemberWeakMember)1229 TEST_F(IncrementalMarkingTest, HeapHashMapSwapMemberWeakMember) {
1230   auto* obj1 = MakeGarbageCollected<Object>();
1231   auto* obj2 = MakeGarbageCollected<Object>();
1232   auto* obj3 = MakeGarbageCollected<Object>();
1233   auto* obj4 = MakeGarbageCollected<Object>();
1234   auto* map1 =
1235       MakeGarbageCollected<HeapHashMap<Member<Object>, WeakMember<Object>>>();
1236   map1->insert(obj1, obj2);
1237   auto* map2 =
1238       MakeGarbageCollected<HeapHashMap<Member<Object>, WeakMember<Object>>>();
1239   map2->insert(obj3, obj4);
1240   {
1241     // Weak references are strongified for the current cycle.
1242     ExpectWriteBarrierFires scope(ThreadState::Current(),
1243                                   {obj1, obj2, obj3, obj4});
1244     std::swap(*map1, *map2);
1245   }
1246 }
1247 
TEST_F(IncrementalMarkingTest,HeapHashMapSwapWeakMemberMember)1248 TEST_F(IncrementalMarkingTest, HeapHashMapSwapWeakMemberMember) {
1249   auto* obj1 = MakeGarbageCollected<Object>();
1250   auto* obj2 = MakeGarbageCollected<Object>();
1251   auto* obj3 = MakeGarbageCollected<Object>();
1252   auto* obj4 = MakeGarbageCollected<Object>();
1253   auto* map1 =
1254       MakeGarbageCollected<HeapHashMap<WeakMember<Object>, Member<Object>>>();
1255   map1->insert(obj1, obj2);
1256   auto* map2 =
1257       MakeGarbageCollected<HeapHashMap<WeakMember<Object>, Member<Object>>>();
1258   map2->insert(obj3, obj4);
1259   {
1260     // Weak references are strongified for the current cycle.
1261     ExpectWriteBarrierFires scope(ThreadState::Current(),
1262                                   {obj1, obj2, obj3, obj4});
1263     std::swap(*map1, *map2);
1264   }
1265 }
1266 
TEST_F(IncrementalMarkingTest,HeapHashMapCopyKeysToVectorMember)1267 TEST_F(IncrementalMarkingTest, HeapHashMapCopyKeysToVectorMember) {
1268   auto* obj1 = MakeGarbageCollected<Object>();
1269   auto* obj2 = MakeGarbageCollected<Object>();
1270   HeapHashMap<Member<Object>, Member<Object>> map;
1271   map.insert(obj1, obj2);
1272   HeapVector<Member<Object>> vec;
1273   {
1274     // Only key should have its write barrier fired. A write barrier call for
1275     // value hints to an inefficient implementation.
1276     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj1});
1277     CopyKeysToVector(map, vec);
1278   }
1279 }
1280 
TEST_F(IncrementalMarkingTest,HeapHashMapCopyValuesToVectorMember)1281 TEST_F(IncrementalMarkingTest, HeapHashMapCopyValuesToVectorMember) {
1282   auto* obj1 = MakeGarbageCollected<Object>();
1283   auto* obj2 = MakeGarbageCollected<Object>();
1284   HeapHashMap<Member<Object>, Member<Object>> map;
1285   map.insert(obj1, obj2);
1286   HeapVector<Member<Object>> vec;
1287   {
1288     // Only value should have its write barrier fired. A write barrier call for
1289     // key hints to an inefficient implementation.
1290     ExpectWriteBarrierFires scope(ThreadState::Current(), {obj2});
1291     CopyValuesToVector(map, vec);
1292   }
1293 }
1294 
1295 // TODO(keishi) Non-weak hash table backings should be promptly freed but they
1296 // are currently not because we emit write barriers for the backings, and we
1297 // don't free marked backings.
TEST_F(IncrementalMarkingTest,DISABLED_WeakHashMapPromptlyFreeDisabled)1298 TEST_F(IncrementalMarkingTest, DISABLED_WeakHashMapPromptlyFreeDisabled) {
1299   ThreadState* state = ThreadState::Current();
1300   state->SetGCState(ThreadState::kIncrementalMarkingStepScheduled);
1301   Persistent<Object> obj1 = MakeGarbageCollected<Object>();
1302   NormalPageArena* arena = static_cast<NormalPageArena*>(
1303       ThreadState::Current()->Heap().Arena(BlinkGC::kHashTableArenaIndex));
1304   CHECK(arena);
1305   {
1306     size_t before = arena->promptly_freed_size();
1307     // Create two maps so we don't promptly free at the allocation point.
1308     HeapHashMap<WeakMember<Object>, Member<Object>> weak_map1;
1309     HeapHashMap<WeakMember<Object>, Member<Object>> weak_map2;
1310     weak_map1.insert(obj1, obj1);
1311     weak_map2.insert(obj1, obj1);
1312     weak_map1.clear();
1313     size_t after = arena->promptly_freed_size();
1314     // Weak hash table backings should not be promptly freed.
1315     EXPECT_EQ(after, before);
1316   }
1317   {
1318     size_t before = arena->promptly_freed_size();
1319     // Create two maps so we don't promptly free at the allocation point.
1320     HeapHashMap<Member<Object>, Member<Object>> map1;
1321     HeapHashMap<Member<Object>, Member<Object>> map2;
1322     map1.insert(obj1, obj1);
1323     map2.insert(obj1, obj1);
1324     map1.clear();
1325     size_t after = arena->promptly_freed_size();
1326     // Non-weak hash table backings should be promptly freed.
1327     EXPECT_GT(after, before);
1328   }
1329   state->SetGCState(ThreadState::kIncrementalMarkingFinalizeScheduled);
1330   state->SetGCState(ThreadState::kNoGCScheduled);
1331 }
1332 
1333 namespace {
1334 
1335 class RegisteringMixin;
1336 using ObjectRegistry = HeapHashMap<void*, Member<RegisteringMixin>>;
1337 
1338 class RegisteringMixin : public GarbageCollectedMixin {
1339  public:
RegisteringMixin(ObjectRegistry * registry)1340   explicit RegisteringMixin(ObjectRegistry* registry) {
1341     HeapObjectHeader* header = HeapObjectHeader::FromPayload(
1342         TraceTrait<RegisteringMixin>::GetTraceDescriptor(this)
1343             .base_object_payload);
1344     EXPECT_TRUE(header->IsInConstruction());
1345     registry->insert(reinterpret_cast<void*>(this), this);
1346   }
1347 };
1348 
1349 class RegisteringObject : public GarbageCollected<RegisteringObject>,
1350                           public RegisteringMixin {
1351  public:
RegisteringObject(ObjectRegistry * registry)1352   explicit RegisteringObject(ObjectRegistry* registry)
1353       : RegisteringMixin(registry) {}
1354 };
1355 
1356 }  // namespace
1357 
TEST_F(IncrementalMarkingTest,WriteBarrierDuringMixinConstruction)1358 TEST_F(IncrementalMarkingTest, WriteBarrierDuringMixinConstruction) {
1359   IncrementalMarkingScope scope(ThreadState::Current());
1360   ObjectRegistry registry;
1361   RegisteringObject* object =
1362       MakeGarbageCollected<RegisteringObject>(&registry);
1363 
1364   // Clear any objects that have been added to the regular marking worklist in
1365   // the process of calling the constructor.
1366   MarkingItem marking_item;
1367   while (scope.marking_worklist()->Pop(WorklistTaskId::MutatorThread,
1368                                        &marking_item)) {
1369     HeapObjectHeader* header =
1370         HeapObjectHeader::FromPayload(marking_item.base_object_payload);
1371     if (header->IsMarked())
1372       header->Unmark();
1373   }
1374   EXPECT_TRUE(scope.marking_worklist()->IsGlobalEmpty());
1375   // Clear any write barriers so far.
1376   HeapObjectHeader* header;
1377   while (scope.write_barrier_worklist()->Pop(WorklistTaskId::MutatorThread,
1378                                              &header)) {
1379     if (header->IsMarked())
1380       header->Unmark();
1381   }
1382   EXPECT_TRUE(scope.write_barrier_worklist()->IsGlobalEmpty());
1383 
1384   EXPECT_FALSE(scope.not_fully_constructed_worklist()->IsGlobalEmpty());
1385   NotFullyConstructedItem partial_item;
1386   bool found_mixin_object = false;
1387   // The same object may be on the marking work list because of expanding
1388   // and rehashing of the backing store in the registry.
1389   while (scope.not_fully_constructed_worklist()->Pop(
1390       WorklistTaskId::MutatorThread, &partial_item)) {
1391     if (object == partial_item)
1392       found_mixin_object = true;
1393     HeapObjectHeader* header = HeapObjectHeader::FromPayload(partial_item);
1394     if (header->IsMarked())
1395       header->Unmark();
1396   }
1397   EXPECT_TRUE(found_mixin_object);
1398   EXPECT_TRUE(scope.not_fully_constructed_worklist()->IsGlobalEmpty());
1399 }
1400 
TEST_F(IncrementalMarkingTest,OverrideAfterMixinConstruction)1401 TEST_F(IncrementalMarkingTest, OverrideAfterMixinConstruction) {
1402   ObjectRegistry registry;
1403   RegisteringMixin* mixin = MakeGarbageCollected<RegisteringObject>(&registry);
1404   HeapObjectHeader* header = HeapObjectHeader::FromPayload(
1405       TraceTrait<RegisteringMixin>::GetTraceDescriptor(mixin)
1406           .base_object_payload);
1407 
1408   EXPECT_FALSE(header->IsInConstruction());
1409 }
1410 
1411 // =============================================================================
1412 // Tests that execute complete incremental garbage collections. ================
1413 // =============================================================================
1414 
TEST_F(IncrementalMarkingTest,TestDriver)1415 TEST_F(IncrementalMarkingTest, TestDriver) {
1416   IncrementalMarkingTestDriver driver(ThreadState::Current());
1417   driver.Start();
1418   EXPECT_TRUE(ThreadState::Current()->IsIncrementalMarking());
1419   driver.SingleStep();
1420   EXPECT_TRUE(ThreadState::Current()->IsIncrementalMarking());
1421   driver.FinishGC();
1422   EXPECT_FALSE(ThreadState::Current()->IsIncrementalMarking());
1423 }
1424 
TEST_F(IncrementalMarkingTest,DropBackingStore)1425 TEST_F(IncrementalMarkingTest, DropBackingStore) {
1426   // Regression test: https://crbug.com/828537
1427   using WeakStore = HeapHashCountedSet<WeakMember<Object>>;
1428 
1429   Persistent<WeakStore> persistent(MakeGarbageCollected<WeakStore>());
1430   persistent->insert(MakeGarbageCollected<Object>());
1431   IncrementalMarkingTestDriver driver(ThreadState::Current());
1432   driver.Start();
1433   driver.FinishSteps();
1434   persistent->clear();
1435   // Marking verifier should not crash on a black backing store with all
1436   // black->white edges.
1437   driver.FinishGC();
1438 }
1439 
TEST_F(IncrementalMarkingTest,NoBackingFreeDuringIncrementalMarking)1440 TEST_F(IncrementalMarkingTest, NoBackingFreeDuringIncrementalMarking) {
1441   // Regression test: https://crbug.com/870306
1442   // Only reproduces in ASAN configurations.
1443   using WeakStore = HeapHashCountedSet<WeakMember<Object>>;
1444 
1445   Persistent<WeakStore> persistent(MakeGarbageCollected<WeakStore>());
1446   // Prefill the collection to grow backing store. A new backing store
1447   // allocationwould trigger the write barrier, mitigating the bug where
1448   // a backing store is promptly freed.
1449   for (size_t i = 0; i < 8; i++) {
1450     persistent->insert(MakeGarbageCollected<Object>());
1451   }
1452   IncrementalMarkingTestDriver driver(ThreadState::Current());
1453   driver.Start();
1454   persistent->insert(MakeGarbageCollected<Object>());
1455   // Is not allowed to free the backing store as the previous insert may have
1456   // registered a slot.
1457   persistent->clear();
1458   driver.FinishSteps();
1459   driver.FinishGC();
1460 }
1461 
TEST_F(IncrementalMarkingTest,DropReferenceWithHeapCompaction)1462 TEST_F(IncrementalMarkingTest, DropReferenceWithHeapCompaction) {
1463   using Store = HeapHashCountedSet<Member<Object>>;
1464 
1465   Persistent<Store> persistent(MakeGarbageCollected<Store>());
1466   persistent->insert(MakeGarbageCollected<Object>());
1467   IncrementalMarkingTestDriver driver(ThreadState::Current());
1468   ThreadState::Current()->EnableCompactionForNextGCForTesting();
1469   driver.Start();
1470   driver.FinishSteps();
1471   persistent->clear();
1472   // Registration of movable and updatable references should not crash because
1473   // if a slot have nullptr reference, it doesn't call registeration method.
1474   driver.FinishGC();
1475 }
1476 
TEST_F(IncrementalMarkingTest,HasInlineCapacityCollectionWithHeapCompaction)1477 TEST_F(IncrementalMarkingTest, HasInlineCapacityCollectionWithHeapCompaction) {
1478   using Store = HeapVector<Member<Object>, 2>;
1479 
1480   Persistent<Store> persistent(MakeGarbageCollected<Store>());
1481   Persistent<Store> persistent2(MakeGarbageCollected<Store>());
1482 
1483   IncrementalMarkingTestDriver driver(ThreadState::Current());
1484   ThreadState::Current()->EnableCompactionForNextGCForTesting();
1485   persistent->push_back(MakeGarbageCollected<Object>());
1486   driver.Start();
1487   driver.FinishGC();
1488 
1489   // Should collect also slots that has only inline buffer and nullptr
1490   // references.
1491 #if defined(ANNOTATE_CONTIGUOUS_CONTAINER)
1492   // When ANNOTATE_CONTIGUOUS_CONTAINER is defined, inline capacity is ignored.
1493   EXPECT_EQ(driver.GetHeapCompactLastFixupCount(), 1u);
1494 #else
1495   EXPECT_EQ(driver.GetHeapCompactLastFixupCount(), 2u);
1496 #endif
1497 }
1498 
TEST_F(IncrementalMarkingTest,WeakHashMapHeapCompaction)1499 TEST_F(IncrementalMarkingTest, WeakHashMapHeapCompaction) {
1500   using Store = HeapHashCountedSet<WeakMember<Object>>;
1501 
1502   Persistent<Store> persistent(MakeGarbageCollected<Store>());
1503 
1504   IncrementalMarkingTestDriver driver(ThreadState::Current());
1505   ThreadState::Current()->EnableCompactionForNextGCForTesting();
1506   driver.Start();
1507   driver.FinishSteps();
1508   persistent->insert(MakeGarbageCollected<Object>());
1509   driver.FinishGC();
1510 
1511   // Weak callback should register the slot.
1512   EXPECT_EQ(1u, driver.GetHeapCompactLastFixupCount());
1513 }
1514 
TEST_F(IncrementalMarkingTest,ConservativeGCWhileCompactionScheduled)1515 TEST_F(IncrementalMarkingTest, ConservativeGCWhileCompactionScheduled) {
1516   using Store = HeapVector<Member<Object>>;
1517   Persistent<Store> persistent(MakeGarbageCollected<Store>());
1518   persistent->push_back(MakeGarbageCollected<Object>());
1519 
1520   IncrementalMarkingTestDriver driver(ThreadState::Current());
1521   ThreadState::Current()->EnableCompactionForNextGCForTesting();
1522   driver.Start();
1523   driver.FinishSteps();
1524   ThreadState::Current()->CollectGarbageForTesting(
1525       BlinkGC::CollectionType::kMajor, BlinkGC::kHeapPointersOnStack,
1526       BlinkGC::kAtomicMarking, BlinkGC::kConcurrentAndLazySweeping,
1527       BlinkGC::GCReason::kForcedGCForTesting);
1528 
1529   // Heap compaction should be canceled if incremental marking finishes with a
1530   // conservative GC.
1531   EXPECT_EQ(driver.GetHeapCompactLastFixupCount(), 0u);
1532 }
1533 
1534 namespace {
1535 
1536 class ObjectWithWeakMember : public GarbageCollected<ObjectWithWeakMember> {
1537  public:
1538   ObjectWithWeakMember() = default;
1539 
set_object(Object * object)1540   void set_object(Object* object) { object_ = object; }
1541 
Trace(Visitor * visitor) const1542   void Trace(Visitor* visitor) const { visitor->Trace(object_); }
1543 
1544  private:
1545   WeakMember<Object> object_ = nullptr;
1546 };
1547 
1548 }  // namespace
1549 
TEST_F(IncrementalMarkingTest,WeakMember)1550 TEST_F(IncrementalMarkingTest, WeakMember) {
1551   // Regression test: https://crbug.com/913431
1552 
1553   Persistent<ObjectWithWeakMember> persistent(
1554       MakeGarbageCollected<ObjectWithWeakMember>());
1555   IncrementalMarkingTestDriver driver(ThreadState::Current());
1556   driver.Start();
1557   driver.FinishSteps();
1558   persistent->set_object(MakeGarbageCollected<Object>());
1559   driver.FinishGC();
1560   ConservativelyCollectGarbage();
1561 }
1562 
TEST_F(IncrementalMarkingTest,MemberSwap)1563 TEST_F(IncrementalMarkingTest, MemberSwap) {
1564   // Regression test: https://crbug.com/913431
1565   //
1566   // MemberBase::Swap may be used to swap in a not-yet-processed member into an
1567   // already-processed member. This leads to a stale pointer that is not marked.
1568 
1569   Persistent<Object> object1(MakeGarbageCollected<Object>());
1570   IncrementalMarkingTestDriver driver(ThreadState::Current());
1571   driver.Start();
1572   // The repro leverages the fact that initializing stores do not emit a barrier
1573   // (because they are still reachable from stack) to simulate the problematic
1574   // interleaving.
1575   driver.FinishSteps();
1576   Object* object2 =
1577       MakeGarbageCollected<Object>(MakeGarbageCollected<Object>());
1578   object2->next_ref().Swap(object1->next_ref());
1579   driver.FinishGC();
1580   ConservativelyCollectGarbage();
1581 }
1582 
1583 namespace {
1584 
1585 template <typename T>
1586 class ObjectHolder : public GarbageCollected<ObjectHolder<T>> {
1587  public:
1588   ObjectHolder() = default;
1589 
Trace(Visitor * visitor) const1590   virtual void Trace(Visitor* visitor) const { visitor->Trace(holder_); }
1591 
set_value(T * value)1592   void set_value(T* value) { holder_ = value; }
value() const1593   T* value() const { return holder_.Get(); }
1594 
1595  private:
1596   Member<T> holder_;
1597 };
1598 
1599 }  // namespace
1600 
TEST_F(IncrementalMarkingTest,StepDuringObjectConstruction)1601 TEST_F(IncrementalMarkingTest, StepDuringObjectConstruction) {
1602   // Test ensures that objects in construction are delayed for processing to
1603   // allow omitting write barriers on initializing stores.
1604 
1605   using O = ObjectWithCallbackBeforeInitializer<Object>;
1606   using Holder = ObjectHolder<O>;
1607   Persistent<Holder> holder(MakeGarbageCollected<Holder>());
1608   IncrementalMarkingTestDriver driver(ThreadState::Current());
1609   driver.Start();
1610   MakeGarbageCollected<O>(
1611       base::BindOnce(
1612           [](IncrementalMarkingTestDriver* driver, Holder* holder, O* thiz) {
1613             // Publish not-fully-constructed object |thiz| by triggering write
1614             // barrier for the object.
1615             holder->set_value(thiz);
1616             // Finish call incremental steps.
1617             driver->FinishSteps(BlinkGC::StackState::kHeapPointersOnStack);
1618           },
1619           &driver, holder.Get()),
1620       MakeGarbageCollected<Object>());
1621   driver.FinishGC();
1622   PreciselyCollectGarbage();
1623 }
1624 
TEST_F(IncrementalMarkingTest,StepDuringMixinObjectConstruction)1625 TEST_F(IncrementalMarkingTest, StepDuringMixinObjectConstruction) {
1626   // Test ensures that mixin objects in construction are delayed for processing
1627   // to allow omitting write barriers on initializing stores.
1628 
1629   using Parent = ObjectWithMixinWithCallbackBeforeInitializer<Object>;
1630   using Mixin = MixinWithCallbackBeforeInitializer<Object>;
1631   using Holder = ObjectHolder<Mixin>;
1632   Persistent<Holder> holder(MakeGarbageCollected<Holder>());
1633   IncrementalMarkingTestDriver driver(ThreadState::Current());
1634   driver.Start();
1635   MakeGarbageCollected<Parent>(
1636       base::BindOnce(
1637           [](IncrementalMarkingTestDriver* driver, Holder* holder,
1638              Mixin* thiz) {
1639             // Publish not-fully-constructed object
1640             // |thiz| by triggering write barrier for
1641             // the object.
1642             holder->set_value(thiz);
1643             // Finish call incremental steps.
1644             driver->FinishSteps(BlinkGC::StackState::kHeapPointersOnStack);
1645           },
1646           &driver, holder.Get()),
1647       MakeGarbageCollected<Object>());
1648   driver.FinishGC();
1649   PreciselyCollectGarbage();
1650 }
1651 
TEST_F(IncrementalMarkingTest,IncrementalMarkingShrinkingBackingCompaction)1652 TEST_F(IncrementalMarkingTest, IncrementalMarkingShrinkingBackingCompaction) {
1653   // Regression test: https://crbug.com/918064
1654 
1655   using Nested = HeapVector<HeapVector<Member<Object>>>;
1656   // The following setup will ensure that the outer HeapVector's backing store
1657   // contains slots to other to-be-compacted backings.
1658   Persistent<Nested> holder(MakeGarbageCollected<Nested>());
1659   for (int i = 0; i < 32; i++) {
1660     holder->emplace_back();
1661     holder->at(i).emplace_back(MakeGarbageCollected<Object>());
1662   }
1663   IncrementalMarkingTestDriver driver(ThreadState::Current());
1664   ThreadState::Current()->EnableCompactionForNextGCForTesting();
1665   driver.Start();
1666   driver.FinishSteps();
1667   // Reduce size of the outer backing store.
1668   for (int i = 0; i < 16; i++) {
1669     holder->pop_back();
1670   }
1671   // Ensure that shrinking the backing does not crash in compaction as there may
1672   // be registered slots left in the area that is already freed.
1673   holder->ShrinkToFit();
1674   driver.FinishGC();
1675 }
1676 
TEST_F(IncrementalMarkingTest,InPayloadWriteBarrierRegistersInvalidSlotForCompaction)1677 TEST_F(IncrementalMarkingTest,
1678        InPayloadWriteBarrierRegistersInvalidSlotForCompaction) {
1679   // Regression test: https://crbug.com/918064
1680 
1681   using Nested = HeapVector<HeapVector<Member<Object>>>;
1682   IncrementalMarkingTestDriver driver(ThreadState::Current());
1683   ThreadState::Current()->EnableCompactionForNextGCForTesting();
1684   // Allocate a vector and reserve a buffer to avoid triggering the write
1685   // barrier during incremental marking.
1686   Nested* nested = MakeGarbageCollected<Nested>();
1687   nested->ReserveCapacity(32);
1688   driver.Start();
1689   // Initialize the inner vector, triggering tracing and slots registration.
1690   // This could be an object using DISALLOW_NEW() but HeapVector is easier to
1691   // test.
1692   nested->emplace_back(1);
1693   // Use the inner vector as otherwise the slot would not be registered due to
1694   // not having a backing store itself.
1695   nested->at(0).emplace_back(MakeGarbageCollected<Object>());
1696   driver.FinishSteps();
1697   // GCs here are without stack. This is just to show that we don't want this
1698   // object marked.
1699   CHECK(!HeapObjectHeader::FromPayload(nested)
1700              ->IsMarked<HeapObjectHeader::AccessMode::kAtomic>());
1701   nested = nullptr;
1702   driver.FinishGC();
1703 }
1704 
TEST_F(IncrementalMarkingTest,AdjustMarkedBytesOnMarkedBackingStore)1705 TEST_F(IncrementalMarkingTest, AdjustMarkedBytesOnMarkedBackingStore) {
1706   // Regression test: https://crbug.com/966456
1707   //
1708   // Test ensures that backing expansion does not crash in trying to adjust
1709   // marked bytes when the page is actually about to be swept and marking is not
1710   // in progress.
1711 
1712   // Disable concurrent sweeping to check that sweeping is not in progress after
1713   // the FinishGC call.
1714   base::test::ScopedFeatureList scoped_feature_list;
1715   scoped_feature_list.InitAndDisableFeature(
1716       blink::features::kBlinkHeapConcurrentSweeping);
1717   using Container = HeapVector<Member<Object>>;
1718   Persistent<Container> holder(MakeGarbageCollected<Container>());
1719   holder->push_back(MakeGarbageCollected<Object>());
1720   holder->Grow(16);
1721   ThreadState::Current()->Heap().ResetAllocationPointForTesting();
1722   // Slowly shrink down the backing, only adjusting capacity without performing
1723   // free as the resulting memory block is too small for a free list entry.
1724   for (int i = 15; i > 0; i--) {
1725     holder->Shrink(i);
1726     holder->ShrinkToFit();
1727   }
1728   IncrementalMarkingTestDriver driver(ThreadState::Current());
1729   driver.Start();
1730   driver.FinishSteps();
1731   // The object is marked at this point.
1732   CHECK(HeapObjectHeader::FromPayload(holder.Get())
1733             ->IsMarked<HeapObjectHeader::AccessMode::kAtomic>());
1734   driver.FinishGC(false);
1735   // The object is still marked as sweeping did not make any progress.
1736   CHECK(HeapObjectHeader::FromPayload(holder.Get())->IsMarked());
1737   // Re-grow to some size within the initial payload size (capacity=16).
1738   holder->Grow(8);
1739 }
1740 
TEST_F(IncrementalMarkingTest,HeapCompactWithStaleSlotInNestedContainer)1741 TEST_F(IncrementalMarkingTest, HeapCompactWithStaleSlotInNestedContainer) {
1742   // Regression test: https://crbug.com/980962
1743   //
1744   // Test ensures that interior pointers are updated even if the backing store
1745   // itself is not referenced anymore. Consider the case where a |B| is
1746   // references a value |V| through slot |B.x|. Even if |B| is not referred to
1747   // from an actual object any more, the slot |B.x| needs to be in valid state
1748   // when |V| is moved.
1749 
1750   using Nested = HeapVector<HeapVector<Member<Object>>>;
1751 
1752   // Allocate dummy storage so that other vector backings are actually moved.
1753   MakeGarbageCollected<HeapVector<Member<Object>>>()->push_back(
1754       MakeGarbageCollected<Object>());
1755 
1756   IncrementalMarkingTestDriver driver(ThreadState::Current());
1757   ThreadState::Current()->EnableCompactionForNextGCForTesting();
1758   driver.Start();
1759   Nested* outer = MakeGarbageCollected<Nested>();
1760   outer->push_back(HeapVector<Member<Object>>());
1761   outer->at(0).push_back(MakeGarbageCollected<Object>());
1762   // The outer HeapVector object is not marked, which leaves the backing store
1763   // as marked with a valid slot inside. Now, if the outer backing store moves
1764   // first and its page is freed, then referring to the slot when the inner
1765   // backing store is moved may crash.
1766   outer = nullptr;
1767   driver.FinishSteps();
1768   driver.FinishGC();
1769 }
1770 
1771 class Destructed final : public GarbageCollected<Destructed> {
1772  public:
~Destructed()1773   ~Destructed() { n_destructed++; }
1774 
Trace(Visitor *) const1775   void Trace(Visitor*) const {}
1776 
1777   static size_t n_destructed;
1778 };
1779 
1780 size_t Destructed::n_destructed = 0;
1781 
1782 class LinkedHashSetWrapper final
1783     : public GarbageCollected<LinkedHashSetWrapper> {
1784  public:
1785   using HashType = HeapLinkedHashSet<Member<Destructed>>;
1786 
LinkedHashSetWrapper()1787   LinkedHashSetWrapper() {
1788     for (size_t i = 0; i < 10; ++i) {
1789       hash_set_.insert(MakeGarbageCollected<Destructed>());
1790     }
1791   }
1792 
Trace(Visitor * v) const1793   void Trace(Visitor* v) const { v->Trace(hash_set_); }
1794 
Swap()1795   void Swap() {
1796     HashType hash_set;
1797     hash_set_.Swap(hash_set);
1798   }
1799 
1800   HashType hash_set_;
1801 };
1802 
TEST_F(IncrementalMarkingTest,LinkedHashSetMovingCallback)1803 TEST_F(IncrementalMarkingTest, LinkedHashSetMovingCallback) {
1804   ClearOutOldGarbage();
1805 
1806   Destructed::n_destructed = 0;
1807   {
1808     HeapHashSet<Member<Destructed>> to_be_destroyed;
1809     to_be_destroyed.ReserveCapacityForSize(100);
1810   }
1811   Persistent<LinkedHashSetWrapper> wrapper =
1812       MakeGarbageCollected<LinkedHashSetWrapper>();
1813 
1814   IncrementalMarkingTestDriver driver(ThreadState::Current());
1815   ThreadState::Current()->EnableCompactionForNextGCForTesting();
1816   driver.Start();
1817   driver.FinishSteps();
1818 
1819   // Destroy the link between original HeapLinkedHashSet object and its backing
1820   // store.
1821   wrapper->Swap();
1822   DCHECK(wrapper->hash_set_.IsEmpty());
1823 
1824   PreciselyCollectGarbage();
1825 
1826   EXPECT_EQ(10u, Destructed::n_destructed);
1827 }
1828 
1829 class DestructedAndTraced final : public GarbageCollected<DestructedAndTraced> {
1830  public:
~DestructedAndTraced()1831   ~DestructedAndTraced() { n_destructed++; }
1832 
Trace(Visitor *) const1833   void Trace(Visitor*) const { n_traced++; }
1834 
1835   static size_t n_destructed;
1836   static size_t n_traced;
1837 };
1838 
1839 size_t DestructedAndTraced::n_destructed = 0;
1840 size_t DestructedAndTraced::n_traced = 0;
1841 
TEST_F(IncrementalMarkingTest,ConservativeGCOfWeakContainer)1842 TEST_F(IncrementalMarkingTest, ConservativeGCOfWeakContainer) {
1843   // Regression test: https://crbug.com/1108676
1844   //
1845   // Test ensures that on-stack references to weak containers (e.g. iterators)
1846   // force re-tracing of the entire container. Otherwise, if the container was
1847   // previously traced and is not re-traced, some bucket might be deleted which
1848   // will make existing iterators invalid.
1849 
1850   using WeakContainer = HeapHashMap<WeakMember<DestructedAndTraced>, size_t>;
1851   Persistent<WeakContainer> map = MakeGarbageCollected<WeakContainer>();
1852   static constexpr size_t kNumObjects = 10u;
1853   for (size_t i = 0; i < kNumObjects; ++i) {
1854     map->insert(MakeGarbageCollected<DestructedAndTraced>(), i);
1855   }
1856   DestructedAndTraced::n_destructed = 0;
1857 
1858   for (auto it = map->begin(); it != map->end(); ++it) {
1859     size_t value = it->value;
1860     DestructedAndTraced::n_traced = 0;
1861     IncrementalMarkingTestDriver driver(ThreadState::Current());
1862     driver.Start();
1863     driver.FinishSteps();
1864     // map should now be marked, but has not been traced since it's weak.
1865     EXPECT_EQ(0u, DestructedAndTraced::n_traced);
1866     ConservativelyCollectGarbage();
1867     // map buckets were traced (at least once).
1868     EXPECT_NE(kNumObjects, DestructedAndTraced::n_traced);
1869     // Check that iterator is still valid.
1870     EXPECT_EQ(value, it->value);
1871   }
1872 
1873   // All buckets were kept alive.
1874   EXPECT_EQ(0u, DestructedAndTraced::n_destructed);
1875 }
1876 
1877 }  // namespace incremental_marking_test
1878 }  // namespace blink
1879