1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <algorithm>
32 #include <atomic>
33 #include <memory>
34 #include <utility>
35
36 #include "base/atomic_ref_count.h"
37 #include "base/bind.h"
38 #include "base/location.h"
39 #include "base/memory/ptr_util.h"
40 #include "base/synchronization/waitable_event.h"
41 #include "base/test/scoped_feature_list.h"
42 #include "build/build_config.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 #include "third_party/blink/public/common/features.h"
45 #include "third_party/blink/public/platform/platform.h"
46 #include "third_party/blink/renderer/platform/bindings/buildflags.h"
47 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
48 #include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h"
49 #include "third_party/blink/renderer/platform/heap/handle.h"
50 #include "third_party/blink/renderer/platform/heap/heap.h"
51 #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
52 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
53 #include "third_party/blink/renderer/platform/heap/marking_visitor.h"
54 #include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
55 #include "third_party/blink/renderer/platform/heap/thread_state.h"
56 #include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
57 #include "third_party/blink/renderer/platform/heap/visitor.h"
58 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
59 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
60 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
61 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
62 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
63 #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
64 #include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
65
66 namespace blink {
67
68 namespace {
69
70 class HeapTest : public TestSupportingGC {};
71
72 class IntWrapper : public GarbageCollected<IntWrapper> {
73 public:
~IntWrapper()74 virtual ~IntWrapper() {
75 destructor_calls_.fetch_add(1, std::memory_order_relaxed);
76 }
77
78 static std::atomic_int destructor_calls_;
Trace(Visitor * visitor)79 void Trace(Visitor* visitor) {}
80
Value() const81 int Value() const { return x_; }
82
operator ==(const IntWrapper & other) const83 bool operator==(const IntWrapper& other) const {
84 return other.Value() == Value();
85 }
86
GetHash()87 unsigned GetHash() { return IntHash<int>::GetHash(x_); }
88
IntWrapper(int x)89 IntWrapper(int x) : x_(x) {}
90
91 private:
92 IntWrapper() = delete;
93 int x_;
94 };
95
96 std::atomic_int IntWrapper::destructor_calls_{0};
97
98 struct IntWrapperHash {
GetHashblink::__anon08a198100111::IntWrapperHash99 static unsigned GetHash(const IntWrapper& key) {
100 return WTF::HashInt(static_cast<uint32_t>(key.Value()));
101 }
102
Equalblink::__anon08a198100111::IntWrapperHash103 static bool Equal(const IntWrapper& a, const IntWrapper& b) { return a == b; }
104 };
105
106 static_assert(WTF::IsTraceable<IntWrapper>::value,
107 "IsTraceable<> template failed to recognize trace method.");
108 static_assert(WTF::IsTraceable<HeapVector<IntWrapper>>::value,
109 "HeapVector<IntWrapper> must be traceable.");
110 static_assert(WTF::IsTraceable<HeapDeque<IntWrapper>>::value,
111 "HeapDeque<IntWrapper> must be traceable.");
112 static_assert(WTF::IsTraceable<HeapHashSet<IntWrapper, IntWrapperHash>>::value,
113 "HeapHashSet<IntWrapper> must be traceable.");
114 static_assert(WTF::IsTraceable<HeapHashMap<int, IntWrapper>>::value,
115 "HeapHashMap<int, IntWrapper> must be traceable.");
116
117 class KeyWithCopyingMoveConstructor final {
118 DISALLOW_NEW();
119
120 public:
121 struct Hash final {
122 STATIC_ONLY(Hash);
123
124 public:
GetHashblink::__anon08a198100111::KeyWithCopyingMoveConstructor::Hash125 static unsigned GetHash(const KeyWithCopyingMoveConstructor& key) {
126 return key.hash_;
127 }
128
Equalblink::__anon08a198100111::KeyWithCopyingMoveConstructor::Hash129 static bool Equal(const KeyWithCopyingMoveConstructor& x,
130 const KeyWithCopyingMoveConstructor& y) {
131 return x.hash_ == y.hash_;
132 }
133
134 static constexpr bool safe_to_compare_to_empty_or_deleted = true;
135 };
136
137 KeyWithCopyingMoveConstructor() = default;
KeyWithCopyingMoveConstructor(WTF::HashTableDeletedValueType)138 KeyWithCopyingMoveConstructor(WTF::HashTableDeletedValueType) : hash_(-1) {}
139 ~KeyWithCopyingMoveConstructor() = default;
KeyWithCopyingMoveConstructor(unsigned hash,const String & string)140 KeyWithCopyingMoveConstructor(unsigned hash, const String& string)
141 : hash_(hash), string_(string) {
142 DCHECK_NE(hash_, 0);
143 DCHECK_NE(hash_, -1);
144 }
145 KeyWithCopyingMoveConstructor(const KeyWithCopyingMoveConstructor&) = default;
146 // The move constructor delegates to the copy constructor intentionally.
KeyWithCopyingMoveConstructor(KeyWithCopyingMoveConstructor && x)147 KeyWithCopyingMoveConstructor(KeyWithCopyingMoveConstructor&& x)
148 : KeyWithCopyingMoveConstructor(x) {}
149 KeyWithCopyingMoveConstructor& operator=(
150 const KeyWithCopyingMoveConstructor&) = default;
operator ==(const KeyWithCopyingMoveConstructor & x) const151 bool operator==(const KeyWithCopyingMoveConstructor& x) const {
152 return hash_ == x.hash_;
153 }
154
IsHashTableDeletedValue() const155 bool IsHashTableDeletedValue() const { return hash_ == -1; }
156
157 private:
158 int hash_ = 0;
159 String string_;
160 };
161
162 struct SameSizeAsPersistent {
163 void* pointer_[4];
164 #if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
165 PersistentLocation location;
166 #endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
167 };
168
169 static_assert(sizeof(Persistent<IntWrapper>) <= sizeof(SameSizeAsPersistent),
170 "Persistent handle should stay small");
171
172 class ThreadMarker {
173 DISALLOW_NEW();
174
175 public:
ThreadMarker()176 ThreadMarker()
177 : creating_thread_(reinterpret_cast<ThreadState*>(0)), num_(0) {}
ThreadMarker(unsigned i)178 ThreadMarker(unsigned i)
179 : creating_thread_(ThreadState::Current()), num_(i) {}
ThreadMarker(WTF::HashTableDeletedValueType deleted)180 ThreadMarker(WTF::HashTableDeletedValueType deleted)
181 : creating_thread_(reinterpret_cast<ThreadState*>(-1)), num_(0) {}
~ThreadMarker()182 ~ThreadMarker() {
183 EXPECT_TRUE((creating_thread_ == ThreadState::Current()) ||
184 (creating_thread_ == reinterpret_cast<ThreadState*>(0)) ||
185 (creating_thread_ == reinterpret_cast<ThreadState*>(-1)));
186 }
IsHashTableDeletedValue() const187 bool IsHashTableDeletedValue() const {
188 return creating_thread_ == reinterpret_cast<ThreadState*>(-1);
189 }
operator ==(const ThreadMarker & other) const190 bool operator==(const ThreadMarker& other) const {
191 return other.creating_thread_ == creating_thread_ && other.num_ == num_;
192 }
193 ThreadState* creating_thread_;
194 unsigned num_;
195 };
196
197 struct ThreadMarkerHash {
GetHashblink::__anon08a198100111::ThreadMarkerHash198 static unsigned GetHash(const ThreadMarker& key) {
199 return static_cast<unsigned>(
200 reinterpret_cast<uintptr_t>(key.creating_thread_) + key.num_);
201 }
202
Equalblink::__anon08a198100111::ThreadMarkerHash203 static bool Equal(const ThreadMarker& a, const ThreadMarker& b) {
204 return a == b;
205 }
206
207 static const bool safe_to_compare_to_empty_or_deleted = false;
208 };
209
210 } // namespace
211
212 } // namespace blink
213
214 namespace WTF {
215
216 template <typename T>
217 struct DefaultHash;
218 template <>
219 struct DefaultHash<blink::ThreadMarker> {
220 typedef blink::ThreadMarkerHash Hash;
221 };
222
223 // ThreadMarkerHash is the default hash for ThreadMarker
224 template <>
225 struct HashTraits<blink::ThreadMarker>
226 : GenericHashTraits<blink::ThreadMarker> {
227 static const bool kEmptyValueIsZero = true;
ConstructDeletedValueWTF::HashTraits228 static void ConstructDeletedValue(blink::ThreadMarker& slot, bool) {
229 new (NotNull, &slot) blink::ThreadMarker(kHashTableDeletedValue);
230 }
IsDeletedValueWTF::HashTraits231 static bool IsDeletedValue(const blink::ThreadMarker& slot) {
232 return slot.IsHashTableDeletedValue();
233 }
234 };
235
236 template <>
237 struct DefaultHash<blink::KeyWithCopyingMoveConstructor> {
238 using Hash = blink::KeyWithCopyingMoveConstructor::Hash;
239 };
240
241 template <>
242 struct HashTraits<blink::KeyWithCopyingMoveConstructor>
243 : public SimpleClassHashTraits<blink::KeyWithCopyingMoveConstructor> {};
244
245 } // namespace WTF
246
247 namespace blink {
248
249 class TestGCCollectGarbageScope {
250 STACK_ALLOCATED();
251
252 public:
TestGCCollectGarbageScope(BlinkGC::StackState state)253 explicit TestGCCollectGarbageScope(BlinkGC::StackState state) {
254 DCHECK(ThreadState::Current()->CheckThread());
255 }
256
~TestGCCollectGarbageScope()257 ~TestGCCollectGarbageScope() { ThreadState::Current()->CompleteSweep(); }
258 };
259
260 class TestGCScope : public TestGCCollectGarbageScope {
261 public:
TestGCScope(BlinkGC::StackState state)262 explicit TestGCScope(BlinkGC::StackState state)
263 : TestGCCollectGarbageScope(state) {
264 ThreadState::Current()->Heap().stats_collector()->NotifyMarkingStarted(
265 BlinkGC::CollectionType::kMajor,
266 BlinkGC::GCReason::kForcedGCForTesting);
267 ThreadState::Current()->AtomicPauseMarkPrologue(
268 BlinkGC::CollectionType::kMajor, state, BlinkGC::kAtomicMarking,
269 BlinkGC::GCReason::kPreciseGC);
270 }
~TestGCScope()271 ~TestGCScope() {
272 ThreadState::Current()->AtomicPauseMarkEpilogue(BlinkGC::kAtomicMarking);
273 ThreadState::Current()->AtomicPauseSweepAndCompact(
274 BlinkGC::CollectionType::kMajor, BlinkGC::kAtomicMarking,
275 BlinkGC::kEagerSweeping);
276 ThreadState::Current()->AtomicPauseEpilogue();
277 }
278 };
279
280 class SimpleObject : public GarbageCollected<SimpleObject> {
281 public:
282 SimpleObject() = default;
Trace(Visitor * visitor)283 void Trace(Visitor* visitor) {}
GetPayload(int i)284 char GetPayload(int i) { return payload[i]; }
285 // This virtual method is unused but it is here to make sure
286 // that this object has a vtable. This object is used
287 // as the super class for objects that also have garbage
288 // collected mixins and having a virtual here makes sure
289 // that adjustment is needed both for marking and for isAlive
290 // checks.
VirtualMethod()291 virtual void VirtualMethod() {}
292
293 protected:
294 char payload[64];
295 };
296
297 class HeapTestSuperClass : public GarbageCollected<HeapTestSuperClass> {
298 public:
299 HeapTestSuperClass() = default;
~HeapTestSuperClass()300 virtual ~HeapTestSuperClass() { ++destructor_calls_; }
301
302 static int destructor_calls_;
Trace(Visitor * visitor)303 void Trace(Visitor* visitor) {}
304 };
305
306 int HeapTestSuperClass::destructor_calls_ = 0;
307
308 class HeapTestOtherSuperClass {
309 public:
310 int payload;
311 };
312
313 static const size_t kClassMagic = 0xABCDDBCA;
314
315 class HeapTestSubClass : public HeapTestOtherSuperClass,
316 public HeapTestSuperClass {
317 public:
HeapTestSubClass()318 HeapTestSubClass() : magic_(kClassMagic) {}
~HeapTestSubClass()319 ~HeapTestSubClass() override {
320 EXPECT_EQ(kClassMagic, magic_);
321 ++destructor_calls_;
322 }
323
324 static int destructor_calls_;
325
326 private:
327 const size_t magic_;
328 };
329
330 int HeapTestSubClass::destructor_calls_ = 0;
331
332 class HeapAllocatedArray : public GarbageCollected<HeapAllocatedArray> {
333 public:
HeapAllocatedArray()334 HeapAllocatedArray() {
335 for (int i = 0; i < kArraySize; ++i) {
336 array_[i] = i % 128;
337 }
338 }
339
at(size_t i)340 int8_t at(size_t i) { return array_[i]; }
Trace(Visitor * visitor)341 void Trace(Visitor* visitor) {}
342
343 private:
344 static const int kArraySize = 1000;
345 int8_t array_[kArraySize];
346 };
347
348 class OffHeapInt : public RefCounted<OffHeapInt> {
349 USING_FAST_MALLOC(OffHeapInt);
350
351 public:
Create(int x)352 static scoped_refptr<OffHeapInt> Create(int x) {
353 return base::AdoptRef(new OffHeapInt(x));
354 }
355
~OffHeapInt()356 virtual ~OffHeapInt() { ++destructor_calls_; }
357
358 static int destructor_calls_;
359
Value() const360 int Value() const { return x_; }
361
operator ==(const OffHeapInt & other) const362 bool operator==(const OffHeapInt& other) const {
363 return other.Value() == Value();
364 }
365
GetHash()366 unsigned GetHash() { return IntHash<int>::GetHash(x_); }
VoidFunction()367 void VoidFunction() {}
368
369 protected:
OffHeapInt(int x)370 OffHeapInt(int x) : x_(x) {}
371
372 private:
373 OffHeapInt() = delete;
374 int x_;
375 };
376
377 int OffHeapInt::destructor_calls_ = 0;
378
379 class ThreadedTesterBase {
380 protected:
Test(ThreadedTesterBase * tester)381 static void Test(ThreadedTesterBase* tester) {
382 std::unique_ptr<Thread> threads[kNumberOfThreads];
383 for (auto& thread : threads) {
384 thread = Platform::Current()->CreateThread(
385 ThreadCreationParams(ThreadType::kTestThread)
386 .SetThreadNameForTest("blink gc testing thread"));
387 PostCrossThreadTask(
388 *thread->GetTaskRunner(), FROM_HERE,
389 CrossThreadBindOnce(ThreadFunc, CrossThreadUnretained(tester)));
390 }
391 tester->done_.Wait();
392 delete tester;
393 }
394
395 virtual void RunThread() = 0;
396
397 protected:
398 static const int kNumberOfThreads = 10;
399 static const int kGcPerThread = 5;
400 static const int kNumberOfAllocations = 50;
401
402 virtual ~ThreadedTesterBase() = default;
403
Done() const404 inline bool Done() const {
405 return gc_count_.load(std::memory_order_acquire) >=
406 kNumberOfThreads * kGcPerThread;
407 }
408
409 std::atomic_int gc_count_{0};
410
411 private:
ThreadFunc(ThreadedTesterBase * tester)412 static void ThreadFunc(ThreadedTesterBase* tester) {
413 ThreadState::AttachCurrentThread();
414 tester->RunThread();
415 ThreadState::DetachCurrentThread();
416 if (!tester->threads_to_finish_.Decrement())
417 tester->done_.Signal();
418 }
419
420 base::AtomicRefCount threads_to_finish_{kNumberOfThreads};
421 base::WaitableEvent done_;
422 };
423
424 // Needed to give this variable a definition (the initializer above is only a
425 // declaration), so that subclasses can use it.
426 const int ThreadedTesterBase::kNumberOfThreads;
427
428 class ThreadedHeapTester : public ThreadedTesterBase {
429 public:
Test()430 static void Test() { ThreadedTesterBase::Test(new ThreadedHeapTester); }
431
~ThreadedHeapTester()432 ~ThreadedHeapTester() override {
433 // Verify that the threads cleared their CTPs when
434 // terminating, preventing access to a finalized heap.
435 for (auto& global_int_wrapper : cross_persistents_) {
436 DCHECK(global_int_wrapper.get());
437 EXPECT_FALSE(global_int_wrapper.get()->Get());
438 }
439 }
440
441 protected:
442 using GlobalIntWrapperPersistent = CrossThreadPersistent<IntWrapper>;
443
444 Mutex mutex_;
445 Vector<std::unique_ptr<GlobalIntWrapperPersistent>> cross_persistents_;
446
CreateGlobalPersistent(int value)447 std::unique_ptr<GlobalIntWrapperPersistent> CreateGlobalPersistent(
448 int value) {
449 return std::make_unique<GlobalIntWrapperPersistent>(
450 MakeGarbageCollected<IntWrapper>(value));
451 }
452
AddGlobalPersistent()453 void AddGlobalPersistent() {
454 MutexLocker lock(mutex_);
455 cross_persistents_.push_back(CreateGlobalPersistent(0x2a2a2a2a));
456 }
457
RunThread()458 void RunThread() override {
459 // Add a cross-thread persistent from this thread; the test object
460 // verifies that it will have been cleared out after the threads
461 // have all detached, running their termination GCs while doing so.
462 AddGlobalPersistent();
463
464 int gc_count = 0;
465 while (!Done()) {
466 {
467 Persistent<IntWrapper> wrapper;
468
469 std::unique_ptr<GlobalIntWrapperPersistent> global_persistent =
470 CreateGlobalPersistent(0x0ed0cabb);
471
472 for (int i = 0; i < kNumberOfAllocations; i++) {
473 wrapper = MakeGarbageCollected<IntWrapper>(0x0bbac0de);
474 if (!(i % 10)) {
475 global_persistent = CreateGlobalPersistent(0x0ed0cabb);
476 }
477 test::YieldCurrentThread();
478 }
479
480 if (gc_count < kGcPerThread) {
481 TestSupportingGC::PreciselyCollectGarbage();
482 gc_count++;
483 gc_count_.fetch_add(1, std::memory_order_release);
484 }
485
486 TestSupportingGC::PreciselyCollectGarbage();
487 EXPECT_EQ(wrapper->Value(), 0x0bbac0de);
488 EXPECT_EQ((*global_persistent)->Value(), 0x0ed0cabb);
489 }
490 test::YieldCurrentThread();
491 }
492 }
493 };
494
495 class ThreadedWeaknessTester : public ThreadedTesterBase {
496 public:
Test()497 static void Test() { ThreadedTesterBase::Test(new ThreadedWeaknessTester); }
498
499 private:
RunThread()500 void RunThread() override {
501 int gc_count = 0;
502 while (!Done()) {
503 {
504 Persistent<HeapHashMap<ThreadMarker, WeakMember<IntWrapper>>> weak_map =
505 MakeGarbageCollected<
506 HeapHashMap<ThreadMarker, WeakMember<IntWrapper>>>();
507
508 for (int i = 0; i < kNumberOfAllocations; i++) {
509 weak_map->insert(static_cast<unsigned>(i),
510 MakeGarbageCollected<IntWrapper>(0));
511 test::YieldCurrentThread();
512 }
513
514 if (gc_count < kGcPerThread) {
515 TestSupportingGC::PreciselyCollectGarbage();
516 gc_count++;
517 gc_count_.fetch_add(1, std::memory_order_release);
518 }
519
520 TestSupportingGC::PreciselyCollectGarbage();
521 EXPECT_TRUE(weak_map->IsEmpty());
522 }
523 test::YieldCurrentThread();
524 }
525 }
526 };
527
528 class ThreadPersistentHeapTester : public ThreadedTesterBase {
529 public:
Test()530 static void Test() {
531 ThreadedTesterBase::Test(new ThreadPersistentHeapTester);
532 }
533
534 protected:
535 class Local final : public GarbageCollected<Local> {
536 public:
537 Local() = default;
538
Trace(Visitor * visitor)539 void Trace(Visitor* visitor) {}
540 };
541
542 class PersistentChain;
543
544 class RefCountedChain : public RefCounted<RefCountedChain> {
545 public:
Create(int count)546 static RefCountedChain* Create(int count) {
547 return new RefCountedChain(count);
548 }
549
550 private:
RefCountedChain(int count)551 explicit RefCountedChain(int count) {
552 if (count > 0) {
553 --count;
554 persistent_chain_ = MakeGarbageCollected<PersistentChain>(count);
555 }
556 }
557
558 Persistent<PersistentChain> persistent_chain_;
559 };
560
561 class PersistentChain final : public GarbageCollected<PersistentChain> {
562 public:
PersistentChain(int count)563 explicit PersistentChain(int count) {
564 ref_counted_chain_ = base::AdoptRef(RefCountedChain::Create(count));
565 }
566
Trace(Visitor * visitor)567 void Trace(Visitor* visitor) {}
568
569 private:
570 scoped_refptr<RefCountedChain> ref_counted_chain_;
571 };
572
RunThread()573 void RunThread() override {
574 MakeGarbageCollected<PersistentChain>(100);
575
576 // Upon thread detach, GCs will run until all persistents have been
577 // released. We verify that the draining of persistents proceeds
578 // as expected by dropping one Persistent<> per GC until there
579 // are none left.
580 }
581 };
582
583 // The accounting for memory includes the memory used by rounding up object
584 // sizes. This is done in a different way on 32 bit and 64 bit, so we have to
585 // have some slack in the tests.
586 template <typename T>
CheckWithSlack(T expected,T actual,int slack)587 void CheckWithSlack(T expected, T actual, int slack) {
588 EXPECT_LE(expected, actual);
589 EXPECT_GE((intptr_t)expected + slack, (intptr_t)actual);
590 }
591
592 class TraceCounter final : public GarbageCollected<TraceCounter> {
593 public:
TraceCounter()594 TraceCounter() : trace_count_(0) {}
595
Trace(Visitor * visitor)596 void Trace(Visitor* visitor) { trace_count_++; }
TraceCount() const597 int TraceCount() const { return trace_count_; }
598
599 private:
600 int trace_count_;
601 };
602
TEST_F(HeapTest,IsHeapObjectAliveForConstPointer)603 TEST_F(HeapTest, IsHeapObjectAliveForConstPointer) {
604 // See http://crbug.com/661363.
605 auto* object = MakeGarbageCollected<SimpleObject>();
606 HeapObjectHeader* header = HeapObjectHeader::FromPayload(object);
607 EXPECT_TRUE(header->TryMark());
608 EXPECT_TRUE(ThreadHeap::IsHeapObjectAlive(object));
609 const SimpleObject* const_object = const_cast<const SimpleObject*>(object);
610 EXPECT_TRUE(ThreadHeap::IsHeapObjectAlive(const_object));
611 }
612
613 class ClassWithMember : public GarbageCollected<ClassWithMember> {
614 public:
ClassWithMember()615 ClassWithMember() : trace_counter_(MakeGarbageCollected<TraceCounter>()) {}
616
Trace(Visitor * visitor)617 void Trace(Visitor* visitor) { visitor->Trace(trace_counter_); }
TraceCount() const618 int TraceCount() const { return trace_counter_->TraceCount(); }
619
620 private:
621 Member<TraceCounter> trace_counter_;
622 };
623
624 class SimpleFinalizedObject final
625 : public GarbageCollected<SimpleFinalizedObject> {
626 public:
627 SimpleFinalizedObject() = default;
~SimpleFinalizedObject()628 ~SimpleFinalizedObject() { ++destructor_calls_; }
629
630 static int destructor_calls_;
631
Trace(Visitor * visitor)632 void Trace(Visitor* visitor) {}
633 };
634
635 int SimpleFinalizedObject::destructor_calls_ = 0;
636
637 class IntNode : public GarbageCollected<IntNode> {
638 public:
639 // IntNode is used to test typed heap allocation. Instead of
640 // redefining blink::Node to our test version, we keep it separate
641 // so as to avoid possible warnings about linker duplicates.
642 // Override operator new to allocate IntNode subtype objects onto
643 // the dedicated heap for blink::Node.
644 //
645 // TODO(haraken): untangling the heap unit tests from Blink would
646 // simplify and avoid running into this problem - http://crbug.com/425381
647 GC_PLUGIN_IGNORE("crbug.com/443854")
operator new(size_t size)648 void* operator new(size_t size) {
649 ThreadState* state = ThreadState::Current();
650 const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(IntNode);
651 return state->Heap().AllocateOnArenaIndex(
652 state, size, BlinkGC::kNodeArenaIndex, GCInfoTrait<IntNode>::Index(),
653 type_name);
654 }
655
Create(int i)656 static IntNode* Create(int i) { return new IntNode(i); }
657
Trace(Visitor * visitor)658 void Trace(Visitor* visitor) {}
659
Value()660 int Value() { return value_; }
661
662 private:
IntNode(int i)663 IntNode(int i) : value_(i) {}
664 int value_;
665 };
666
667 class Bar : public GarbageCollected<Bar> {
668 public:
Bar()669 Bar() : magic_(kMagic) { live_++; }
670
FinalizeGarbageCollectedObject()671 void FinalizeGarbageCollectedObject() {
672 EXPECT_TRUE(magic_ == kMagic);
673 magic_ = 0;
674 live_--;
675 }
HasBeenFinalized() const676 bool HasBeenFinalized() const { return !magic_; }
677
Trace(Visitor * visitor)678 virtual void Trace(Visitor* visitor) {}
679 static unsigned live_;
680
681 protected:
682 static const int kMagic = 1337;
683 int magic_;
684 };
685
686 unsigned Bar::live_ = 0;
687
688 class Baz : public GarbageCollected<Baz> {
689 public:
Baz(Bar * bar)690 explicit Baz(Bar* bar) : bar_(bar) {}
691
Trace(Visitor * visitor)692 void Trace(Visitor* visitor) { visitor->Trace(bar_); }
693
Clear()694 void Clear() { bar_.Release(); }
695
696 // willFinalize is called by FinalizationObserver.
WillFinalize()697 void WillFinalize() { EXPECT_TRUE(!bar_->HasBeenFinalized()); }
698
699 private:
700 Member<Bar> bar_;
701 };
702
703 class Foo : public Bar {
704 public:
Foo(Bar * bar)705 Foo(Bar* bar) : Bar(), bar_(bar), points_to_foo_(false) {}
706
Foo(Foo * foo)707 Foo(Foo* foo) : Bar(), bar_(foo), points_to_foo_(true) {}
708
Trace(Visitor * visitor)709 void Trace(Visitor* visitor) override {
710 if (points_to_foo_)
711 visitor->Trace(static_cast<const Foo*>(bar_));
712 else
713 visitor->Trace(bar_);
714 }
715
716 private:
717 const Bar* bar_;
718 const bool points_to_foo_;
719 };
720
721 class Bars : public Bar {
722 public:
Bars()723 Bars() : width_(0) {
724 for (unsigned i = 0; i < kWidth; i++) {
725 bars_[i] = MakeGarbageCollected<Bar>();
726 width_++;
727 }
728 }
729
Trace(Visitor * visitor)730 void Trace(Visitor* visitor) override {
731 for (unsigned i = 0; i < width_; i++)
732 visitor->Trace(bars_[i]);
733 }
734
GetWidth() const735 unsigned GetWidth() const { return width_; }
736
737 static const unsigned kWidth = 7500;
738
739 private:
740 unsigned width_;
741 Member<Bar> bars_[kWidth];
742 };
743
744 class ConstructorAllocation : public GarbageCollected<ConstructorAllocation> {
745 public:
ConstructorAllocation()746 ConstructorAllocation() {
747 int_wrapper_ = MakeGarbageCollected<IntWrapper>(42);
748 }
749
Trace(Visitor * visitor)750 void Trace(Visitor* visitor) { visitor->Trace(int_wrapper_); }
751
752 private:
753 Member<IntWrapper> int_wrapper_;
754 };
755
756 class LargeHeapObject final : public GarbageCollected<LargeHeapObject> {
757 public:
LargeHeapObject()758 LargeHeapObject() { int_wrapper_ = MakeGarbageCollected<IntWrapper>(23); }
~LargeHeapObject()759 ~LargeHeapObject() { destructor_calls_++; }
760
Get(size_t i)761 char Get(size_t i) { return data_[i]; }
Set(size_t i,char c)762 void Set(size_t i, char c) { data_[i] = c; }
length()763 size_t length() { return kLength; }
Trace(Visitor * visitor)764 void Trace(Visitor* visitor) { visitor->Trace(int_wrapper_); }
765 static int destructor_calls_;
766
767 private:
768 static const size_t kLength = 1024 * 1024;
769 Member<IntWrapper> int_wrapper_;
770 char data_[kLength];
771 };
772
773 int LargeHeapObject::destructor_calls_ = 0;
774
775 // This test class served a more important role while Blink
776 // was transitioned over to using Oilpan. That required classes
777 // that were hybrid, both ref-counted and on the Oilpan heap
778 // (the RefCountedGarbageCollected<> class providing just that.)
779 //
780 // There's no current need for having a ref-counted veneer on
781 // top of a GCed class, but we preserve it here to exercise the
782 // implementation technique that it used -- keeping an internal
783 // "keep alive" persistent reference that is set & cleared across
784 // ref-counting operations.
785 //
786 class RefCountedAndGarbageCollected final
787 : public GarbageCollected<RefCountedAndGarbageCollected> {
788 public:
RefCountedAndGarbageCollected()789 RefCountedAndGarbageCollected() : keep_alive_(PERSISTENT_FROM_HERE) {}
~RefCountedAndGarbageCollected()790 ~RefCountedAndGarbageCollected() { ++destructor_calls_; }
791
AddRef()792 void AddRef() {
793 if (UNLIKELY(!ref_count_)) {
794 #if DCHECK_IS_ON()
795 DCHECK(ThreadState::Current()->Heap().FindPageFromAddress(
796 reinterpret_cast<Address>(this)));
797 #endif
798 keep_alive_ = this;
799 }
800 ++ref_count_;
801 }
802
Release()803 void Release() {
804 DCHECK_GT(ref_count_, 0);
805 if (!--ref_count_)
806 keep_alive_.Clear();
807 }
808
Trace(Visitor * visitor)809 void Trace(Visitor* visitor) {}
810
811 static int destructor_calls_;
812
813 private:
814 int ref_count_ = 0;
815 SelfKeepAlive<RefCountedAndGarbageCollected> keep_alive_;
816 };
817
818 int RefCountedAndGarbageCollected::destructor_calls_ = 0;
819
820 class RefCountedAndGarbageCollected2 final
821 : public HeapTestOtherSuperClass,
822 public GarbageCollected<RefCountedAndGarbageCollected2> {
823 public:
RefCountedAndGarbageCollected2()824 RefCountedAndGarbageCollected2() : keep_alive_(PERSISTENT_FROM_HERE) {}
~RefCountedAndGarbageCollected2()825 ~RefCountedAndGarbageCollected2() { ++destructor_calls_; }
826
Ref()827 void Ref() {
828 if (UNLIKELY(!ref_count_)) {
829 #if DCHECK_IS_ON()
830 DCHECK(ThreadState::Current()->Heap().FindPageFromAddress(
831 reinterpret_cast<Address>(this)));
832 #endif
833 keep_alive_ = this;
834 }
835 ++ref_count_;
836 }
837
Deref()838 void Deref() {
839 DCHECK_GT(ref_count_, 0);
840 if (!--ref_count_)
841 keep_alive_.Clear();
842 }
843
Trace(Visitor * visitor)844 void Trace(Visitor* visitor) {}
845
846 static int destructor_calls_;
847
848 private:
849 int ref_count_ = 0;
850 SelfKeepAlive<RefCountedAndGarbageCollected2> keep_alive_;
851 };
852
853 int RefCountedAndGarbageCollected2::destructor_calls_ = 0;
854
855 class Weak : public Bar {
856 public:
Weak(Bar * strong_bar,Bar * weak_bar)857 Weak(Bar* strong_bar, Bar* weak_bar)
858 : Bar(), strong_bar_(strong_bar), weak_bar_(weak_bar) {}
859
Trace(Visitor * visitor)860 void Trace(Visitor* visitor) override {
861 visitor->Trace(strong_bar_);
862 visitor->template RegisterWeakCallbackMethod<Weak, &Weak::ZapWeakMembers>(
863 this);
864 }
865
ZapWeakMembers(const WeakCallbackInfo & info)866 void ZapWeakMembers(const WeakCallbackInfo& info) {
867 if (!info.IsHeapObjectAlive(weak_bar_))
868 weak_bar_ = nullptr;
869 }
870
StrongIsThere()871 bool StrongIsThere() { return !!strong_bar_; }
WeakIsThere()872 bool WeakIsThere() { return !!weak_bar_; }
873
874 private:
875 Member<Bar> strong_bar_;
876 Bar* weak_bar_;
877 };
878
879 class WithWeakMember : public Bar {
880 public:
WithWeakMember(Bar * strong_bar,Bar * weak_bar)881 WithWeakMember(Bar* strong_bar, Bar* weak_bar)
882 : Bar(), strong_bar_(strong_bar), weak_bar_(weak_bar) {}
883
Trace(Visitor * visitor)884 void Trace(Visitor* visitor) override {
885 visitor->Trace(strong_bar_);
886 visitor->Trace(weak_bar_);
887 }
888
StrongIsThere()889 bool StrongIsThere() { return !!strong_bar_; }
WeakIsThere()890 bool WeakIsThere() { return !!weak_bar_; }
891
892 private:
893 Member<Bar> strong_bar_;
894 WeakMember<Bar> weak_bar_;
895 };
896
897 class Observable final : public GarbageCollected<Observable> {
898 USING_PRE_FINALIZER(Observable, WillFinalize);
899
900 public:
Observable(Bar * bar)901 explicit Observable(Bar* bar) : bar_(bar), was_destructed_(false) {}
~Observable()902 ~Observable() { was_destructed_ = true; }
Trace(Visitor * visitor)903 void Trace(Visitor* visitor) { visitor->Trace(bar_); }
904
905 // willFinalize is called by FinalizationObserver. willFinalize can touch
906 // other on-heap objects.
WillFinalize()907 void WillFinalize() {
908 EXPECT_FALSE(was_destructed_);
909 EXPECT_FALSE(bar_->HasBeenFinalized());
910 will_finalize_was_called_ = true;
911 }
912 static bool will_finalize_was_called_;
913
914 private:
915 Member<Bar> bar_;
916 bool was_destructed_;
917 };
918
919 bool Observable::will_finalize_was_called_ = false;
920
921 class ObservableWithPreFinalizer final
922 : public GarbageCollected<ObservableWithPreFinalizer> {
923 USING_PRE_FINALIZER(ObservableWithPreFinalizer, Dispose);
924
925 public:
ObservableWithPreFinalizer()926 ObservableWithPreFinalizer() : was_destructed_(false) {}
~ObservableWithPreFinalizer()927 ~ObservableWithPreFinalizer() { was_destructed_ = true; }
Trace(Visitor * visitor)928 void Trace(Visitor* visitor) {}
Dispose()929 void Dispose() {
930 EXPECT_FALSE(was_destructed_);
931 dispose_was_called_ = true;
932 }
933 static bool dispose_was_called_;
934
935 protected:
936 bool was_destructed_;
937 };
938
939 bool ObservableWithPreFinalizer::dispose_was_called_ = false;
940
941 bool g_dispose_was_called_for_pre_finalizer_base = false;
942 bool g_dispose_was_called_for_pre_finalizer_mixin = false;
943 bool g_dispose_was_called_for_pre_finalizer_sub_class = false;
944
945 class PreFinalizerBase : public GarbageCollected<PreFinalizerBase> {
946 USING_PRE_FINALIZER(PreFinalizerBase, Dispose);
947
948 public:
PreFinalizerBase()949 PreFinalizerBase() : was_destructed_(false) {}
~PreFinalizerBase()950 virtual ~PreFinalizerBase() { was_destructed_ = true; }
Trace(Visitor * visitor)951 virtual void Trace(Visitor* visitor) {}
Dispose()952 void Dispose() {
953 EXPECT_FALSE(g_dispose_was_called_for_pre_finalizer_base);
954 EXPECT_TRUE(g_dispose_was_called_for_pre_finalizer_sub_class);
955 EXPECT_TRUE(g_dispose_was_called_for_pre_finalizer_mixin);
956 EXPECT_FALSE(was_destructed_);
957 g_dispose_was_called_for_pre_finalizer_base = true;
958 }
959
960 protected:
961 bool was_destructed_;
962 };
963
964 class PreFinalizerMixin : public GarbageCollectedMixin {
965 USING_PRE_FINALIZER(PreFinalizerMixin, Dispose);
966
967 public:
~PreFinalizerMixin()968 ~PreFinalizerMixin() { was_destructed_ = true; }
Trace(Visitor * visitor)969 void Trace(Visitor* visitor) override {}
Dispose()970 void Dispose() {
971 EXPECT_FALSE(g_dispose_was_called_for_pre_finalizer_base);
972 EXPECT_TRUE(g_dispose_was_called_for_pre_finalizer_sub_class);
973 EXPECT_FALSE(g_dispose_was_called_for_pre_finalizer_mixin);
974 EXPECT_FALSE(was_destructed_);
975 g_dispose_was_called_for_pre_finalizer_mixin = true;
976 }
977
978 protected:
PreFinalizerMixin()979 PreFinalizerMixin() : was_destructed_(false) {}
980 bool was_destructed_;
981 };
982
983 class PreFinalizerSubClass : public PreFinalizerBase, public PreFinalizerMixin {
984 USING_GARBAGE_COLLECTED_MIXIN(PreFinalizerSubClass);
985 USING_PRE_FINALIZER(PreFinalizerSubClass, Dispose);
986
987 public:
PreFinalizerSubClass()988 PreFinalizerSubClass() : was_destructed_(false) {}
~PreFinalizerSubClass()989 ~PreFinalizerSubClass() override { was_destructed_ = true; }
Trace(Visitor * visitor)990 void Trace(Visitor* visitor) override {}
Dispose()991 void Dispose() {
992 EXPECT_FALSE(g_dispose_was_called_for_pre_finalizer_base);
993 EXPECT_FALSE(g_dispose_was_called_for_pre_finalizer_sub_class);
994 EXPECT_FALSE(g_dispose_was_called_for_pre_finalizer_mixin);
995 EXPECT_FALSE(was_destructed_);
996 g_dispose_was_called_for_pre_finalizer_sub_class = true;
997 }
998
999 protected:
1000 bool was_destructed_;
1001 };
1002
1003 template <typename T>
1004 class FinalizationObserver : public GarbageCollected<FinalizationObserver<T>> {
1005 public:
FinalizationObserver(T * data)1006 FinalizationObserver(T* data) : data_(data), did_call_will_finalize_(false) {}
1007
DidCallWillFinalize() const1008 bool DidCallWillFinalize() const { return did_call_will_finalize_; }
1009
Trace(Visitor * visitor)1010 void Trace(Visitor* visitor) {
1011 visitor->template RegisterWeakCallbackMethod<
1012 FinalizationObserver<T>, &FinalizationObserver<T>::ZapWeakMembers>(
1013 this);
1014 }
1015
ZapWeakMembers(const WeakCallbackInfo & info)1016 void ZapWeakMembers(const WeakCallbackInfo& info) {
1017 if (data_ && !info.IsHeapObjectAlive(data_)) {
1018 data_->WillFinalize();
1019 data_ = nullptr;
1020 did_call_will_finalize_ = true;
1021 }
1022 }
1023
1024 private:
1025 WeakMember<T> data_;
1026 bool did_call_will_finalize_;
1027 };
1028
1029 class FinalizationObserverWithHashMap {
1030 public:
1031 typedef HeapHashMap<WeakMember<Observable>,
1032 std::unique_ptr<FinalizationObserverWithHashMap>>
1033 ObserverMap;
1034
FinalizationObserverWithHashMap(Observable & target)1035 explicit FinalizationObserverWithHashMap(Observable& target)
1036 : target_(target) {}
~FinalizationObserverWithHashMap()1037 ~FinalizationObserverWithHashMap() {
1038 target_.WillFinalize();
1039 did_call_will_finalize_ = true;
1040 }
1041
Observe(Observable & target)1042 static ObserverMap& Observe(Observable& target) {
1043 ObserverMap& map = Observers();
1044 ObserverMap::AddResult result = map.insert(&target, nullptr);
1045 if (result.is_new_entry) {
1046 result.stored_value->value =
1047 std::make_unique<FinalizationObserverWithHashMap>(target);
1048 } else {
1049 DCHECK(result.stored_value->value);
1050 }
1051 return map;
1052 }
1053
ClearObservers()1054 static void ClearObservers() {
1055 delete observer_map_;
1056 observer_map_ = nullptr;
1057 }
1058
1059 static bool did_call_will_finalize_;
1060
1061 private:
Observers()1062 static ObserverMap& Observers() {
1063 if (!observer_map_) {
1064 observer_map_ =
1065 new Persistent<ObserverMap>(MakeGarbageCollected<ObserverMap>());
1066 }
1067 return **observer_map_;
1068 }
1069
1070 Observable& target_;
1071 static Persistent<ObserverMap>* observer_map_;
1072 };
1073
1074 bool FinalizationObserverWithHashMap::did_call_will_finalize_ = false;
1075 Persistent<FinalizationObserverWithHashMap::ObserverMap>*
1076 FinalizationObserverWithHashMap::observer_map_;
1077
1078 class SuperClass;
1079
1080 class PointsBack final : public GarbageCollected<PointsBack> {
1081 public:
PointsBack()1082 PointsBack() : back_pointer_(nullptr) { ++alive_count_; }
~PointsBack()1083 ~PointsBack() { --alive_count_; }
1084
SetBackPointer(SuperClass * back_pointer)1085 void SetBackPointer(SuperClass* back_pointer) {
1086 back_pointer_ = back_pointer;
1087 }
1088
BackPointer() const1089 SuperClass* BackPointer() const { return back_pointer_; }
1090
Trace(Visitor * visitor)1091 void Trace(Visitor* visitor) { visitor->Trace(back_pointer_); }
1092
1093 static int alive_count_;
1094
1095 private:
1096 WeakMember<SuperClass> back_pointer_;
1097 };
1098
1099 int PointsBack::alive_count_ = 0;
1100
1101 class SuperClass : public GarbageCollected<SuperClass> {
1102 public:
SuperClass(PointsBack * points_back)1103 explicit SuperClass(PointsBack* points_back) : points_back_(points_back) {
1104 points_back_->SetBackPointer(this);
1105 ++alive_count_;
1106 }
~SuperClass()1107 virtual ~SuperClass() { --alive_count_; }
1108
DoStuff(SuperClass * target,PointsBack * points_back,int super_class_count)1109 void DoStuff(SuperClass* target,
1110 PointsBack* points_back,
1111 int super_class_count) {
1112 TestSupportingGC::ConservativelyCollectGarbage();
1113 EXPECT_EQ(points_back, target->GetPointsBack());
1114 EXPECT_EQ(super_class_count, SuperClass::alive_count_);
1115 }
1116
Trace(Visitor * visitor)1117 virtual void Trace(Visitor* visitor) { visitor->Trace(points_back_); }
1118
GetPointsBack() const1119 PointsBack* GetPointsBack() const { return points_back_.Get(); }
1120
1121 static int alive_count_;
1122
1123 private:
1124 Member<PointsBack> points_back_;
1125 };
1126
1127 int SuperClass::alive_count_ = 0;
1128 class SubData final : public GarbageCollected<SubData> {
1129 public:
SubData()1130 SubData() { ++alive_count_; }
~SubData()1131 ~SubData() { --alive_count_; }
1132
Trace(Visitor * visitor)1133 void Trace(Visitor* visitor) {}
1134
1135 static int alive_count_;
1136 };
1137
1138 int SubData::alive_count_ = 0;
1139
1140 class SubClass : public SuperClass {
1141 public:
SubClass(PointsBack * points_back)1142 explicit SubClass(PointsBack* points_back)
1143 : SuperClass(points_back), data_(MakeGarbageCollected<SubData>()) {
1144 ++alive_count_;
1145 }
~SubClass()1146 ~SubClass() override { --alive_count_; }
1147
Trace(Visitor * visitor)1148 void Trace(Visitor* visitor) override {
1149 visitor->Trace(data_);
1150 SuperClass::Trace(visitor);
1151 }
1152
1153 static int alive_count_;
1154
1155 private:
1156 Member<SubData> data_;
1157 };
1158
1159 int SubClass::alive_count_ = 0;
1160
1161 class Mixin : public GarbageCollectedMixin {
1162 public:
Trace(Visitor * visitor)1163 void Trace(Visitor* visitor) override {}
1164
GetPayload(int i)1165 virtual char GetPayload(int i) { return padding_[i]; }
1166
1167 protected:
1168 int padding_[8];
1169 };
1170
1171 class UseMixin : public SimpleObject, public Mixin {
1172 USING_GARBAGE_COLLECTED_MIXIN(UseMixin);
1173
1174 public:
UseMixin()1175 UseMixin() {
1176 // Verify that WTF::IsGarbageCollectedType<> works as expected for mixins.
1177 static_assert(WTF::IsGarbageCollectedType<UseMixin>::value,
1178 "IsGarbageCollectedType<> sanity check failed for GC mixin.");
1179 trace_count_ = 0;
1180 }
1181
1182 static int trace_count_;
Trace(Visitor * visitor)1183 void Trace(Visitor* visitor) override {
1184 SimpleObject::Trace(visitor);
1185 Mixin::Trace(visitor);
1186 ++trace_count_;
1187 }
1188 };
1189
1190 int UseMixin::trace_count_ = 0;
1191
1192 class VectorObject {
1193 DISALLOW_NEW();
1194
1195 public:
VectorObject()1196 VectorObject() { value_ = MakeGarbageCollected<SimpleFinalizedObject>(); }
1197
Trace(Visitor * visitor)1198 void Trace(Visitor* visitor) { visitor->Trace(value_); }
1199
1200 private:
1201 Member<SimpleFinalizedObject> value_;
1202 };
1203
1204 class VectorObjectInheritedTrace : public VectorObject {};
1205
1206 class VectorObjectNoTrace {
1207 DISALLOW_NEW();
1208
1209 public:
VectorObjectNoTrace()1210 VectorObjectNoTrace() {
1211 value_ = MakeGarbageCollected<SimpleFinalizedObject>();
1212 }
1213
1214 private:
1215 Member<SimpleFinalizedObject> value_;
1216 };
1217
1218 class TerminatedArrayItem {
1219 DISALLOW_NEW();
1220
1221 public:
TerminatedArrayItem(IntWrapper * payload)1222 TerminatedArrayItem(IntWrapper* payload)
1223 : payload_(payload), is_last_(false) {}
1224
Trace(Visitor * visitor)1225 void Trace(Visitor* visitor) { visitor->Trace(payload_); }
1226
IsLastInArray() const1227 bool IsLastInArray() const { return is_last_; }
SetLastInArray(bool value)1228 void SetLastInArray(bool value) { is_last_ = value; }
1229
Payload() const1230 IntWrapper* Payload() const { return payload_; }
1231
1232 private:
1233 Member<IntWrapper> payload_;
1234 bool is_last_;
1235 };
1236
1237 } // namespace blink
1238
1239 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::TerminatedArrayItem)
1240 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::VectorObject)
1241 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(
1242 blink::VectorObjectInheritedTrace)
1243 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::VectorObjectNoTrace)
1244
1245 namespace blink {
1246
1247 class OneKiloByteObject final : public GarbageCollected<OneKiloByteObject> {
1248 public:
~OneKiloByteObject()1249 ~OneKiloByteObject() { destructor_calls_++; }
Data()1250 char* Data() { return data_; }
Trace(Visitor * visitor)1251 void Trace(Visitor* visitor) {}
1252 static int destructor_calls_;
1253
1254 private:
1255 static const size_t kLength = 1024;
1256 char data_[kLength];
1257 };
1258
1259 int OneKiloByteObject::destructor_calls_ = 0;
1260
1261 class DynamicallySizedObject : public GarbageCollected<DynamicallySizedObject> {
1262 public:
Create(size_t size)1263 static DynamicallySizedObject* Create(size_t size) {
1264 void* slot = ThreadHeap::Allocate<DynamicallySizedObject>(size);
1265 return new (slot) DynamicallySizedObject();
1266 }
1267
operator new(std::size_t,void * location)1268 void* operator new(std::size_t, void* location) { return location; }
1269
Get(int i)1270 uint8_t Get(int i) { return *(reinterpret_cast<uint8_t*>(this) + i); }
1271
Trace(Visitor * visitor)1272 void Trace(Visitor* visitor) {}
1273
1274 private:
1275 DynamicallySizedObject() = default;
1276 };
1277
1278 class FinalizationAllocator final
1279 : public GarbageCollected<FinalizationAllocator> {
1280 public:
FinalizationAllocator(Persistent<IntWrapper> * wrapper)1281 FinalizationAllocator(Persistent<IntWrapper>* wrapper) : wrapper_(wrapper) {}
1282
~FinalizationAllocator()1283 ~FinalizationAllocator() {
1284 for (int i = 0; i < 10; ++i)
1285 *wrapper_ = MakeGarbageCollected<IntWrapper>(42);
1286 for (int i = 0; i < 512; ++i)
1287 MakeGarbageCollected<OneKiloByteObject>();
1288 for (int i = 0; i < 32; ++i)
1289 MakeGarbageCollected<LargeHeapObject>();
1290 }
1291
Trace(Visitor * visitor)1292 void Trace(Visitor* visitor) {}
1293
1294 private:
1295 Persistent<IntWrapper>* wrapper_;
1296 };
1297
1298 class PreFinalizerBackingShrinkForbidden final
1299 : public GarbageCollected<PreFinalizerBackingShrinkForbidden> {
1300 USING_PRE_FINALIZER(PreFinalizerBackingShrinkForbidden, Dispose);
1301
1302 public:
PreFinalizerBackingShrinkForbidden()1303 PreFinalizerBackingShrinkForbidden() {
1304 for (int i = 0; i < 32; ++i) {
1305 vector_.push_back(MakeGarbageCollected<IntWrapper>(i));
1306 }
1307 EXPECT_LT(31ul, vector_.capacity());
1308
1309 for (int i = 0; i < 32; ++i) {
1310 map_.insert(i + 1, MakeGarbageCollected<IntWrapper>(i + 1));
1311 }
1312 EXPECT_LT(31ul, map_.Capacity());
1313 }
1314
Dispose()1315 void Dispose() {
1316 // Remove all elemets except one so that vector_ will try to shrink.
1317 for (int i = 1; i < 32; ++i) {
1318 vector_.pop_back();
1319 }
1320 // Check that vector_ hasn't shrunk.
1321 EXPECT_LT(31ul, vector_.capacity());
1322 // Just releasing the backing is allowed.
1323 vector_.clear();
1324 EXPECT_EQ(0ul, vector_.capacity());
1325
1326 // Remove elemets so that map_ will try to shrink.
1327 for (int i = 0; i < 32; ++i) {
1328 map_.erase(i + 1);
1329 }
1330 // Check that map_ hasn't shrunk.
1331 EXPECT_LT(31ul, map_.Capacity());
1332 // Just releasing the backing is allowed.
1333 map_.clear();
1334 EXPECT_EQ(0ul, map_.Capacity());
1335 }
1336
Trace(Visitor * visitor)1337 void Trace(Visitor* visitor) {
1338 visitor->Trace(vector_);
1339 visitor->Trace(map_);
1340 }
1341
1342 private:
1343 HeapVector<Member<IntWrapper>> vector_;
1344 HeapHashMap<int, Member<IntWrapper>> map_;
1345 };
1346
1347 // Following 2 tests check for allocation failures. These failures happen
1348 // only when DCHECK is on.
1349 #if DCHECK_IS_ON()
TEST_F(HeapTest,PreFinalizerBackingShrinkForbidden)1350 TEST_F(HeapTest, PreFinalizerBackingShrinkForbidden) {
1351 MakeGarbageCollected<PreFinalizerBackingShrinkForbidden>();
1352 PreciselyCollectGarbage();
1353 }
1354
1355 class PreFinalizerVectorBackingExpandForbidden final
1356 : public GarbageCollected<PreFinalizerVectorBackingExpandForbidden> {
1357 USING_PRE_FINALIZER(PreFinalizerVectorBackingExpandForbidden, Dispose);
1358
1359 public:
PreFinalizerVectorBackingExpandForbidden()1360 PreFinalizerVectorBackingExpandForbidden() {
1361 vector_.push_back(MakeGarbageCollected<IntWrapper>(1));
1362 }
1363
Dispose()1364 void Dispose() { EXPECT_DEATH(Test(), ""); }
1365
Test()1366 void Test() {
1367 // vector_'s backing will need to expand.
1368 for (int i = 0; i < 32; ++i) {
1369 vector_.push_back(nullptr);
1370 }
1371 }
1372
Trace(Visitor * visitor)1373 void Trace(Visitor* visitor) { visitor->Trace(vector_); }
1374
1375 private:
1376 HeapVector<Member<IntWrapper>> vector_;
1377 };
1378
TEST(HeapDeathTest,PreFinalizerVectorBackingExpandForbidden)1379 TEST(HeapDeathTest, PreFinalizerVectorBackingExpandForbidden) {
1380 MakeGarbageCollected<PreFinalizerVectorBackingExpandForbidden>();
1381 TestSupportingGC::PreciselyCollectGarbage();
1382 }
1383
1384 class PreFinalizerHashTableBackingExpandForbidden final
1385 : public GarbageCollected<PreFinalizerHashTableBackingExpandForbidden> {
1386 USING_PRE_FINALIZER(PreFinalizerHashTableBackingExpandForbidden, Dispose);
1387
1388 public:
PreFinalizerHashTableBackingExpandForbidden()1389 PreFinalizerHashTableBackingExpandForbidden() {
1390 map_.insert(123, MakeGarbageCollected<IntWrapper>(123));
1391 }
1392
Dispose()1393 void Dispose() { EXPECT_DEATH(Test(), ""); }
1394
Test()1395 void Test() {
1396 // map_'s backing will need to expand.
1397 for (int i = 1; i < 32; ++i) {
1398 map_.insert(i, nullptr);
1399 }
1400 }
1401
Trace(Visitor * visitor)1402 void Trace(Visitor* visitor) { visitor->Trace(map_); }
1403
1404 private:
1405 HeapHashMap<int, Member<IntWrapper>> map_;
1406 };
1407
TEST(HeapDeathTest,PreFinalizerHashTableBackingExpandForbidden)1408 TEST(HeapDeathTest, PreFinalizerHashTableBackingExpandForbidden) {
1409 MakeGarbageCollected<PreFinalizerHashTableBackingExpandForbidden>();
1410 TestSupportingGC::PreciselyCollectGarbage();
1411 }
1412 #endif // DCHECK_IS_ON()
1413
1414 class PreFinalizerAllocationForbidden
1415 : public GarbageCollected<PreFinalizerAllocationForbidden> {
1416 USING_PRE_FINALIZER(PreFinalizerAllocationForbidden, Dispose);
1417
1418 public:
Dispose()1419 void Dispose() {
1420 EXPECT_FALSE(ThreadState::Current()->IsAllocationAllowed());
1421 #if DCHECK_IS_ON()
1422 EXPECT_DEATH(MakeGarbageCollected<IntWrapper>(1), "");
1423 #endif // DCHECK_IS_ON()
1424 }
1425
Trace(Visitor * visitor)1426 void Trace(Visitor* visitor) {}
1427 };
1428
TEST(HeapDeathTest,PreFinalizerAllocationForbidden)1429 TEST(HeapDeathTest, PreFinalizerAllocationForbidden) {
1430 MakeGarbageCollected<PreFinalizerAllocationForbidden>();
1431 TestSupportingGC::PreciselyCollectGarbage();
1432 }
1433
1434 #if DCHECK_IS_ON()
1435 namespace {
1436
1437 class HeapTestResurrectingPreFinalizer
1438 : public GarbageCollected<HeapTestResurrectingPreFinalizer> {
1439 USING_PRE_FINALIZER(HeapTestResurrectingPreFinalizer, Dispose);
1440
1441 public:
1442 enum TestType {
1443 kHeapVectorMember,
1444 kHeapHashSetMember,
1445 kHeapHashSetWeakMember
1446 };
1447
1448 class GlobalStorage : public GarbageCollected<GlobalStorage> {
1449 public:
GlobalStorage()1450 GlobalStorage() {
1451 // Reserve storage upfront to avoid allocations during pre-finalizer
1452 // insertion.
1453 vector_member.ReserveCapacity(32);
1454 hash_set_member.ReserveCapacityForSize(32);
1455 hash_set_weak_member.ReserveCapacityForSize(32);
1456 }
1457
Trace(Visitor * visitor)1458 void Trace(Visitor* visitor) {
1459 visitor->Trace(vector_member);
1460 visitor->Trace(hash_set_member);
1461 visitor->Trace(hash_set_weak_member);
1462 }
1463
1464 HeapVector<Member<LinkedObject>> vector_member;
1465 HeapHashSet<Member<LinkedObject>> hash_set_member;
1466 HeapHashSet<WeakMember<LinkedObject>> hash_set_weak_member;
1467 };
1468
HeapTestResurrectingPreFinalizer(TestType test_type,GlobalStorage * storage,LinkedObject * object_that_dies)1469 HeapTestResurrectingPreFinalizer(TestType test_type,
1470 GlobalStorage* storage,
1471 LinkedObject* object_that_dies)
1472 : test_type_(test_type),
1473 storage_(storage),
1474 object_that_dies_(object_that_dies) {}
1475
Trace(Visitor * visitor)1476 void Trace(Visitor* visitor) {
1477 visitor->Trace(storage_);
1478 visitor->Trace(object_that_dies_);
1479 }
1480
1481 private:
Dispose()1482 void Dispose() { EXPECT_DEATH(Test(), ""); }
1483
Test()1484 void Test() {
1485 switch (test_type_) {
1486 case TestType::kHeapVectorMember:
1487 storage_->vector_member.push_back(object_that_dies_);
1488 break;
1489 case TestType::kHeapHashSetMember:
1490 storage_->hash_set_member.insert(object_that_dies_);
1491 break;
1492 case TestType::kHeapHashSetWeakMember:
1493 storage_->hash_set_weak_member.insert(object_that_dies_);
1494 break;
1495 }
1496 }
1497
1498 TestType test_type_;
1499 Member<GlobalStorage> storage_;
1500 Member<LinkedObject> object_that_dies_;
1501 };
1502
1503 } // namespace
1504
TEST(HeapDeathTest,DiesOnResurrectedHeapVectorMember)1505 TEST(HeapDeathTest, DiesOnResurrectedHeapVectorMember) {
1506 Persistent<HeapTestResurrectingPreFinalizer::GlobalStorage> storage(
1507 MakeGarbageCollected<HeapTestResurrectingPreFinalizer::GlobalStorage>());
1508 MakeGarbageCollected<HeapTestResurrectingPreFinalizer>(
1509 HeapTestResurrectingPreFinalizer::kHeapVectorMember, storage.Get(),
1510 MakeGarbageCollected<LinkedObject>());
1511 TestSupportingGC::PreciselyCollectGarbage();
1512 }
1513
TEST(HeapDeathTest,DiesOnResurrectedHeapHashSetMember)1514 TEST(HeapDeathTest, DiesOnResurrectedHeapHashSetMember) {
1515 Persistent<HeapTestResurrectingPreFinalizer::GlobalStorage> storage(
1516 MakeGarbageCollected<HeapTestResurrectingPreFinalizer::GlobalStorage>());
1517 MakeGarbageCollected<HeapTestResurrectingPreFinalizer>(
1518 HeapTestResurrectingPreFinalizer::kHeapHashSetMember, storage.Get(),
1519 MakeGarbageCollected<LinkedObject>());
1520 TestSupportingGC::PreciselyCollectGarbage();
1521 }
1522
TEST(HeapDeathTest,DiesOnResurrectedHeapHashSetWeakMember)1523 TEST(HeapDeathTest, DiesOnResurrectedHeapHashSetWeakMember) {
1524 Persistent<HeapTestResurrectingPreFinalizer::GlobalStorage> storage(
1525 MakeGarbageCollected<HeapTestResurrectingPreFinalizer::GlobalStorage>());
1526 MakeGarbageCollected<HeapTestResurrectingPreFinalizer>(
1527 HeapTestResurrectingPreFinalizer::kHeapHashSetWeakMember, storage.Get(),
1528 MakeGarbageCollected<LinkedObject>());
1529 TestSupportingGC::PreciselyCollectGarbage();
1530 }
1531 #endif // DCHECK_IS_ON()
1532
1533 class LargeMixin : public GarbageCollected<LargeMixin>, public Mixin {
1534 USING_GARBAGE_COLLECTED_MIXIN(LargeMixin);
1535
1536 private:
1537 char data[65536];
1538 };
1539
TEST(HeapDeathTest,LargeGarbageCollectedMixin)1540 TEST(HeapDeathTest, LargeGarbageCollectedMixin) {
1541 EXPECT_DEATH(MakeGarbageCollected<LargeMixin>(AdditionalBytes(1)), "");
1542 }
1543
TEST_F(HeapTest,Transition)1544 TEST_F(HeapTest, Transition) {
1545 {
1546 RefCountedAndGarbageCollected::destructor_calls_ = 0;
1547 Persistent<RefCountedAndGarbageCollected> ref_counted =
1548 MakeGarbageCollected<RefCountedAndGarbageCollected>();
1549 PreciselyCollectGarbage();
1550 EXPECT_EQ(0, RefCountedAndGarbageCollected::destructor_calls_);
1551 }
1552 PreciselyCollectGarbage();
1553 EXPECT_EQ(1, RefCountedAndGarbageCollected::destructor_calls_);
1554 RefCountedAndGarbageCollected::destructor_calls_ = 0;
1555
1556 Persistent<PointsBack> points_back1 = MakeGarbageCollected<PointsBack>();
1557 Persistent<PointsBack> points_back2 = MakeGarbageCollected<PointsBack>();
1558 Persistent<SuperClass> super_class =
1559 MakeGarbageCollected<SuperClass>(points_back1);
1560 Persistent<SubClass> sub_class = MakeGarbageCollected<SubClass>(points_back2);
1561 EXPECT_EQ(2, PointsBack::alive_count_);
1562 EXPECT_EQ(2, SuperClass::alive_count_);
1563 EXPECT_EQ(1, SubClass::alive_count_);
1564 EXPECT_EQ(1, SubData::alive_count_);
1565
1566 PreciselyCollectGarbage();
1567 EXPECT_EQ(0, RefCountedAndGarbageCollected::destructor_calls_);
1568 EXPECT_EQ(2, PointsBack::alive_count_);
1569 EXPECT_EQ(2, SuperClass::alive_count_);
1570 EXPECT_EQ(1, SubClass::alive_count_);
1571 EXPECT_EQ(1, SubData::alive_count_);
1572
1573 super_class->DoStuff(super_class.Release(), points_back1.Get(), 2);
1574 PreciselyCollectGarbage();
1575 EXPECT_EQ(2, PointsBack::alive_count_);
1576 EXPECT_EQ(1, SuperClass::alive_count_);
1577 EXPECT_EQ(1, SubClass::alive_count_);
1578 EXPECT_EQ(1, SubData::alive_count_);
1579 EXPECT_EQ(nullptr, points_back1->BackPointer());
1580
1581 points_back1.Release();
1582 PreciselyCollectGarbage();
1583 EXPECT_EQ(1, PointsBack::alive_count_);
1584 EXPECT_EQ(1, SuperClass::alive_count_);
1585 EXPECT_EQ(1, SubClass::alive_count_);
1586 EXPECT_EQ(1, SubData::alive_count_);
1587
1588 sub_class->DoStuff(sub_class.Release(), points_back2.Get(), 1);
1589 PreciselyCollectGarbage();
1590 EXPECT_EQ(1, PointsBack::alive_count_);
1591 EXPECT_EQ(0, SuperClass::alive_count_);
1592 EXPECT_EQ(0, SubClass::alive_count_);
1593 EXPECT_EQ(0, SubData::alive_count_);
1594 EXPECT_EQ(nullptr, points_back2->BackPointer());
1595
1596 points_back2.Release();
1597 PreciselyCollectGarbage();
1598 EXPECT_EQ(0, PointsBack::alive_count_);
1599 EXPECT_EQ(0, SuperClass::alive_count_);
1600 EXPECT_EQ(0, SubClass::alive_count_);
1601 EXPECT_EQ(0, SubData::alive_count_);
1602
1603 EXPECT_TRUE(super_class == sub_class);
1604 }
1605
TEST_F(HeapTest,Threading)1606 TEST_F(HeapTest, Threading) {
1607 ThreadedHeapTester::Test();
1608 }
1609
TEST_F(HeapTest,ThreadedWeakness)1610 TEST_F(HeapTest, ThreadedWeakness) {
1611 ThreadedWeaknessTester::Test();
1612 }
1613
TEST_F(HeapTest,ThreadPersistent)1614 TEST_F(HeapTest, ThreadPersistent) {
1615 ThreadPersistentHeapTester::Test();
1616 }
1617
TEST_F(HeapTest,BasicFunctionality)1618 TEST_F(HeapTest, BasicFunctionality) {
1619 ThreadHeap& heap = ThreadState::Current()->Heap();
1620 ClearOutOldGarbage();
1621 size_t initial_object_payload_size = heap.ObjectPayloadSizeForTesting();
1622 {
1623 wtf_size_t slack = 0;
1624
1625 // When the test starts there may already have been leaked some memory
1626 // on the heap, so we establish a base line.
1627 size_t base_level = initial_object_payload_size;
1628 bool test_pages_allocated = !base_level;
1629 if (test_pages_allocated)
1630 EXPECT_EQ(0ul, heap.stats_collector()->allocated_space_bytes());
1631
1632 // This allocates objects on the general heap which should add a page of
1633 // memory.
1634 DynamicallySizedObject* alloc32 = DynamicallySizedObject::Create(32);
1635 slack += 4;
1636 memset(alloc32, 40, 32);
1637 DynamicallySizedObject* alloc64 = DynamicallySizedObject::Create(64);
1638 slack += 4;
1639 memset(alloc64, 27, 64);
1640
1641 size_t total = 96;
1642
1643 CheckWithSlack(base_level + total, heap.ObjectPayloadSizeForTesting(),
1644 slack);
1645 if (test_pages_allocated) {
1646 EXPECT_EQ(kBlinkPageSize * 2,
1647 heap.stats_collector()->allocated_space_bytes());
1648 }
1649
1650 EXPECT_EQ(alloc32->Get(0), 40);
1651 EXPECT_EQ(alloc32->Get(31), 40);
1652 EXPECT_EQ(alloc64->Get(0), 27);
1653 EXPECT_EQ(alloc64->Get(63), 27);
1654
1655 ConservativelyCollectGarbage();
1656
1657 EXPECT_EQ(alloc32->Get(0), 40);
1658 EXPECT_EQ(alloc32->Get(31), 40);
1659 EXPECT_EQ(alloc64->Get(0), 27);
1660 EXPECT_EQ(alloc64->Get(63), 27);
1661 }
1662
1663 ClearOutOldGarbage();
1664 size_t total = 0;
1665 wtf_size_t slack = 0;
1666 size_t base_level = heap.ObjectPayloadSizeForTesting();
1667 bool test_pages_allocated = !base_level;
1668 if (test_pages_allocated)
1669 EXPECT_EQ(0ul, heap.stats_collector()->allocated_space_bytes());
1670
1671 size_t big = 1008;
1672 Persistent<DynamicallySizedObject> big_area =
1673 DynamicallySizedObject::Create(big);
1674 total += big;
1675 slack += 4;
1676
1677 size_t persistent_count = 0;
1678 const size_t kNumPersistents = 100000;
1679 Persistent<DynamicallySizedObject>* persistents[kNumPersistents];
1680
1681 for (int i = 0; i < 1000; i++) {
1682 size_t size = 128 + i * 8;
1683 total += size;
1684 persistents[persistent_count++] = new Persistent<DynamicallySizedObject>(
1685 DynamicallySizedObject::Create(size));
1686 slack += 4;
1687 // The allocations in the loop may trigger GC with lazy sweeping.
1688 CompleteSweepingIfNeeded();
1689 CheckWithSlack(base_level + total, heap.ObjectPayloadSizeForTesting(),
1690 slack);
1691 if (test_pages_allocated) {
1692 EXPECT_EQ(0ul, heap.stats_collector()->allocated_space_bytes() &
1693 (kBlinkPageSize - 1));
1694 }
1695 }
1696
1697 {
1698 DynamicallySizedObject* alloc32b(DynamicallySizedObject::Create(32));
1699 slack += 4;
1700 memset(alloc32b, 40, 32);
1701 DynamicallySizedObject* alloc64b(DynamicallySizedObject::Create(64));
1702 slack += 4;
1703 memset(alloc64b, 27, 64);
1704 EXPECT_TRUE(alloc32b != alloc64b);
1705
1706 total += 96;
1707 CheckWithSlack(base_level + total, heap.ObjectPayloadSizeForTesting(),
1708 slack);
1709 if (test_pages_allocated) {
1710 EXPECT_EQ(0ul, heap.stats_collector()->allocated_space_bytes() &
1711 (kBlinkPageSize - 1));
1712 }
1713 }
1714
1715 ClearOutOldGarbage();
1716 total -= 96;
1717 slack -= 8;
1718 if (test_pages_allocated) {
1719 EXPECT_EQ(0ul, heap.stats_collector()->allocated_space_bytes() &
1720 (kBlinkPageSize - 1));
1721 }
1722
1723 // Clear the persistent, so that the big area will be garbage collected.
1724 big_area.Release();
1725 ClearOutOldGarbage();
1726
1727 total -= big;
1728 slack -= 4;
1729 CheckWithSlack(base_level + total, heap.ObjectPayloadSizeForTesting(), slack);
1730 if (test_pages_allocated) {
1731 EXPECT_EQ(0ul, heap.stats_collector()->allocated_space_bytes() &
1732 (kBlinkPageSize - 1));
1733 }
1734
1735 CheckWithSlack(base_level + total, heap.ObjectPayloadSizeForTesting(), slack);
1736 if (test_pages_allocated) {
1737 EXPECT_EQ(0ul, heap.stats_collector()->allocated_space_bytes() &
1738 (kBlinkPageSize - 1));
1739 }
1740
1741 for (size_t i = 0; i < persistent_count; i++) {
1742 delete persistents[i];
1743 persistents[i] = nullptr;
1744 }
1745 }
1746
TEST_F(HeapTest,SimpleAllocation)1747 TEST_F(HeapTest, SimpleAllocation) {
1748 ThreadHeap& heap = ThreadState::Current()->Heap();
1749 ClearOutOldGarbage();
1750 EXPECT_EQ(0ul, heap.ObjectPayloadSizeForTesting());
1751
1752 // Allocate an object in the heap.
1753 HeapAllocatedArray* array = MakeGarbageCollected<HeapAllocatedArray>();
1754 EXPECT_TRUE(heap.ObjectPayloadSizeForTesting() >= sizeof(HeapAllocatedArray));
1755
1756 // Sanity check of the contents in the heap.
1757 EXPECT_EQ(0, array->at(0));
1758 EXPECT_EQ(42, array->at(42));
1759 EXPECT_EQ(0, array->at(128));
1760 EXPECT_EQ(999 % 128, array->at(999));
1761 }
1762
TEST_F(HeapTest,SimplePersistent)1763 TEST_F(HeapTest, SimplePersistent) {
1764 Persistent<TraceCounter> trace_counter = MakeGarbageCollected<TraceCounter>();
1765 EXPECT_EQ(0, trace_counter->TraceCount());
1766 PreciselyCollectGarbage();
1767 int saved_trace_count = trace_counter->TraceCount();
1768 EXPECT_LT(0, saved_trace_count);
1769
1770 Persistent<ClassWithMember> class_with_member =
1771 MakeGarbageCollected<ClassWithMember>();
1772 EXPECT_EQ(0, class_with_member->TraceCount());
1773 PreciselyCollectGarbage();
1774 EXPECT_LT(0, class_with_member->TraceCount());
1775 EXPECT_LT(saved_trace_count, trace_counter->TraceCount());
1776 }
1777
TEST_F(HeapTest,SimpleFinalization)1778 TEST_F(HeapTest, SimpleFinalization) {
1779 ClearOutOldGarbage();
1780 {
1781 SimpleFinalizedObject::destructor_calls_ = 0;
1782 Persistent<SimpleFinalizedObject> finalized =
1783 MakeGarbageCollected<SimpleFinalizedObject>();
1784 EXPECT_EQ(0, SimpleFinalizedObject::destructor_calls_);
1785 PreciselyCollectGarbage();
1786 EXPECT_EQ(0, SimpleFinalizedObject::destructor_calls_);
1787 }
1788
1789 PreciselyCollectGarbage();
1790 EXPECT_EQ(1, SimpleFinalizedObject::destructor_calls_);
1791 }
1792
1793 #if DCHECK_IS_ON() || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
TEST_F(HeapTest,FreelistReuse)1794 TEST_F(HeapTest, FreelistReuse) {
1795 ClearOutOldGarbage();
1796
1797 for (int i = 0; i < 100; i++)
1798 MakeGarbageCollected<IntWrapper>(i);
1799 IntWrapper* p1 = MakeGarbageCollected<IntWrapper>(100);
1800 PreciselyCollectGarbage();
1801 // In non-production builds, we delay reusing freed memory for at least
1802 // one GC cycle.
1803 for (int i = 0; i < 100; i++) {
1804 IntWrapper* p2 = MakeGarbageCollected<IntWrapper>(i);
1805 EXPECT_NE(p1, p2);
1806 }
1807
1808 PreciselyCollectGarbage();
1809 PreciselyCollectGarbage();
1810 // Now the freed memory in the first GC should be reused.
1811 bool reused_memory_found = false;
1812 for (int i = 0; i < 10000; i++) {
1813 IntWrapper* p2 = MakeGarbageCollected<IntWrapper>(i);
1814 if (p1 == p2) {
1815 reused_memory_found = true;
1816 break;
1817 }
1818 }
1819 EXPECT_TRUE(reused_memory_found);
1820 }
1821 #endif
1822
TEST_F(HeapTest,LazySweepingPages)1823 TEST_F(HeapTest, LazySweepingPages) {
1824 ClearOutOldGarbage();
1825
1826 SimpleFinalizedObject::destructor_calls_ = 0;
1827 EXPECT_EQ(0, SimpleFinalizedObject::destructor_calls_);
1828 for (int i = 0; i < 1000; i++)
1829 MakeGarbageCollected<SimpleFinalizedObject>();
1830 ThreadState::Current()->CollectGarbage(
1831 BlinkGC::CollectionType::kMajor, BlinkGC::kNoHeapPointersOnStack,
1832 BlinkGC::kAtomicMarking, BlinkGC::kConcurrentAndLazySweeping,
1833 BlinkGC::GCReason::kForcedGCForTesting);
1834 EXPECT_EQ(0, SimpleFinalizedObject::destructor_calls_);
1835 for (int i = 0; i < 10000; i++)
1836 MakeGarbageCollected<SimpleFinalizedObject>();
1837 EXPECT_EQ(1000, SimpleFinalizedObject::destructor_calls_);
1838 PreciselyCollectGarbage();
1839 EXPECT_EQ(11000, SimpleFinalizedObject::destructor_calls_);
1840 }
1841
TEST_F(HeapTest,LazySweepingLargeObjectPages)1842 TEST_F(HeapTest, LazySweepingLargeObjectPages) {
1843 // Disable concurrent sweeping to check lazy sweeping on allocation.
1844 base::test::ScopedFeatureList scoped_feature_list;
1845 scoped_feature_list.InitAndDisableFeature(
1846 blink::features::kBlinkHeapConcurrentSweeping);
1847
1848 ClearOutOldGarbage();
1849
1850 // Create free lists that can be reused for IntWrappers created in
1851 // MakeGarbageCollected<LargeHeapObject>().
1852 Persistent<IntWrapper> p1 = MakeGarbageCollected<IntWrapper>(1);
1853 for (int i = 0; i < 100; i++) {
1854 MakeGarbageCollected<IntWrapper>(i);
1855 }
1856 Persistent<IntWrapper> p2 = MakeGarbageCollected<IntWrapper>(2);
1857 PreciselyCollectGarbage();
1858 PreciselyCollectGarbage();
1859
1860 LargeHeapObject::destructor_calls_ = 0;
1861 EXPECT_EQ(0, LargeHeapObject::destructor_calls_);
1862 for (int i = 0; i < 10; i++)
1863 MakeGarbageCollected<LargeHeapObject>();
1864 ThreadState::Current()->CollectGarbage(
1865 BlinkGC::CollectionType::kMajor, BlinkGC::kNoHeapPointersOnStack,
1866 BlinkGC::kAtomicMarking, BlinkGC::kConcurrentAndLazySweeping,
1867 BlinkGC::GCReason::kForcedGCForTesting);
1868 EXPECT_EQ(0, LargeHeapObject::destructor_calls_);
1869 for (int i = 0; i < 10; i++) {
1870 MakeGarbageCollected<LargeHeapObject>();
1871 EXPECT_EQ(i + 1, LargeHeapObject::destructor_calls_);
1872 }
1873 MakeGarbageCollected<LargeHeapObject>();
1874 MakeGarbageCollected<LargeHeapObject>();
1875 EXPECT_EQ(10, LargeHeapObject::destructor_calls_);
1876 ThreadState::Current()->CollectGarbage(
1877 BlinkGC::CollectionType::kMajor, BlinkGC::kNoHeapPointersOnStack,
1878 BlinkGC::kAtomicMarking, BlinkGC::kConcurrentAndLazySweeping,
1879 BlinkGC::GCReason::kForcedGCForTesting);
1880 EXPECT_EQ(10, LargeHeapObject::destructor_calls_);
1881 PreciselyCollectGarbage();
1882 EXPECT_EQ(22, LargeHeapObject::destructor_calls_);
1883 }
1884
TEST_F(HeapTest,Finalization)1885 TEST_F(HeapTest, Finalization) {
1886 {
1887 HeapTestSubClass::destructor_calls_ = 0;
1888 HeapTestSuperClass::destructor_calls_ = 0;
1889 auto* t1 = MakeGarbageCollected<HeapTestSubClass>();
1890 auto* t2 = MakeGarbageCollected<HeapTestSubClass>();
1891 auto* t3 = MakeGarbageCollected<HeapTestSuperClass>();
1892 // FIXME(oilpan): Ignore unused variables.
1893 (void)t1;
1894 (void)t2;
1895 (void)t3;
1896 }
1897 // Nothing is marked so the GC should free everything and call
1898 // the finalizer on all three objects.
1899 PreciselyCollectGarbage();
1900 EXPECT_EQ(2, HeapTestSubClass::destructor_calls_);
1901 EXPECT_EQ(3, HeapTestSuperClass::destructor_calls_);
1902 // Destructors not called again when GCing again.
1903 PreciselyCollectGarbage();
1904 EXPECT_EQ(2, HeapTestSubClass::destructor_calls_);
1905 EXPECT_EQ(3, HeapTestSuperClass::destructor_calls_);
1906 }
1907
TEST_F(HeapTest,TypedArenaSanity)1908 TEST_F(HeapTest, TypedArenaSanity) {
1909 // We use TraceCounter for allocating an object on the general heap.
1910 Persistent<TraceCounter> general_heap_object =
1911 MakeGarbageCollected<TraceCounter>();
1912 Persistent<IntNode> typed_heap_object = IntNode::Create(0);
1913 EXPECT_NE(PageFromObject(general_heap_object.Get()),
1914 PageFromObject(typed_heap_object.Get()));
1915 }
1916
TEST_F(HeapTest,NoAllocation)1917 TEST_F(HeapTest, NoAllocation) {
1918 ThreadState* state = ThreadState::Current();
1919 EXPECT_TRUE(state->IsAllocationAllowed());
1920 {
1921 // Disallow allocation
1922 ThreadState::NoAllocationScope no_allocation_scope(state);
1923 EXPECT_FALSE(state->IsAllocationAllowed());
1924 }
1925 EXPECT_TRUE(state->IsAllocationAllowed());
1926 }
1927
TEST_F(HeapTest,Members)1928 TEST_F(HeapTest, Members) {
1929 ClearOutOldGarbage();
1930 Bar::live_ = 0;
1931 {
1932 Persistent<Baz> h1;
1933 Persistent<Baz> h2;
1934 {
1935 h1 = MakeGarbageCollected<Baz>(MakeGarbageCollected<Bar>());
1936 PreciselyCollectGarbage();
1937 EXPECT_EQ(1u, Bar::live_);
1938 h2 = MakeGarbageCollected<Baz>(MakeGarbageCollected<Bar>());
1939 PreciselyCollectGarbage();
1940 EXPECT_EQ(2u, Bar::live_);
1941 }
1942 PreciselyCollectGarbage();
1943 EXPECT_EQ(2u, Bar::live_);
1944 h1->Clear();
1945 PreciselyCollectGarbage();
1946 EXPECT_EQ(1u, Bar::live_);
1947 }
1948 PreciselyCollectGarbage();
1949 EXPECT_EQ(0u, Bar::live_);
1950 }
1951
TEST_F(HeapTest,MarkTest)1952 TEST_F(HeapTest, MarkTest) {
1953 ClearOutOldGarbage();
1954 {
1955 Bar::live_ = 0;
1956 Persistent<Bar> bar = MakeGarbageCollected<Bar>();
1957 #if DCHECK_IS_ON()
1958 DCHECK(ThreadState::Current()->Heap().FindPageFromAddress(bar));
1959 #endif
1960 EXPECT_EQ(1u, Bar::live_);
1961 {
1962 auto* foo = MakeGarbageCollected<Foo>(bar);
1963 #if DCHECK_IS_ON()
1964 DCHECK(ThreadState::Current()->Heap().FindPageFromAddress(foo));
1965 #endif
1966 EXPECT_EQ(2u, Bar::live_);
1967 EXPECT_TRUE(reinterpret_cast<Address>(foo) !=
1968 reinterpret_cast<Address>(bar.Get()));
1969 ConservativelyCollectGarbage();
1970 EXPECT_TRUE(foo != bar); // To make sure foo is kept alive.
1971 EXPECT_EQ(2u, Bar::live_);
1972 }
1973 PreciselyCollectGarbage();
1974 EXPECT_EQ(1u, Bar::live_);
1975 }
1976 PreciselyCollectGarbage();
1977 EXPECT_EQ(0u, Bar::live_);
1978 }
1979
TEST_F(HeapTest,DeepTest)1980 TEST_F(HeapTest, DeepTest) {
1981 ClearOutOldGarbage();
1982 const unsigned kDepth = 100000;
1983 Bar::live_ = 0;
1984 {
1985 auto* bar = MakeGarbageCollected<Bar>();
1986 #if DCHECK_IS_ON()
1987 DCHECK(ThreadState::Current()->Heap().FindPageFromAddress(bar));
1988 #endif
1989 auto* foo = MakeGarbageCollected<Foo>(bar);
1990 #if DCHECK_IS_ON()
1991 DCHECK(ThreadState::Current()->Heap().FindPageFromAddress(foo));
1992 #endif
1993 EXPECT_EQ(2u, Bar::live_);
1994 for (unsigned i = 0; i < kDepth; i++) {
1995 auto* foo2 = MakeGarbageCollected<Foo>(foo);
1996 foo = foo2;
1997 #if DCHECK_IS_ON()
1998 DCHECK(ThreadState::Current()->Heap().FindPageFromAddress(foo));
1999 #endif
2000 }
2001 EXPECT_EQ(kDepth + 2, Bar::live_);
2002 ConservativelyCollectGarbage();
2003 EXPECT_TRUE(foo != bar); // To make sure foo and bar are kept alive.
2004 EXPECT_EQ(kDepth + 2, Bar::live_);
2005 }
2006 PreciselyCollectGarbage();
2007 EXPECT_EQ(0u, Bar::live_);
2008 }
2009
TEST_F(HeapTest,WideTest)2010 TEST_F(HeapTest, WideTest) {
2011 ClearOutOldGarbage();
2012 Bar::live_ = 0;
2013 {
2014 auto* bars = MakeGarbageCollected<Bars>();
2015 unsigned width = Bars::kWidth;
2016 EXPECT_EQ(width + 1, Bar::live_);
2017 ConservativelyCollectGarbage();
2018 EXPECT_EQ(width + 1, Bar::live_);
2019 // Use bars here to make sure that it will be on the stack
2020 // for the conservative stack scan to find.
2021 EXPECT_EQ(width, bars->GetWidth());
2022 }
2023 EXPECT_EQ(Bars::kWidth + 1, Bar::live_);
2024 PreciselyCollectGarbage();
2025 EXPECT_EQ(0u, Bar::live_);
2026 }
2027
TEST_F(HeapTest,HashMapOfMembers)2028 TEST_F(HeapTest, HashMapOfMembers) {
2029 ClearOutOldGarbage();
2030 ThreadHeap& heap = ThreadState::Current()->Heap();
2031 IntWrapper::destructor_calls_ = 0;
2032 size_t initial_object_payload_size = heap.ObjectPayloadSizeForTesting();
2033 {
2034 typedef HeapHashMap<Member<IntWrapper>, Member<IntWrapper>,
2035 DefaultHash<Member<IntWrapper>>::Hash,
2036 HashTraits<Member<IntWrapper>>,
2037 HashTraits<Member<IntWrapper>>>
2038 HeapObjectIdentityMap;
2039
2040 Persistent<HeapObjectIdentityMap> map =
2041 MakeGarbageCollected<HeapObjectIdentityMap>();
2042
2043 map->clear();
2044 size_t after_set_was_created = heap.ObjectPayloadSizeForTesting();
2045 EXPECT_TRUE(after_set_was_created > initial_object_payload_size);
2046
2047 PreciselyCollectGarbage();
2048 size_t after_gc = heap.ObjectPayloadSizeForTesting();
2049 EXPECT_EQ(after_gc, after_set_was_created);
2050
2051 // If the additions below cause garbage collections, these
2052 // pointers should be found by conservative stack scanning.
2053 auto* one(MakeGarbageCollected<IntWrapper>(1));
2054 auto* another_one(MakeGarbageCollected<IntWrapper>(1));
2055
2056 map->insert(one, one);
2057
2058 size_t after_one_add = heap.ObjectPayloadSizeForTesting();
2059 EXPECT_TRUE(after_one_add > after_gc);
2060
2061 HeapObjectIdentityMap::iterator it(map->begin());
2062 HeapObjectIdentityMap::iterator it2(map->begin());
2063 ++it;
2064 ++it2;
2065
2066 map->insert(another_one, one);
2067
2068 // The addition above can cause an allocation of a new
2069 // backing store. We therefore garbage collect before
2070 // taking the heap stats in order to get rid of the old
2071 // backing store. We make sure to not use conservative
2072 // stack scanning as that could find a pointer to the
2073 // old backing.
2074 PreciselyCollectGarbage();
2075 size_t after_add_and_gc = heap.ObjectPayloadSizeForTesting();
2076 EXPECT_TRUE(after_add_and_gc >= after_one_add);
2077
2078 EXPECT_EQ(map->size(), 2u); // Two different wrappings of '1' are distinct.
2079
2080 PreciselyCollectGarbage();
2081 EXPECT_TRUE(map->Contains(one));
2082 EXPECT_TRUE(map->Contains(another_one));
2083
2084 IntWrapper* gotten(map->at(one));
2085 EXPECT_EQ(gotten->Value(), one->Value());
2086 EXPECT_EQ(gotten, one);
2087
2088 size_t after_gc2 = heap.ObjectPayloadSizeForTesting();
2089 EXPECT_EQ(after_gc2, after_add_and_gc);
2090
2091 IntWrapper* dozen = nullptr;
2092
2093 for (int i = 1; i < 1000; i++) { // 999 iterations.
2094 auto* i_wrapper(MakeGarbageCollected<IntWrapper>(i));
2095 auto* i_squared(MakeGarbageCollected<IntWrapper>(i * i));
2096 map->insert(i_wrapper, i_squared);
2097 if (i == 12)
2098 dozen = i_wrapper;
2099 }
2100 size_t after_adding1000 = heap.ObjectPayloadSizeForTesting();
2101 EXPECT_TRUE(after_adding1000 > after_gc2);
2102
2103 IntWrapper* gross(map->at(dozen));
2104 EXPECT_EQ(gross->Value(), 144);
2105
2106 // This should clear out any junk backings created by all the adds.
2107 PreciselyCollectGarbage();
2108 size_t after_gc3 = heap.ObjectPayloadSizeForTesting();
2109 EXPECT_TRUE(after_gc3 <= after_adding1000);
2110 }
2111
2112 PreciselyCollectGarbage();
2113 // The objects 'one', anotherOne, and the 999 other pairs.
2114 EXPECT_EQ(IntWrapper::destructor_calls_, 2000);
2115 size_t after_gc4 = heap.ObjectPayloadSizeForTesting();
2116 EXPECT_EQ(after_gc4, initial_object_payload_size);
2117 }
2118
TEST_F(HeapTest,NestedAllocation)2119 TEST_F(HeapTest, NestedAllocation) {
2120 ThreadHeap& heap = ThreadState::Current()->Heap();
2121 ClearOutOldGarbage();
2122 size_t initial_object_payload_size = heap.ObjectPayloadSizeForTesting();
2123 {
2124 Persistent<ConstructorAllocation> constructor_allocation =
2125 MakeGarbageCollected<ConstructorAllocation>();
2126 }
2127 ClearOutOldGarbage();
2128 size_t after_free = heap.ObjectPayloadSizeForTesting();
2129 EXPECT_TRUE(initial_object_payload_size == after_free);
2130 }
2131
TEST_F(HeapTest,LargeHeapObjects)2132 TEST_F(HeapTest, LargeHeapObjects) {
2133 ThreadHeap& heap = ThreadState::Current()->Heap();
2134 ClearOutOldGarbage();
2135 size_t initial_object_payload_size = heap.ObjectPayloadSizeForTesting();
2136 size_t initial_allocated_space =
2137 heap.stats_collector()->allocated_space_bytes();
2138 IntWrapper::destructor_calls_ = 0;
2139 LargeHeapObject::destructor_calls_ = 0;
2140 {
2141 int slack =
2142 8; // LargeHeapObject points to an IntWrapper that is also allocated.
2143 Persistent<LargeHeapObject> object =
2144 MakeGarbageCollected<LargeHeapObject>();
2145 #if DCHECK_IS_ON()
2146 DCHECK(ThreadState::Current()->Heap().FindPageFromAddress(object));
2147 DCHECK(ThreadState::Current()->Heap().FindPageFromAddress(
2148 reinterpret_cast<char*>(object.Get()) + sizeof(LargeHeapObject) - 1));
2149 #endif
2150 ClearOutOldGarbage();
2151 size_t after_allocation = heap.stats_collector()->allocated_space_bytes();
2152 {
2153 object->Set(0, 'a');
2154 EXPECT_EQ('a', object->Get(0));
2155 object->Set(object->length() - 1, 'b');
2156 EXPECT_EQ('b', object->Get(object->length() - 1));
2157 size_t expected_large_heap_object_payload_size =
2158 ThreadHeap::AllocationSizeFromSize(sizeof(LargeHeapObject)) -
2159 sizeof(HeapObjectHeader);
2160 size_t expected_object_payload_size =
2161 expected_large_heap_object_payload_size + sizeof(IntWrapper);
2162 size_t actual_object_payload_size =
2163 heap.ObjectPayloadSizeForTesting() - initial_object_payload_size;
2164 CheckWithSlack(expected_object_payload_size, actual_object_payload_size,
2165 slack);
2166 // There is probably space for the IntWrapper in a heap page without
2167 // allocating extra pages. However, the IntWrapper allocation might cause
2168 // the addition of a heap page.
2169 size_t large_object_allocation_size =
2170 sizeof(LargeObjectPage) + expected_large_heap_object_payload_size;
2171 size_t allocated_space_lower_bound =
2172 initial_allocated_space + large_object_allocation_size;
2173 size_t allocated_space_upper_bound =
2174 allocated_space_lower_bound + slack + kBlinkPageSize;
2175 EXPECT_LE(allocated_space_lower_bound, after_allocation);
2176 EXPECT_LE(after_allocation, allocated_space_upper_bound);
2177 EXPECT_EQ(0, IntWrapper::destructor_calls_);
2178 EXPECT_EQ(0, LargeHeapObject::destructor_calls_);
2179 for (int i = 0; i < 10; i++)
2180 object = MakeGarbageCollected<LargeHeapObject>();
2181 }
2182 ClearOutOldGarbage();
2183 EXPECT_EQ(after_allocation,
2184 heap.stats_collector()->allocated_space_bytes());
2185 EXPECT_EQ(10, IntWrapper::destructor_calls_);
2186 EXPECT_EQ(10, LargeHeapObject::destructor_calls_);
2187 }
2188 ClearOutOldGarbage();
2189 EXPECT_TRUE(initial_object_payload_size ==
2190 heap.ObjectPayloadSizeForTesting());
2191 EXPECT_EQ(initial_allocated_space,
2192 heap.stats_collector()->allocated_space_bytes());
2193 EXPECT_EQ(11, IntWrapper::destructor_calls_);
2194 EXPECT_EQ(11, LargeHeapObject::destructor_calls_);
2195 PreciselyCollectGarbage();
2196 }
2197
2198 // This test often fails on Android (https://crbug.com/843032).
2199 // We run out of memory on Android devices because ReserveCapacityForSize
2200 // actually allocates a much larger backing than specified (in this case 400MB).
2201 #if defined(OS_ANDROID)
2202 #define MAYBE_LargeHashMap DISABLED_LargeHashMap
2203 #else
2204 #define MAYBE_LargeHashMap LargeHashMap
2205 #endif
TEST_F(HeapTest,MAYBE_LargeHashMap)2206 TEST_F(HeapTest, MAYBE_LargeHashMap) {
2207 ClearOutOldGarbage();
2208
2209 // Try to allocate a HashTable larger than kMaxHeapObjectSize
2210 // (crbug.com/597953).
2211 wtf_size_t size = kMaxHeapObjectSize /
2212 sizeof(HeapHashMap<int, Member<IntWrapper>>::ValueType);
2213 Persistent<HeapHashMap<int, Member<IntWrapper>>> map =
2214 MakeGarbageCollected<HeapHashMap<int, Member<IntWrapper>>>();
2215 map->ReserveCapacityForSize(size);
2216 EXPECT_LE(size, map->Capacity());
2217 }
2218
TEST_F(HeapTest,LargeVector)2219 TEST_F(HeapTest, LargeVector) {
2220 ClearOutOldGarbage();
2221
2222 // Try to allocate a HeapVectors larger than kMaxHeapObjectSize
2223 // (crbug.com/597953).
2224 const wtf_size_t size = kMaxHeapObjectSize / sizeof(Member<IntWrapper>);
2225 Persistent<HeapVector<Member<IntWrapper>>> vector =
2226 MakeGarbageCollected<HeapVector<Member<IntWrapper>>>(size);
2227 EXPECT_LE(size, vector->capacity());
2228 }
2229
2230 typedef std::pair<Member<IntWrapper>, int> PairWrappedUnwrapped;
2231 typedef std::pair<int, Member<IntWrapper>> PairUnwrappedWrapped;
2232 typedef std::pair<WeakMember<IntWrapper>, Member<IntWrapper>> PairWeakStrong;
2233 typedef std::pair<Member<IntWrapper>, WeakMember<IntWrapper>> PairStrongWeak;
2234 typedef std::pair<WeakMember<IntWrapper>, int> PairWeakUnwrapped;
2235 typedef std::pair<int, WeakMember<IntWrapper>> PairUnwrappedWeak;
2236
2237 class Container final : public GarbageCollected<Container> {
2238 public:
2239 HeapHashMap<Member<IntWrapper>, Member<IntWrapper>> map;
2240 HeapHashSet<Member<IntWrapper>> set;
2241 HeapHashSet<Member<IntWrapper>> set2;
2242 HeapHashCountedSet<Member<IntWrapper>> set3;
2243 HeapVector<Member<IntWrapper>, 2> vector;
2244 HeapVector<PairWrappedUnwrapped, 2> vector_wu;
2245 HeapVector<PairUnwrappedWrapped, 2> vector_uw;
2246 HeapDeque<Member<IntWrapper>> deque;
Trace(Visitor * visitor)2247 void Trace(Visitor* visitor) {
2248 visitor->Trace(map);
2249 visitor->Trace(set);
2250 visitor->Trace(set2);
2251 visitor->Trace(set3);
2252 visitor->Trace(vector);
2253 visitor->Trace(vector_wu);
2254 visitor->Trace(vector_uw);
2255 visitor->Trace(deque);
2256 }
2257 };
2258
2259 struct NeedsTracingTrait {
NeedsTracingTraitblink::NeedsTracingTrait2260 explicit NeedsTracingTrait(IntWrapper* wrapper) : wrapper_(wrapper) {}
Traceblink::NeedsTracingTrait2261 void Trace(Visitor* visitor) { visitor->Trace(wrapper_); }
2262 Member<IntWrapper> wrapper_;
2263 };
2264
TEST_F(HeapTest,HeapVectorFilledWithValue)2265 TEST_F(HeapTest, HeapVectorFilledWithValue) {
2266 auto* val = MakeGarbageCollected<IntWrapper>(1);
2267 HeapVector<Member<IntWrapper>> vector(10, val);
2268 EXPECT_EQ(10u, vector.size());
2269 for (wtf_size_t i = 0; i < vector.size(); i++)
2270 EXPECT_EQ(val, vector[i]);
2271 }
2272
TEST_F(HeapTest,HeapVectorWithInlineCapacity)2273 TEST_F(HeapTest, HeapVectorWithInlineCapacity) {
2274 auto* one = MakeGarbageCollected<IntWrapper>(1);
2275 auto* two = MakeGarbageCollected<IntWrapper>(2);
2276 auto* three = MakeGarbageCollected<IntWrapper>(3);
2277 auto* four = MakeGarbageCollected<IntWrapper>(4);
2278 auto* five = MakeGarbageCollected<IntWrapper>(5);
2279 auto* six = MakeGarbageCollected<IntWrapper>(6);
2280 {
2281 HeapVector<Member<IntWrapper>, 2> vector;
2282 vector.push_back(one);
2283 vector.push_back(two);
2284 ConservativelyCollectGarbage();
2285 EXPECT_TRUE(vector.Contains(one));
2286 EXPECT_TRUE(vector.Contains(two));
2287
2288 vector.push_back(three);
2289 vector.push_back(four);
2290 ConservativelyCollectGarbage();
2291 EXPECT_TRUE(vector.Contains(one));
2292 EXPECT_TRUE(vector.Contains(two));
2293 EXPECT_TRUE(vector.Contains(three));
2294 EXPECT_TRUE(vector.Contains(four));
2295
2296 vector.Shrink(1);
2297 ConservativelyCollectGarbage();
2298 EXPECT_TRUE(vector.Contains(one));
2299 EXPECT_FALSE(vector.Contains(two));
2300 EXPECT_FALSE(vector.Contains(three));
2301 EXPECT_FALSE(vector.Contains(four));
2302 }
2303 {
2304 HeapVector<Member<IntWrapper>, 2> vector1;
2305 HeapVector<Member<IntWrapper>, 2> vector2;
2306
2307 vector1.push_back(one);
2308 vector2.push_back(two);
2309 vector1.swap(vector2);
2310 ConservativelyCollectGarbage();
2311 EXPECT_TRUE(vector1.Contains(two));
2312 EXPECT_TRUE(vector2.Contains(one));
2313 }
2314 {
2315 HeapVector<Member<IntWrapper>, 2> vector1;
2316 HeapVector<Member<IntWrapper>, 2> vector2;
2317
2318 vector1.push_back(one);
2319 vector1.push_back(two);
2320 vector2.push_back(three);
2321 vector2.push_back(four);
2322 vector2.push_back(five);
2323 vector2.push_back(six);
2324 vector1.swap(vector2);
2325 ConservativelyCollectGarbage();
2326 EXPECT_TRUE(vector1.Contains(three));
2327 EXPECT_TRUE(vector1.Contains(four));
2328 EXPECT_TRUE(vector1.Contains(five));
2329 EXPECT_TRUE(vector1.Contains(six));
2330 EXPECT_TRUE(vector2.Contains(one));
2331 EXPECT_TRUE(vector2.Contains(two));
2332 }
2333 }
2334
TEST_F(HeapTest,HeapVectorShrinkCapacity)2335 TEST_F(HeapTest, HeapVectorShrinkCapacity) {
2336 ClearOutOldGarbage();
2337 HeapVector<Member<IntWrapper>> vector1;
2338 HeapVector<Member<IntWrapper>> vector2;
2339 vector1.ReserveCapacity(96);
2340 EXPECT_LE(96u, vector1.capacity());
2341 vector1.Grow(vector1.capacity());
2342
2343 // Assumes none was allocated just after a vector backing of vector1.
2344 vector1.Shrink(56);
2345 vector1.ShrinkToFit();
2346 EXPECT_GT(96u, vector1.capacity());
2347
2348 vector2.ReserveCapacity(20);
2349 // Assumes another vector backing was allocated just after the vector
2350 // backing of vector1.
2351 vector1.Shrink(10);
2352 vector1.ShrinkToFit();
2353 EXPECT_GT(56u, vector1.capacity());
2354
2355 vector1.Grow(192);
2356 EXPECT_LE(192u, vector1.capacity());
2357 }
2358
TEST_F(HeapTest,HeapVectorShrinkInlineCapacity)2359 TEST_F(HeapTest, HeapVectorShrinkInlineCapacity) {
2360 ClearOutOldGarbage();
2361 const size_t kInlineCapacity = 64;
2362 HeapVector<Member<IntWrapper>, kInlineCapacity> vector1;
2363 vector1.ReserveCapacity(128);
2364 EXPECT_LE(128u, vector1.capacity());
2365 vector1.Grow(vector1.capacity());
2366
2367 // Shrink the external buffer.
2368 vector1.Shrink(90);
2369 vector1.ShrinkToFit();
2370 EXPECT_GT(128u, vector1.capacity());
2371
2372 // TODO(sof): if the ASan support for 'contiguous containers' is enabled,
2373 // Vector inline buffers are disabled; that constraint should be attempted
2374 // removed, but until that time, disable testing handling of capacities
2375 // of inline buffers.
2376 #if !defined(ANNOTATE_CONTIGUOUS_CONTAINER)
2377 // Shrinking switches the buffer from the external one to the inline one.
2378 vector1.Shrink(kInlineCapacity - 1);
2379 vector1.ShrinkToFit();
2380 EXPECT_EQ(kInlineCapacity, vector1.capacity());
2381
2382 // Try to shrink the inline buffer.
2383 vector1.Shrink(1);
2384 vector1.ShrinkToFit();
2385 EXPECT_EQ(kInlineCapacity, vector1.capacity());
2386 #endif
2387 }
2388
TEST_F(HeapTest,HeapVectorOnStackLargeObjectPageSized)2389 TEST_F(HeapTest, HeapVectorOnStackLargeObjectPageSized) {
2390 ClearOutOldGarbage();
2391 // Try to allocate a vector of a size that will end exactly where the
2392 // LargeObjectPage ends.
2393 using Container = HeapVector<Member<IntWrapper>>;
2394 Container vector;
2395 wtf_size_t size =
2396 (kLargeObjectSizeThreshold + kBlinkGuardPageSize -
2397 static_cast<wtf_size_t>(LargeObjectPage::PageHeaderSize()) -
2398 sizeof(HeapObjectHeader)) /
2399 sizeof(Container::ValueType);
2400 vector.ReserveCapacity(size);
2401 for (unsigned i = 0; i < size; ++i)
2402 vector.push_back(MakeGarbageCollected<IntWrapper>(i));
2403 ConservativelyCollectGarbage();
2404 }
2405
2406 template <typename T, typename U>
DequeContains(HeapDeque<T> & deque,U u)2407 bool DequeContains(HeapDeque<T>& deque, U u) {
2408 typedef typename HeapDeque<T>::iterator iterator;
2409 for (iterator it = deque.begin(); it != deque.end(); ++it) {
2410 if (*it == u)
2411 return true;
2412 }
2413 return false;
2414 }
2415
TEST_F(HeapTest,HeapCollectionTypes)2416 TEST_F(HeapTest, HeapCollectionTypes) {
2417 IntWrapper::destructor_calls_ = 0;
2418
2419 typedef HeapHashMap<Member<IntWrapper>, Member<IntWrapper>> MemberMember;
2420 typedef HeapHashMap<Member<IntWrapper>, int> MemberPrimitive;
2421 typedef HeapHashMap<int, Member<IntWrapper>> PrimitiveMember;
2422
2423 typedef HeapHashSet<Member<IntWrapper>> MemberSet;
2424 typedef HeapHashCountedSet<Member<IntWrapper>> MemberCountedSet;
2425
2426 typedef HeapVector<Member<IntWrapper>, 2> MemberVector;
2427 typedef HeapDeque<Member<IntWrapper>> MemberDeque;
2428
2429 typedef HeapVector<PairWrappedUnwrapped, 2> VectorWU;
2430 typedef HeapVector<PairUnwrappedWrapped, 2> VectorUW;
2431
2432 Persistent<MemberMember> member_member = MakeGarbageCollected<MemberMember>();
2433 Persistent<MemberMember> member_member2 =
2434 MakeGarbageCollected<MemberMember>();
2435 Persistent<MemberMember> member_member3 =
2436 MakeGarbageCollected<MemberMember>();
2437 Persistent<MemberPrimitive> member_primitive =
2438 MakeGarbageCollected<MemberPrimitive>();
2439 Persistent<PrimitiveMember> primitive_member =
2440 MakeGarbageCollected<PrimitiveMember>();
2441 Persistent<MemberSet> set = MakeGarbageCollected<MemberSet>();
2442 Persistent<MemberSet> set2 = MakeGarbageCollected<MemberSet>();
2443 Persistent<MemberCountedSet> set3 = MakeGarbageCollected<MemberCountedSet>();
2444 Persistent<MemberVector> vector = MakeGarbageCollected<MemberVector>();
2445 Persistent<MemberVector> vector2 = MakeGarbageCollected<MemberVector>();
2446 Persistent<VectorWU> vector_wu = MakeGarbageCollected<VectorWU>();
2447 Persistent<VectorWU> vector_wu2 = MakeGarbageCollected<VectorWU>();
2448 Persistent<VectorUW> vector_uw = MakeGarbageCollected<VectorUW>();
2449 Persistent<VectorUW> vector_uw2 = MakeGarbageCollected<VectorUW>();
2450 Persistent<MemberDeque> deque = MakeGarbageCollected<MemberDeque>();
2451 Persistent<MemberDeque> deque2 = MakeGarbageCollected<MemberDeque>();
2452 Persistent<Container> container = MakeGarbageCollected<Container>();
2453
2454 ClearOutOldGarbage();
2455 {
2456 Persistent<IntWrapper> one(MakeGarbageCollected<IntWrapper>(1));
2457 Persistent<IntWrapper> two(MakeGarbageCollected<IntWrapper>(2));
2458 Persistent<IntWrapper> one_b(MakeGarbageCollected<IntWrapper>(1));
2459 Persistent<IntWrapper> two_b(MakeGarbageCollected<IntWrapper>(2));
2460 Persistent<IntWrapper> one_c(MakeGarbageCollected<IntWrapper>(1));
2461 Persistent<IntWrapper> one_d(MakeGarbageCollected<IntWrapper>(1));
2462 Persistent<IntWrapper> one_e(MakeGarbageCollected<IntWrapper>(1));
2463 Persistent<IntWrapper> one_f(MakeGarbageCollected<IntWrapper>(1));
2464 {
2465 auto* three_b(MakeGarbageCollected<IntWrapper>(3));
2466 auto* three_c(MakeGarbageCollected<IntWrapper>(3));
2467 auto* three_d(MakeGarbageCollected<IntWrapper>(3));
2468 auto* three_e(MakeGarbageCollected<IntWrapper>(3));
2469 auto* three(MakeGarbageCollected<IntWrapper>(3));
2470 auto* four_b(MakeGarbageCollected<IntWrapper>(4));
2471 auto* four_c(MakeGarbageCollected<IntWrapper>(4));
2472 auto* four_d(MakeGarbageCollected<IntWrapper>(4));
2473 auto* four_e(MakeGarbageCollected<IntWrapper>(4));
2474 auto* four(MakeGarbageCollected<IntWrapper>(4));
2475 auto* five_c(MakeGarbageCollected<IntWrapper>(5));
2476 auto* five_d(MakeGarbageCollected<IntWrapper>(5));
2477
2478 // Member Collections.
2479 member_member2->insert(one, two);
2480 member_member2->insert(two, three);
2481 member_member2->insert(three, four);
2482 member_member2->insert(four, one);
2483 primitive_member->insert(1, two);
2484 primitive_member->insert(2, three);
2485 primitive_member->insert(3, four);
2486 primitive_member->insert(4, one);
2487 member_primitive->insert(one, 2);
2488 member_primitive->insert(two, 3);
2489 member_primitive->insert(three, 4);
2490 member_primitive->insert(four, 1);
2491 set2->insert(one);
2492 set2->insert(two);
2493 set2->insert(three);
2494 set2->insert(four);
2495 set->insert(one_b);
2496 set3->insert(one_b);
2497 set3->insert(one_b);
2498 vector->push_back(one_b);
2499 deque->push_back(one_b);
2500 vector2->push_back(three_b);
2501 vector2->push_back(four_b);
2502 deque2->push_back(three_e);
2503 deque2->push_back(four_e);
2504 vector_wu->push_back(PairWrappedUnwrapped(&*one_c, 42));
2505 vector_wu2->push_back(PairWrappedUnwrapped(&*three_c, 43));
2506 vector_wu2->push_back(PairWrappedUnwrapped(&*four_c, 44));
2507 vector_wu2->push_back(PairWrappedUnwrapped(&*five_c, 45));
2508 vector_uw->push_back(PairUnwrappedWrapped(1, &*one_d));
2509 vector_uw2->push_back(PairUnwrappedWrapped(103, &*three_d));
2510 vector_uw2->push_back(PairUnwrappedWrapped(104, &*four_d));
2511 vector_uw2->push_back(PairUnwrappedWrapped(105, &*five_d));
2512
2513 EXPECT_TRUE(DequeContains(*deque, one_b));
2514
2515 // Collect garbage. This should change nothing since we are keeping
2516 // alive the IntWrapper objects with on-stack pointers.
2517 ConservativelyCollectGarbage();
2518
2519 EXPECT_TRUE(DequeContains(*deque, one_b));
2520
2521 EXPECT_EQ(0u, member_member->size());
2522 EXPECT_EQ(4u, member_member2->size());
2523 EXPECT_EQ(4u, primitive_member->size());
2524 EXPECT_EQ(4u, member_primitive->size());
2525 EXPECT_EQ(1u, set->size());
2526 EXPECT_EQ(4u, set2->size());
2527 EXPECT_EQ(1u, set3->size());
2528 EXPECT_EQ(1u, vector->size());
2529 EXPECT_EQ(2u, vector2->size());
2530 EXPECT_EQ(1u, vector_wu->size());
2531 EXPECT_EQ(3u, vector_wu2->size());
2532 EXPECT_EQ(1u, vector_uw->size());
2533 EXPECT_EQ(3u, vector_uw2->size());
2534 EXPECT_EQ(1u, deque->size());
2535 EXPECT_EQ(2u, deque2->size());
2536
2537 MemberVector& cvec = container->vector;
2538 cvec.swap(*vector.Get());
2539 vector2->swap(cvec);
2540 vector->swap(cvec);
2541
2542 VectorWU& cvec_wu = container->vector_wu;
2543 cvec_wu.swap(*vector_wu.Get());
2544 vector_wu2->swap(cvec_wu);
2545 vector_wu->swap(cvec_wu);
2546
2547 VectorUW& cvec_uw = container->vector_uw;
2548 cvec_uw.swap(*vector_uw.Get());
2549 vector_uw2->swap(cvec_uw);
2550 vector_uw->swap(cvec_uw);
2551
2552 MemberDeque& c_deque = container->deque;
2553 c_deque.Swap(*deque.Get());
2554 deque2->Swap(c_deque);
2555 deque->Swap(c_deque);
2556
2557 // Swap set and set2 in a roundabout way.
2558 MemberSet& cset1 = container->set;
2559 MemberSet& cset2 = container->set2;
2560 set->swap(cset1);
2561 set2->swap(cset2);
2562 set->swap(cset2);
2563 cset1.swap(cset2);
2564 cset2.swap(*set2);
2565
2566 MemberCountedSet& c_counted_set = container->set3;
2567 set3->swap(c_counted_set);
2568 EXPECT_EQ(0u, set3->size());
2569 set3->swap(c_counted_set);
2570
2571 // Triple swap.
2572 container->map.swap(*member_member2);
2573 MemberMember& contained_map = container->map;
2574 member_member3->swap(contained_map);
2575 member_member3->swap(*member_member);
2576
2577 EXPECT_TRUE(member_member->at(one) == two);
2578 EXPECT_TRUE(member_member->at(two) == three);
2579 EXPECT_TRUE(member_member->at(three) == four);
2580 EXPECT_TRUE(member_member->at(four) == one);
2581 EXPECT_TRUE(primitive_member->at(1) == two);
2582 EXPECT_TRUE(primitive_member->at(2) == three);
2583 EXPECT_TRUE(primitive_member->at(3) == four);
2584 EXPECT_TRUE(primitive_member->at(4) == one);
2585 EXPECT_EQ(1, member_primitive->at(four));
2586 EXPECT_EQ(2, member_primitive->at(one));
2587 EXPECT_EQ(3, member_primitive->at(two));
2588 EXPECT_EQ(4, member_primitive->at(three));
2589 EXPECT_TRUE(set->Contains(one));
2590 EXPECT_TRUE(set->Contains(two));
2591 EXPECT_TRUE(set->Contains(three));
2592 EXPECT_TRUE(set->Contains(four));
2593 EXPECT_TRUE(set2->Contains(one_b));
2594 EXPECT_TRUE(set3->Contains(one_b));
2595 EXPECT_TRUE(vector->Contains(three_b));
2596 EXPECT_TRUE(vector->Contains(four_b));
2597 EXPECT_TRUE(DequeContains(*deque, three_e));
2598 EXPECT_TRUE(DequeContains(*deque, four_e));
2599 EXPECT_TRUE(vector2->Contains(one_b));
2600 EXPECT_FALSE(vector2->Contains(three_b));
2601 EXPECT_TRUE(DequeContains(*deque2, one_b));
2602 EXPECT_FALSE(DequeContains(*deque2, three_e));
2603 EXPECT_TRUE(vector_wu->Contains(PairWrappedUnwrapped(&*three_c, 43)));
2604 EXPECT_TRUE(vector_wu->Contains(PairWrappedUnwrapped(&*four_c, 44)));
2605 EXPECT_TRUE(vector_wu->Contains(PairWrappedUnwrapped(&*five_c, 45)));
2606 EXPECT_TRUE(vector_wu2->Contains(PairWrappedUnwrapped(&*one_c, 42)));
2607 EXPECT_FALSE(vector_wu2->Contains(PairWrappedUnwrapped(&*three_c, 43)));
2608 EXPECT_TRUE(vector_uw->Contains(PairUnwrappedWrapped(103, &*three_d)));
2609 EXPECT_TRUE(vector_uw->Contains(PairUnwrappedWrapped(104, &*four_d)));
2610 EXPECT_TRUE(vector_uw->Contains(PairUnwrappedWrapped(105, &*five_d)));
2611 EXPECT_TRUE(vector_uw2->Contains(PairUnwrappedWrapped(1, &*one_d)));
2612 EXPECT_FALSE(vector_uw2->Contains(PairUnwrappedWrapped(103, &*three_d)));
2613 }
2614
2615 PreciselyCollectGarbage();
2616
2617 EXPECT_EQ(4u, member_member->size());
2618 EXPECT_EQ(0u, member_member2->size());
2619 EXPECT_EQ(4u, primitive_member->size());
2620 EXPECT_EQ(4u, member_primitive->size());
2621 EXPECT_EQ(4u, set->size());
2622 EXPECT_EQ(1u, set2->size());
2623 EXPECT_EQ(1u, set3->size());
2624 EXPECT_EQ(2u, vector->size());
2625 EXPECT_EQ(1u, vector2->size());
2626 EXPECT_EQ(3u, vector_uw->size());
2627 EXPECT_EQ(1u, vector2->size());
2628 EXPECT_EQ(2u, deque->size());
2629 EXPECT_EQ(1u, deque2->size());
2630 EXPECT_EQ(1u, deque2->size());
2631
2632 EXPECT_TRUE(member_member->at(one) == two);
2633 EXPECT_TRUE(primitive_member->at(1) == two);
2634 EXPECT_TRUE(primitive_member->at(4) == one);
2635 EXPECT_EQ(2, member_primitive->at(one));
2636 EXPECT_EQ(3, member_primitive->at(two));
2637 EXPECT_TRUE(set->Contains(one));
2638 EXPECT_TRUE(set->Contains(two));
2639 EXPECT_FALSE(set->Contains(one_b));
2640 EXPECT_TRUE(set2->Contains(one_b));
2641 EXPECT_TRUE(set3->Contains(one_b));
2642 EXPECT_EQ(2u, set3->find(one_b)->value);
2643 EXPECT_EQ(3, vector->at(0)->Value());
2644 EXPECT_EQ(4, vector->at(1)->Value());
2645 EXPECT_EQ(3, deque->begin()->Get()->Value());
2646 }
2647
2648 PreciselyCollectGarbage();
2649 PreciselyCollectGarbage();
2650
2651 EXPECT_EQ(4u, member_member->size());
2652 EXPECT_EQ(4u, primitive_member->size());
2653 EXPECT_EQ(4u, member_primitive->size());
2654 EXPECT_EQ(4u, set->size());
2655 EXPECT_EQ(1u, set2->size());
2656 EXPECT_EQ(2u, vector->size());
2657 EXPECT_EQ(1u, vector2->size());
2658 EXPECT_EQ(3u, vector_wu->size());
2659 EXPECT_EQ(1u, vector_wu2->size());
2660 EXPECT_EQ(3u, vector_uw->size());
2661 EXPECT_EQ(1u, vector_uw2->size());
2662 EXPECT_EQ(2u, deque->size());
2663 EXPECT_EQ(1u, deque2->size());
2664 }
2665
TEST_F(HeapTest,PersistentVector)2666 TEST_F(HeapTest, PersistentVector) {
2667 IntWrapper::destructor_calls_ = 0;
2668
2669 typedef Vector<Persistent<IntWrapper>> PersistentVector;
2670
2671 Persistent<IntWrapper> one(MakeGarbageCollected<IntWrapper>(1));
2672 Persistent<IntWrapper> two(MakeGarbageCollected<IntWrapper>(2));
2673 Persistent<IntWrapper> three(MakeGarbageCollected<IntWrapper>(3));
2674 Persistent<IntWrapper> four(MakeGarbageCollected<IntWrapper>(4));
2675 Persistent<IntWrapper> five(MakeGarbageCollected<IntWrapper>(5));
2676 Persistent<IntWrapper> six(MakeGarbageCollected<IntWrapper>(6));
2677 {
2678 PersistentVector vector;
2679 vector.push_back(one);
2680 vector.push_back(two);
2681 ConservativelyCollectGarbage();
2682 EXPECT_TRUE(vector.Contains(one));
2683 EXPECT_TRUE(vector.Contains(two));
2684
2685 vector.push_back(three);
2686 vector.push_back(four);
2687 ConservativelyCollectGarbage();
2688 EXPECT_TRUE(vector.Contains(one));
2689 EXPECT_TRUE(vector.Contains(two));
2690 EXPECT_TRUE(vector.Contains(three));
2691 EXPECT_TRUE(vector.Contains(four));
2692
2693 vector.Shrink(1);
2694 ConservativelyCollectGarbage();
2695 EXPECT_TRUE(vector.Contains(one));
2696 EXPECT_FALSE(vector.Contains(two));
2697 EXPECT_FALSE(vector.Contains(three));
2698 EXPECT_FALSE(vector.Contains(four));
2699 }
2700 {
2701 PersistentVector vector1;
2702 PersistentVector vector2;
2703
2704 vector1.push_back(one);
2705 vector2.push_back(two);
2706 vector1.swap(vector2);
2707 ConservativelyCollectGarbage();
2708 EXPECT_TRUE(vector1.Contains(two));
2709 EXPECT_TRUE(vector2.Contains(one));
2710 }
2711 {
2712 PersistentVector vector1;
2713 PersistentVector vector2;
2714
2715 vector1.push_back(one);
2716 vector1.push_back(two);
2717 vector2.push_back(three);
2718 vector2.push_back(four);
2719 vector2.push_back(five);
2720 vector2.push_back(six);
2721 vector1.swap(vector2);
2722 ConservativelyCollectGarbage();
2723 EXPECT_TRUE(vector1.Contains(three));
2724 EXPECT_TRUE(vector1.Contains(four));
2725 EXPECT_TRUE(vector1.Contains(five));
2726 EXPECT_TRUE(vector1.Contains(six));
2727 EXPECT_TRUE(vector2.Contains(one));
2728 EXPECT_TRUE(vector2.Contains(two));
2729 }
2730 }
2731
TEST_F(HeapTest,CrossThreadPersistentVector)2732 TEST_F(HeapTest, CrossThreadPersistentVector) {
2733 IntWrapper::destructor_calls_ = 0;
2734
2735 typedef Vector<CrossThreadPersistent<IntWrapper>> CrossThreadPersistentVector;
2736
2737 CrossThreadPersistent<IntWrapper> one(MakeGarbageCollected<IntWrapper>(1));
2738 CrossThreadPersistent<IntWrapper> two(MakeGarbageCollected<IntWrapper>(2));
2739 CrossThreadPersistent<IntWrapper> three(MakeGarbageCollected<IntWrapper>(3));
2740 CrossThreadPersistent<IntWrapper> four(MakeGarbageCollected<IntWrapper>(4));
2741 CrossThreadPersistent<IntWrapper> five(MakeGarbageCollected<IntWrapper>(5));
2742 CrossThreadPersistent<IntWrapper> six(MakeGarbageCollected<IntWrapper>(6));
2743 {
2744 CrossThreadPersistentVector vector;
2745 vector.push_back(one);
2746 vector.push_back(two);
2747 ConservativelyCollectGarbage();
2748 EXPECT_TRUE(vector.Contains(one));
2749 EXPECT_TRUE(vector.Contains(two));
2750
2751 vector.push_back(three);
2752 vector.push_back(four);
2753 ConservativelyCollectGarbage();
2754 EXPECT_TRUE(vector.Contains(one));
2755 EXPECT_TRUE(vector.Contains(two));
2756 EXPECT_TRUE(vector.Contains(three));
2757 EXPECT_TRUE(vector.Contains(four));
2758
2759 vector.Shrink(1);
2760 ConservativelyCollectGarbage();
2761 EXPECT_TRUE(vector.Contains(one));
2762 EXPECT_FALSE(vector.Contains(two));
2763 EXPECT_FALSE(vector.Contains(three));
2764 EXPECT_FALSE(vector.Contains(four));
2765 }
2766 {
2767 CrossThreadPersistentVector vector1;
2768 CrossThreadPersistentVector vector2;
2769
2770 vector1.push_back(one);
2771 vector2.push_back(two);
2772 vector1.swap(vector2);
2773 ConservativelyCollectGarbage();
2774 EXPECT_TRUE(vector1.Contains(two));
2775 EXPECT_TRUE(vector2.Contains(one));
2776 }
2777 {
2778 CrossThreadPersistentVector vector1;
2779 CrossThreadPersistentVector vector2;
2780
2781 vector1.push_back(one);
2782 vector1.push_back(two);
2783 vector2.push_back(three);
2784 vector2.push_back(four);
2785 vector2.push_back(five);
2786 vector2.push_back(six);
2787 vector1.swap(vector2);
2788 ConservativelyCollectGarbage();
2789 EXPECT_TRUE(vector1.Contains(three));
2790 EXPECT_TRUE(vector1.Contains(four));
2791 EXPECT_TRUE(vector1.Contains(five));
2792 EXPECT_TRUE(vector1.Contains(six));
2793 EXPECT_TRUE(vector2.Contains(one));
2794 EXPECT_TRUE(vector2.Contains(two));
2795 }
2796 }
2797
TEST_F(HeapTest,PersistentSet)2798 TEST_F(HeapTest, PersistentSet) {
2799 IntWrapper::destructor_calls_ = 0;
2800
2801 typedef HashSet<Persistent<IntWrapper>> PersistentSet;
2802
2803 auto* one_raw = MakeGarbageCollected<IntWrapper>(1);
2804 Persistent<IntWrapper> one(one_raw);
2805 Persistent<IntWrapper> one2(one_raw);
2806 Persistent<IntWrapper> two(MakeGarbageCollected<IntWrapper>(2));
2807 Persistent<IntWrapper> three(MakeGarbageCollected<IntWrapper>(3));
2808 Persistent<IntWrapper> four(MakeGarbageCollected<IntWrapper>(4));
2809 Persistent<IntWrapper> five(MakeGarbageCollected<IntWrapper>(5));
2810 Persistent<IntWrapper> six(MakeGarbageCollected<IntWrapper>(6));
2811 {
2812 PersistentSet set;
2813 set.insert(one);
2814 set.insert(two);
2815 ConservativelyCollectGarbage();
2816 EXPECT_TRUE(set.Contains(one));
2817 EXPECT_TRUE(set.Contains(one2));
2818 EXPECT_TRUE(set.Contains(two));
2819
2820 set.insert(three);
2821 set.insert(four);
2822 ConservativelyCollectGarbage();
2823 EXPECT_TRUE(set.Contains(one));
2824 EXPECT_TRUE(set.Contains(two));
2825 EXPECT_TRUE(set.Contains(three));
2826 EXPECT_TRUE(set.Contains(four));
2827
2828 set.clear();
2829 ConservativelyCollectGarbage();
2830 EXPECT_FALSE(set.Contains(one));
2831 EXPECT_FALSE(set.Contains(two));
2832 EXPECT_FALSE(set.Contains(three));
2833 EXPECT_FALSE(set.Contains(four));
2834 }
2835 {
2836 PersistentSet set1;
2837 PersistentSet set2;
2838
2839 set1.insert(one);
2840 set2.insert(two);
2841 set1.swap(set2);
2842 ConservativelyCollectGarbage();
2843 EXPECT_TRUE(set1.Contains(two));
2844 EXPECT_TRUE(set2.Contains(one));
2845 EXPECT_TRUE(set2.Contains(one2));
2846 }
2847 }
2848
TEST_F(HeapTest,CrossThreadPersistentSet)2849 TEST_F(HeapTest, CrossThreadPersistentSet) {
2850 IntWrapper::destructor_calls_ = 0;
2851
2852 typedef HashSet<CrossThreadPersistent<IntWrapper>> CrossThreadPersistentSet;
2853
2854 auto* one_raw = MakeGarbageCollected<IntWrapper>(1);
2855 CrossThreadPersistent<IntWrapper> one(one_raw);
2856 CrossThreadPersistent<IntWrapper> one2(one_raw);
2857 CrossThreadPersistent<IntWrapper> two(MakeGarbageCollected<IntWrapper>(2));
2858 CrossThreadPersistent<IntWrapper> three(MakeGarbageCollected<IntWrapper>(3));
2859 CrossThreadPersistent<IntWrapper> four(MakeGarbageCollected<IntWrapper>(4));
2860 CrossThreadPersistent<IntWrapper> five(MakeGarbageCollected<IntWrapper>(5));
2861 CrossThreadPersistent<IntWrapper> six(MakeGarbageCollected<IntWrapper>(6));
2862 {
2863 CrossThreadPersistentSet set;
2864 set.insert(one);
2865 set.insert(two);
2866 ConservativelyCollectGarbage();
2867 EXPECT_TRUE(set.Contains(one));
2868 EXPECT_TRUE(set.Contains(one2));
2869 EXPECT_TRUE(set.Contains(two));
2870
2871 set.insert(three);
2872 set.insert(four);
2873 ConservativelyCollectGarbage();
2874 EXPECT_TRUE(set.Contains(one));
2875 EXPECT_TRUE(set.Contains(two));
2876 EXPECT_TRUE(set.Contains(three));
2877 EXPECT_TRUE(set.Contains(four));
2878
2879 set.clear();
2880 ConservativelyCollectGarbage();
2881 EXPECT_FALSE(set.Contains(one));
2882 EXPECT_FALSE(set.Contains(two));
2883 EXPECT_FALSE(set.Contains(three));
2884 EXPECT_FALSE(set.Contains(four));
2885 }
2886 {
2887 CrossThreadPersistentSet set1;
2888 CrossThreadPersistentSet set2;
2889
2890 set1.insert(one);
2891 set2.insert(two);
2892 set1.swap(set2);
2893 ConservativelyCollectGarbage();
2894 EXPECT_TRUE(set1.Contains(two));
2895 EXPECT_TRUE(set2.Contains(one));
2896 EXPECT_TRUE(set2.Contains(one2));
2897 }
2898 }
2899
2900 class NonTrivialObject final {
2901 DISALLOW_NEW();
2902
2903 public:
2904 NonTrivialObject() = default;
NonTrivialObject(int num)2905 explicit NonTrivialObject(int num) {
2906 deque_.push_back(MakeGarbageCollected<IntWrapper>(num));
2907 vector_.push_back(MakeGarbageCollected<IntWrapper>(num));
2908 }
Trace(Visitor * visitor)2909 void Trace(Visitor* visitor) {
2910 visitor->Trace(deque_);
2911 visitor->Trace(vector_);
2912 }
2913
2914 private:
2915 HeapDeque<Member<IntWrapper>> deque_;
2916 HeapVector<Member<IntWrapper>> vector_;
2917 };
2918
TEST_F(HeapTest,HeapHashMapWithInlinedObject)2919 TEST_F(HeapTest, HeapHashMapWithInlinedObject) {
2920 HeapHashMap<int, NonTrivialObject> map;
2921 for (int num = 1; num < 1000; num++) {
2922 NonTrivialObject object(num);
2923 map.insert(num, object);
2924 }
2925 }
2926
2927 template <typename T>
MapIteratorCheck(T & it,const T & end,int expected)2928 void MapIteratorCheck(T& it, const T& end, int expected) {
2929 int found = 0;
2930 while (it != end) {
2931 found++;
2932 int key = it->key->Value();
2933 int value = it->value->Value();
2934 EXPECT_TRUE(key >= 0 && key < 1100);
2935 EXPECT_TRUE(value >= 0 && value < 1100);
2936 ++it;
2937 }
2938 EXPECT_EQ(expected, found);
2939 }
2940
2941 template <typename T>
SetIteratorCheck(T & it,const T & end,int expected)2942 void SetIteratorCheck(T& it, const T& end, int expected) {
2943 int found = 0;
2944 while (it != end) {
2945 found++;
2946 int value = (*it)->Value();
2947 EXPECT_TRUE(value >= 0 && value < 1100);
2948 ++it;
2949 }
2950 EXPECT_EQ(expected, found);
2951 }
2952
TEST_F(HeapTest,HeapWeakCollectionSimple)2953 TEST_F(HeapTest, HeapWeakCollectionSimple) {
2954 ClearOutOldGarbage();
2955 IntWrapper::destructor_calls_ = 0;
2956
2957 Persistent<HeapVector<Member<IntWrapper>>> keep_numbers_alive =
2958 MakeGarbageCollected<HeapVector<Member<IntWrapper>>>();
2959
2960 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper>> WeakStrong;
2961 typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper>> StrongWeak;
2962 typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper>> WeakWeak;
2963 typedef HeapHashSet<WeakMember<IntWrapper>> WeakSet;
2964 typedef HeapHashCountedSet<WeakMember<IntWrapper>> WeakCountedSet;
2965
2966 Persistent<WeakStrong> weak_strong = MakeGarbageCollected<WeakStrong>();
2967 Persistent<StrongWeak> strong_weak = MakeGarbageCollected<StrongWeak>();
2968 Persistent<WeakWeak> weak_weak = MakeGarbageCollected<WeakWeak>();
2969 Persistent<WeakSet> weak_set = MakeGarbageCollected<WeakSet>();
2970 Persistent<WeakCountedSet> weak_counted_set =
2971 MakeGarbageCollected<WeakCountedSet>();
2972
2973 Persistent<IntWrapper> two = MakeGarbageCollected<IntWrapper>(2);
2974
2975 keep_numbers_alive->push_back(MakeGarbageCollected<IntWrapper>(103));
2976 keep_numbers_alive->push_back(MakeGarbageCollected<IntWrapper>(10));
2977
2978 {
2979 weak_strong->insert(MakeGarbageCollected<IntWrapper>(1), two);
2980 strong_weak->insert(two, MakeGarbageCollected<IntWrapper>(1));
2981 weak_weak->insert(two, MakeGarbageCollected<IntWrapper>(42));
2982 weak_weak->insert(MakeGarbageCollected<IntWrapper>(42), two);
2983 weak_set->insert(MakeGarbageCollected<IntWrapper>(0));
2984 weak_set->insert(two);
2985 weak_set->insert(keep_numbers_alive->at(0));
2986 weak_set->insert(keep_numbers_alive->at(1));
2987 weak_counted_set->insert(MakeGarbageCollected<IntWrapper>(0));
2988 weak_counted_set->insert(two);
2989 weak_counted_set->insert(two);
2990 weak_counted_set->insert(two);
2991 weak_counted_set->insert(keep_numbers_alive->at(0));
2992 weak_counted_set->insert(keep_numbers_alive->at(1));
2993 EXPECT_EQ(1u, weak_strong->size());
2994 EXPECT_EQ(1u, strong_weak->size());
2995 EXPECT_EQ(2u, weak_weak->size());
2996 EXPECT_EQ(4u, weak_set->size());
2997 EXPECT_EQ(4u, weak_counted_set->size());
2998 EXPECT_EQ(3u, weak_counted_set->find(two)->value);
2999 weak_counted_set->erase(two);
3000 EXPECT_EQ(2u, weak_counted_set->find(two)->value);
3001 }
3002
3003 keep_numbers_alive->at(0) = nullptr;
3004
3005 PreciselyCollectGarbage();
3006
3007 EXPECT_EQ(0u, weak_strong->size());
3008 EXPECT_EQ(0u, strong_weak->size());
3009 EXPECT_EQ(0u, weak_weak->size());
3010 EXPECT_EQ(2u, weak_set->size());
3011 EXPECT_EQ(2u, weak_counted_set->size());
3012 }
3013
3014 template <typename Set>
OrderedSetHelper(bool strong)3015 void OrderedSetHelper(bool strong) {
3016 IntWrapper::destructor_calls_ = 0;
3017
3018 Persistent<HeapVector<Member<IntWrapper>>> keep_numbers_alive =
3019 MakeGarbageCollected<HeapVector<Member<IntWrapper>>>();
3020
3021 Persistent<Set> set1 = MakeGarbageCollected<Set>();
3022 Persistent<Set> set2 = MakeGarbageCollected<Set>();
3023
3024 const Set& const_set = *set1.Get();
3025
3026 keep_numbers_alive->push_back(MakeGarbageCollected<IntWrapper>(2));
3027 keep_numbers_alive->push_back(MakeGarbageCollected<IntWrapper>(103));
3028 keep_numbers_alive->push_back(MakeGarbageCollected<IntWrapper>(10));
3029
3030 set1->insert(MakeGarbageCollected<IntWrapper>(0));
3031 set1->insert(keep_numbers_alive->at(0));
3032 set1->insert(keep_numbers_alive->at(1));
3033 set1->insert(keep_numbers_alive->at(2));
3034
3035 set2->clear();
3036 set2->insert(MakeGarbageCollected<IntWrapper>(42));
3037 set2->clear();
3038
3039 EXPECT_EQ(4u, set1->size());
3040 typename Set::iterator it(set1->begin());
3041 typename Set::reverse_iterator reverse(set1->rbegin());
3042 typename Set::const_iterator cit(const_set.begin());
3043 typename Set::const_reverse_iterator creverse(const_set.rbegin());
3044
3045 EXPECT_EQ(0, (*it)->Value());
3046 EXPECT_EQ(0, (*cit)->Value());
3047 ++it;
3048 ++cit;
3049 EXPECT_EQ(2, (*it)->Value());
3050 EXPECT_EQ(2, (*cit)->Value());
3051 --it;
3052 --cit;
3053 EXPECT_EQ(0, (*it)->Value());
3054 EXPECT_EQ(0, (*cit)->Value());
3055 ++it;
3056 ++cit;
3057 ++it;
3058 ++cit;
3059 EXPECT_EQ(103, (*it)->Value());
3060 EXPECT_EQ(103, (*cit)->Value());
3061 ++it;
3062 ++cit;
3063 EXPECT_EQ(10, (*it)->Value());
3064 EXPECT_EQ(10, (*cit)->Value());
3065 ++it;
3066 ++cit;
3067
3068 EXPECT_EQ(10, (*reverse)->Value());
3069 EXPECT_EQ(10, (*creverse)->Value());
3070 ++reverse;
3071 ++creverse;
3072 EXPECT_EQ(103, (*reverse)->Value());
3073 EXPECT_EQ(103, (*creverse)->Value());
3074 --reverse;
3075 --creverse;
3076 EXPECT_EQ(10, (*reverse)->Value());
3077 EXPECT_EQ(10, (*creverse)->Value());
3078 ++reverse;
3079 ++creverse;
3080 ++reverse;
3081 ++creverse;
3082 EXPECT_EQ(2, (*reverse)->Value());
3083 EXPECT_EQ(2, (*creverse)->Value());
3084 ++reverse;
3085 ++creverse;
3086 EXPECT_EQ(0, (*reverse)->Value());
3087 EXPECT_EQ(0, (*creverse)->Value());
3088 ++reverse;
3089 ++creverse;
3090
3091 EXPECT_EQ(set1->end(), it);
3092 EXPECT_EQ(const_set.end(), cit);
3093 EXPECT_EQ(set1->rend(), reverse);
3094 EXPECT_EQ(const_set.rend(), creverse);
3095
3096 typename Set::iterator i_x(set2->begin());
3097 EXPECT_EQ(set2->end(), i_x);
3098
3099 if (strong)
3100 set1->erase(keep_numbers_alive->at(0));
3101
3102 keep_numbers_alive->at(0) = nullptr;
3103
3104 TestSupportingGC::PreciselyCollectGarbage();
3105
3106 EXPECT_EQ(2u + (strong ? 1u : 0u), set1->size());
3107
3108 EXPECT_EQ(2 + (strong ? 0 : 1), IntWrapper::destructor_calls_);
3109
3110 typename Set::iterator i2(set1->begin());
3111 if (strong) {
3112 EXPECT_EQ(0, (*i2)->Value());
3113 ++i2;
3114 EXPECT_NE(set1->end(), i2);
3115 }
3116 EXPECT_EQ(103, (*i2)->Value());
3117 ++i2;
3118 EXPECT_NE(set1->end(), i2);
3119 EXPECT_EQ(10, (*i2)->Value());
3120 ++i2;
3121 EXPECT_EQ(set1->end(), i2);
3122 }
3123
TEST_F(HeapTest,HeapWeakLinkedHashSet)3124 TEST_F(HeapTest, HeapWeakLinkedHashSet) {
3125 ClearOutOldGarbage();
3126 OrderedSetHelper<HeapLinkedHashSet<Member<IntWrapper>>>(true);
3127 ClearOutOldGarbage();
3128 OrderedSetHelper<HeapLinkedHashSet<WeakMember<IntWrapper>>>(false);
3129 ClearOutOldGarbage();
3130 OrderedSetHelper<HeapListHashSet<Member<IntWrapper>>>(true);
3131 ClearOutOldGarbage();
3132 // TODO(keinakashima): add a test case for WeakMember once it's supported
3133 OrderedSetHelper<HeapNewLinkedHashSet<Member<IntWrapper>>>(true);
3134 }
3135
3136 class ThingWithDestructor {
3137 DISALLOW_NEW();
3138
3139 public:
ThingWithDestructor()3140 ThingWithDestructor() : x_(kEmptyValue) { live_things_with_destructor_++; }
3141
ThingWithDestructor(int x)3142 ThingWithDestructor(int x) : x_(x) { live_things_with_destructor_++; }
3143
ThingWithDestructor(const ThingWithDestructor & other)3144 ThingWithDestructor(const ThingWithDestructor& other) {
3145 *this = other;
3146 live_things_with_destructor_++;
3147 }
3148
~ThingWithDestructor()3149 ~ThingWithDestructor() { live_things_with_destructor_--; }
3150
Value()3151 int Value() { return x_; }
3152
3153 static int live_things_with_destructor_;
3154
GetHash()3155 unsigned GetHash() { return IntHash<int>::GetHash(x_); }
3156
3157 private:
3158 static const int kEmptyValue = 0;
3159 int x_;
3160 };
3161
3162 int ThingWithDestructor::live_things_with_destructor_;
3163
HeapMapDestructorHelper(bool clear_maps)3164 static void HeapMapDestructorHelper(bool clear_maps) {
3165 ThingWithDestructor::live_things_with_destructor_ = 0;
3166
3167 typedef HeapHashMap<WeakMember<IntWrapper>,
3168 Member<RefCountedAndGarbageCollected>>
3169 RefMap;
3170
3171 typedef HeapHashMap<WeakMember<IntWrapper>, ThingWithDestructor,
3172 DefaultHash<WeakMember<IntWrapper>>::Hash,
3173 HashTraits<WeakMember<IntWrapper>>>
3174 Map;
3175
3176 Persistent<Map> map(MakeGarbageCollected<Map>());
3177 Persistent<RefMap> ref_map(MakeGarbageCollected<RefMap>());
3178
3179 Persistent<IntWrapper> luck(MakeGarbageCollected<IntWrapper>(103));
3180
3181 int base_line, ref_base_line;
3182
3183 {
3184 Map stack_map;
3185 RefMap stack_ref_map;
3186
3187 TestSupportingGC::PreciselyCollectGarbage();
3188 TestSupportingGC::PreciselyCollectGarbage();
3189
3190 stack_map.insert(MakeGarbageCollected<IntWrapper>(42),
3191 ThingWithDestructor(1729));
3192 stack_map.insert(luck, ThingWithDestructor(8128));
3193 stack_ref_map.insert(MakeGarbageCollected<IntWrapper>(42),
3194 MakeGarbageCollected<RefCountedAndGarbageCollected>());
3195 stack_ref_map.insert(luck,
3196 MakeGarbageCollected<RefCountedAndGarbageCollected>());
3197
3198 base_line = ThingWithDestructor::live_things_with_destructor_;
3199 ref_base_line = RefCountedAndGarbageCollected::destructor_calls_;
3200
3201 // Although the heap maps are on-stack, we can't expect prompt
3202 // finalization of the elements, so when they go out of scope here we
3203 // will not necessarily have called the relevant destructors.
3204 }
3205
3206 // The RefCountedAndGarbageCollected things need an extra GC to discover
3207 // that they are no longer ref counted.
3208 TestSupportingGC::PreciselyCollectGarbage();
3209 TestSupportingGC::PreciselyCollectGarbage();
3210 EXPECT_EQ(base_line - 2, ThingWithDestructor::live_things_with_destructor_);
3211 EXPECT_EQ(ref_base_line + 2,
3212 RefCountedAndGarbageCollected::destructor_calls_);
3213
3214 // Now use maps kept alive with persistents. Here we don't expect any
3215 // destructors to be called before there have been GCs.
3216
3217 map->insert(MakeGarbageCollected<IntWrapper>(42), ThingWithDestructor(1729));
3218 map->insert(luck, ThingWithDestructor(8128));
3219 ref_map->insert(MakeGarbageCollected<IntWrapper>(42),
3220 MakeGarbageCollected<RefCountedAndGarbageCollected>());
3221 ref_map->insert(luck, MakeGarbageCollected<RefCountedAndGarbageCollected>());
3222
3223 base_line = ThingWithDestructor::live_things_with_destructor_;
3224 ref_base_line = RefCountedAndGarbageCollected::destructor_calls_;
3225
3226 luck.Clear();
3227 if (clear_maps) {
3228 map->clear(); // Clear map.
3229 ref_map->clear(); // Clear map.
3230 } else {
3231 map.Clear(); // Clear Persistent handle, not map.
3232 ref_map.Clear(); // Clear Persistent handle, not map.
3233 TestSupportingGC::PreciselyCollectGarbage();
3234 TestSupportingGC::PreciselyCollectGarbage();
3235 }
3236
3237 EXPECT_EQ(base_line - 2, ThingWithDestructor::live_things_with_destructor_);
3238
3239 // Need a GC to make sure that the RefCountedAndGarbageCollected thing
3240 // noticies it's been decremented to zero.
3241 TestSupportingGC::PreciselyCollectGarbage();
3242 EXPECT_EQ(ref_base_line + 2,
3243 RefCountedAndGarbageCollected::destructor_calls_);
3244 }
3245
TEST_F(HeapTest,HeapMapDestructor)3246 TEST_F(HeapTest, HeapMapDestructor) {
3247 ClearOutOldGarbage();
3248 HeapMapDestructorHelper(true);
3249 ClearOutOldGarbage();
3250 HeapMapDestructorHelper(false);
3251 }
3252
3253 typedef HeapHashSet<PairWeakStrong> WeakStrongSet;
3254 typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet;
3255 typedef HeapHashSet<PairStrongWeak> StrongWeakSet;
3256 typedef HeapHashSet<PairUnwrappedWeak> UnwrappedWeakSet;
3257 typedef HeapLinkedHashSet<PairWeakStrong> WeakStrongLinkedSet;
3258 typedef HeapLinkedHashSet<PairWeakUnwrapped> WeakUnwrappedLinkedSet;
3259 typedef HeapLinkedHashSet<PairStrongWeak> StrongWeakLinkedSet;
3260 typedef HeapLinkedHashSet<PairUnwrappedWeak> UnwrappedWeakLinkedSet;
3261 // TODO(bartekn): add HeapNewLinkedHashSet cases once WeakMember is supported
3262 typedef HeapHashCountedSet<PairWeakStrong> WeakStrongCountedSet;
3263 typedef HeapHashCountedSet<PairWeakUnwrapped> WeakUnwrappedCountedSet;
3264 typedef HeapHashCountedSet<PairStrongWeak> StrongWeakCountedSet;
3265 typedef HeapHashCountedSet<PairUnwrappedWeak> UnwrappedWeakCountedSet;
3266
3267 template <typename T>
IteratorExtractor(WTF::KeyValuePair<T,unsigned> & pair)3268 T& IteratorExtractor(WTF::KeyValuePair<T, unsigned>& pair) {
3269 return pair.key;
3270 }
3271
3272 template <typename T>
IteratorExtractor(T & not_a_pair)3273 T& IteratorExtractor(T& not_a_pair) {
3274 return not_a_pair;
3275 }
3276
3277 template <typename WSSet, typename SWSet, typename WUSet, typename UWSet>
CheckPairSets(Persistent<WSSet> & weak_strong,Persistent<SWSet> & strong_weak,Persistent<WUSet> & weak_unwrapped,Persistent<UWSet> & unwrapped_weak,bool ones,Persistent<IntWrapper> & two)3278 void CheckPairSets(Persistent<WSSet>& weak_strong,
3279 Persistent<SWSet>& strong_weak,
3280 Persistent<WUSet>& weak_unwrapped,
3281 Persistent<UWSet>& unwrapped_weak,
3282 bool ones,
3283 Persistent<IntWrapper>& two) {
3284 typename WSSet::iterator it_ws = weak_strong->begin();
3285 typename SWSet::iterator it_sw = strong_weak->begin();
3286 typename WUSet::iterator it_wu = weak_unwrapped->begin();
3287 typename UWSet::iterator it_uw = unwrapped_weak->begin();
3288
3289 EXPECT_EQ(2u, weak_strong->size());
3290 EXPECT_EQ(2u, strong_weak->size());
3291 EXPECT_EQ(2u, weak_unwrapped->size());
3292 EXPECT_EQ(2u, unwrapped_weak->size());
3293
3294 PairWeakStrong p = IteratorExtractor(*it_ws);
3295 PairStrongWeak p2 = IteratorExtractor(*it_sw);
3296 PairWeakUnwrapped p3 = IteratorExtractor(*it_wu);
3297 PairUnwrappedWeak p4 = IteratorExtractor(*it_uw);
3298 if (p.first == two && p.second == two)
3299 ++it_ws;
3300 if (p2.first == two && p2.second == two)
3301 ++it_sw;
3302 if (p3.first == two && p3.second == 2)
3303 ++it_wu;
3304 if (p4.first == 2 && p4.second == two)
3305 ++it_uw;
3306 p = IteratorExtractor(*it_ws);
3307 p2 = IteratorExtractor(*it_sw);
3308 p3 = IteratorExtractor(*it_wu);
3309 p4 = IteratorExtractor(*it_uw);
3310 IntWrapper* null_wrapper = nullptr;
3311 if (ones) {
3312 EXPECT_EQ(p.first->Value(), 1);
3313 EXPECT_EQ(p2.second->Value(), 1);
3314 EXPECT_EQ(p3.first->Value(), 1);
3315 EXPECT_EQ(p4.second->Value(), 1);
3316 } else {
3317 EXPECT_EQ(p.first, null_wrapper);
3318 EXPECT_EQ(p2.second, null_wrapper);
3319 EXPECT_EQ(p3.first, null_wrapper);
3320 EXPECT_EQ(p4.second, null_wrapper);
3321 }
3322
3323 EXPECT_EQ(p.second->Value(), 2);
3324 EXPECT_EQ(p2.first->Value(), 2);
3325 EXPECT_EQ(p3.second, 2);
3326 EXPECT_EQ(p4.first, 2);
3327
3328 EXPECT_TRUE(weak_strong->Contains(PairWeakStrong(&*two, &*two)));
3329 EXPECT_TRUE(strong_weak->Contains(PairStrongWeak(&*two, &*two)));
3330 EXPECT_TRUE(weak_unwrapped->Contains(PairWeakUnwrapped(&*two, 2)));
3331 EXPECT_TRUE(unwrapped_weak->Contains(PairUnwrappedWeak(2, &*two)));
3332 }
3333
TEST_F(HeapTest,HeapWeakCollectionTypes)3334 TEST_F(HeapTest, HeapWeakCollectionTypes) {
3335 IntWrapper::destructor_calls_ = 0;
3336
3337 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper>> WeakStrong;
3338 typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper>> StrongWeak;
3339 typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper>> WeakWeak;
3340 typedef HeapHashSet<WeakMember<IntWrapper>> WeakSet;
3341 typedef HeapLinkedHashSet<WeakMember<IntWrapper>> WeakOrderedSet;
3342 // TODO(bartekn): add HeapNewLinkedHashSet case once WeakMember is supported
3343
3344 ClearOutOldGarbage();
3345
3346 const int kWeakStrongIndex = 0;
3347 const int kStrongWeakIndex = 1;
3348 const int kWeakWeakIndex = 2;
3349 const int kNumberOfMapIndices = 3;
3350 const int kWeakSetIndex = 3;
3351 const int kWeakOrderedSetIndex = 4;
3352 const int kNumberOfCollections = 5;
3353
3354 for (int test_run = 0; test_run < 4; test_run++) {
3355 for (int collection_number = 0; collection_number < kNumberOfCollections;
3356 collection_number++) {
3357 bool delete_afterwards = (test_run == 1);
3358 bool add_afterwards = (test_run == 2);
3359 bool test_that_iterators_make_strong = (test_run == 3);
3360
3361 // The test doesn't work for strongWeak with deleting because we lost
3362 // the key from the keepNumbersAlive array, so we can't do the lookup.
3363 if (delete_afterwards && collection_number == kStrongWeakIndex)
3364 continue;
3365
3366 unsigned added = add_afterwards ? 100 : 0;
3367
3368 Persistent<WeakStrong> weak_strong = MakeGarbageCollected<WeakStrong>();
3369 Persistent<StrongWeak> strong_weak = MakeGarbageCollected<StrongWeak>();
3370 Persistent<WeakWeak> weak_weak = MakeGarbageCollected<WeakWeak>();
3371
3372 Persistent<WeakSet> weak_set = MakeGarbageCollected<WeakSet>();
3373 Persistent<WeakOrderedSet> weak_ordered_set =
3374 MakeGarbageCollected<WeakOrderedSet>();
3375
3376 Persistent<HeapVector<Member<IntWrapper>>> keep_numbers_alive =
3377 MakeGarbageCollected<HeapVector<Member<IntWrapper>>>();
3378 for (int i = 0; i < 128; i += 2) {
3379 auto* wrapped = MakeGarbageCollected<IntWrapper>(i);
3380 auto* wrapped2 = MakeGarbageCollected<IntWrapper>(i + 1);
3381 keep_numbers_alive->push_back(wrapped);
3382 keep_numbers_alive->push_back(wrapped2);
3383 weak_strong->insert(wrapped, wrapped2);
3384 strong_weak->insert(wrapped2, wrapped);
3385 weak_weak->insert(wrapped, wrapped2);
3386 weak_set->insert(wrapped);
3387 weak_ordered_set->insert(wrapped);
3388 }
3389
3390 EXPECT_EQ(64u, weak_strong->size());
3391 EXPECT_EQ(64u, strong_weak->size());
3392 EXPECT_EQ(64u, weak_weak->size());
3393 EXPECT_EQ(64u, weak_set->size());
3394 EXPECT_EQ(64u, weak_ordered_set->size());
3395
3396 // Collect garbage. This should change nothing since we are keeping
3397 // alive the IntWrapper objects.
3398 PreciselyCollectGarbage();
3399
3400 EXPECT_EQ(64u, weak_strong->size());
3401 EXPECT_EQ(64u, strong_weak->size());
3402 EXPECT_EQ(64u, weak_weak->size());
3403 EXPECT_EQ(64u, weak_set->size());
3404 EXPECT_EQ(64u, weak_ordered_set->size());
3405
3406 for (int i = 0; i < 128; i += 2) {
3407 IntWrapper* wrapped = keep_numbers_alive->at(i);
3408 IntWrapper* wrapped2 = keep_numbers_alive->at(i + 1);
3409 EXPECT_EQ(wrapped2, weak_strong->at(wrapped));
3410 EXPECT_EQ(wrapped, strong_weak->at(wrapped2));
3411 EXPECT_EQ(wrapped2, weak_weak->at(wrapped));
3412 EXPECT_TRUE(weak_set->Contains(wrapped));
3413 EXPECT_TRUE(weak_ordered_set->Contains(wrapped));
3414 }
3415
3416 for (int i = 0; i < 128; i += 3)
3417 keep_numbers_alive->at(i) = nullptr;
3418
3419 if (collection_number != kWeakStrongIndex)
3420 weak_strong->clear();
3421 if (collection_number != kStrongWeakIndex)
3422 strong_weak->clear();
3423 if (collection_number != kWeakWeakIndex)
3424 weak_weak->clear();
3425 if (collection_number != kWeakSetIndex)
3426 weak_set->clear();
3427 if (collection_number != kWeakOrderedSetIndex)
3428 weak_ordered_set->clear();
3429
3430 if (test_that_iterators_make_strong) {
3431 WeakStrong::iterator it1 = weak_strong->begin();
3432 StrongWeak::iterator it2 = strong_weak->begin();
3433 WeakWeak::iterator it3 = weak_weak->begin();
3434 WeakSet::iterator it4 = weak_set->begin();
3435 WeakOrderedSet::iterator it5 = weak_ordered_set->begin();
3436 // Collect garbage. This should change nothing since the
3437 // iterators make the collections strong.
3438 ConservativelyCollectGarbage();
3439 if (collection_number == kWeakStrongIndex) {
3440 EXPECT_EQ(64u, weak_strong->size());
3441 MapIteratorCheck(it1, weak_strong->end(), 64);
3442 } else if (collection_number == kStrongWeakIndex) {
3443 EXPECT_EQ(64u, strong_weak->size());
3444 MapIteratorCheck(it2, strong_weak->end(), 64);
3445 } else if (collection_number == kWeakWeakIndex) {
3446 EXPECT_EQ(64u, weak_weak->size());
3447 MapIteratorCheck(it3, weak_weak->end(), 64);
3448 } else if (collection_number == kWeakSetIndex) {
3449 EXPECT_EQ(64u, weak_set->size());
3450 SetIteratorCheck(it4, weak_set->end(), 64);
3451 } else if (collection_number == kWeakOrderedSetIndex) {
3452 EXPECT_EQ(64u, weak_ordered_set->size());
3453 SetIteratorCheck(it5, weak_ordered_set->end(), 64);
3454 }
3455 } else {
3456 // Collect garbage. This causes weak processing to remove
3457 // things from the collections.
3458 PreciselyCollectGarbage();
3459 unsigned count = 0;
3460 for (int i = 0; i < 128; i += 2) {
3461 bool first_alive = keep_numbers_alive->at(i);
3462 bool second_alive = keep_numbers_alive->at(i + 1);
3463 if (first_alive && (collection_number == kWeakStrongIndex ||
3464 collection_number == kStrongWeakIndex))
3465 second_alive = true;
3466 if (first_alive && second_alive &&
3467 collection_number < kNumberOfMapIndices) {
3468 if (collection_number == kWeakStrongIndex) {
3469 if (delete_afterwards) {
3470 EXPECT_EQ(
3471 i + 1,
3472 weak_strong->Take(keep_numbers_alive->at(i))->Value());
3473 }
3474 } else if (collection_number == kStrongWeakIndex) {
3475 if (delete_afterwards) {
3476 EXPECT_EQ(
3477 i,
3478 strong_weak->Take(keep_numbers_alive->at(i + 1))->Value());
3479 }
3480 } else if (collection_number == kWeakWeakIndex) {
3481 if (delete_afterwards) {
3482 EXPECT_EQ(i + 1,
3483 weak_weak->Take(keep_numbers_alive->at(i))->Value());
3484 }
3485 }
3486 if (!delete_afterwards)
3487 count++;
3488 } else if (collection_number == kWeakSetIndex && first_alive) {
3489 ASSERT_TRUE(weak_set->Contains(keep_numbers_alive->at(i)));
3490 if (delete_afterwards)
3491 weak_set->erase(keep_numbers_alive->at(i));
3492 else
3493 count++;
3494 } else if (collection_number == kWeakOrderedSetIndex && first_alive) {
3495 ASSERT_TRUE(weak_ordered_set->Contains(keep_numbers_alive->at(i)));
3496 if (delete_afterwards)
3497 weak_ordered_set->erase(keep_numbers_alive->at(i));
3498 else
3499 count++;
3500 }
3501 }
3502 if (add_afterwards) {
3503 for (int i = 1000; i < 1100; i++) {
3504 auto* wrapped = MakeGarbageCollected<IntWrapper>(i);
3505 keep_numbers_alive->push_back(wrapped);
3506 weak_strong->insert(wrapped, wrapped);
3507 strong_weak->insert(wrapped, wrapped);
3508 weak_weak->insert(wrapped, wrapped);
3509 weak_set->insert(wrapped);
3510 weak_ordered_set->insert(wrapped);
3511 }
3512 }
3513 if (collection_number == kWeakStrongIndex)
3514 EXPECT_EQ(count + added, weak_strong->size());
3515 else if (collection_number == kStrongWeakIndex)
3516 EXPECT_EQ(count + added, strong_weak->size());
3517 else if (collection_number == kWeakWeakIndex)
3518 EXPECT_EQ(count + added, weak_weak->size());
3519 else if (collection_number == kWeakSetIndex)
3520 EXPECT_EQ(count + added, weak_set->size());
3521 else if (collection_number == kWeakOrderedSetIndex)
3522 EXPECT_EQ(count + added, weak_ordered_set->size());
3523 WeakStrong::iterator it1 = weak_strong->begin();
3524 StrongWeak::iterator it2 = strong_weak->begin();
3525 WeakWeak::iterator it3 = weak_weak->begin();
3526 WeakSet::iterator it4 = weak_set->begin();
3527 WeakOrderedSet::iterator it5 = weak_ordered_set->begin();
3528 MapIteratorCheck(
3529 it1, weak_strong->end(),
3530 (collection_number == kWeakStrongIndex ? count : 0) + added);
3531 MapIteratorCheck(
3532 it2, strong_weak->end(),
3533 (collection_number == kStrongWeakIndex ? count : 0) + added);
3534 MapIteratorCheck(
3535 it3, weak_weak->end(),
3536 (collection_number == kWeakWeakIndex ? count : 0) + added);
3537 SetIteratorCheck(
3538 it4, weak_set->end(),
3539 (collection_number == kWeakSetIndex ? count : 0) + added);
3540 SetIteratorCheck(
3541 it5, weak_ordered_set->end(),
3542 (collection_number == kWeakOrderedSetIndex ? count : 0) + added);
3543 }
3544 for (unsigned i = 0; i < 128 + added; i++)
3545 keep_numbers_alive->at(i) = nullptr;
3546 PreciselyCollectGarbage();
3547 EXPECT_EQ(0u, weak_strong->size());
3548 EXPECT_EQ(0u, strong_weak->size());
3549 EXPECT_EQ(0u, weak_weak->size());
3550 EXPECT_EQ(0u, weak_set->size());
3551 EXPECT_EQ(0u, weak_ordered_set->size());
3552 }
3553 }
3554 }
3555
TEST_F(HeapTest,HeapHashCountedSetToVector)3556 TEST_F(HeapTest, HeapHashCountedSetToVector) {
3557 HeapHashCountedSet<Member<IntWrapper>> set;
3558 HeapVector<Member<IntWrapper>> vector;
3559 set.insert(MakeGarbageCollected<IntWrapper>(1));
3560 set.insert(MakeGarbageCollected<IntWrapper>(1));
3561 set.insert(MakeGarbageCollected<IntWrapper>(2));
3562
3563 CopyToVector(set, vector);
3564 EXPECT_EQ(3u, vector.size());
3565
3566 Vector<int> int_vector;
3567 for (const auto& i : vector)
3568 int_vector.push_back(i->Value());
3569 std::sort(int_vector.begin(), int_vector.end());
3570 ASSERT_EQ(3u, int_vector.size());
3571 EXPECT_EQ(1, int_vector[0]);
3572 EXPECT_EQ(1, int_vector[1]);
3573 EXPECT_EQ(2, int_vector[2]);
3574 }
3575
TEST_F(HeapTest,WeakHeapHashCountedSetToVector)3576 TEST_F(HeapTest, WeakHeapHashCountedSetToVector) {
3577 HeapHashCountedSet<WeakMember<IntWrapper>> set;
3578 HeapVector<Member<IntWrapper>> vector;
3579 set.insert(MakeGarbageCollected<IntWrapper>(1));
3580 set.insert(MakeGarbageCollected<IntWrapper>(1));
3581 set.insert(MakeGarbageCollected<IntWrapper>(2));
3582
3583 CopyToVector(set, vector);
3584 EXPECT_LE(3u, vector.size());
3585 for (const auto& i : vector)
3586 EXPECT_TRUE(i->Value() == 1 || i->Value() == 2);
3587 }
3588
TEST_F(HeapTest,RefCountedGarbageCollected)3589 TEST_F(HeapTest, RefCountedGarbageCollected) {
3590 RefCountedAndGarbageCollected::destructor_calls_ = 0;
3591 {
3592 scoped_refptr<RefCountedAndGarbageCollected> ref_ptr3;
3593 {
3594 Persistent<RefCountedAndGarbageCollected> persistent;
3595 {
3596 Persistent<RefCountedAndGarbageCollected> ref_ptr1 =
3597 MakeGarbageCollected<RefCountedAndGarbageCollected>();
3598 Persistent<RefCountedAndGarbageCollected> ref_ptr2 =
3599 MakeGarbageCollected<RefCountedAndGarbageCollected>();
3600 PreciselyCollectGarbage();
3601 EXPECT_EQ(0, RefCountedAndGarbageCollected::destructor_calls_);
3602 persistent = ref_ptr1.Get();
3603 }
3604 // Reference count is zero for both objects but one of
3605 // them is kept alive by a persistent handle.
3606 PreciselyCollectGarbage();
3607 EXPECT_EQ(1, RefCountedAndGarbageCollected::destructor_calls_);
3608 ref_ptr3 = persistent.Get();
3609 }
3610 // The persistent handle is gone but the ref count has been
3611 // increased to 1.
3612 PreciselyCollectGarbage();
3613 EXPECT_EQ(1, RefCountedAndGarbageCollected::destructor_calls_);
3614 }
3615 // Both persistent handle is gone and ref count is zero so the
3616 // object can be collected.
3617 PreciselyCollectGarbage();
3618 EXPECT_EQ(2, RefCountedAndGarbageCollected::destructor_calls_);
3619 }
3620
TEST_F(HeapTest,WeakMembers)3621 TEST_F(HeapTest, WeakMembers) {
3622 ClearOutOldGarbage();
3623 Bar::live_ = 0;
3624 {
3625 Persistent<Bar> h1 = MakeGarbageCollected<Bar>();
3626 Persistent<Weak> h4;
3627 Persistent<WithWeakMember> h5;
3628 PreciselyCollectGarbage();
3629 ASSERT_EQ(1u, Bar::live_); // h1 is live.
3630 {
3631 auto* h2 = MakeGarbageCollected<Bar>();
3632 auto* h3 = MakeGarbageCollected<Bar>();
3633 h4 = MakeGarbageCollected<Weak>(h2, h3);
3634 h5 = MakeGarbageCollected<WithWeakMember>(h2, h3);
3635 ConservativelyCollectGarbage();
3636 EXPECT_EQ(5u, Bar::live_); // The on-stack pointer keeps h3 alive.
3637 EXPECT_FALSE(h3->HasBeenFinalized());
3638 EXPECT_TRUE(h4->StrongIsThere());
3639 EXPECT_TRUE(h4->WeakIsThere());
3640 EXPECT_TRUE(h5->StrongIsThere());
3641 EXPECT_TRUE(h5->WeakIsThere());
3642 }
3643 // h3 is collected, weak pointers from h4 and h5 don't keep it alive.
3644 PreciselyCollectGarbage();
3645 EXPECT_EQ(4u, Bar::live_);
3646 EXPECT_TRUE(h4->StrongIsThere());
3647 EXPECT_FALSE(h4->WeakIsThere()); // h3 is gone from weak pointer.
3648 EXPECT_TRUE(h5->StrongIsThere());
3649 EXPECT_FALSE(h5->WeakIsThere()); // h3 is gone from weak pointer.
3650 h1.Release(); // Zero out h1.
3651 PreciselyCollectGarbage();
3652 EXPECT_EQ(3u, Bar::live_); // Only h4, h5 and h2 are left.
3653 EXPECT_TRUE(h4->StrongIsThere()); // h2 is still pointed to from h4.
3654 EXPECT_TRUE(h5->StrongIsThere()); // h2 is still pointed to from h5.
3655 }
3656 // h4 and h5 have gone out of scope now and they were keeping h2 alive.
3657 PreciselyCollectGarbage();
3658 EXPECT_EQ(0u, Bar::live_); // All gone.
3659 }
3660
TEST_F(HeapTest,FinalizationObserver)3661 TEST_F(HeapTest, FinalizationObserver) {
3662 Persistent<FinalizationObserver<Observable>> o;
3663 {
3664 auto* foo = MakeGarbageCollected<Observable>(MakeGarbageCollected<Bar>());
3665 // |o| observes |foo|.
3666 o = MakeGarbageCollected<FinalizationObserver<Observable>>(foo);
3667 }
3668 // FinalizationObserver doesn't have a strong reference to |foo|. So |foo|
3669 // and its member will be collected.
3670 PreciselyCollectGarbage();
3671 EXPECT_EQ(0u, Bar::live_);
3672 EXPECT_TRUE(o->DidCallWillFinalize());
3673
3674 FinalizationObserverWithHashMap::did_call_will_finalize_ = false;
3675 auto* foo = MakeGarbageCollected<Observable>(MakeGarbageCollected<Bar>());
3676 FinalizationObserverWithHashMap::ObserverMap& map =
3677 FinalizationObserverWithHashMap::Observe(*foo);
3678 EXPECT_EQ(1u, map.size());
3679 foo = nullptr;
3680 // FinalizationObserverWithHashMap doesn't have a strong reference to
3681 // |foo|. So |foo| and its member will be collected.
3682 PreciselyCollectGarbage();
3683 EXPECT_EQ(0u, Bar::live_);
3684 EXPECT_EQ(0u, map.size());
3685 EXPECT_TRUE(FinalizationObserverWithHashMap::did_call_will_finalize_);
3686
3687 FinalizationObserverWithHashMap::ClearObservers();
3688 }
3689
TEST_F(HeapTest,PreFinalizer)3690 TEST_F(HeapTest, PreFinalizer) {
3691 Observable::will_finalize_was_called_ = false;
3692 { MakeGarbageCollected<Observable>(MakeGarbageCollected<Bar>()); }
3693 PreciselyCollectGarbage();
3694 EXPECT_TRUE(Observable::will_finalize_was_called_);
3695 }
3696
TEST_F(HeapTest,PreFinalizerUnregistersItself)3697 TEST_F(HeapTest, PreFinalizerUnregistersItself) {
3698 ObservableWithPreFinalizer::dispose_was_called_ = false;
3699 MakeGarbageCollected<ObservableWithPreFinalizer>();
3700 PreciselyCollectGarbage();
3701 EXPECT_TRUE(ObservableWithPreFinalizer::dispose_was_called_);
3702 // Don't crash, and assertions don't fail.
3703 }
3704
TEST_F(HeapTest,NestedPreFinalizer)3705 TEST_F(HeapTest, NestedPreFinalizer) {
3706 g_dispose_was_called_for_pre_finalizer_base = false;
3707 g_dispose_was_called_for_pre_finalizer_sub_class = false;
3708 g_dispose_was_called_for_pre_finalizer_mixin = false;
3709 MakeGarbageCollected<PreFinalizerSubClass>();
3710 PreciselyCollectGarbage();
3711 EXPECT_TRUE(g_dispose_was_called_for_pre_finalizer_base);
3712 EXPECT_TRUE(g_dispose_was_called_for_pre_finalizer_sub_class);
3713 EXPECT_TRUE(g_dispose_was_called_for_pre_finalizer_mixin);
3714 // Don't crash, and assertions don't fail.
3715 }
3716
TEST_F(HeapTest,Comparisons)3717 TEST_F(HeapTest, Comparisons) {
3718 Persistent<Bar> bar_persistent = MakeGarbageCollected<Bar>();
3719 Persistent<Foo> foo_persistent = MakeGarbageCollected<Foo>(bar_persistent);
3720 EXPECT_TRUE(bar_persistent != foo_persistent);
3721 bar_persistent = foo_persistent;
3722 EXPECT_TRUE(bar_persistent == foo_persistent);
3723 }
3724
3725 namespace {
3726
ExpectObjectMarkedAndUnmark(MarkingWorklist * worklist,void * expected)3727 void ExpectObjectMarkedAndUnmark(MarkingWorklist* worklist, void* expected) {
3728 MarkingItem item;
3729 CHECK(worklist->Pop(0, &item));
3730 CHECK_EQ(expected, item.base_object_payload);
3731 HeapObjectHeader* header =
3732 HeapObjectHeader::FromPayload(item.base_object_payload);
3733 CHECK(header->IsMarked());
3734 header->Unmark();
3735 CHECK(worklist->IsGlobalEmpty());
3736 }
3737
3738 } // namespace
3739
TEST_F(HeapTest,CheckAndMarkPointer)3740 TEST_F(HeapTest, CheckAndMarkPointer) {
3741 // This test ensures that conservative marking primitives can use any address
3742 // contained within an object to mark the corresponding object.
3743
3744 ThreadHeap& heap = ThreadState::Current()->Heap();
3745 ClearOutOldGarbage();
3746
3747 Vector<Address> object_addresses;
3748 Vector<Address> end_addresses;
3749 for (int i = 0; i < 10; i++) {
3750 auto* object = MakeGarbageCollected<SimpleObject>();
3751 Address object_address = reinterpret_cast<Address>(object);
3752 object_addresses.push_back(object_address);
3753 end_addresses.push_back(object_address + sizeof(SimpleObject) - 1);
3754 }
3755 Address large_object_address =
3756 reinterpret_cast<Address>(MakeGarbageCollected<LargeHeapObject>());
3757 Address large_object_end_address =
3758 large_object_address + sizeof(LargeHeapObject) - 1;
3759
3760 {
3761 TestGCScope scope(BlinkGC::kHeapPointersOnStack);
3762 MarkingVisitor visitor(ThreadState::Current(),
3763 MarkingVisitor::kGlobalMarking);
3764 // Record marking speed as counter generation requires valid marking timings
3765 // for heaps >1MB.
3766 ThreadHeapStatsCollector::Scope stats_scope(
3767 heap.stats_collector(),
3768 ThreadHeapStatsCollector::kAtomicPauseMarkTransitiveClosure);
3769
3770 // Conservative marker should find the interesting objects by using anything
3771 // between object start and end.
3772 MarkingWorklist* worklist = heap.GetMarkingWorklist();
3773 CHECK(worklist->IsGlobalEmpty());
3774 for (wtf_size_t i = 0; i < object_addresses.size(); i++) {
3775 heap.CheckAndMarkPointer(&visitor, object_addresses[i]);
3776 ExpectObjectMarkedAndUnmark(worklist, object_addresses[i]);
3777 heap.CheckAndMarkPointer(&visitor, end_addresses[i]);
3778 ExpectObjectMarkedAndUnmark(worklist, object_addresses[i]);
3779 }
3780 heap.CheckAndMarkPointer(&visitor, large_object_address);
3781 ExpectObjectMarkedAndUnmark(worklist, large_object_address);
3782 heap.CheckAndMarkPointer(&visitor, large_object_end_address);
3783 ExpectObjectMarkedAndUnmark(worklist, large_object_address);
3784 }
3785
3786 // This forces a GC without stack scanning which results in the objects
3787 // being collected. This will also rebuild the above mentioned freelists,
3788 // however we don't rely on that below since we don't have any allocations.
3789 ClearOutOldGarbage();
3790
3791 {
3792 TestGCScope scope(BlinkGC::kHeapPointersOnStack);
3793 MarkingVisitor visitor(ThreadState::Current(),
3794 MarkingVisitor::kGlobalMarking);
3795 // Record marking speed as counter generation requires valid marking timings
3796 // for heaps >1MB.
3797 ThreadHeapStatsCollector::Scope stats_scope(
3798 heap.stats_collector(),
3799 ThreadHeapStatsCollector::kAtomicPauseMarkTransitiveClosure);
3800
3801 // After collecting all interesting objects the conservative marker should
3802 // not find them anymore.
3803 MarkingWorklist* worklist = heap.GetMarkingWorklist();
3804 CHECK(worklist->IsGlobalEmpty());
3805 for (wtf_size_t i = 0; i < object_addresses.size(); i++) {
3806 heap.CheckAndMarkPointer(&visitor, object_addresses[i]);
3807 CHECK(worklist->IsGlobalEmpty());
3808 heap.CheckAndMarkPointer(&visitor, end_addresses[i]);
3809 CHECK(worklist->IsGlobalEmpty());
3810 }
3811 heap.CheckAndMarkPointer(&visitor, large_object_address);
3812 CHECK(worklist->IsGlobalEmpty());
3813 heap.CheckAndMarkPointer(&visitor, large_object_end_address);
3814 CHECK(worklist->IsGlobalEmpty());
3815 }
3816 }
3817
TEST_F(HeapTest,CollectionNesting)3818 TEST_F(HeapTest, CollectionNesting) {
3819 ClearOutOldGarbage();
3820 int k;
3821 int* key = &k;
3822 IntWrapper::destructor_calls_ = 0;
3823 typedef HeapVector<Member<IntWrapper>> IntVector;
3824 typedef HeapDeque<Member<IntWrapper>> IntDeque;
3825 HeapHashMap<void*, IntVector>* map =
3826 MakeGarbageCollected<HeapHashMap<void*, IntVector>>();
3827 HeapHashMap<void*, IntDeque>* map2 =
3828 MakeGarbageCollected<HeapHashMap<void*, IntDeque>>();
3829 static_assert(WTF::IsTraceable<IntVector>::value,
3830 "Failed to recognize HeapVector as traceable");
3831 static_assert(WTF::IsTraceable<IntDeque>::value,
3832 "Failed to recognize HeapDeque as traceable");
3833
3834 map->insert(key, IntVector());
3835 map2->insert(key, IntDeque());
3836
3837 HeapHashMap<void*, IntVector>::iterator it = map->find(key);
3838 EXPECT_EQ(0u, map->at(key).size());
3839
3840 HeapHashMap<void*, IntDeque>::iterator it2 = map2->find(key);
3841 EXPECT_EQ(0u, map2->at(key).size());
3842
3843 it->value.push_back(MakeGarbageCollected<IntWrapper>(42));
3844 EXPECT_EQ(1u, map->at(key).size());
3845
3846 it2->value.push_back(MakeGarbageCollected<IntWrapper>(42));
3847 EXPECT_EQ(1u, map2->at(key).size());
3848
3849 Persistent<HeapHashMap<void*, IntVector>> keep_alive(map);
3850 Persistent<HeapHashMap<void*, IntDeque>> keep_alive2(map2);
3851
3852 for (int i = 0; i < 100; i++) {
3853 map->insert(key + 1 + i, IntVector());
3854 map2->insert(key + 1 + i, IntDeque());
3855 }
3856
3857 PreciselyCollectGarbage();
3858
3859 EXPECT_EQ(1u, map->at(key).size());
3860 EXPECT_EQ(1u, map2->at(key).size());
3861 EXPECT_EQ(0, IntWrapper::destructor_calls_);
3862
3863 keep_alive = nullptr;
3864 PreciselyCollectGarbage();
3865 EXPECT_EQ(1, IntWrapper::destructor_calls_);
3866 }
3867
TEST_F(HeapTest,GarbageCollectedMixin)3868 TEST_F(HeapTest, GarbageCollectedMixin) {
3869 ClearOutOldGarbage();
3870
3871 Persistent<UseMixin> usemixin = MakeGarbageCollected<UseMixin>();
3872 EXPECT_EQ(0, UseMixin::trace_count_);
3873 PreciselyCollectGarbage();
3874 EXPECT_EQ(1, UseMixin::trace_count_);
3875
3876 Persistent<Mixin> mixin = usemixin;
3877 usemixin = nullptr;
3878 PreciselyCollectGarbage();
3879 EXPECT_EQ(2, UseMixin::trace_count_);
3880
3881 Persistent<HeapHashSet<WeakMember<Mixin>>> weak_map =
3882 MakeGarbageCollected<HeapHashSet<WeakMember<Mixin>>>();
3883 weak_map->insert(MakeGarbageCollected<UseMixin>());
3884 PreciselyCollectGarbage();
3885 EXPECT_EQ(0u, weak_map->size());
3886 }
3887
TEST_F(HeapTest,CollectionNesting2)3888 TEST_F(HeapTest, CollectionNesting2) {
3889 ClearOutOldGarbage();
3890 void* key = &IntWrapper::destructor_calls_;
3891 IntWrapper::destructor_calls_ = 0;
3892 typedef HeapHashSet<Member<IntWrapper>> IntSet;
3893 HeapHashMap<void*, IntSet>* map =
3894 MakeGarbageCollected<HeapHashMap<void*, IntSet>>();
3895
3896 map->insert(key, IntSet());
3897
3898 HeapHashMap<void*, IntSet>::iterator it = map->find(key);
3899 EXPECT_EQ(0u, map->at(key).size());
3900
3901 it->value.insert(MakeGarbageCollected<IntWrapper>(42));
3902 EXPECT_EQ(1u, map->at(key).size());
3903
3904 Persistent<HeapHashMap<void*, IntSet>> keep_alive(map);
3905 PreciselyCollectGarbage();
3906 EXPECT_EQ(1u, map->at(key).size());
3907 EXPECT_EQ(0, IntWrapper::destructor_calls_);
3908 }
3909
TEST_F(HeapTest,CollectionNesting3)3910 TEST_F(HeapTest, CollectionNesting3) {
3911 ClearOutOldGarbage();
3912 IntWrapper::destructor_calls_ = 0;
3913 typedef HeapVector<Member<IntWrapper>> IntVector;
3914 HeapVector<IntVector>* vector = MakeGarbageCollected<HeapVector<IntVector>>();
3915
3916 vector->push_back(IntVector());
3917
3918 HeapVector<IntVector>::iterator it = vector->begin();
3919 EXPECT_EQ(0u, it->size());
3920
3921 it->push_back(MakeGarbageCollected<IntWrapper>(42));
3922 EXPECT_EQ(1u, it->size());
3923
3924 Persistent<HeapVector<IntVector>> keep_alive(vector);
3925 PreciselyCollectGarbage();
3926 EXPECT_EQ(1u, it->size());
3927 EXPECT_EQ(0, IntWrapper::destructor_calls_);
3928 }
3929
TEST_F(HeapTest,EmbeddedInVector)3930 TEST_F(HeapTest, EmbeddedInVector) {
3931 ClearOutOldGarbage();
3932 SimpleFinalizedObject::destructor_calls_ = 0;
3933 {
3934 Persistent<HeapVector<VectorObject, 2>> inline_vector =
3935 MakeGarbageCollected<HeapVector<VectorObject, 2>>();
3936 Persistent<HeapVector<VectorObject>> outline_vector =
3937 MakeGarbageCollected<HeapVector<VectorObject>>();
3938 VectorObject i1, i2;
3939 inline_vector->push_back(i1);
3940 inline_vector->push_back(i2);
3941
3942 VectorObject o1, o2;
3943 outline_vector->push_back(o1);
3944 outline_vector->push_back(o2);
3945
3946 Persistent<HeapVector<VectorObjectInheritedTrace>> vector_inherited_trace =
3947 MakeGarbageCollected<HeapVector<VectorObjectInheritedTrace>>();
3948 VectorObjectInheritedTrace it1, it2;
3949 vector_inherited_trace->push_back(it1);
3950 vector_inherited_trace->push_back(it2);
3951
3952 PreciselyCollectGarbage();
3953 EXPECT_EQ(0, SimpleFinalizedObject::destructor_calls_);
3954 }
3955 PreciselyCollectGarbage();
3956 EXPECT_EQ(6, SimpleFinalizedObject::destructor_calls_);
3957 }
3958
3959 class InlinedVectorObject {
3960 DISALLOW_NEW();
3961
3962 public:
3963 InlinedVectorObject() = default;
~InlinedVectorObject()3964 ~InlinedVectorObject() { destructor_calls_++; }
Trace(Visitor * visitor)3965 void Trace(Visitor* visitor) {}
3966
3967 static int destructor_calls_;
3968 };
3969
3970 int InlinedVectorObject::destructor_calls_ = 0;
3971
3972 class InlinedVectorObjectWithVtable {
3973 DISALLOW_NEW();
3974
3975 public:
3976 InlinedVectorObjectWithVtable() = default;
~InlinedVectorObjectWithVtable()3977 virtual ~InlinedVectorObjectWithVtable() { destructor_calls_++; }
VirtualMethod()3978 virtual void VirtualMethod() {}
Trace(Visitor * visitor)3979 void Trace(Visitor* visitor) {}
3980
3981 static int destructor_calls_;
3982 };
3983
3984 int InlinedVectorObjectWithVtable::destructor_calls_ = 0;
3985
3986 } // namespace blink
3987
3988 WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(blink::InlinedVectorObject)
3989
3990 namespace blink {
3991
3992 class InlinedVectorObjectWrapper final
3993 : public GarbageCollected<InlinedVectorObjectWrapper> {
3994 public:
InlinedVectorObjectWrapper()3995 InlinedVectorObjectWrapper() {
3996 InlinedVectorObject i1, i2;
3997 vector1_.push_back(i1);
3998 vector1_.push_back(i2);
3999 vector2_.push_back(i1);
4000 vector2_.push_back(i2); // This allocates an out-of-line buffer.
4001 vector3_.push_back(i1);
4002 vector3_.push_back(i2);
4003 }
4004
Trace(Visitor * visitor)4005 void Trace(Visitor* visitor) {
4006 visitor->Trace(vector1_);
4007 visitor->Trace(vector2_);
4008 visitor->Trace(vector3_);
4009 }
4010
4011 private:
4012 HeapVector<InlinedVectorObject> vector1_;
4013 HeapVector<InlinedVectorObject, 1> vector2_;
4014 HeapVector<InlinedVectorObject, 2> vector3_;
4015 };
4016
4017 class InlinedVectorObjectWithVtableWrapper final
4018 : public GarbageCollected<InlinedVectorObjectWithVtableWrapper> {
4019 public:
InlinedVectorObjectWithVtableWrapper()4020 InlinedVectorObjectWithVtableWrapper() {
4021 InlinedVectorObjectWithVtable i1, i2;
4022 vector1_.push_back(i1);
4023 vector1_.push_back(i2);
4024 vector2_.push_back(i1);
4025 vector2_.push_back(i2); // This allocates an out-of-line buffer.
4026 vector3_.push_back(i1);
4027 vector3_.push_back(i2);
4028 }
4029
Trace(Visitor * visitor)4030 void Trace(Visitor* visitor) {
4031 visitor->Trace(vector1_);
4032 visitor->Trace(vector2_);
4033 visitor->Trace(vector3_);
4034 }
4035
4036 private:
4037 HeapVector<InlinedVectorObjectWithVtable> vector1_;
4038 HeapVector<InlinedVectorObjectWithVtable, 1> vector2_;
4039 HeapVector<InlinedVectorObjectWithVtable, 2> vector3_;
4040 };
4041
TEST_F(HeapTest,VectorDestructors)4042 TEST_F(HeapTest, VectorDestructors) {
4043 ClearOutOldGarbage();
4044 InlinedVectorObject::destructor_calls_ = 0;
4045 {
4046 HeapVector<InlinedVectorObject> vector;
4047 InlinedVectorObject i1, i2;
4048 vector.push_back(i1);
4049 vector.push_back(i2);
4050 }
4051 PreciselyCollectGarbage();
4052 // This is not EXPECT_EQ but EXPECT_LE because a HeapVectorBacking calls
4053 // destructors for all elements in (not the size but) the capacity of
4054 // the vector. Thus the number of destructors called becomes larger
4055 // than the actual number of objects in the vector.
4056 EXPECT_LE(4, InlinedVectorObject::destructor_calls_);
4057
4058 InlinedVectorObject::destructor_calls_ = 0;
4059 {
4060 HeapVector<InlinedVectorObject, 1> vector;
4061 InlinedVectorObject i1, i2;
4062 vector.push_back(i1);
4063 vector.push_back(i2); // This allocates an out-of-line buffer.
4064 }
4065 PreciselyCollectGarbage();
4066 EXPECT_LE(4, InlinedVectorObject::destructor_calls_);
4067
4068 InlinedVectorObject::destructor_calls_ = 0;
4069 {
4070 HeapVector<InlinedVectorObject, 2> vector;
4071 InlinedVectorObject i1, i2;
4072 vector.push_back(i1);
4073 vector.push_back(i2);
4074 }
4075 PreciselyCollectGarbage();
4076 EXPECT_LE(4, InlinedVectorObject::destructor_calls_);
4077
4078 InlinedVectorObject::destructor_calls_ = 0;
4079 {
4080 Persistent<InlinedVectorObjectWrapper> vector_wrapper =
4081 MakeGarbageCollected<InlinedVectorObjectWrapper>();
4082 ConservativelyCollectGarbage();
4083 EXPECT_EQ(2, InlinedVectorObject::destructor_calls_);
4084 }
4085 PreciselyCollectGarbage();
4086 EXPECT_LE(8, InlinedVectorObject::destructor_calls_);
4087 }
4088
4089 // TODO(Oilpan): when Vector.h's contiguous container support no longer disables
4090 // Vector<>s with inline capacity, enable this test.
4091 #if !defined(ANNOTATE_CONTIGUOUS_CONTAINER)
TEST_F(HeapTest,VectorDestructorsWithVtable)4092 TEST_F(HeapTest, VectorDestructorsWithVtable) {
4093 ClearOutOldGarbage();
4094 InlinedVectorObjectWithVtable::destructor_calls_ = 0;
4095 {
4096 HeapVector<InlinedVectorObjectWithVtable> vector;
4097 InlinedVectorObjectWithVtable i1, i2;
4098 vector.push_back(i1);
4099 vector.push_back(i2);
4100 }
4101 PreciselyCollectGarbage();
4102 EXPECT_EQ(4, InlinedVectorObjectWithVtable::destructor_calls_);
4103
4104 InlinedVectorObjectWithVtable::destructor_calls_ = 0;
4105 {
4106 HeapVector<InlinedVectorObjectWithVtable, 1> vector;
4107 InlinedVectorObjectWithVtable i1, i2;
4108 vector.push_back(i1);
4109 vector.push_back(i2); // This allocates an out-of-line buffer.
4110 }
4111 PreciselyCollectGarbage();
4112 EXPECT_EQ(5, InlinedVectorObjectWithVtable::destructor_calls_);
4113
4114 InlinedVectorObjectWithVtable::destructor_calls_ = 0;
4115 {
4116 HeapVector<InlinedVectorObjectWithVtable, 2> vector;
4117 InlinedVectorObjectWithVtable i1, i2;
4118 vector.push_back(i1);
4119 vector.push_back(i2);
4120 }
4121 PreciselyCollectGarbage();
4122 EXPECT_EQ(4, InlinedVectorObjectWithVtable::destructor_calls_);
4123
4124 InlinedVectorObjectWithVtable::destructor_calls_ = 0;
4125 {
4126 Persistent<InlinedVectorObjectWithVtableWrapper> vector_wrapper =
4127 MakeGarbageCollected<InlinedVectorObjectWithVtableWrapper>();
4128 ConservativelyCollectGarbage();
4129 EXPECT_EQ(3, InlinedVectorObjectWithVtable::destructor_calls_);
4130 }
4131 PreciselyCollectGarbage();
4132 EXPECT_EQ(9, InlinedVectorObjectWithVtable::destructor_calls_);
4133 }
4134 #endif
4135
4136 template <typename Set>
RawPtrInHashHelper()4137 void RawPtrInHashHelper() {
4138 Set set;
4139 set.Add(new int(42));
4140 set.Add(new int(42));
4141 EXPECT_EQ(2u, set.size());
4142 for (typename Set::iterator it = set.begin(); it != set.end(); ++it) {
4143 EXPECT_EQ(42, **it);
4144 delete *it;
4145 }
4146 }
4147
TEST_F(HeapTest,AllocationDuringFinalization)4148 TEST_F(HeapTest, AllocationDuringFinalization) {
4149 ClearOutOldGarbage();
4150 IntWrapper::destructor_calls_ = 0;
4151 OneKiloByteObject::destructor_calls_ = 0;
4152 LargeHeapObject::destructor_calls_ = 0;
4153
4154 Persistent<IntWrapper> wrapper;
4155 MakeGarbageCollected<FinalizationAllocator>(&wrapper);
4156
4157 PreciselyCollectGarbage();
4158 EXPECT_EQ(0, IntWrapper::destructor_calls_);
4159 EXPECT_EQ(0, OneKiloByteObject::destructor_calls_);
4160 EXPECT_EQ(0, LargeHeapObject::destructor_calls_);
4161 // Check that the wrapper allocated during finalization is not
4162 // swept away and zapped later in the same sweeping phase.
4163 EXPECT_EQ(42, wrapper->Value());
4164
4165 wrapper.Clear();
4166 PreciselyCollectGarbage();
4167 // The 42 IntWrappers were the ones allocated in ~FinalizationAllocator
4168 // and the ones allocated in LargeHeapObject.
4169 EXPECT_EQ(42, IntWrapper::destructor_calls_);
4170 EXPECT_EQ(512, OneKiloByteObject::destructor_calls_);
4171 EXPECT_EQ(32, LargeHeapObject::destructor_calls_);
4172 }
4173
4174 class SimpleClassWithDestructor {
4175 public:
4176 SimpleClassWithDestructor() = default;
~SimpleClassWithDestructor()4177 ~SimpleClassWithDestructor() { was_destructed_ = true; }
4178 static bool was_destructed_;
4179 };
4180
4181 bool SimpleClassWithDestructor::was_destructed_;
4182
4183 class RefCountedWithDestructor : public RefCounted<RefCountedWithDestructor> {
4184 public:
4185 RefCountedWithDestructor() = default;
~RefCountedWithDestructor()4186 ~RefCountedWithDestructor() { was_destructed_ = true; }
4187 static bool was_destructed_;
4188 };
4189
4190 bool RefCountedWithDestructor::was_destructed_;
4191
4192 template <typename Set>
DestructorsCalledOnGC(bool add_lots)4193 void DestructorsCalledOnGC(bool add_lots) {
4194 RefCountedWithDestructor::was_destructed_ = false;
4195 {
4196 Set set;
4197 RefCountedWithDestructor* has_destructor = new RefCountedWithDestructor();
4198 set.Add(base::AdoptRef(has_destructor));
4199 EXPECT_FALSE(RefCountedWithDestructor::was_destructed_);
4200
4201 if (add_lots) {
4202 for (int i = 0; i < 1000; i++) {
4203 set.Add(base::AdoptRef(new RefCountedWithDestructor()));
4204 }
4205 }
4206
4207 EXPECT_FALSE(RefCountedWithDestructor::was_destructed_);
4208 TestSupportingGC::ConservativelyCollectGarbage();
4209 EXPECT_FALSE(RefCountedWithDestructor::was_destructed_);
4210 }
4211 // The destructors of the sets don't call the destructors of the elements
4212 // in the heap sets. You have to actually remove the elments, call clear()
4213 // or have a GC to get the destructors called.
4214 EXPECT_FALSE(RefCountedWithDestructor::was_destructed_);
4215 TestSupportingGC::PreciselyCollectGarbage();
4216 EXPECT_TRUE(RefCountedWithDestructor::was_destructed_);
4217 }
4218
4219 template <typename Set>
DestructorsCalledOnClear(bool add_lots)4220 void DestructorsCalledOnClear(bool add_lots) {
4221 RefCountedWithDestructor::was_destructed_ = false;
4222 Set set;
4223 RefCountedWithDestructor* has_destructor = new RefCountedWithDestructor();
4224 set.Add(base::AdoptRef(has_destructor));
4225 EXPECT_FALSE(RefCountedWithDestructor::was_destructed_);
4226
4227 if (add_lots) {
4228 for (int i = 0; i < 1000; i++) {
4229 set.Add(base::AdoptRef(new RefCountedWithDestructor()));
4230 }
4231 }
4232
4233 EXPECT_FALSE(RefCountedWithDestructor::was_destructed_);
4234 set.Clear();
4235 EXPECT_TRUE(RefCountedWithDestructor::was_destructed_);
4236 }
4237
TEST_F(HeapTest,DestructorsCalled)4238 TEST_F(HeapTest, DestructorsCalled) {
4239 HeapHashMap<Member<IntWrapper>, std::unique_ptr<SimpleClassWithDestructor>>
4240 map;
4241 SimpleClassWithDestructor* has_destructor = new SimpleClassWithDestructor();
4242 map.insert(MakeGarbageCollected<IntWrapper>(1),
4243 base::WrapUnique(has_destructor));
4244 SimpleClassWithDestructor::was_destructed_ = false;
4245 map.clear();
4246 EXPECT_TRUE(SimpleClassWithDestructor::was_destructed_);
4247 }
4248
4249 class MixinA : public GarbageCollectedMixin {
4250 public:
MixinA()4251 MixinA() : obj_(MakeGarbageCollected<IntWrapper>(100)) {}
Trace(Visitor * visitor)4252 void Trace(Visitor* visitor) override {
4253 trace_count_++;
4254 visitor->Trace(obj_);
4255 }
4256
4257 static int trace_count_;
4258
4259 Member<IntWrapper> obj_;
4260 };
4261
4262 int MixinA::trace_count_ = 0;
4263
4264 class MixinB : public GarbageCollectedMixin {
4265 public:
MixinB()4266 MixinB() : obj_(MakeGarbageCollected<IntWrapper>(101)) {}
Trace(Visitor * visitor)4267 void Trace(Visitor* visitor) override { visitor->Trace(obj_); }
4268 Member<IntWrapper> obj_;
4269 };
4270
4271 class MultipleMixins : public GarbageCollected<MultipleMixins>,
4272 public MixinA,
4273 public MixinB {
4274 USING_GARBAGE_COLLECTED_MIXIN(MultipleMixins);
4275
4276 public:
MultipleMixins()4277 MultipleMixins() : obj_(MakeGarbageCollected<IntWrapper>(102)) {}
Trace(Visitor * visitor)4278 void Trace(Visitor* visitor) override {
4279 visitor->Trace(obj_);
4280 MixinA::Trace(visitor);
4281 MixinB::Trace(visitor);
4282 }
4283 Member<IntWrapper> obj_;
4284 };
4285
4286 class DerivedMultipleMixins : public MultipleMixins {
4287 public:
DerivedMultipleMixins()4288 DerivedMultipleMixins() : obj_(MakeGarbageCollected<IntWrapper>(103)) {}
4289
Trace(Visitor * visitor)4290 void Trace(Visitor* visitor) override {
4291 trace_called_++;
4292 visitor->Trace(obj_);
4293 MultipleMixins::Trace(visitor);
4294 }
4295
4296 static int trace_called_;
4297
4298 private:
4299 Member<IntWrapper> obj_;
4300 };
4301
4302 int DerivedMultipleMixins::trace_called_ = 0;
4303
4304 static const bool kIsMixinTrue = IsGarbageCollectedMixin<MultipleMixins>::value;
4305 static const bool kIsMixinFalse = IsGarbageCollectedMixin<IntWrapper>::value;
4306
TEST_F(HeapTest,MultipleMixins)4307 TEST_F(HeapTest, MultipleMixins) {
4308 EXPECT_TRUE(kIsMixinTrue);
4309 EXPECT_FALSE(kIsMixinFalse);
4310
4311 ClearOutOldGarbage();
4312 IntWrapper::destructor_calls_ = 0;
4313 MultipleMixins* obj = MakeGarbageCollected<MultipleMixins>();
4314 {
4315 Persistent<MixinA> a = obj;
4316 PreciselyCollectGarbage();
4317 EXPECT_EQ(0, IntWrapper::destructor_calls_);
4318 }
4319 {
4320 Persistent<MixinB> b = obj;
4321 PreciselyCollectGarbage();
4322 EXPECT_EQ(0, IntWrapper::destructor_calls_);
4323 }
4324 PreciselyCollectGarbage();
4325 EXPECT_EQ(3, IntWrapper::destructor_calls_);
4326 }
4327
TEST_F(HeapTest,DerivedMultipleMixins)4328 TEST_F(HeapTest, DerivedMultipleMixins) {
4329 ClearOutOldGarbage();
4330 IntWrapper::destructor_calls_ = 0;
4331 DerivedMultipleMixins::trace_called_ = 0;
4332
4333 DerivedMultipleMixins* obj = MakeGarbageCollected<DerivedMultipleMixins>();
4334 {
4335 Persistent<MixinA> a = obj;
4336 PreciselyCollectGarbage();
4337 EXPECT_EQ(0, IntWrapper::destructor_calls_);
4338 EXPECT_LT(0, DerivedMultipleMixins::trace_called_);
4339 }
4340 {
4341 Persistent<MixinB> b = obj;
4342 PreciselyCollectGarbage();
4343 EXPECT_EQ(0, IntWrapper::destructor_calls_);
4344 EXPECT_LT(0, DerivedMultipleMixins::trace_called_);
4345 }
4346 PreciselyCollectGarbage();
4347 EXPECT_EQ(4, IntWrapper::destructor_calls_);
4348 }
4349
4350 class MixinInstanceWithoutTrace
4351 : public GarbageCollected<MixinInstanceWithoutTrace>,
4352 public MixinA {
4353 USING_GARBAGE_COLLECTED_MIXIN(MixinInstanceWithoutTrace);
4354
4355 public:
4356 MixinInstanceWithoutTrace() = default;
4357 };
4358
TEST_F(HeapTest,MixinInstanceWithoutTrace)4359 TEST_F(HeapTest, MixinInstanceWithoutTrace) {
4360 // Verify that a mixin instance without any traceable
4361 // references inherits the mixin's trace implementation.
4362 ClearOutOldGarbage();
4363 MixinA::trace_count_ = 0;
4364 MixinInstanceWithoutTrace* obj =
4365 MakeGarbageCollected<MixinInstanceWithoutTrace>();
4366 int saved_trace_count = 0;
4367 {
4368 Persistent<MixinA> a = obj;
4369 PreciselyCollectGarbage();
4370 saved_trace_count = MixinA::trace_count_;
4371 EXPECT_LT(0, saved_trace_count);
4372 }
4373 {
4374 Persistent<MixinInstanceWithoutTrace> b = obj;
4375 PreciselyCollectGarbage();
4376 EXPECT_LT(saved_trace_count, MixinA::trace_count_);
4377 saved_trace_count = MixinA::trace_count_;
4378 }
4379 PreciselyCollectGarbage();
4380 // Oilpan might still call trace on dead objects for various reasons which is
4381 // valid before sweeping started.
4382 EXPECT_LE(saved_trace_count, MixinA::trace_count_);
4383 }
4384
TEST_F(HeapTest,NeedsAdjustPointer)4385 TEST_F(HeapTest, NeedsAdjustPointer) {
4386 // class Mixin : public GarbageCollectedMixin {};
4387 static_assert(NeedsAdjustPointer<Mixin>::value,
4388 "A Mixin pointer needs adjustment");
4389 static_assert(NeedsAdjustPointer<const Mixin>::value,
4390 "A const Mixin pointer needs adjustment");
4391
4392 // class SimpleObject : public GarbageCollected<SimpleObject> {};
4393 static_assert(!NeedsAdjustPointer<SimpleObject>::value,
4394 "A SimpleObject pointer does not need adjustment");
4395 static_assert(!NeedsAdjustPointer<const SimpleObject>::value,
4396 "A const SimpleObject pointer does not need adjustment");
4397
4398 // class UseMixin : public SimpleObject, public Mixin {};
4399 static_assert(!NeedsAdjustPointer<UseMixin>::value,
4400 "A UseMixin pointer does not need adjustment");
4401 static_assert(!NeedsAdjustPointer<const UseMixin>::value,
4402 "A const UseMixin pointer does not need adjustment");
4403 }
4404
AddElementsToWeakMap(HeapHashMap<int,WeakMember<IntWrapper>> * map)4405 static void AddElementsToWeakMap(
4406 HeapHashMap<int, WeakMember<IntWrapper>>* map) {
4407 // Key cannot be zero in hashmap.
4408 for (int i = 1; i < 11; i++)
4409 map->insert(i, MakeGarbageCollected<IntWrapper>(i));
4410 }
4411
4412 // crbug.com/402426
4413 // If it doesn't assert a concurrent modification to the map, then it's passing.
TEST_F(HeapTest,RegressNullIsStrongified)4414 TEST_F(HeapTest, RegressNullIsStrongified) {
4415 Persistent<HeapHashMap<int, WeakMember<IntWrapper>>> map =
4416 MakeGarbageCollected<HeapHashMap<int, WeakMember<IntWrapper>>>();
4417 AddElementsToWeakMap(map);
4418 HeapHashMap<int, WeakMember<IntWrapper>>::AddResult result =
4419 map->insert(800, nullptr);
4420 ConservativelyCollectGarbage();
4421 result.stored_value->value = MakeGarbageCollected<IntWrapper>(42);
4422 }
4423
TEST_F(HeapTest,Bind)4424 TEST_F(HeapTest, Bind) {
4425 base::OnceClosure closure =
4426 WTF::Bind(static_cast<void (Bar::*)(Visitor*)>(&Bar::Trace),
4427 WrapPersistent(MakeGarbageCollected<Bar>()), nullptr);
4428 // OffHeapInt* should not make Persistent.
4429 base::OnceClosure closure2 =
4430 WTF::Bind(&OffHeapInt::VoidFunction, OffHeapInt::Create(1));
4431 PreciselyCollectGarbage();
4432 // The closure should have a persistent handle to the Bar.
4433 EXPECT_EQ(1u, Bar::live_);
4434
4435 UseMixin::trace_count_ = 0;
4436 auto* mixin = MakeGarbageCollected<UseMixin>();
4437 base::OnceClosure mixin_closure =
4438 WTF::Bind(static_cast<void (Mixin::*)(Visitor*)>(&Mixin::Trace),
4439 WrapPersistent(mixin), nullptr);
4440 PreciselyCollectGarbage();
4441 // The closure should have a persistent handle to the mixin.
4442 EXPECT_EQ(1, UseMixin::trace_count_);
4443 }
4444
4445 typedef HeapHashSet<WeakMember<IntWrapper>> WeakSet;
4446
TEST_F(HeapTest,EphemeronsInEphemerons)4447 TEST_F(HeapTest, EphemeronsInEphemerons) {
4448 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper>> InnerMap;
4449 typedef HeapHashMap<WeakMember<IntWrapper>, InnerMap> OuterMap;
4450
4451 for (int keep_outer_alive = 0; keep_outer_alive <= 1; keep_outer_alive++) {
4452 for (int keep_inner_alive = 0; keep_inner_alive <= 1; keep_inner_alive++) {
4453 Persistent<OuterMap> outer = MakeGarbageCollected<OuterMap>();
4454 Persistent<IntWrapper> one = MakeGarbageCollected<IntWrapper>(1);
4455 Persistent<IntWrapper> two = MakeGarbageCollected<IntWrapper>(2);
4456 outer->insert(one, InnerMap());
4457 outer->begin()->value.insert(two, MakeGarbageCollected<IntWrapper>(3));
4458 EXPECT_EQ(1u, outer->at(one).size());
4459 if (!keep_outer_alive)
4460 one.Clear();
4461 if (!keep_inner_alive)
4462 two.Clear();
4463 PreciselyCollectGarbage();
4464 if (keep_outer_alive) {
4465 const InnerMap& inner = outer->at(one);
4466 if (keep_inner_alive) {
4467 EXPECT_EQ(1u, inner.size());
4468 IntWrapper* three = inner.at(two);
4469 EXPECT_EQ(3, three->Value());
4470 } else {
4471 EXPECT_EQ(0u, inner.size());
4472 }
4473 } else {
4474 EXPECT_EQ(0u, outer->size());
4475 }
4476 outer->clear();
4477 Persistent<IntWrapper> deep = MakeGarbageCollected<IntWrapper>(42);
4478 Persistent<IntWrapper> home = MakeGarbageCollected<IntWrapper>(103);
4479 Persistent<IntWrapper> composite = MakeGarbageCollected<IntWrapper>(91);
4480 Persistent<HeapVector<Member<IntWrapper>>> keep_alive =
4481 MakeGarbageCollected<HeapVector<Member<IntWrapper>>>();
4482 for (int i = 0; i < 10000; i++) {
4483 auto* value = MakeGarbageCollected<IntWrapper>(i);
4484 keep_alive->push_back(value);
4485 OuterMap::AddResult new_entry = outer->insert(value, InnerMap());
4486 new_entry.stored_value->value.insert(deep, home);
4487 new_entry.stored_value->value.insert(composite, home);
4488 }
4489 composite.Clear();
4490 PreciselyCollectGarbage();
4491 EXPECT_EQ(10000u, outer->size());
4492 for (int i = 0; i < 10000; i++) {
4493 IntWrapper* value = keep_alive->at(i);
4494 EXPECT_EQ(1u,
4495 outer->at(value)
4496 .size()); // Other one was deleted by weak handling.
4497 if (i & 1)
4498 keep_alive->at(i) = nullptr;
4499 }
4500 PreciselyCollectGarbage();
4501 EXPECT_EQ(5000u, outer->size());
4502 }
4503 }
4504 }
4505
4506 class EphemeronWrapper : public GarbageCollected<EphemeronWrapper> {
4507 public:
Trace(Visitor * visitor)4508 void Trace(Visitor* visitor) { visitor->Trace(map_); }
4509
4510 typedef HeapHashMap<WeakMember<IntWrapper>, Member<EphemeronWrapper>> Map;
GetMap()4511 Map& GetMap() { return map_; }
4512
4513 private:
4514 Map map_;
4515 };
4516
TEST_F(HeapTest,EphemeronsPointToEphemerons)4517 TEST_F(HeapTest, EphemeronsPointToEphemerons) {
4518 Persistent<IntWrapper> key = MakeGarbageCollected<IntWrapper>(42);
4519 Persistent<IntWrapper> key2 = MakeGarbageCollected<IntWrapper>(103);
4520
4521 Persistent<EphemeronWrapper> chain;
4522 for (int i = 0; i < 100; i++) {
4523 EphemeronWrapper* old_head = chain;
4524 chain = MakeGarbageCollected<EphemeronWrapper>();
4525 if (i == 50)
4526 chain->GetMap().insert(key2, old_head);
4527 else
4528 chain->GetMap().insert(key, old_head);
4529 chain->GetMap().insert(MakeGarbageCollected<IntWrapper>(103),
4530 MakeGarbageCollected<EphemeronWrapper>());
4531 }
4532
4533 PreciselyCollectGarbage();
4534
4535 EphemeronWrapper* wrapper = chain;
4536 for (int i = 0; i < 100; i++) {
4537 EXPECT_EQ(1u, wrapper->GetMap().size());
4538 if (i == 49)
4539 wrapper = wrapper->GetMap().at(key2);
4540 else
4541 wrapper = wrapper->GetMap().at(key);
4542 }
4543 EXPECT_EQ(nullptr, wrapper);
4544
4545 key2.Clear();
4546 PreciselyCollectGarbage();
4547
4548 wrapper = chain;
4549 for (int i = 0; i < 50; i++) {
4550 EXPECT_EQ(i == 49 ? 0u : 1u, wrapper->GetMap().size());
4551 wrapper = wrapper->GetMap().at(key);
4552 }
4553 EXPECT_EQ(nullptr, wrapper);
4554
4555 key.Clear();
4556 PreciselyCollectGarbage();
4557 EXPECT_EQ(0u, chain->GetMap().size());
4558 }
4559
TEST_F(HeapTest,Ephemeron)4560 TEST_F(HeapTest, Ephemeron) {
4561 typedef HeapHashSet<WeakMember<IntWrapper>> Set;
4562
4563 Persistent<Set> set = MakeGarbageCollected<Set>();
4564
4565 Persistent<IntWrapper> wp1 = MakeGarbageCollected<IntWrapper>(1);
4566 Persistent<IntWrapper> wp2 = MakeGarbageCollected<IntWrapper>(2);
4567 Persistent<IntWrapper> pw1 = MakeGarbageCollected<IntWrapper>(3);
4568 Persistent<IntWrapper> pw2 = MakeGarbageCollected<IntWrapper>(4);
4569
4570 set->insert(wp1);
4571 set->insert(wp2);
4572 set->insert(pw1);
4573 set->insert(pw2);
4574
4575 PreciselyCollectGarbage();
4576
4577 EXPECT_EQ(4u, set->size());
4578
4579 wp2.Clear(); // Kills all entries in the weakPairMaps except the first.
4580 pw2.Clear(); // Kills all entries in the pairWeakMaps except the first.
4581
4582 for (int i = 0; i < 2; i++) {
4583 PreciselyCollectGarbage();
4584
4585 EXPECT_EQ(2u, set->size()); // wp1 and pw1.
4586 }
4587
4588 wp1.Clear();
4589 pw1.Clear();
4590
4591 PreciselyCollectGarbage();
4592
4593 EXPECT_EQ(0u, set->size());
4594 }
4595
4596 class Link1 : public GarbageCollected<Link1> {
4597 public:
Link1(IntWrapper * link)4598 Link1(IntWrapper* link) : link_(link) {}
4599
Trace(Visitor * visitor)4600 void Trace(Visitor* visitor) { visitor->Trace(link_); }
4601
Link()4602 IntWrapper* Link() { return link_; }
4603
4604 private:
4605 Member<IntWrapper> link_;
4606 };
4607
TEST_F(HeapTest,IndirectStrongToWeak)4608 TEST_F(HeapTest, IndirectStrongToWeak) {
4609 typedef HeapHashMap<WeakMember<IntWrapper>, Member<Link1>> Map;
4610 Persistent<Map> map = MakeGarbageCollected<Map>();
4611 Persistent<IntWrapper> dead_object = MakeGarbageCollected<IntWrapper>(
4612 100); // Named for "Drowning by Numbers" (1988).
4613 Persistent<IntWrapper> life_object = MakeGarbageCollected<IntWrapper>(42);
4614 map->insert(dead_object, MakeGarbageCollected<Link1>(dead_object));
4615 map->insert(life_object, MakeGarbageCollected<Link1>(life_object));
4616 EXPECT_EQ(2u, map->size());
4617 PreciselyCollectGarbage();
4618 EXPECT_EQ(2u, map->size());
4619 EXPECT_EQ(dead_object, map->at(dead_object)->Link());
4620 EXPECT_EQ(life_object, map->at(life_object)->Link());
4621 dead_object.Clear(); // Now it can live up to its name.
4622 PreciselyCollectGarbage();
4623 EXPECT_EQ(1u, map->size());
4624 EXPECT_EQ(life_object, map->at(life_object)->Link());
4625 life_object.Clear(); // Despite its name.
4626 PreciselyCollectGarbage();
4627 EXPECT_EQ(0u, map->size());
4628 }
4629
AllocateAndReturnBool()4630 static bool AllocateAndReturnBool() {
4631 TestSupportingGC::ConservativelyCollectGarbage();
4632 return true;
4633 }
4634
4635 template <typename T>
4636 class TraceIfNeededTester final
4637 : public GarbageCollected<TraceIfNeededTester<T>> {
4638 public:
4639 TraceIfNeededTester() = default;
TraceIfNeededTester(const T & obj)4640 explicit TraceIfNeededTester(const T& obj) : obj_(obj) {}
4641
Trace(Visitor * visitor)4642 void Trace(Visitor* visitor) { TraceIfNeeded<T>::Trace(visitor, obj_); }
Obj()4643 T& Obj() { return obj_; }
4644 ~TraceIfNeededTester() = default;
4645
4646 private:
4647 T obj_;
4648 };
4649
4650 class PartObject {
4651 DISALLOW_NEW();
4652
4653 public:
PartObject()4654 PartObject() : obj_(MakeGarbageCollected<SimpleObject>()) {}
Trace(Visitor * visitor)4655 void Trace(Visitor* visitor) { visitor->Trace(obj_); }
4656
4657 private:
4658 Member<SimpleObject> obj_;
4659 };
4660
4661 class AllocatesOnAssignment {
4662 public:
AllocatesOnAssignment(std::nullptr_t)4663 AllocatesOnAssignment(std::nullptr_t) : value_(nullptr) {}
AllocatesOnAssignment(int x)4664 AllocatesOnAssignment(int x) : value_(MakeGarbageCollected<IntWrapper>(x)) {}
AllocatesOnAssignment(IntWrapper * x)4665 AllocatesOnAssignment(IntWrapper* x) : value_(x) {}
4666
operator =(const AllocatesOnAssignment x)4667 AllocatesOnAssignment& operator=(const AllocatesOnAssignment x) {
4668 value_ = x.value_;
4669 return *this;
4670 }
4671
4672 enum DeletedMarker { kDeletedValue };
4673
AllocatesOnAssignment(const AllocatesOnAssignment & other)4674 AllocatesOnAssignment(const AllocatesOnAssignment& other) {
4675 if (!ThreadState::Current()->IsGCForbidden())
4676 TestSupportingGC::ConservativelyCollectGarbage();
4677 value_ = MakeGarbageCollected<IntWrapper>(other.value_->Value());
4678 }
4679
AllocatesOnAssignment(DeletedMarker)4680 AllocatesOnAssignment(DeletedMarker) : value_(WTF::kHashTableDeletedValue) {}
4681
IsDeleted() const4682 inline bool IsDeleted() const { return value_.IsHashTableDeletedValue(); }
4683
Trace(Visitor * visitor)4684 void Trace(Visitor* visitor) { visitor->Trace(value_); }
4685
Value()4686 int Value() { return value_->Value(); }
4687
4688 private:
4689 Member<IntWrapper> value_;
4690
4691 friend bool operator==(const AllocatesOnAssignment&,
4692 const AllocatesOnAssignment&);
4693 friend void swap(AllocatesOnAssignment&, AllocatesOnAssignment&);
4694 };
4695
operator ==(const AllocatesOnAssignment & a,const AllocatesOnAssignment & b)4696 bool operator==(const AllocatesOnAssignment& a,
4697 const AllocatesOnAssignment& b) {
4698 if (a.value_)
4699 return b.value_ && a.value_->Value() == b.value_->Value();
4700 return !b.value_;
4701 }
4702
swap(AllocatesOnAssignment & a,AllocatesOnAssignment & b)4703 void swap(AllocatesOnAssignment& a, AllocatesOnAssignment& b) {
4704 std::swap(a.value_, b.value_);
4705 }
4706
4707 struct DegenerateHash {
GetHashblink::DegenerateHash4708 static unsigned GetHash(const AllocatesOnAssignment&) { return 0; }
Equalblink::DegenerateHash4709 static bool Equal(const AllocatesOnAssignment& a,
4710 const AllocatesOnAssignment& b) {
4711 return !a.IsDeleted() && a == b;
4712 }
4713 static const bool safe_to_compare_to_empty_or_deleted = true;
4714 };
4715
4716 struct AllocatesOnAssignmentHashTraits
4717 : WTF::GenericHashTraits<AllocatesOnAssignment> {
4718 typedef AllocatesOnAssignment T;
4719 typedef std::nullptr_t EmptyValueType;
EmptyValueblink::AllocatesOnAssignmentHashTraits4720 static EmptyValueType EmptyValue() { return nullptr; }
4721 static const bool kEmptyValueIsZero =
4722 false; // Can't be zero if it has a vtable.
ConstructDeletedValueblink::AllocatesOnAssignmentHashTraits4723 static void ConstructDeletedValue(T& slot, bool) {
4724 slot = T(AllocatesOnAssignment::kDeletedValue);
4725 }
IsDeletedValueblink::AllocatesOnAssignmentHashTraits4726 static bool IsDeletedValue(const T& value) { return value.IsDeleted(); }
4727 };
4728
4729 } // namespace blink
4730
4731 namespace WTF {
4732
4733 template <>
4734 struct DefaultHash<blink::AllocatesOnAssignment> {
4735 typedef blink::DegenerateHash Hash;
4736 };
4737
4738 template <>
4739 struct HashTraits<blink::AllocatesOnAssignment>
4740 : blink::AllocatesOnAssignmentHashTraits {};
4741
4742 } // namespace WTF
4743
4744 namespace blink {
4745
TEST_F(HeapTest,GCInHashMapOperations)4746 TEST_F(HeapTest, GCInHashMapOperations) {
4747 typedef HeapHashMap<AllocatesOnAssignment, AllocatesOnAssignment> Map;
4748 Map* map = MakeGarbageCollected<Map>();
4749 IntWrapper* key = MakeGarbageCollected<IntWrapper>(42);
4750 map->insert(key, AllocatesOnAssignment(103));
4751 map->erase(key);
4752 for (int i = 0; i < 10; i++)
4753 map->insert(AllocatesOnAssignment(i), AllocatesOnAssignment(i));
4754 for (Map::iterator it = map->begin(); it != map->end(); ++it)
4755 EXPECT_EQ(it->key.Value(), it->value.Value());
4756 }
4757
4758 class PartObjectWithVirtualMethod {
4759 public:
Trace(Visitor * visitor)4760 virtual void Trace(Visitor* visitor) {}
4761 };
4762
4763 class ObjectWithVirtualPartObject
4764 : public GarbageCollected<ObjectWithVirtualPartObject> {
4765 public:
ObjectWithVirtualPartObject()4766 ObjectWithVirtualPartObject() : dummy_(AllocateAndReturnBool()) {}
Trace(Visitor * visitor)4767 void Trace(Visitor* visitor) { visitor->Trace(part_); }
4768
4769 private:
4770 bool dummy_;
4771 PartObjectWithVirtualMethod part_;
4772 };
4773
TEST_F(HeapTest,PartObjectWithVirtualMethod)4774 TEST_F(HeapTest, PartObjectWithVirtualMethod) {
4775 ObjectWithVirtualPartObject* object =
4776 MakeGarbageCollected<ObjectWithVirtualPartObject>();
4777 EXPECT_TRUE(object);
4778 }
4779
4780 class AllocInSuperConstructorArgumentSuper
4781 : public GarbageCollected<AllocInSuperConstructorArgumentSuper> {
4782 public:
AllocInSuperConstructorArgumentSuper(bool value)4783 AllocInSuperConstructorArgumentSuper(bool value) : value_(value) {}
4784 virtual ~AllocInSuperConstructorArgumentSuper() = default;
Trace(Visitor * visitor)4785 virtual void Trace(Visitor* visitor) {}
Value()4786 bool Value() { return value_; }
4787
4788 private:
4789 bool value_;
4790 };
4791
4792 class AllocInSuperConstructorArgument
4793 : public AllocInSuperConstructorArgumentSuper {
4794 public:
AllocInSuperConstructorArgument()4795 AllocInSuperConstructorArgument()
4796 : AllocInSuperConstructorArgumentSuper(AllocateAndReturnBool()) {}
4797 };
4798
4799 // Regression test for crbug.com/404511. Tests conservative marking of
4800 // an object with an uninitialized vtable.
TEST_F(HeapTest,AllocationInSuperConstructorArgument)4801 TEST_F(HeapTest, AllocationInSuperConstructorArgument) {
4802 AllocInSuperConstructorArgument* object =
4803 MakeGarbageCollected<AllocInSuperConstructorArgument>();
4804 EXPECT_TRUE(object);
4805 ThreadState::Current()->CollectAllGarbageForTesting();
4806 }
4807
4808 class NonNodeAllocatingNodeInDestructor final
4809 : public GarbageCollected<NonNodeAllocatingNodeInDestructor> {
4810 public:
~NonNodeAllocatingNodeInDestructor()4811 ~NonNodeAllocatingNodeInDestructor() {
4812 node_ = new Persistent<IntNode>(IntNode::Create(10));
4813 }
4814
Trace(Visitor * visitor)4815 void Trace(Visitor* visitor) {}
4816
4817 static Persistent<IntNode>* node_;
4818 };
4819
4820 Persistent<IntNode>* NonNodeAllocatingNodeInDestructor::node_ = nullptr;
4821
TEST_F(HeapTest,NonNodeAllocatingNodeInDestructor)4822 TEST_F(HeapTest, NonNodeAllocatingNodeInDestructor) {
4823 MakeGarbageCollected<NonNodeAllocatingNodeInDestructor>();
4824 PreciselyCollectGarbage();
4825 EXPECT_EQ(10, (*NonNodeAllocatingNodeInDestructor::node_)->Value());
4826 delete NonNodeAllocatingNodeInDestructor::node_;
4827 NonNodeAllocatingNodeInDestructor::node_ = nullptr;
4828 }
4829
4830 class DeepEagerly final : public GarbageCollected<DeepEagerly> {
4831 public:
DeepEagerly(DeepEagerly * next)4832 DeepEagerly(DeepEagerly* next) : next_(next) {}
4833
Trace(Visitor * visitor)4834 void Trace(Visitor* visitor) {
4835 int calls = ++s_trace_calls_;
4836 if (s_trace_lazy_ <= 2)
4837 visitor->Trace(next_);
4838 if (s_trace_calls_ == calls)
4839 s_trace_lazy_++;
4840 }
4841
4842 Member<DeepEagerly> next_;
4843
4844 static int s_trace_calls_;
4845 static int s_trace_lazy_;
4846 };
4847
4848 int DeepEagerly::s_trace_calls_ = 0;
4849 int DeepEagerly::s_trace_lazy_ = 0;
4850
TEST_F(HeapTest,TraceDeepEagerly)4851 TEST_F(HeapTest, TraceDeepEagerly) {
4852 // The allocation & GC overhead is considerable for this test,
4853 // straining debug builds and lower-end targets too much to be
4854 // worth running.
4855 #if !DCHECK_IS_ON() && !defined(OS_ANDROID)
4856 DeepEagerly* obj = nullptr;
4857 for (int i = 0; i < 10000000; i++)
4858 obj = MakeGarbageCollected<DeepEagerly>(obj);
4859
4860 Persistent<DeepEagerly> persistent(obj);
4861 PreciselyCollectGarbage();
4862
4863 // Verify that the DeepEagerly chain isn't completely unravelled
4864 // by performing eager trace() calls, but the explicit mark
4865 // stack is switched once some nesting limit is exceeded.
4866 EXPECT_GT(DeepEagerly::s_trace_lazy_, 2);
4867 #endif
4868 }
4869
TEST_F(HeapTest,DequeExpand)4870 TEST_F(HeapTest, DequeExpand) {
4871 // Test expansion of a HeapDeque<>'s buffer.
4872
4873 typedef HeapDeque<Member<IntWrapper>> IntDeque;
4874
4875 Persistent<IntDeque> deque = MakeGarbageCollected<IntDeque>();
4876
4877 // Append a sequence, bringing about repeated expansions of the
4878 // deque's buffer.
4879 int i = 0;
4880 for (; i < 60; ++i)
4881 deque->push_back(MakeGarbageCollected<IntWrapper>(i));
4882
4883 EXPECT_EQ(60u, deque->size());
4884 i = 0;
4885 for (const auto& int_wrapper : *deque) {
4886 EXPECT_EQ(i, int_wrapper->Value());
4887 i++;
4888 }
4889
4890 // Remove most of the queued objects and have the buffer's start index
4891 // 'point' somewhere into the buffer, just behind the end index.
4892 for (i = 0; i < 50; ++i)
4893 deque->TakeFirst();
4894
4895 EXPECT_EQ(10u, deque->size());
4896 i = 0;
4897 for (const auto& int_wrapper : *deque) {
4898 EXPECT_EQ(50 + i, int_wrapper->Value());
4899 i++;
4900 }
4901
4902 // Append even more, eventually causing an expansion of the underlying
4903 // buffer once the end index wraps around and reaches the start index.
4904 for (i = 0; i < 70; ++i)
4905 deque->push_back(MakeGarbageCollected<IntWrapper>(60 + i));
4906
4907 // Verify that the final buffer expansion copied the start and end segments
4908 // of the old buffer to both ends of the expanded buffer, along with
4909 // re-adjusting both start&end indices in terms of that expanded buffer.
4910 EXPECT_EQ(80u, deque->size());
4911 i = 0;
4912 for (const auto& int_wrapper : *deque) {
4913 EXPECT_EQ(i + 50, int_wrapper->Value());
4914 i++;
4915 }
4916 }
4917
4918 class SimpleRefValue : public RefCounted<SimpleRefValue> {
4919 public:
Create(int i)4920 static scoped_refptr<SimpleRefValue> Create(int i) {
4921 return base::AdoptRef(new SimpleRefValue(i));
4922 }
4923
Value() const4924 int Value() const { return value_; }
4925
4926 private:
SimpleRefValue(int value)4927 explicit SimpleRefValue(int value) : value_(value) {}
4928
4929 int value_;
4930 };
4931
4932 class PartObjectWithRef {
4933 DISALLOW_NEW();
4934
4935 public:
PartObjectWithRef(int i)4936 PartObjectWithRef(int i) : value_(SimpleRefValue::Create(i)) {}
4937
Trace(Visitor * visitor)4938 void Trace(Visitor* visitor) {}
4939
Value() const4940 int Value() const { return value_->Value(); }
4941
4942 private:
4943 scoped_refptr<SimpleRefValue> value_;
4944 };
4945
4946 } // namespace blink
4947
4948 WTF_ALLOW_INIT_WITH_MEM_FUNCTIONS(blink::PartObjectWithRef)
4949
4950 namespace blink {
4951
TEST_F(HeapTest,HeapVectorPartObjects)4952 TEST_F(HeapTest, HeapVectorPartObjects) {
4953 HeapVector<PartObjectWithRef> vector1;
4954 HeapVector<PartObjectWithRef> vector2;
4955
4956 for (int i = 0; i < 10; ++i) {
4957 vector1.push_back(PartObjectWithRef(i));
4958 vector2.push_back(PartObjectWithRef(i));
4959 }
4960
4961 vector1.ReserveCapacity(150);
4962 EXPECT_LE(150u, vector1.capacity());
4963 EXPECT_EQ(10u, vector1.size());
4964
4965 vector2.ReserveCapacity(100);
4966 EXPECT_LE(100u, vector2.capacity());
4967 EXPECT_EQ(10u, vector2.size());
4968
4969 for (int i = 0; i < 4; ++i) {
4970 vector1.push_back(PartObjectWithRef(10 + i));
4971 vector2.push_back(PartObjectWithRef(10 + i));
4972 vector2.push_back(PartObjectWithRef(10 + i));
4973 }
4974
4975 // Shrinking heap vector backing stores always succeeds,
4976 // so these two will not currently exercise the code path
4977 // where shrinking causes copying into a new, small buffer.
4978 vector2.ShrinkToReasonableCapacity();
4979 EXPECT_EQ(18u, vector2.size());
4980
4981 vector1.ShrinkToReasonableCapacity();
4982 EXPECT_EQ(14u, vector1.size());
4983 }
4984
4985 class TestMixinAllocationA : public GarbageCollected<TestMixinAllocationA>,
4986 public GarbageCollectedMixin {
4987 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationA);
4988
4989 public:
4990 TestMixinAllocationA() = default;
4991
Trace(Visitor * visitor)4992 void Trace(Visitor* visitor) override {}
4993 };
4994
4995 class TestMixinAllocationB : public TestMixinAllocationA {
4996 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationB);
4997
4998 public:
TestMixinAllocationB()4999 TestMixinAllocationB()
5000 // Construct object during a mixin construction.
5001 : a_(MakeGarbageCollected<TestMixinAllocationA>()) {}
5002
Trace(Visitor * visitor)5003 void Trace(Visitor* visitor) override {
5004 visitor->Trace(a_);
5005 TestMixinAllocationA::Trace(visitor);
5006 }
5007
5008 private:
5009 Member<TestMixinAllocationA> a_;
5010 };
5011
5012 class TestMixinAllocationC final : public TestMixinAllocationB {
5013 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationC);
5014
5015 public:
TestMixinAllocationC()5016 TestMixinAllocationC() { DCHECK(!ThreadState::Current()->IsGCForbidden()); }
5017
Trace(Visitor * visitor)5018 void Trace(Visitor* visitor) override {
5019 TestMixinAllocationB::Trace(visitor);
5020 }
5021 };
5022
TEST_F(HeapTest,NestedMixinConstruction)5023 TEST_F(HeapTest, NestedMixinConstruction) {
5024 TestMixinAllocationC* object = MakeGarbageCollected<TestMixinAllocationC>();
5025 EXPECT_TRUE(object);
5026 }
5027
5028 class ObjectWithLargeAmountsOfAllocationInConstructor {
5029 public:
ObjectWithLargeAmountsOfAllocationInConstructor(size_t number_of_large_objects_to_allocate,ClassWithMember * member)5030 ObjectWithLargeAmountsOfAllocationInConstructor(
5031 size_t number_of_large_objects_to_allocate,
5032 ClassWithMember* member) {
5033 // Should a constructor allocate plenty in its constructor,
5034 // and it is a base of GC mixin, GCs will remain locked out
5035 // regardless, as we cannot safely trace the leftmost GC
5036 // mixin base.
5037 DCHECK(ThreadState::Current()->IsGCForbidden());
5038 for (size_t i = 0; i < number_of_large_objects_to_allocate; i++) {
5039 auto* large_object = MakeGarbageCollected<LargeHeapObject>();
5040 EXPECT_TRUE(large_object);
5041 EXPECT_EQ(0, member->TraceCount());
5042 }
5043 }
5044 };
5045
5046 class WeakPersistentHolder final {
5047 public:
WeakPersistentHolder(IntWrapper * object)5048 explicit WeakPersistentHolder(IntWrapper* object) : object_(object) {}
Object() const5049 IntWrapper* Object() const { return object_; }
5050
5051 private:
5052 WeakPersistent<IntWrapper> object_;
5053 };
5054
TEST_F(HeapTest,WeakPersistent)5055 TEST_F(HeapTest, WeakPersistent) {
5056 Persistent<IntWrapper> object = MakeGarbageCollected<IntWrapper>(20);
5057 std::unique_ptr<WeakPersistentHolder> holder =
5058 std::make_unique<WeakPersistentHolder>(object);
5059 PreciselyCollectGarbage();
5060 EXPECT_TRUE(holder->Object());
5061 object = nullptr;
5062 PreciselyCollectGarbage();
5063 EXPECT_FALSE(holder->Object());
5064 }
5065
5066 namespace {
5067
5068 class ThreadedClearOnShutdownTester : public ThreadedTesterBase {
5069 public:
Test()5070 static void Test() {
5071 IntWrapper::destructor_calls_ = 0;
5072 ThreadedTesterBase::Test(new ThreadedClearOnShutdownTester);
5073 EXPECT_EQ(kNumberOfThreads, IntWrapper::destructor_calls_);
5074 }
5075
5076 private:
5077 void RunWhileAttached();
5078
RunThread()5079 void RunThread() override {
5080 EXPECT_EQ(42, ThreadSpecificIntWrapper().Value());
5081 RunWhileAttached();
5082 }
5083
5084 class HeapObject;
5085 friend class HeapObject;
5086
5087 using WeakHeapObjectSet = HeapHashSet<WeakMember<HeapObject>>;
5088
5089 static WeakHeapObjectSet& GetWeakHeapObjectSet();
5090
5091 using HeapObjectSet = HeapHashSet<Member<HeapObject>>;
5092 static HeapObjectSet& GetHeapObjectSet();
5093
ThreadSpecificIntWrapper()5094 static IntWrapper& ThreadSpecificIntWrapper() {
5095 DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<Persistent<IntWrapper>>,
5096 int_wrapper, ());
5097 Persistent<IntWrapper>& handle = *int_wrapper;
5098 if (!handle) {
5099 handle = MakeGarbageCollected<IntWrapper>(42);
5100 handle.RegisterAsStaticReference();
5101 }
5102 return *handle;
5103 }
5104 };
5105
5106 class ThreadedClearOnShutdownTester::HeapObject final
5107 : public GarbageCollected<ThreadedClearOnShutdownTester::HeapObject> {
5108 public:
HeapObject(bool test_destructor)5109 explicit HeapObject(bool test_destructor)
5110 : test_destructor_(test_destructor) {}
~HeapObject()5111 ~HeapObject() {
5112 if (!test_destructor_)
5113 return;
5114
5115 // Verify that the weak reference is gone.
5116 EXPECT_FALSE(GetWeakHeapObjectSet().Contains(this));
5117
5118 // Add a new member to the static singleton; this will
5119 // re-initializes the persistent node of the collection
5120 // object. Done while terminating the test thread, so
5121 // verify that this brings about the release of the
5122 // persistent also.
5123 GetHeapObjectSet().insert(MakeGarbageCollected<HeapObject>(false));
5124 }
5125
Trace(Visitor * visitor)5126 void Trace(Visitor* visitor) {}
5127
5128 private:
5129 bool test_destructor_;
5130 };
5131
5132 ThreadedClearOnShutdownTester::WeakHeapObjectSet&
GetWeakHeapObjectSet()5133 ThreadedClearOnShutdownTester::GetWeakHeapObjectSet() {
5134 DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<Persistent<WeakHeapObjectSet>>,
5135 singleton, ());
5136 Persistent<WeakHeapObjectSet>& singleton_persistent = *singleton;
5137 if (!singleton_persistent) {
5138 singleton_persistent = MakeGarbageCollected<WeakHeapObjectSet>();
5139 singleton_persistent.RegisterAsStaticReference();
5140 }
5141 return *singleton_persistent;
5142 }
5143
5144 ThreadedClearOnShutdownTester::HeapObjectSet&
GetHeapObjectSet()5145 ThreadedClearOnShutdownTester::GetHeapObjectSet() {
5146 DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<Persistent<HeapObjectSet>>,
5147 singleton, ());
5148 Persistent<HeapObjectSet>& singleton_persistent = *singleton;
5149 if (!singleton_persistent) {
5150 singleton_persistent = MakeGarbageCollected<HeapObjectSet>();
5151 singleton_persistent.RegisterAsStaticReference();
5152 }
5153 return *singleton_persistent;
5154 }
5155
RunWhileAttached()5156 void ThreadedClearOnShutdownTester::RunWhileAttached() {
5157 EXPECT_EQ(42, ThreadSpecificIntWrapper().Value());
5158 // Creates a thread-specific singleton to a weakly held object.
5159 GetWeakHeapObjectSet().insert(MakeGarbageCollected<HeapObject>(true));
5160 }
5161
5162 } // namespace
5163
TEST_F(HeapTest,TestClearOnShutdown)5164 TEST_F(HeapTest, TestClearOnShutdown) {
5165 ThreadedClearOnShutdownTester::Test();
5166 }
5167
5168 // Verify that WeakMember<const T> compiles and behaves as expected.
5169 class WithWeakConstObject final : public GarbageCollected<WithWeakConstObject> {
5170 public:
WithWeakConstObject(const IntWrapper * int_wrapper)5171 WithWeakConstObject(const IntWrapper* int_wrapper) : wrapper_(int_wrapper) {}
5172
Trace(Visitor * visitor)5173 void Trace(Visitor* visitor) { visitor->Trace(wrapper_); }
5174
Value() const5175 const IntWrapper* Value() const { return wrapper_; }
5176
5177 private:
5178 WeakMember<const IntWrapper> wrapper_;
5179 };
5180
TEST_F(HeapTest,TestWeakConstObject)5181 TEST_F(HeapTest, TestWeakConstObject) {
5182 Persistent<WithWeakConstObject> weak_wrapper;
5183 {
5184 const auto* wrapper = MakeGarbageCollected<IntWrapper>(42);
5185 weak_wrapper = MakeGarbageCollected<WithWeakConstObject>(wrapper);
5186 ConservativelyCollectGarbage();
5187 EXPECT_EQ(wrapper, weak_wrapper->Value());
5188 // Stub out any stack reference.
5189 wrapper = nullptr;
5190 }
5191 PreciselyCollectGarbage();
5192 EXPECT_EQ(nullptr, weak_wrapper->Value());
5193 }
5194
5195 class EmptyMixin : public GarbageCollectedMixin {};
5196 class UseMixinFromLeftmostInherited : public UseMixin, public EmptyMixin {
5197 public:
5198 ~UseMixinFromLeftmostInherited() = default;
5199 };
5200
TEST_F(HeapTest,IsGarbageCollected)5201 TEST_F(HeapTest, IsGarbageCollected) {
5202 // Static sanity checks covering the correct operation of
5203 // IsGarbageCollectedType<>.
5204
5205 static_assert(WTF::IsGarbageCollectedType<SimpleObject>::value,
5206 "GarbageCollected<>");
5207 static_assert(WTF::IsGarbageCollectedType<const SimpleObject>::value,
5208 "const GarbageCollected<>");
5209 static_assert(WTF::IsGarbageCollectedType<IntWrapper>::value,
5210 "GarbageCollected<>");
5211 static_assert(WTF::IsGarbageCollectedType<GarbageCollectedMixin>::value,
5212 "GarbageCollectedMixin");
5213 static_assert(WTF::IsGarbageCollectedType<const GarbageCollectedMixin>::value,
5214 "const GarbageCollectedMixin");
5215 static_assert(WTF::IsGarbageCollectedType<UseMixin>::value,
5216 "GarbageCollectedMixin instance");
5217 static_assert(WTF::IsGarbageCollectedType<const UseMixin>::value,
5218 "const GarbageCollectedMixin instance");
5219 static_assert(
5220 WTF::IsGarbageCollectedType<UseMixinFromLeftmostInherited>::value,
5221 "GarbageCollectedMixin derived instance");
5222 static_assert(WTF::IsGarbageCollectedType<MultipleMixins>::value,
5223 "GarbageCollectedMixin");
5224
5225 static_assert(
5226 WTF::IsGarbageCollectedType<HeapHashSet<Member<IntWrapper>>>::value,
5227 "HeapHashSet");
5228 static_assert(
5229 WTF::IsGarbageCollectedType<HeapLinkedHashSet<Member<IntWrapper>>>::value,
5230 "HeapLinkedHashSet");
5231 static_assert(WTF::IsGarbageCollectedType<
5232 HeapNewLinkedHashSet<Member<IntWrapper>>>::value,
5233 "HeapNewLinkedHashSet");
5234 static_assert(
5235 WTF::IsGarbageCollectedType<HeapListHashSet<Member<IntWrapper>>>::value,
5236 "HeapListHashSet");
5237 static_assert(WTF::IsGarbageCollectedType<
5238 HeapHashCountedSet<Member<IntWrapper>>>::value,
5239 "HeapHashCountedSet");
5240 static_assert(
5241 WTF::IsGarbageCollectedType<HeapHashMap<int, Member<IntWrapper>>>::value,
5242 "HeapHashMap");
5243 static_assert(
5244 WTF::IsGarbageCollectedType<HeapVector<Member<IntWrapper>>>::value,
5245 "HeapVector");
5246 static_assert(
5247 WTF::IsGarbageCollectedType<HeapDeque<Member<IntWrapper>>>::value,
5248 "HeapDeque");
5249 }
5250
TEST_F(HeapTest,HeapHashMapCallsDestructor)5251 TEST_F(HeapTest, HeapHashMapCallsDestructor) {
5252 String string = "string";
5253 EXPECT_TRUE(string.Impl()->HasOneRef());
5254
5255 HeapHashMap<KeyWithCopyingMoveConstructor, Member<IntWrapper>> map;
5256
5257 EXPECT_TRUE(string.Impl()->HasOneRef());
5258
5259 for (int i = 1; i <= 100; ++i) {
5260 KeyWithCopyingMoveConstructor key(i, string);
5261 map.insert(key, MakeGarbageCollected<IntWrapper>(i));
5262 }
5263
5264 EXPECT_FALSE(string.Impl()->HasOneRef());
5265 map.clear();
5266
5267 EXPECT_TRUE(string.Impl()->HasOneRef());
5268 }
5269
TEST_F(HeapTest,ShrinkVector)5270 TEST_F(HeapTest, ShrinkVector) {
5271 // Regression test: https://crbug.com/823289
5272
5273 HeapVector<Member<IntWrapper>> vector;
5274 vector.ReserveCapacity(32);
5275 for (int i = 0; i < 4; i++) {
5276 vector.push_back(MakeGarbageCollected<IntWrapper>(i));
5277 }
5278
5279 ConservativelyCollectGarbage(BlinkGC::kConcurrentAndLazySweeping);
5280
5281 // The following call tries to promptly free the left overs. In the buggy
5282 // scenario that would create a free HeapObjectHeader that is assumed to be
5283 // black which it is not.
5284 vector.ShrinkToFit();
5285 }
5286
TEST_F(HeapTest,GarbageCollectedInConstruction)5287 TEST_F(HeapTest, GarbageCollectedInConstruction) {
5288 using O = ObjectWithCallbackBeforeInitializer<IntWrapper>;
5289 MakeGarbageCollected<O>(base::BindOnce([](O* thiz) {
5290 CHECK(HeapObjectHeader::FromPayload(thiz)->IsInConstruction());
5291 }));
5292 }
5293
TEST_F(HeapTest,GarbageCollectedMixinInConstruction)5294 TEST_F(HeapTest, GarbageCollectedMixinInConstruction) {
5295 using O = ObjectWithMixinWithCallbackBeforeInitializer<IntWrapper>;
5296 MakeGarbageCollected<O>(base::BindOnce([](O::Mixin* thiz) {
5297 const HeapObjectHeader* const header =
5298 HeapObjectHeader::FromInnerAddress(reinterpret_cast<Address>(thiz));
5299 CHECK(header->IsInConstruction());
5300 }));
5301 }
5302
TEST_F(HeapTest,GarbageCollectedMixinIsAliveDuringConstruction)5303 TEST_F(HeapTest, GarbageCollectedMixinIsAliveDuringConstruction) {
5304 using O = ObjectWithMixinWithCallbackBeforeInitializer<IntWrapper>;
5305 MakeGarbageCollected<O>(base::BindOnce(
5306 [](O::Mixin* thiz) { CHECK(ThreadHeap::IsHeapObjectAlive(thiz)); }));
5307
5308 using P = HeapVector<Member<HeapLinkedHashSet<Member<IntWrapper>>>>;
5309 MakeGarbageCollected<P>();
5310 using Q = HeapVector<Member<HeapNewLinkedHashSet<Member<IntWrapper>>>>;
5311 MakeGarbageCollected<Q>();
5312 }
5313
TEST_F(HeapTest,PersistentAssignsDeletedValue)5314 TEST_F(HeapTest, PersistentAssignsDeletedValue) {
5315 // Regression test: https://crbug.com/982313
5316
5317 Persistent<IntWrapper> deleted(WTF::kHashTableDeletedValue);
5318 Persistent<IntWrapper> pre_initialized(MakeGarbageCollected<IntWrapper>(1));
5319 pre_initialized = deleted;
5320 PreciselyCollectGarbage();
5321 }
5322
5323 struct HeapHashMapWrapper final : GarbageCollected<HeapHashMapWrapper> {
HeapHashMapWrapperblink::HeapHashMapWrapper5324 HeapHashMapWrapper() {
5325 for (int i = 0; i < 100; ++i) {
5326 map_.insert(MakeGarbageCollected<IntWrapper>(i),
5327 NonTriviallyDestructible());
5328 }
5329 }
5330 // This should call ~HeapHapMap() -> ~HashMap() -> ~HashTable().
5331 ~HeapHashMapWrapper() = default;
5332
Traceblink::HeapHashMapWrapper5333 void Trace(Visitor* visitor) { visitor->Trace(map_); }
5334
5335 private:
5336 struct NonTriviallyDestructible {
~NonTriviallyDestructibleblink::HeapHashMapWrapper::NonTriviallyDestructible5337 ~NonTriviallyDestructible() {}
5338 };
5339 HeapHashMap<Member<IntWrapper>, NonTriviallyDestructible> map_;
5340 };
5341
TEST_F(HeapTest,AccessDeletedBackingStore)5342 TEST_F(HeapTest, AccessDeletedBackingStore) {
5343 // Regression test: https://crbug.com/985443
5344 base::test::ScopedFeatureList scoped_feature_list;
5345 scoped_feature_list.InitAndDisableFeature(
5346 blink::features::kBlinkHeapConcurrentSweeping);
5347 ClearOutOldGarbage();
5348
5349 ThreadState* thread_state = ThreadState::Current();
5350
5351 auto* map = MakeGarbageCollected<HeapHashMapWrapper>();
5352 // Run marking.
5353 PreciselyCollectGarbage(BlinkGC::kConcurrentAndLazySweeping);
5354 // Perform complete sweep on hash_arena.
5355 BaseArena* hash_arena =
5356 thread_state->Heap().Arena(BlinkGC::kHashTableArenaIndex);
5357 {
5358 ThreadState::AtomicPauseScope scope(thread_state);
5359 ScriptForbiddenScope script_forbidden_scope;
5360 ThreadState::SweepForbiddenScope sweep_forbidden(thread_state);
5361 hash_arena->CompleteSweep();
5362 }
5363 BaseArena* map_arena = PageFromObject(map)->Arena();
5364 // Sweep normal arena, but don't call finalizers.
5365 while (!map_arena->ConcurrentSweepOnePage()) {
5366 }
5367 // Now complete sweeping with PerformIdleLazySweep and call finalizers.
5368 while (thread_state->IsSweepingInProgress()) {
5369 thread_state->PerformIdleLazySweep(base::TimeTicks::Max());
5370 }
5371 }
5372
5373 class GCBase : public GarbageCollected<GCBase> {
5374 public:
Trace(Visitor *)5375 virtual void Trace(Visitor*) {}
5376 };
5377
5378 class GCDerived final : public GCBase {
5379 public:
5380 static int destructor_called;
Trace(Visitor *)5381 void Trace(Visitor*) override {}
~GCDerived()5382 ~GCDerived() { ++destructor_called; }
5383 };
5384
5385 int GCDerived::destructor_called = 0;
5386
TEST_F(HeapTest,CallMostDerivedFinalizer)5387 TEST_F(HeapTest, CallMostDerivedFinalizer) {
5388 MakeGarbageCollected<GCDerived>();
5389 PreciselyCollectGarbage();
5390 EXPECT_EQ(1, GCDerived::destructor_called);
5391 }
5392
5393 #if defined(ADDRESS_SANITIZER)
TEST(HeapDeathTest,DieOnPoisonedObjectHeaderAccess)5394 TEST(HeapDeathTest, DieOnPoisonedObjectHeaderAccess) {
5395 auto* ptr = MakeGarbageCollected<IntWrapper>(1);
5396 HeapObjectHeader* header = HeapObjectHeader::FromPayload(ptr);
5397 auto* low = reinterpret_cast<uint16_t*>(header);
5398 auto access = [low] {
5399 volatile uint16_t half = WTF::AsAtomicPtr(low)->load();
5400 WTF::AsAtomicPtr(low)->store(half);
5401 };
5402 EXPECT_DEATH(access(), "");
5403 }
5404
TEST_F(HeapTest,SuccessfulUnsanitizedAccessToObjectHeader)5405 TEST_F(HeapTest, SuccessfulUnsanitizedAccessToObjectHeader) {
5406 auto* ptr = MakeGarbageCollected<IntWrapper>(1);
5407 HeapObjectHeader* header = HeapObjectHeader::FromPayload(ptr);
5408 auto* low = reinterpret_cast<uint16_t*>(header);
5409 volatile uint16_t half = internal::AsUnsanitizedAtomic(low)->load();
5410 internal::AsUnsanitizedAtomic(low)->store(half);
5411 }
5412 #endif // ADDRESS_SANITIZER
5413
5414 } // namespace blink
5415