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 "config.h"
32
33 #include "platform/heap/Handle.h"
34 #include "platform/heap/Heap.h"
35 #include "platform/heap/HeapLinkedStack.h"
36 #include "platform/heap/HeapTerminatedArrayBuilder.h"
37 #include "platform/heap/ThreadState.h"
38 #include "platform/heap/Visitor.h"
39 #include "public/platform/Platform.h"
40 #include "wtf/HashTraits.h"
41 #include "wtf/LinkedHashSet.h"
42
43 #include <gtest/gtest.h>
44
45 namespace WebCore {
46
47 class IntWrapper : public GarbageCollectedFinalized<IntWrapper> {
48 public:
create(int x)49 static IntWrapper* create(int x)
50 {
51 return new IntWrapper(x);
52 }
53
~IntWrapper()54 virtual ~IntWrapper()
55 {
56 ++s_destructorCalls;
57 }
58
59 static int s_destructorCalls;
trace(Visitor *)60 static void trace(Visitor*) { }
61
value() const62 int value() const { return m_x; }
63
operator ==(const IntWrapper & other) const64 bool operator==(const IntWrapper& other) const { return other.value() == value(); }
65
hash()66 unsigned hash() { return IntHash<int>::hash(m_x); }
67
68 protected:
IntWrapper(int x)69 IntWrapper(int x) : m_x(x) { }
70
71 private:
72 IntWrapper();
73 int m_x;
74 };
75
76 USED_FROM_MULTIPLE_THREADS(IntWrapper);
77
78 class ThreadMarker {
79 public:
ThreadMarker()80 ThreadMarker() : m_creatingThread(reinterpret_cast<ThreadState*>(0)), m_num(0) { }
ThreadMarker(unsigned i)81 ThreadMarker(unsigned i) : m_creatingThread(ThreadState::current()), m_num(i) { }
ThreadMarker(WTF::HashTableDeletedValueType deleted)82 ThreadMarker(WTF::HashTableDeletedValueType deleted) : m_creatingThread(reinterpret_cast<ThreadState*>(-1)), m_num(0) { }
~ThreadMarker()83 ~ThreadMarker()
84 {
85 EXPECT_TRUE((m_creatingThread == ThreadState::current())
86 || (m_creatingThread == reinterpret_cast<ThreadState*>(0))
87 || (m_creatingThread == reinterpret_cast<ThreadState*>(-1)));
88 }
isHashTableDeletedValue() const89 bool isHashTableDeletedValue() const { return m_creatingThread == reinterpret_cast<ThreadState*>(-1); }
operator ==(const ThreadMarker & other) const90 bool operator==(const ThreadMarker& other) const { return other.m_creatingThread == m_creatingThread && other.m_num == m_num; }
91 ThreadState* m_creatingThread;
92 unsigned m_num;
93 };
94
95 struct ThreadMarkerHash {
hashWebCore::ThreadMarkerHash96 static unsigned hash(const ThreadMarker& key)
97 {
98 return static_cast<unsigned>(reinterpret_cast<uintptr_t>(key.m_creatingThread) + key.m_num);
99 }
100
equalWebCore::ThreadMarkerHash101 static bool equal(const ThreadMarker& a, const ThreadMarker& b)
102 {
103 return a == b;
104 }
105
106 static const bool safeToCompareToEmptyOrDeleted = false;
107 };
108
109 typedef std::pair<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeakPair;
110
111 struct PairWithWeakHandling : public StrongWeakPair {
112 ALLOW_ONLY_INLINE_ALLOCATION();
113
114 public:
115 // Regular constructor.
PairWithWeakHandlingWebCore::PairWithWeakHandling116 PairWithWeakHandling(IntWrapper* one, IntWrapper* two)
117 : StrongWeakPair(one, two)
118 {
119 ASSERT(one); // We use null first field to indicate empty slots in the hash table.
120 }
121
122 // The HashTable (via the HashTrait) calls this constructor with a
123 // placement new to mark slots in the hash table as being deleted. We will
124 // never call trace or the destructor on these slots. We mark ourselves deleted
125 // with a pointer to -1 in the first field.
PairWithWeakHandlingWebCore::PairWithWeakHandling126 PairWithWeakHandling(WTF::HashTableDeletedValueType)
127 : StrongWeakPair(reinterpret_cast<IntWrapper*>(-1), nullptr)
128 {
129 }
130
131 // Used by the HashTable (via the HashTrait) to skip deleted slots in the
132 // table. Recognizes objects that were 'constructed' using the above
133 // constructor.
isHashTableDeletedValueWebCore::PairWithWeakHandling134 bool isHashTableDeletedValue() const { return first == reinterpret_cast<IntWrapper*>(-1); }
135
136 // Since we don't allocate independent objects of this type, we don't need
137 // a regular trace method. Instead, we use a traceInCollection method.
traceInCollectionWebCore::PairWithWeakHandling138 void traceInCollection(Visitor* visitor, ShouldWeakPointersBeMarkedStrongly strongify)
139 {
140 visitor->trace(first);
141 visitor->traceInCollection(second, strongify);
142 }
143 // The traceInCollection may not trace the weak members, so it is vital
144 // that shouldRemoveFromCollection checks them so the entry can be removed
145 // from the collection (otherwise it would contain a dangling pointer).
shouldRemoveFromCollectionWebCore::PairWithWeakHandling146 bool shouldRemoveFromCollection(Visitor* visitor)
147 {
148 return !visitor->isAlive(second);
149 }
150 };
151
152 }
153
154 namespace WTF {
155
156 template<typename T> struct DefaultHash;
157 template<> struct DefaultHash<WebCore::ThreadMarker> {
158 typedef WebCore::ThreadMarkerHash Hash;
159 };
160
161 // ThreadMarkerHash is the default hash for ThreadMarker
162 template<> struct HashTraits<WebCore::ThreadMarker> : GenericHashTraits<WebCore::ThreadMarker> {
163 static const bool emptyValueIsZero = true;
constructDeletedValueWTF::HashTraits164 static void constructDeletedValue(WebCore::ThreadMarker& slot) { new (NotNull, &slot) WebCore::ThreadMarker(HashTableDeletedValue); }
isDeletedValueWTF::HashTraits165 static bool isDeletedValue(const WebCore::ThreadMarker& slot) { return slot.isHashTableDeletedValue(); }
166 };
167
168 // The hash algorithm for our custom pair class is just the standard double
169 // hash for pairs. Note that this means you can't mutate either of the parts of
170 // the pair while they are in the hash table, as that would change their hash
171 // code and thus their preferred placement in the table.
172 template<> struct DefaultHash<WebCore::PairWithWeakHandling> {
173 typedef PairHash<WebCore::Member<WebCore::IntWrapper>, WebCore::WeakMember<WebCore::IntWrapper> > Hash;
174 };
175
176 // Custom traits for the pair. These are weakness handling traits, which means
177 // PairWithWeakHandling must implement the traceInCollection and
178 // shouldRemoveFromCollection methods. In addition, these traits are concerned
179 // with the two magic values for the object, that represent empty and deleted
180 // slots in the hash table. The SimpleClassHashTraits allow empty slots in the
181 // table to be initialzed with memset to zero, and we use -1 in the first part
182 // of the pair to represent deleted slots.
183 template<> struct HashTraits<WebCore::PairWithWeakHandling> : WebCore::WeakHandlingHashTraits<WebCore::PairWithWeakHandling> {
184 static const bool needsDestruction = false;
185 static const bool hasIsEmptyValueFunction = true;
isEmptyValueWTF::HashTraits186 static bool isEmptyValue(const WebCore::PairWithWeakHandling& value) { return !value.first; }
constructDeletedValueWTF::HashTraits187 static void constructDeletedValue(WebCore::PairWithWeakHandling& slot) { new (NotNull, &slot) WebCore::PairWithWeakHandling(HashTableDeletedValue); }
isDeletedValueWTF::HashTraits188 static bool isDeletedValue(const WebCore::PairWithWeakHandling& value) { return value.isHashTableDeletedValue(); }
189 };
190
191 }
192
193 namespace WebCore {
194
195 class TestGCScope {
196 public:
TestGCScope(ThreadState::StackState state)197 explicit TestGCScope(ThreadState::StackState state)
198 : m_state(ThreadState::current())
199 , m_safePointScope(state)
200 , m_parkedAllThreads(false)
201 {
202 m_state->checkThread();
203 EXPECT_FALSE(m_state->isInGC());
204 if (LIKELY(ThreadState::stopThreads())) {
205 m_state->enterGC();
206 m_parkedAllThreads = true;
207 }
208 }
209
allThreadsParked()210 bool allThreadsParked() { return m_parkedAllThreads; }
211
~TestGCScope()212 ~TestGCScope()
213 {
214 // Only cleanup if we parked all threads in which case the GC happened
215 // and we need to resume the other threads.
216 if (LIKELY(m_parkedAllThreads)) {
217 m_state->leaveGC();
218 EXPECT_FALSE(m_state->isInGC());
219 ThreadState::resumeThreads();
220 }
221 }
222
223 private:
224 ThreadState* m_state;
225 ThreadState::SafePointScope m_safePointScope;
226 bool m_parkedAllThreads; // False if we fail to park all threads
227 };
228
getHeapStats(HeapStats * stats)229 static void getHeapStats(HeapStats* stats)
230 {
231 TestGCScope scope(ThreadState::NoHeapPointersOnStack);
232 EXPECT_TRUE(scope.allThreadsParked());
233 Heap::getStats(stats);
234 }
235
236 #define DEFINE_VISITOR_METHODS(Type) \
237 virtual void mark(const Type* object, TraceCallback callback) OVERRIDE \
238 { \
239 if (object) \
240 m_count++; \
241 } \
242 virtual bool isMarked(const Type*) OVERRIDE { return false; }
243
244 class CountingVisitor : public Visitor {
245 public:
CountingVisitor()246 CountingVisitor()
247 : m_count(0)
248 {
249 }
250
mark(const void * object,TraceCallback)251 virtual void mark(const void* object, TraceCallback) OVERRIDE
252 {
253 if (object)
254 m_count++;
255 }
256
mark(HeapObjectHeader * header,TraceCallback callback)257 virtual void mark(HeapObjectHeader* header, TraceCallback callback) OVERRIDE
258 {
259 ASSERT(header->payload());
260 m_count++;
261 }
262
mark(FinalizedHeapObjectHeader * header,TraceCallback callback)263 virtual void mark(FinalizedHeapObjectHeader* header, TraceCallback callback) OVERRIDE
264 {
265 ASSERT(header->payload());
266 m_count++;
267 }
268
markConservatively(HeapObjectHeader * header)269 virtual void markConservatively(HeapObjectHeader* header) OVERRIDE
270 {
271 ASSERT_NOT_REACHED();
272 }
273
markConservatively(FinalizedHeapObjectHeader * header)274 virtual void markConservatively(FinalizedHeapObjectHeader* header) OVERRIDE
275 {
276 ASSERT_NOT_REACHED();
277 }
278
registerWeakMembers(const void *,const void *,WeakPointerCallback)279 virtual void registerWeakMembers(const void*, const void*, WeakPointerCallback) OVERRIDE { }
registerWeakCell(void **,WeakPointerCallback)280 virtual void registerWeakCell(void**, WeakPointerCallback) OVERRIDE { }
isMarked(const void *)281 virtual bool isMarked(const void*) OVERRIDE { return false; }
282
FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS)283 FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS)
284
285 size_t count() { return m_count; }
reset()286 void reset() { m_count = 0; }
287
288 private:
289 size_t m_count;
290 };
291
292 class SimpleObject : public GarbageCollected<SimpleObject> {
293 public:
create()294 static SimpleObject* create() { return new SimpleObject(); }
trace(Visitor *)295 void trace(Visitor*) { }
getPayload(int i)296 char getPayload(int i) { return payload[i]; }
297 // This virtual method is unused but it is here to make sure
298 // that this object has a vtable. This object is used
299 // as the super class for objects that also have garbage
300 // collected mixins and having a virtual here makes sure
301 // that adjustment is needed both for marking and for isAlive
302 // checks.
virtualMethod()303 virtual void virtualMethod() { }
304 protected:
SimpleObject()305 SimpleObject() { }
306 char payload[64];
307 };
308
309 #undef DEFINE_VISITOR_METHODS
310
311 class HeapTestSuperClass : public GarbageCollectedFinalized<HeapTestSuperClass> {
312 public:
create()313 static HeapTestSuperClass* create()
314 {
315 return new HeapTestSuperClass();
316 }
317
~HeapTestSuperClass()318 virtual ~HeapTestSuperClass()
319 {
320 ++s_destructorCalls;
321 }
322
323 static int s_destructorCalls;
trace(Visitor *)324 void trace(Visitor*) { }
325
326 protected:
HeapTestSuperClass()327 HeapTestSuperClass() { }
328 };
329
330 int HeapTestSuperClass::s_destructorCalls = 0;
331
332 class HeapTestOtherSuperClass {
333 public:
334 int payload;
335 };
336
337 static const size_t classMagic = 0xABCDDBCA;
338
339 class HeapTestSubClass : public HeapTestOtherSuperClass, public HeapTestSuperClass {
340 public:
create()341 static HeapTestSubClass* create()
342 {
343 return new HeapTestSubClass();
344 }
345
~HeapTestSubClass()346 virtual ~HeapTestSubClass()
347 {
348 EXPECT_EQ(classMagic, m_magic);
349 ++s_destructorCalls;
350 }
351
352 static int s_destructorCalls;
353
354 private:
355
HeapTestSubClass()356 HeapTestSubClass() : m_magic(classMagic) { }
357
358 const size_t m_magic;
359 };
360
361 int HeapTestSubClass::s_destructorCalls = 0;
362
363 class HeapAllocatedArray : public GarbageCollected<HeapAllocatedArray> {
364 public:
HeapAllocatedArray()365 HeapAllocatedArray()
366 {
367 for (int i = 0; i < s_arraySize; ++i) {
368 m_array[i] = i % 128;
369 }
370 }
371
at(size_t i)372 int8_t at(size_t i) { return m_array[i]; }
trace(Visitor *)373 void trace(Visitor*) { }
374 private:
375 static const int s_arraySize = 1000;
376 int8_t m_array[s_arraySize];
377 };
378
379 // Do several GCs to make sure that later GCs don't free up old memory from
380 // previously run tests in this process.
clearOutOldGarbage(HeapStats * heapStats)381 static void clearOutOldGarbage(HeapStats* heapStats)
382 {
383 while (true) {
384 getHeapStats(heapStats);
385 size_t used = heapStats->totalObjectSpace();
386 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
387 getHeapStats(heapStats);
388 if (heapStats->totalObjectSpace() >= used)
389 break;
390 }
391 }
392
393 class OffHeapInt : public RefCounted<OffHeapInt> {
394 public:
create(int x)395 static RefPtr<OffHeapInt> create(int x)
396 {
397 return adoptRef(new OffHeapInt(x));
398 }
399
~OffHeapInt()400 virtual ~OffHeapInt()
401 {
402 ++s_destructorCalls;
403 }
404
405 static int s_destructorCalls;
406
value() const407 int value() const { return m_x; }
408
operator ==(const OffHeapInt & other) const409 bool operator==(const OffHeapInt& other) const { return other.value() == value(); }
410
hash()411 unsigned hash() { return IntHash<int>::hash(m_x); }
voidFunction()412 void voidFunction() { }
413
414 protected:
OffHeapInt(int x)415 OffHeapInt(int x) : m_x(x) { }
416
417 private:
418 OffHeapInt();
419 int m_x;
420 };
421
422 int IntWrapper::s_destructorCalls = 0;
423 int OffHeapInt::s_destructorCalls = 0;
424
425 class ThreadedTesterBase {
426 protected:
test(ThreadedTesterBase * tester)427 static void test(ThreadedTesterBase* tester)
428 {
429 for (int i = 0; i < numberOfThreads; i++)
430 createThread(&threadFunc, tester, "testing thread");
431 while (tester->m_threadsToFinish) {
432 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack);
433 yield();
434 }
435 delete tester;
436 }
437
438 virtual void runThread() = 0;
439
440 protected:
441 static const int numberOfThreads = 10;
442 static const int gcPerThread = 5;
443 static const int numberOfAllocations = 50;
444
ThreadedTesterBase()445 ThreadedTesterBase() : m_gcCount(0), m_threadsToFinish(numberOfThreads)
446 {
447 }
448
~ThreadedTesterBase()449 virtual ~ThreadedTesterBase()
450 {
451 }
452
done() const453 inline bool done() const { return m_gcCount >= numberOfThreads * gcPerThread; }
454
455 volatile int m_gcCount;
456 volatile int m_threadsToFinish;
457
458 private:
threadFunc(void * data)459 static void threadFunc(void* data)
460 {
461 reinterpret_cast<ThreadedTesterBase*>(data)->runThread();
462 }
463 };
464
465 class ThreadedHeapTester : public ThreadedTesterBase {
466 public:
test()467 static void test()
468 {
469 ThreadedTesterBase::test(new ThreadedHeapTester);
470 }
471
472 protected:
runThread()473 virtual void runThread() OVERRIDE
474 {
475 ThreadState::attach();
476
477 int gcCount = 0;
478 while (!done()) {
479 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
480 {
481 Persistent<IntWrapper> wrapper;
482
483 typedef Persistent<IntWrapper, GlobalPersistents> GlobalIntWrapperPersistent;
484 OwnPtr<GlobalIntWrapperPersistent> globalPersistent = adoptPtr(new GlobalIntWrapperPersistent(IntWrapper::create(0x0ed0cabb)));
485
486 for (int i = 0; i < numberOfAllocations; i++) {
487 wrapper = IntWrapper::create(0x0bbac0de);
488 if (!(i % 10)) {
489 globalPersistent = adoptPtr(new GlobalIntWrapperPersistent(IntWrapper::create(0x0ed0cabb)));
490 }
491 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack);
492 yield();
493 }
494
495 if (gcCount < gcPerThread) {
496 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
497 gcCount++;
498 atomicIncrement(&m_gcCount);
499 }
500
501 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
502 EXPECT_EQ(wrapper->value(), 0x0bbac0de);
503 EXPECT_EQ((*globalPersistent)->value(), 0x0ed0cabb);
504 }
505 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack);
506 yield();
507 }
508 ThreadState::detach();
509 atomicDecrement(&m_threadsToFinish);
510 }
511 };
512
513 class ThreadedWeaknessTester : public ThreadedTesterBase {
514 public:
test()515 static void test()
516 {
517 ThreadedTesterBase::test(new ThreadedWeaknessTester);
518 }
519
520 private:
runThread()521 virtual void runThread() OVERRIDE
522 {
523 ThreadState::attach();
524
525 int gcCount = 0;
526 while (!done()) {
527 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
528 {
529 Persistent<HeapHashMap<ThreadMarker, WeakMember<IntWrapper> > > weakMap = new HeapHashMap<ThreadMarker, WeakMember<IntWrapper> >;
530 PersistentHeapHashMap<ThreadMarker, WeakMember<IntWrapper> > weakMap2;
531
532 for (int i = 0; i < numberOfAllocations; i++) {
533 weakMap->add(static_cast<unsigned>(i), IntWrapper::create(0));
534 weakMap2.add(static_cast<unsigned>(i), IntWrapper::create(0));
535 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack);
536 yield();
537 }
538
539 if (gcCount < gcPerThread) {
540 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
541 gcCount++;
542 atomicIncrement(&m_gcCount);
543 }
544
545 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
546 EXPECT_TRUE(weakMap->isEmpty());
547 EXPECT_TRUE(weakMap2.isEmpty());
548 }
549 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack);
550 yield();
551 }
552 ThreadState::detach();
553 atomicDecrement(&m_threadsToFinish);
554 }
555 };
556
557 // The accounting for memory includes the memory used by rounding up object
558 // sizes. This is done in a different way on 32 bit and 64 bit, so we have to
559 // have some slack in the tests.
560 template<typename T>
CheckWithSlack(T expected,T actual,int slack)561 void CheckWithSlack(T expected, T actual, int slack)
562 {
563 EXPECT_LE(expected, actual);
564 EXPECT_GE((intptr_t)expected + slack, (intptr_t)actual);
565 }
566
567 class TraceCounter : public GarbageCollectedFinalized<TraceCounter> {
568 public:
create()569 static TraceCounter* create()
570 {
571 return new TraceCounter();
572 }
573
trace(Visitor *)574 void trace(Visitor*) { m_traceCount++; }
575
traceCount()576 int traceCount() { return m_traceCount; }
577
578 private:
TraceCounter()579 TraceCounter()
580 : m_traceCount(0)
581 {
582 }
583
584 int m_traceCount;
585 };
586
587 class ClassWithMember : public GarbageCollected<ClassWithMember> {
588 public:
create()589 static ClassWithMember* create()
590 {
591 return new ClassWithMember();
592 }
593
trace(Visitor * visitor)594 void trace(Visitor* visitor)
595 {
596 EXPECT_TRUE(visitor->isMarked(this));
597 if (!traceCount())
598 EXPECT_FALSE(visitor->isMarked(m_traceCounter));
599 else
600 EXPECT_TRUE(visitor->isMarked(m_traceCounter));
601
602 visitor->trace(m_traceCounter);
603 }
604
traceCount()605 int traceCount() { return m_traceCounter->traceCount(); }
606
607 private:
ClassWithMember()608 ClassWithMember()
609 : m_traceCounter(TraceCounter::create())
610 { }
611
612 Member<TraceCounter> m_traceCounter;
613 };
614
615 class SimpleFinalizedObject : public GarbageCollectedFinalized<SimpleFinalizedObject> {
616 public:
create()617 static SimpleFinalizedObject* create()
618 {
619 return new SimpleFinalizedObject();
620 }
621
~SimpleFinalizedObject()622 ~SimpleFinalizedObject()
623 {
624 ++s_destructorCalls;
625 }
626
627 static int s_destructorCalls;
628
trace(Visitor *)629 void trace(Visitor*) { }
630
631 private:
SimpleFinalizedObject()632 SimpleFinalizedObject() { }
633 };
634
635 int SimpleFinalizedObject::s_destructorCalls = 0;
636
637 class TestTypedHeapClass : public GarbageCollected<TestTypedHeapClass> {
638 public:
create()639 static TestTypedHeapClass* create()
640 {
641 return new TestTypedHeapClass();
642 }
643
trace(Visitor *)644 void trace(Visitor*) { }
645
646 private:
TestTypedHeapClass()647 TestTypedHeapClass() { }
648 };
649
650 class Bar : public GarbageCollectedFinalized<Bar> {
651 public:
create()652 static Bar* create()
653 {
654 return new Bar();
655 }
656
finalizeGarbageCollectedObject()657 void finalizeGarbageCollectedObject()
658 {
659 EXPECT_TRUE(m_magic == magic);
660 m_magic = 0;
661 s_live--;
662 }
hasBeenFinalized() const663 bool hasBeenFinalized() const { return !m_magic; }
664
trace(Visitor * visitor)665 virtual void trace(Visitor* visitor) { }
666 static unsigned s_live;
667
668 protected:
669 static const int magic = 1337;
670 int m_magic;
671
Bar()672 Bar()
673 : m_magic(magic)
674 {
675 s_live++;
676 }
677 };
678
679 unsigned Bar::s_live = 0;
680
681 class Baz : public GarbageCollected<Baz> {
682 public:
create(Bar * bar)683 static Baz* create(Bar* bar)
684 {
685 return new Baz(bar);
686 }
687
trace(Visitor * visitor)688 void trace(Visitor* visitor)
689 {
690 visitor->trace(m_bar);
691 }
692
clear()693 void clear() { m_bar.release(); }
694
695 // willFinalize is called by FinalizationObserver.
willFinalize()696 void willFinalize()
697 {
698 EXPECT_TRUE(!m_bar->hasBeenFinalized());
699 }
700
701 private:
Baz(Bar * bar)702 explicit Baz(Bar* bar)
703 : m_bar(bar)
704 {
705 }
706
707 Member<Bar> m_bar;
708 };
709
710 class Foo : public Bar {
711 public:
create(Bar * bar)712 static Foo* create(Bar* bar)
713 {
714 return new Foo(bar);
715 }
716
create(Foo * foo)717 static Foo* create(Foo* foo)
718 {
719 return new Foo(foo);
720 }
721
trace(Visitor * visitor)722 virtual void trace(Visitor* visitor) OVERRIDE
723 {
724 if (m_pointsToFoo)
725 visitor->mark(static_cast<Foo*>(m_bar));
726 else
727 visitor->mark(m_bar);
728 }
729
730 private:
Foo(Bar * bar)731 Foo(Bar* bar)
732 : Bar()
733 , m_bar(bar)
734 , m_pointsToFoo(false)
735 {
736 }
737
Foo(Foo * foo)738 Foo(Foo* foo)
739 : Bar()
740 , m_bar(foo)
741 , m_pointsToFoo(true)
742 {
743 }
744
745 Bar* m_bar;
746 bool m_pointsToFoo;
747 };
748
749 class Bars : public Bar {
750 public:
create()751 static Bars* create()
752 {
753 return new Bars();
754 }
755
trace(Visitor * visitor)756 virtual void trace(Visitor* visitor) OVERRIDE
757 {
758 for (unsigned i = 0; i < m_width; i++)
759 visitor->trace(m_bars[i]);
760 }
761
getWidth() const762 unsigned getWidth() const
763 {
764 return m_width;
765 }
766
767 static const unsigned width = 7500;
768 private:
Bars()769 Bars() : m_width(0)
770 {
771 for (unsigned i = 0; i < width; i++) {
772 m_bars[i] = Bar::create();
773 m_width++;
774 }
775 }
776
777 unsigned m_width;
778 Member<Bar> m_bars[width];
779 };
780
781 class ConstructorAllocation : public GarbageCollected<ConstructorAllocation> {
782 public:
create()783 static ConstructorAllocation* create() { return new ConstructorAllocation(); }
784
trace(Visitor * visitor)785 void trace(Visitor* visitor) { visitor->trace(m_intWrapper); }
786
787 private:
ConstructorAllocation()788 ConstructorAllocation()
789 {
790 m_intWrapper = IntWrapper::create(42);
791 }
792
793 Member<IntWrapper> m_intWrapper;
794 };
795
796 class LargeObject : public GarbageCollectedFinalized<LargeObject> {
797 public:
~LargeObject()798 ~LargeObject()
799 {
800 s_destructorCalls++;
801 }
create()802 static LargeObject* create() { return new LargeObject(); }
get(size_t i)803 char get(size_t i) { return m_data[i]; }
set(size_t i,char c)804 void set(size_t i, char c) { m_data[i] = c; }
length()805 size_t length() { return s_length; }
trace(Visitor * visitor)806 void trace(Visitor* visitor)
807 {
808 visitor->trace(m_intWrapper);
809 }
810 static int s_destructorCalls;
811
812 private:
813 static const size_t s_length = 1024*1024;
LargeObject()814 LargeObject()
815 {
816 m_intWrapper = IntWrapper::create(23);
817 }
818 Member<IntWrapper> m_intWrapper;
819 char m_data[s_length];
820 };
821
822 int LargeObject::s_destructorCalls = 0;
823
824 class RefCountedAndGarbageCollected : public RefCountedGarbageCollected<RefCountedAndGarbageCollected> {
825 public:
create()826 static PassRefPtr<RefCountedAndGarbageCollected> create()
827 {
828 return adoptRef(new RefCountedAndGarbageCollected());
829 }
830
~RefCountedAndGarbageCollected()831 ~RefCountedAndGarbageCollected()
832 {
833 ++s_destructorCalls;
834 }
835
836 // These are here with their default implementations so you can break in
837 // them in the debugger.
ref()838 void ref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::ref(); }
deref()839 void deref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::deref(); }
840
trace(Visitor *)841 void trace(Visitor*) { }
842
843 static int s_destructorCalls;
844
845 private:
RefCountedAndGarbageCollected()846 RefCountedAndGarbageCollected()
847 {
848 }
849 };
850
851 int RefCountedAndGarbageCollected::s_destructorCalls = 0;
852
853 class RefCountedAndGarbageCollected2 : public HeapTestOtherSuperClass, public RefCountedGarbageCollected<RefCountedAndGarbageCollected2> {
854 public:
create()855 static RefCountedAndGarbageCollected2* create()
856 {
857 return adoptRefCountedGarbageCollected(new RefCountedAndGarbageCollected2());
858 }
859
~RefCountedAndGarbageCollected2()860 ~RefCountedAndGarbageCollected2()
861 {
862 ++s_destructorCalls;
863 }
864
trace(Visitor *)865 void trace(Visitor*) { }
866
867 static int s_destructorCalls;
868
869 private:
RefCountedAndGarbageCollected2()870 RefCountedAndGarbageCollected2()
871 {
872 }
873 };
874
875 int RefCountedAndGarbageCollected2::s_destructorCalls = 0;
876
877 #define DEFINE_VISITOR_METHODS(Type) \
878 virtual void mark(const Type* object, TraceCallback callback) OVERRIDE \
879 { \
880 mark(object); \
881 } \
882
883 class RefCountedGarbageCollectedVisitor : public CountingVisitor {
884 public:
RefCountedGarbageCollectedVisitor(int expected,void ** objects)885 RefCountedGarbageCollectedVisitor(int expected, void** objects)
886 : m_count(0)
887 , m_expectedCount(expected)
888 , m_expectedObjects(objects)
889 {
890 }
891
mark(const void * ptr)892 void mark(const void* ptr) { markNoTrace(ptr); }
893
markNoTrace(const void * ptr)894 virtual void markNoTrace(const void* ptr)
895 {
896 if (!ptr)
897 return;
898 if (m_count < m_expectedCount)
899 EXPECT_TRUE(expectedObject(ptr));
900 else
901 EXPECT_FALSE(expectedObject(ptr));
902 m_count++;
903 }
904
mark(const void * ptr,TraceCallback)905 virtual void mark(const void* ptr, TraceCallback) OVERRIDE
906 {
907 mark(ptr);
908 }
909
mark(HeapObjectHeader * header,TraceCallback callback)910 virtual void mark(HeapObjectHeader* header, TraceCallback callback) OVERRIDE
911 {
912 mark(header->payload());
913 }
914
mark(FinalizedHeapObjectHeader * header,TraceCallback callback)915 virtual void mark(FinalizedHeapObjectHeader* header, TraceCallback callback) OVERRIDE
916 {
917 mark(header->payload());
918 }
919
validate()920 bool validate() { return m_count >= m_expectedCount; }
reset()921 void reset() { m_count = 0; }
922
923 FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS)
924
925 private:
expectedObject(const void * ptr)926 bool expectedObject(const void* ptr)
927 {
928 for (int i = 0; i < m_expectedCount; i++) {
929 if (m_expectedObjects[i] == ptr)
930 return true;
931 }
932 return false;
933 }
934
935 int m_count;
936 int m_expectedCount;
937 void** m_expectedObjects;
938 };
939
940 #undef DEFINE_VISITOR_METHODS
941
942 class Weak : public Bar {
943 public:
create(Bar * strong,Bar * weak)944 static Weak* create(Bar* strong, Bar* weak)
945 {
946 return new Weak(strong, weak);
947 }
948
trace(Visitor * visitor)949 virtual void trace(Visitor* visitor) OVERRIDE
950 {
951 visitor->trace(m_strongBar);
952 visitor->registerWeakMembers(this, zapWeakMembers);
953 }
954
zapWeakMembers(Visitor * visitor,void * self)955 static void zapWeakMembers(Visitor* visitor, void* self)
956 {
957 reinterpret_cast<Weak*>(self)->zapWeakMembers(visitor);
958 }
959
strongIsThere()960 bool strongIsThere() { return !!m_strongBar; }
weakIsThere()961 bool weakIsThere() { return !!m_weakBar; }
962
963 private:
Weak(Bar * strongBar,Bar * weakBar)964 Weak(Bar* strongBar, Bar* weakBar)
965 : Bar()
966 , m_strongBar(strongBar)
967 , m_weakBar(weakBar)
968 {
969 }
970
zapWeakMembers(Visitor * visitor)971 void zapWeakMembers(Visitor* visitor)
972 {
973 if (!visitor->isAlive(m_weakBar))
974 m_weakBar = 0;
975 }
976
977 Member<Bar> m_strongBar;
978 Bar* m_weakBar;
979 };
980
981 class WithWeakMember : public Bar {
982 public:
create(Bar * strong,Bar * weak)983 static WithWeakMember* create(Bar* strong, Bar* weak)
984 {
985 return new WithWeakMember(strong, weak);
986 }
987
trace(Visitor * visitor)988 virtual void trace(Visitor* visitor) OVERRIDE
989 {
990 visitor->trace(m_strongBar);
991 visitor->trace(m_weakBar);
992 }
993
strongIsThere()994 bool strongIsThere() { return !!m_strongBar; }
weakIsThere()995 bool weakIsThere() { return !!m_weakBar; }
996
997 private:
WithWeakMember(Bar * strongBar,Bar * weakBar)998 WithWeakMember(Bar* strongBar, Bar* weakBar)
999 : Bar()
1000 , m_strongBar(strongBar)
1001 , m_weakBar(weakBar)
1002 {
1003 }
1004
1005 Member<Bar> m_strongBar;
1006 WeakMember<Bar> m_weakBar;
1007 };
1008
1009 class Observable : public GarbageCollectedFinalized<Observable> {
1010 public:
create(Bar * bar)1011 static Observable* create(Bar* bar) { return new Observable(bar); }
~Observable()1012 ~Observable() { m_wasDestructed = true; }
trace(Visitor * visitor)1013 void trace(Visitor* visitor) { visitor->trace(m_bar); }
1014
1015 // willFinalize is called by FinalizationObserver. willFinalize can touch
1016 // other on-heap objects.
willFinalize()1017 void willFinalize()
1018 {
1019 EXPECT_FALSE(m_wasDestructed);
1020 EXPECT_FALSE(m_bar->hasBeenFinalized());
1021 }
1022
1023 private:
Observable(Bar * bar)1024 explicit Observable(Bar* bar)
1025 : m_bar(bar)
1026 , m_wasDestructed(false)
1027 {
1028 }
1029
1030 Member<Bar> m_bar;
1031 bool m_wasDestructed;
1032 };
1033
1034 template <typename T> class FinalizationObserver : public GarbageCollected<FinalizationObserver<T> > {
1035 public:
create(T * data)1036 static FinalizationObserver* create(T* data) { return new FinalizationObserver(data); }
didCallWillFinalize() const1037 bool didCallWillFinalize() const { return m_didCallWillFinalize; }
1038
trace(Visitor * visitor)1039 void trace(Visitor* visitor)
1040 {
1041 visitor->registerWeakMembers(this, zapWeakMembers);
1042 }
1043
1044 private:
FinalizationObserver(T * data)1045 FinalizationObserver(T* data)
1046 : m_data(data)
1047 , m_didCallWillFinalize(false)
1048 {
1049 }
1050
zapWeakMembers(Visitor * visitor,void * self)1051 static void zapWeakMembers(Visitor* visitor, void* self)
1052 {
1053 FinalizationObserver* o = reinterpret_cast<FinalizationObserver*>(self);
1054 if (o->m_data && !visitor->isAlive(o->m_data)) {
1055 o->m_data->willFinalize();
1056 o->m_data = nullptr;
1057 o->m_didCallWillFinalize = true;
1058 }
1059 }
1060
1061 WeakMember<T> m_data;
1062 bool m_didCallWillFinalize;
1063 };
1064
1065 class FinalizationObserverWithHashMap {
1066 public:
1067 typedef HeapHashMap<WeakMember<Observable>, OwnPtr<FinalizationObserverWithHashMap> > ObserverMap;
1068
FinalizationObserverWithHashMap(Observable & target)1069 explicit FinalizationObserverWithHashMap(Observable& target) : m_target(target) { }
~FinalizationObserverWithHashMap()1070 ~FinalizationObserverWithHashMap()
1071 {
1072 m_target.willFinalize();
1073 s_didCallWillFinalize = true;
1074 }
1075
observe(Observable & target)1076 static ObserverMap& observe(Observable& target)
1077 {
1078 ObserverMap& map = observers();
1079 ObserverMap::AddResult result = map.add(&target, nullptr);
1080 if (result.isNewEntry)
1081 result.storedValue->value = adoptPtr(new FinalizationObserverWithHashMap(target));
1082 else
1083 ASSERT(result.storedValue->value);
1084 return map;
1085 }
1086
1087 static bool s_didCallWillFinalize;
1088
1089 private:
observers()1090 static ObserverMap& observers()
1091 {
1092 DEFINE_STATIC_LOCAL(Persistent<ObserverMap>, observerMap, ());
1093 if (!observerMap)
1094 observerMap = new ObserverMap();
1095 return *observerMap;
1096 }
1097
1098 Observable& m_target;
1099 };
1100
1101 bool FinalizationObserverWithHashMap::s_didCallWillFinalize = false;
1102
1103 class SuperClass;
1104
1105 class PointsBack : public RefCountedWillBeGarbageCollectedFinalized<PointsBack> {
1106 public:
create()1107 static PassRefPtrWillBeRawPtr<PointsBack> create()
1108 {
1109 return adoptRefWillBeNoop(new PointsBack());
1110 }
1111
~PointsBack()1112 ~PointsBack()
1113 {
1114 --s_aliveCount;
1115 }
1116
setBackPointer(SuperClass * backPointer)1117 void setBackPointer(SuperClass* backPointer)
1118 {
1119 m_backPointer = backPointer;
1120 }
1121
backPointer() const1122 SuperClass* backPointer() const { return m_backPointer; }
1123
trace(Visitor * visitor)1124 void trace(Visitor* visitor)
1125 {
1126 #if ENABLE_OILPAN
1127 visitor->trace(m_backPointer);
1128 #endif
1129 }
1130
1131 static int s_aliveCount;
1132 private:
PointsBack()1133 PointsBack() : m_backPointer(nullptr)
1134 {
1135 ++s_aliveCount;
1136 }
1137
1138 RawPtrWillBeWeakMember<SuperClass> m_backPointer;
1139 };
1140
1141 int PointsBack::s_aliveCount = 0;
1142
1143 class SuperClass : public RefCountedWillBeGarbageCollectedFinalized<SuperClass> {
1144 public:
create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)1145 static PassRefPtrWillBeRawPtr<SuperClass> create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
1146 {
1147 return adoptRefWillBeNoop(new SuperClass(pointsBack));
1148 }
1149
~SuperClass()1150 virtual ~SuperClass()
1151 {
1152 #if !ENABLE_OILPAN
1153 m_pointsBack->setBackPointer(0);
1154 #endif
1155 --s_aliveCount;
1156 }
1157
doStuff(PassRefPtrWillBeRawPtr<SuperClass> targetPass,PointsBack * pointsBack,int superClassCount)1158 void doStuff(PassRefPtrWillBeRawPtr<SuperClass> targetPass, PointsBack* pointsBack, int superClassCount)
1159 {
1160 RefPtrWillBeRawPtr<SuperClass> target = targetPass;
1161 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1162 EXPECT_EQ(pointsBack, target->pointsBack());
1163 EXPECT_EQ(superClassCount, SuperClass::s_aliveCount);
1164 }
1165
trace(Visitor * visitor)1166 virtual void trace(Visitor* visitor)
1167 {
1168 #if ENABLE_OILPAN
1169 visitor->trace(m_pointsBack);
1170 #endif
1171 }
1172
pointsBack() const1173 PointsBack* pointsBack() const { return m_pointsBack.get(); }
1174
1175 static int s_aliveCount;
1176 protected:
SuperClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)1177 explicit SuperClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
1178 : m_pointsBack(pointsBack)
1179 {
1180 m_pointsBack->setBackPointer(this);
1181 ++s_aliveCount;
1182 }
1183
1184 private:
1185 RefPtrWillBeMember<PointsBack> m_pointsBack;
1186 };
1187
1188 int SuperClass::s_aliveCount = 0;
1189 class SubData : public NoBaseWillBeGarbageCollectedFinalized<SubData> {
1190 public:
SubData()1191 SubData() { ++s_aliveCount; }
~SubData()1192 ~SubData() { --s_aliveCount; }
1193
trace(Visitor *)1194 void trace(Visitor*) { }
1195
1196 static int s_aliveCount;
1197 };
1198
1199 int SubData::s_aliveCount = 0;
1200
1201 class SubClass : public SuperClass {
1202 public:
create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)1203 static PassRefPtrWillBeRawPtr<SubClass> create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
1204 {
1205 return adoptRefWillBeNoop(new SubClass(pointsBack));
1206 }
1207
~SubClass()1208 virtual ~SubClass()
1209 {
1210 --s_aliveCount;
1211 }
1212
trace(Visitor * visitor)1213 virtual void trace(Visitor* visitor)
1214 {
1215 #if ENABLE_OILPAN
1216 SuperClass::trace(visitor);
1217 visitor->trace(m_data);
1218 #endif
1219 }
1220
1221 static int s_aliveCount;
1222 private:
SubClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)1223 explicit SubClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
1224 : SuperClass(pointsBack)
1225 , m_data(adoptPtrWillBeNoop(new SubData()))
1226 {
1227 ++s_aliveCount;
1228 }
1229
1230 private:
1231 OwnPtrWillBeMember<SubData> m_data;
1232 };
1233
1234 int SubClass::s_aliveCount = 0;
1235
1236 class TransitionRefCounted : public RefCountedWillBeRefCountedGarbageCollected<TransitionRefCounted> {
1237 public:
create()1238 static PassRefPtrWillBeRawPtr<TransitionRefCounted> create()
1239 {
1240 return adoptRefWillBeRefCountedGarbageCollected(new TransitionRefCounted());
1241 }
1242
~TransitionRefCounted()1243 ~TransitionRefCounted()
1244 {
1245 --s_aliveCount;
1246 }
1247
trace(Visitor * visitor)1248 void trace(Visitor* visitor) { }
1249
1250 static int s_aliveCount;
1251
1252 private:
TransitionRefCounted()1253 TransitionRefCounted()
1254 {
1255 ++s_aliveCount;
1256 }
1257 };
1258
1259 int TransitionRefCounted::s_aliveCount = 0;
1260
1261 class Mixin : public GarbageCollectedMixin {
1262 public:
trace(Visitor * visitor)1263 virtual void trace(Visitor* visitor) { }
1264
getPayload(int i)1265 virtual char getPayload(int i) { return m_padding[i]; }
1266
1267 protected:
1268 int m_padding[8];
1269 };
1270
1271 class UseMixin : public SimpleObject, public Mixin {
1272 USING_GARBAGE_COLLECTED_MIXIN(UseMixin)
1273 public:
create()1274 static UseMixin* create()
1275 {
1276 return new UseMixin();
1277 }
1278
1279 static int s_traceCount;
trace(Visitor * visitor)1280 virtual void trace(Visitor* visitor)
1281 {
1282 SimpleObject::trace(visitor);
1283 Mixin::trace(visitor);
1284 ++s_traceCount;
1285 }
1286
1287 private:
UseMixin()1288 UseMixin()
1289 {
1290 s_traceCount = 0;
1291 }
1292 };
1293
1294 int UseMixin::s_traceCount = 0;
1295
1296 class VectorObject {
1297 ALLOW_ONLY_INLINE_ALLOCATION();
1298 public:
VectorObject()1299 VectorObject()
1300 {
1301 m_value = SimpleFinalizedObject::create();
1302 }
1303
trace(Visitor * visitor)1304 void trace(Visitor* visitor)
1305 {
1306 visitor->trace(m_value);
1307 }
1308
1309 private:
1310 Member<SimpleFinalizedObject> m_value;
1311 };
1312
1313 class VectorObjectInheritedTrace : public VectorObject { };
1314
1315 class VectorObjectNoTrace {
1316 ALLOW_ONLY_INLINE_ALLOCATION();
1317 public:
VectorObjectNoTrace()1318 VectorObjectNoTrace()
1319 {
1320 m_value = SimpleFinalizedObject::create();
1321 }
1322
1323 private:
1324 Member<SimpleFinalizedObject> m_value;
1325 };
1326
1327 class TerminatedArrayItem {
1328 ALLOW_ONLY_INLINE_ALLOCATION();
1329 public:
TerminatedArrayItem(IntWrapper * payload)1330 TerminatedArrayItem(IntWrapper* payload) : m_payload(payload), m_isLast(false) { }
1331
trace(Visitor * visitor)1332 void trace(Visitor* visitor) { visitor->trace(m_payload); }
1333
isLastInArray() const1334 bool isLastInArray() const { return m_isLast; }
setLastInArray(bool value)1335 void setLastInArray(bool value) { m_isLast = value; }
1336
payload() const1337 IntWrapper* payload() const { return m_payload; }
1338
1339 private:
1340 Member<IntWrapper> m_payload;
1341 bool m_isLast;
1342 };
1343
1344 } // WebCore namespace
1345
1346 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(WebCore::VectorObject);
1347 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(WebCore::VectorObjectInheritedTrace);
1348 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(WebCore::VectorObjectNoTrace);
1349
1350 namespace WebCore {
1351
1352 class OneKiloByteObject : public GarbageCollectedFinalized<OneKiloByteObject> {
1353 public:
~OneKiloByteObject()1354 ~OneKiloByteObject() { s_destructorCalls++; }
data()1355 char* data() { return m_data; }
trace(Visitor * visitor)1356 void trace(Visitor* visitor) { }
1357 static int s_destructorCalls;
1358
1359 private:
1360 static const size_t s_length = 1024;
1361 char m_data[s_length];
1362 };
1363
1364 int OneKiloByteObject::s_destructorCalls = 0;
1365
1366 class DynamicallySizedObject : public GarbageCollected<DynamicallySizedObject> {
1367 public:
create(size_t size)1368 static DynamicallySizedObject* create(size_t size)
1369 {
1370 void* slot = Heap::allocate<DynamicallySizedObject>(size);
1371 return new (slot) DynamicallySizedObject();
1372 }
1373
operator new(std::size_t,void * location)1374 void* operator new(std::size_t, void* location)
1375 {
1376 return location;
1377 }
1378
get(int i)1379 uint8_t get(int i)
1380 {
1381 return *(reinterpret_cast<uint8_t*>(this) + i);
1382 }
1383
trace(Visitor *)1384 void trace(Visitor*) { }
1385
1386 private:
DynamicallySizedObject()1387 DynamicallySizedObject() { }
1388 };
1389
1390 class FinalizationAllocator : public GarbageCollectedFinalized<FinalizationAllocator> {
1391 public:
FinalizationAllocator(Persistent<IntWrapper> * wrapper)1392 FinalizationAllocator(Persistent<IntWrapper>* wrapper)
1393 : m_wrapper(wrapper)
1394 {
1395 }
1396
~FinalizationAllocator()1397 ~FinalizationAllocator()
1398 {
1399 for (int i = 0; i < 10; ++i)
1400 *m_wrapper = IntWrapper::create(42);
1401 for (int i = 0; i < 512; ++i)
1402 new OneKiloByteObject();
1403 }
1404
trace(Visitor *)1405 void trace(Visitor*) { }
1406
1407 private:
1408 Persistent<IntWrapper>* m_wrapper;
1409 };
1410
TEST(HeapTest,Transition)1411 TEST(HeapTest, Transition)
1412 {
1413 {
1414 RefPtr<TransitionRefCounted> refCounted = TransitionRefCounted::create();
1415 EXPECT_EQ(1, TransitionRefCounted::s_aliveCount);
1416 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1417 EXPECT_EQ(1, TransitionRefCounted::s_aliveCount);
1418 }
1419 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1420 EXPECT_EQ(0, TransitionRefCounted::s_aliveCount);
1421
1422 RefPtrWillBePersistent<PointsBack> pointsBack1 = PointsBack::create();
1423 RefPtrWillBePersistent<PointsBack> pointsBack2 = PointsBack::create();
1424 RefPtrWillBePersistent<SuperClass> superClass = SuperClass::create(pointsBack1);
1425 RefPtrWillBePersistent<SubClass> subClass = SubClass::create(pointsBack2);
1426 EXPECT_EQ(2, PointsBack::s_aliveCount);
1427 EXPECT_EQ(2, SuperClass::s_aliveCount);
1428 EXPECT_EQ(1, SubClass::s_aliveCount);
1429 EXPECT_EQ(1, SubData::s_aliveCount);
1430
1431 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1432 EXPECT_EQ(0, TransitionRefCounted::s_aliveCount);
1433 EXPECT_EQ(2, PointsBack::s_aliveCount);
1434 EXPECT_EQ(2, SuperClass::s_aliveCount);
1435 EXPECT_EQ(1, SubClass::s_aliveCount);
1436 EXPECT_EQ(1, SubData::s_aliveCount);
1437
1438 superClass->doStuff(superClass.release(), pointsBack1.get(), 2);
1439 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1440 EXPECT_EQ(2, PointsBack::s_aliveCount);
1441 EXPECT_EQ(1, SuperClass::s_aliveCount);
1442 EXPECT_EQ(1, SubClass::s_aliveCount);
1443 EXPECT_EQ(1, SubData::s_aliveCount);
1444 EXPECT_EQ(0, pointsBack1->backPointer());
1445
1446 pointsBack1.release();
1447 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1448 EXPECT_EQ(1, PointsBack::s_aliveCount);
1449 EXPECT_EQ(1, SuperClass::s_aliveCount);
1450 EXPECT_EQ(1, SubClass::s_aliveCount);
1451 EXPECT_EQ(1, SubData::s_aliveCount);
1452
1453 subClass->doStuff(subClass.release(), pointsBack2.get(), 1);
1454 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1455 EXPECT_EQ(1, PointsBack::s_aliveCount);
1456 EXPECT_EQ(0, SuperClass::s_aliveCount);
1457 EXPECT_EQ(0, SubClass::s_aliveCount);
1458 EXPECT_EQ(0, SubData::s_aliveCount);
1459 EXPECT_EQ(0, pointsBack2->backPointer());
1460
1461 pointsBack2.release();
1462 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1463 EXPECT_EQ(0, PointsBack::s_aliveCount);
1464 EXPECT_EQ(0, SuperClass::s_aliveCount);
1465 EXPECT_EQ(0, SubClass::s_aliveCount);
1466 EXPECT_EQ(0, SubData::s_aliveCount);
1467
1468 EXPECT_TRUE(superClass == subClass);
1469 }
1470
TEST(HeapTest,Threading)1471 TEST(HeapTest, Threading)
1472 {
1473 ThreadedHeapTester::test();
1474 }
1475
TEST(HeapTest,ThreadedWeakness)1476 TEST(HeapTest, ThreadedWeakness)
1477 {
1478 ThreadedWeaknessTester::test();
1479 }
1480
TEST(HeapTest,BasicFunctionality)1481 TEST(HeapTest, BasicFunctionality)
1482 {
1483 HeapStats heapStats;
1484 clearOutOldGarbage(&heapStats);
1485 {
1486 size_t slack = 0;
1487
1488 // When the test starts there may already have been leaked some memory
1489 // on the heap, so we establish a base line.
1490 size_t baseLevel = heapStats.totalObjectSpace();
1491 bool testPagesAllocated = !baseLevel;
1492 if (testPagesAllocated)
1493 EXPECT_EQ(heapStats.totalAllocatedSpace(), 0ul);
1494
1495 // This allocates objects on the general heap which should add a page of memory.
1496 DynamicallySizedObject* alloc32 = DynamicallySizedObject::create(32);
1497 slack += 4;
1498 memset(alloc32, 40, 32);
1499 DynamicallySizedObject* alloc64 = DynamicallySizedObject::create(64);
1500 slack += 4;
1501 memset(alloc64, 27, 64);
1502
1503 size_t total = 96;
1504
1505 getHeapStats(&heapStats);
1506 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack);
1507 if (testPagesAllocated)
1508 EXPECT_EQ(heapStats.totalAllocatedSpace(), blinkPageSize);
1509
1510 CheckWithSlack(alloc32 + 32 + sizeof(HeapObjectHeader), alloc64, slack);
1511
1512 EXPECT_EQ(alloc32->get(0), 40);
1513 EXPECT_EQ(alloc32->get(31), 40);
1514 EXPECT_EQ(alloc64->get(0), 27);
1515 EXPECT_EQ(alloc64->get(63), 27);
1516
1517 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1518
1519 EXPECT_EQ(alloc32->get(0), 40);
1520 EXPECT_EQ(alloc32->get(31), 40);
1521 EXPECT_EQ(alloc64->get(0), 27);
1522 EXPECT_EQ(alloc64->get(63), 27);
1523 }
1524
1525 clearOutOldGarbage(&heapStats);
1526 size_t total = 0;
1527 size_t slack = 0;
1528 size_t baseLevel = heapStats.totalObjectSpace();
1529 bool testPagesAllocated = !baseLevel;
1530 if (testPagesAllocated)
1531 EXPECT_EQ(heapStats.totalAllocatedSpace(), 0ul);
1532
1533 size_t big = 1008;
1534 Persistent<DynamicallySizedObject> bigArea = DynamicallySizedObject::create(big);
1535 total += big;
1536 slack += 4;
1537
1538 size_t persistentCount = 0;
1539 const size_t numPersistents = 100000;
1540 Persistent<DynamicallySizedObject>* persistents[numPersistents];
1541
1542 for (int i = 0; i < 1000; i++) {
1543 size_t size = 128 + i * 8;
1544 total += size;
1545 persistents[persistentCount++] = new Persistent<DynamicallySizedObject>(DynamicallySizedObject::create(size));
1546 slack += 4;
1547 getHeapStats(&heapStats);
1548 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack);
1549 if (testPagesAllocated)
1550 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
1551 }
1552
1553 {
1554 DynamicallySizedObject* alloc32b(DynamicallySizedObject::create(32));
1555 slack += 4;
1556 memset(alloc32b, 40, 32);
1557 DynamicallySizedObject* alloc64b(DynamicallySizedObject::create(64));
1558 slack += 4;
1559 memset(alloc64b, 27, 64);
1560 EXPECT_TRUE(alloc32b != alloc64b);
1561
1562 total += 96;
1563 getHeapStats(&heapStats);
1564 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack);
1565 if (testPagesAllocated)
1566 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
1567 }
1568
1569 clearOutOldGarbage(&heapStats);
1570 total -= 96;
1571 slack -= 8;
1572 if (testPagesAllocated)
1573 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
1574
1575 DynamicallySizedObject* bigAreaRaw = bigArea;
1576 // Clear the persistent, so that the big area will be garbage collected.
1577 bigArea.release();
1578 clearOutOldGarbage(&heapStats);
1579
1580 total -= big;
1581 slack -= 4;
1582 getHeapStats(&heapStats);
1583 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack);
1584 if (testPagesAllocated)
1585 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
1586
1587 // Endless loop unless we eventually get the memory back that we just freed.
1588 while (true) {
1589 Persistent<DynamicallySizedObject>* alloc = new Persistent<DynamicallySizedObject>(DynamicallySizedObject::create(big / 2));
1590 slack += 4;
1591 persistents[persistentCount++] = alloc;
1592 EXPECT_LT(persistentCount, numPersistents);
1593 total += big / 2;
1594 if (bigAreaRaw == alloc->get())
1595 break;
1596 }
1597
1598 getHeapStats(&heapStats);
1599 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack);
1600 if (testPagesAllocated)
1601 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
1602
1603 for (size_t i = 0; i < persistentCount; i++) {
1604 delete persistents[i];
1605 persistents[i] = 0;
1606 }
1607
1608 uint8_t* address = reinterpret_cast<uint8_t*>(Heap::reallocate<DynamicallySizedObject>(0, 100));
1609 for (int i = 0; i < 100; i++)
1610 address[i] = i;
1611 address = reinterpret_cast<uint8_t*>(Heap::reallocate<DynamicallySizedObject>(address, 100000));
1612 for (int i = 0; i < 100; i++)
1613 EXPECT_EQ(address[i], i);
1614 address = reinterpret_cast<uint8_t*>(Heap::reallocate<DynamicallySizedObject>(address, 50));
1615 for (int i = 0; i < 50; i++)
1616 EXPECT_EQ(address[i], i);
1617 // This should be equivalent to free(address).
1618 EXPECT_EQ(reinterpret_cast<uintptr_t>(Heap::reallocate<DynamicallySizedObject>(address, 0)), 0ul);
1619 // This should be equivalent to malloc(0).
1620 EXPECT_EQ(reinterpret_cast<uintptr_t>(Heap::reallocate<DynamicallySizedObject>(0, 0)), 0ul);
1621 }
1622
TEST(HeapTest,SimpleAllocation)1623 TEST(HeapTest, SimpleAllocation)
1624 {
1625 HeapStats initialHeapStats;
1626 clearOutOldGarbage(&initialHeapStats);
1627 EXPECT_EQ(0ul, initialHeapStats.totalObjectSpace());
1628
1629 // Allocate an object in the heap.
1630 HeapAllocatedArray* array = new HeapAllocatedArray();
1631 HeapStats statsAfterAllocation;
1632 getHeapStats(&statsAfterAllocation);
1633 EXPECT_TRUE(statsAfterAllocation.totalObjectSpace() >= sizeof(HeapAllocatedArray));
1634
1635 // Sanity check of the contents in the heap.
1636 EXPECT_EQ(0, array->at(0));
1637 EXPECT_EQ(42, array->at(42));
1638 EXPECT_EQ(0, array->at(128));
1639 EXPECT_EQ(999 % 128, array->at(999));
1640 }
1641
TEST(HeapTest,SimplePersistent)1642 TEST(HeapTest, SimplePersistent)
1643 {
1644 Persistent<TraceCounter> traceCounter = TraceCounter::create();
1645 EXPECT_EQ(0, traceCounter->traceCount());
1646
1647 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1648 EXPECT_EQ(1, traceCounter->traceCount());
1649
1650 Persistent<ClassWithMember> classWithMember = ClassWithMember::create();
1651 EXPECT_EQ(0, classWithMember->traceCount());
1652
1653 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1654 EXPECT_EQ(1, classWithMember->traceCount());
1655 EXPECT_EQ(2, traceCounter->traceCount());
1656 }
1657
TEST(HeapTest,SimpleFinalization)1658 TEST(HeapTest, SimpleFinalization)
1659 {
1660 {
1661 Persistent<SimpleFinalizedObject> finalized = SimpleFinalizedObject::create();
1662 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls);
1663 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1664 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls);
1665 }
1666
1667 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1668 EXPECT_EQ(1, SimpleFinalizedObject::s_destructorCalls);
1669 }
1670
TEST(HeapTest,Finalization)1671 TEST(HeapTest, Finalization)
1672 {
1673 {
1674 HeapTestSubClass* t1 = HeapTestSubClass::create();
1675 HeapTestSubClass* t2 = HeapTestSubClass::create();
1676 HeapTestSuperClass* t3 = HeapTestSuperClass::create();
1677 // FIXME(oilpan): Ignore unused variables.
1678 (void)t1;
1679 (void)t2;
1680 (void)t3;
1681 }
1682 // Nothing is marked so the GC should free everything and call
1683 // the finalizer on all three objects.
1684 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1685 EXPECT_EQ(2, HeapTestSubClass::s_destructorCalls);
1686 EXPECT_EQ(3, HeapTestSuperClass::s_destructorCalls);
1687 // Destructors not called again when GCing again.
1688 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1689 EXPECT_EQ(2, HeapTestSubClass::s_destructorCalls);
1690 EXPECT_EQ(3, HeapTestSuperClass::s_destructorCalls);
1691 }
1692
TEST(HeapTest,TypedHeapSanity)1693 TEST(HeapTest, TypedHeapSanity)
1694 {
1695 // We use TraceCounter for allocating an object on the general heap.
1696 Persistent<TraceCounter> generalHeapObject = TraceCounter::create();
1697 Persistent<TestTypedHeapClass> typedHeapObject = TestTypedHeapClass::create();
1698 EXPECT_NE(pageHeaderAddress(reinterpret_cast<Address>(generalHeapObject.get())),
1699 pageHeaderAddress(reinterpret_cast<Address>(typedHeapObject.get())));
1700 }
1701
TEST(HeapTest,NoAllocation)1702 TEST(HeapTest, NoAllocation)
1703 {
1704 EXPECT_TRUE(ThreadState::current()->isAllocationAllowed());
1705 {
1706 // Disallow allocation
1707 NoAllocationScope<AnyThread> noAllocationScope;
1708 EXPECT_FALSE(ThreadState::current()->isAllocationAllowed());
1709 }
1710 EXPECT_TRUE(ThreadState::current()->isAllocationAllowed());
1711 }
1712
TEST(HeapTest,Members)1713 TEST(HeapTest, Members)
1714 {
1715 Bar::s_live = 0;
1716 {
1717 Persistent<Baz> h1;
1718 Persistent<Baz> h2;
1719 {
1720 h1 = Baz::create(Bar::create());
1721 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1722 EXPECT_EQ(1u, Bar::s_live);
1723 h2 = Baz::create(Bar::create());
1724 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1725 EXPECT_EQ(2u, Bar::s_live);
1726 }
1727 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1728 EXPECT_EQ(2u, Bar::s_live);
1729 h1->clear();
1730 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1731 EXPECT_EQ(1u, Bar::s_live);
1732 }
1733 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1734 EXPECT_EQ(0u, Bar::s_live);
1735 }
1736
TEST(HeapTest,MarkTest)1737 TEST(HeapTest, MarkTest)
1738 {
1739 {
1740 Bar::s_live = 0;
1741 Persistent<Bar> bar = Bar::create();
1742 EXPECT_TRUE(ThreadState::current()->contains(bar));
1743 EXPECT_EQ(1u, Bar::s_live);
1744 {
1745 Foo* foo = Foo::create(bar);
1746 EXPECT_TRUE(ThreadState::current()->contains(foo));
1747 EXPECT_EQ(2u, Bar::s_live);
1748 EXPECT_TRUE(reinterpret_cast<Address>(foo) != reinterpret_cast<Address>(bar.get()));
1749 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1750 EXPECT_TRUE(foo != bar); // To make sure foo is kept alive.
1751 EXPECT_EQ(2u, Bar::s_live);
1752 }
1753 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1754 EXPECT_EQ(1u, Bar::s_live);
1755 }
1756 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1757 EXPECT_EQ(0u, Bar::s_live);
1758 }
1759
TEST(HeapTest,DeepTest)1760 TEST(HeapTest, DeepTest)
1761 {
1762 const unsigned depth = 100000;
1763 Bar::s_live = 0;
1764 {
1765 Bar* bar = Bar::create();
1766 EXPECT_TRUE(ThreadState::current()->contains(bar));
1767 Foo* foo = Foo::create(bar);
1768 EXPECT_TRUE(ThreadState::current()->contains(foo));
1769 EXPECT_EQ(2u, Bar::s_live);
1770 for (unsigned i = 0; i < depth; i++) {
1771 Foo* foo2 = Foo::create(foo);
1772 foo = foo2;
1773 EXPECT_TRUE(ThreadState::current()->contains(foo));
1774 }
1775 EXPECT_EQ(depth + 2, Bar::s_live);
1776 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1777 EXPECT_TRUE(foo != bar); // To make sure foo and bar are kept alive.
1778 EXPECT_EQ(depth + 2, Bar::s_live);
1779 }
1780 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1781 EXPECT_EQ(0u, Bar::s_live);
1782 }
1783
TEST(HeapTest,WideTest)1784 TEST(HeapTest, WideTest)
1785 {
1786 Bar::s_live = 0;
1787 {
1788 Bars* bars = Bars::create();
1789 unsigned width = Bars::width;
1790 EXPECT_EQ(width + 1, Bar::s_live);
1791 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1792 EXPECT_EQ(width + 1, Bar::s_live);
1793 // Use bars here to make sure that it will be on the stack
1794 // for the conservative stack scan to find.
1795 EXPECT_EQ(width, bars->getWidth());
1796 }
1797 EXPECT_EQ(Bars::width + 1, Bar::s_live);
1798 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1799 EXPECT_EQ(0u, Bar::s_live);
1800 }
1801
TEST(HeapTest,HashMapOfMembers)1802 TEST(HeapTest, HashMapOfMembers)
1803 {
1804 HeapStats initialHeapSize;
1805 IntWrapper::s_destructorCalls = 0;
1806
1807 clearOutOldGarbage(&initialHeapSize);
1808 {
1809 typedef HeapHashMap<
1810 Member<IntWrapper>,
1811 Member<IntWrapper>,
1812 DefaultHash<Member<IntWrapper> >::Hash,
1813 HashTraits<Member<IntWrapper> >,
1814 HashTraits<Member<IntWrapper> > > HeapObjectIdentityMap;
1815
1816 Persistent<HeapObjectIdentityMap> map = new HeapObjectIdentityMap();
1817
1818 map->clear();
1819 HeapStats afterSetWasCreated;
1820 getHeapStats(&afterSetWasCreated);
1821 EXPECT_TRUE(afterSetWasCreated.totalObjectSpace() > initialHeapSize.totalObjectSpace());
1822
1823 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1824 HeapStats afterGC;
1825 getHeapStats(&afterGC);
1826 EXPECT_EQ(afterGC.totalObjectSpace(), afterSetWasCreated.totalObjectSpace());
1827
1828 // If the additions below cause garbage collections, these
1829 // pointers should be found by conservative stack scanning.
1830 IntWrapper* one(IntWrapper::create(1));
1831 IntWrapper* anotherOne(IntWrapper::create(1));
1832
1833 map->add(one, one);
1834
1835 HeapStats afterOneAdd;
1836 getHeapStats(&afterOneAdd);
1837 EXPECT_TRUE(afterOneAdd.totalObjectSpace() > afterGC.totalObjectSpace());
1838
1839 HeapObjectIdentityMap::iterator it(map->begin());
1840 HeapObjectIdentityMap::iterator it2(map->begin());
1841 ++it;
1842 ++it2;
1843
1844 map->add(anotherOne, one);
1845
1846 // The addition above can cause an allocation of a new
1847 // backing store. We therefore garbage collect before
1848 // taking the heap stats in order to get rid of the old
1849 // backing store. We make sure to not use conservative
1850 // stack scanning as that could find a pointer to the
1851 // old backing.
1852 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1853 HeapStats afterAddAndGC;
1854 getHeapStats(&afterAddAndGC);
1855 EXPECT_TRUE(afterAddAndGC.totalObjectSpace() >= afterOneAdd.totalObjectSpace());
1856
1857 EXPECT_EQ(map->size(), 2u); // Two different wrappings of '1' are distinct.
1858
1859 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1860 EXPECT_TRUE(map->contains(one));
1861 EXPECT_TRUE(map->contains(anotherOne));
1862
1863 IntWrapper* gotten(map->get(one));
1864 EXPECT_EQ(gotten->value(), one->value());
1865 EXPECT_EQ(gotten, one);
1866
1867 HeapStats afterGC2;
1868 getHeapStats(&afterGC2);
1869 EXPECT_EQ(afterGC2.totalObjectSpace(), afterAddAndGC.totalObjectSpace());
1870
1871 IntWrapper* dozen = 0;
1872
1873 for (int i = 1; i < 1000; i++) { // 999 iterations.
1874 IntWrapper* iWrapper(IntWrapper::create(i));
1875 IntWrapper* iSquared(IntWrapper::create(i * i));
1876 map->add(iWrapper, iSquared);
1877 if (i == 12)
1878 dozen = iWrapper;
1879 }
1880 HeapStats afterAdding1000;
1881 getHeapStats(&afterAdding1000);
1882 EXPECT_TRUE(afterAdding1000.totalObjectSpace() > afterGC2.totalObjectSpace());
1883
1884 IntWrapper* gross(map->get(dozen));
1885 EXPECT_EQ(gross->value(), 144);
1886
1887 // This should clear out junk created by all the adds.
1888 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1889 HeapStats afterGC3;
1890 getHeapStats(&afterGC3);
1891 EXPECT_TRUE(afterGC3.totalObjectSpace() < afterAdding1000.totalObjectSpace());
1892 }
1893
1894 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1895 // The objects 'one', anotherOne, and the 999 other pairs.
1896 EXPECT_EQ(IntWrapper::s_destructorCalls, 2000);
1897 HeapStats afterGC4;
1898 getHeapStats(&afterGC4);
1899 EXPECT_EQ(afterGC4.totalObjectSpace(), initialHeapSize.totalObjectSpace());
1900 }
1901
TEST(HeapTest,NestedAllocation)1902 TEST(HeapTest, NestedAllocation)
1903 {
1904 HeapStats initialHeapSize;
1905 clearOutOldGarbage(&initialHeapSize);
1906 {
1907 Persistent<ConstructorAllocation> constructorAllocation = ConstructorAllocation::create();
1908 }
1909 HeapStats afterFree;
1910 clearOutOldGarbage(&afterFree);
1911 EXPECT_TRUE(initialHeapSize == afterFree);
1912 }
1913
TEST(HeapTest,LargeObjects)1914 TEST(HeapTest, LargeObjects)
1915 {
1916 HeapStats initialHeapSize;
1917 clearOutOldGarbage(&initialHeapSize);
1918 IntWrapper::s_destructorCalls = 0;
1919 LargeObject::s_destructorCalls = 0;
1920 {
1921 int slack = 8; // LargeObject points to an IntWrapper that is also allocated.
1922 Persistent<LargeObject> object = LargeObject::create();
1923 EXPECT_TRUE(ThreadState::current()->contains(object));
1924 EXPECT_TRUE(ThreadState::current()->contains(reinterpret_cast<char*>(object.get()) + sizeof(LargeObject) - 1));
1925 #if ENABLE(GC_TRACING)
1926 const GCInfo* info = ThreadState::current()->findGCInfo(reinterpret_cast<Address>(object.get()));
1927 EXPECT_NE(reinterpret_cast<const GCInfo*>(0), info);
1928 EXPECT_EQ(info, ThreadState::current()->findGCInfo(reinterpret_cast<Address>(object.get()) + sizeof(LargeObject) - 1));
1929 EXPECT_NE(info, ThreadState::current()->findGCInfo(reinterpret_cast<Address>(object.get()) + sizeof(LargeObject)));
1930 EXPECT_NE(info, ThreadState::current()->findGCInfo(reinterpret_cast<Address>(object.get()) - 1));
1931 #endif
1932 HeapStats afterAllocation;
1933 clearOutOldGarbage(&afterAllocation);
1934 {
1935 object->set(0, 'a');
1936 EXPECT_EQ('a', object->get(0));
1937 object->set(object->length() - 1, 'b');
1938 EXPECT_EQ('b', object->get(object->length() - 1));
1939 size_t expectedObjectSpace = sizeof(LargeObject) + sizeof(IntWrapper);
1940 size_t actualObjectSpace =
1941 afterAllocation.totalObjectSpace() - initialHeapSize.totalObjectSpace();
1942 CheckWithSlack(expectedObjectSpace, actualObjectSpace, slack);
1943 // There is probably space for the IntWrapper in a heap page without
1944 // allocating extra pages. However, the IntWrapper allocation might cause
1945 // the addition of a heap page.
1946 size_t largeObjectAllocationSize =
1947 sizeof(LargeObject) + sizeof(LargeHeapObject<FinalizedHeapObjectHeader>) + sizeof(FinalizedHeapObjectHeader);
1948 size_t allocatedSpaceLowerBound =
1949 initialHeapSize.totalAllocatedSpace() + largeObjectAllocationSize;
1950 size_t allocatedSpaceUpperBound = allocatedSpaceLowerBound + slack + blinkPageSize;
1951 EXPECT_LE(allocatedSpaceLowerBound, afterAllocation.totalAllocatedSpace());
1952 EXPECT_LE(afterAllocation.totalAllocatedSpace(), allocatedSpaceUpperBound);
1953 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
1954 EXPECT_EQ(0, LargeObject::s_destructorCalls);
1955 for (int i = 0; i < 10; i++)
1956 object = LargeObject::create();
1957 }
1958 HeapStats oneLargeObject;
1959 clearOutOldGarbage(&oneLargeObject);
1960 EXPECT_TRUE(oneLargeObject == afterAllocation);
1961 EXPECT_EQ(10, IntWrapper::s_destructorCalls);
1962 EXPECT_EQ(10, LargeObject::s_destructorCalls);
1963 }
1964 HeapStats backToInitial;
1965 clearOutOldGarbage(&backToInitial);
1966 EXPECT_TRUE(initialHeapSize == backToInitial);
1967 EXPECT_EQ(11, IntWrapper::s_destructorCalls);
1968 EXPECT_EQ(11, LargeObject::s_destructorCalls);
1969 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1970 }
1971
1972 typedef std::pair<Member<IntWrapper>, int> PairWrappedUnwrapped;
1973 typedef std::pair<int, Member<IntWrapper> > PairUnwrappedWrapped;
1974 typedef std::pair<WeakMember<IntWrapper>, Member<IntWrapper> > PairWeakStrong;
1975 typedef std::pair<Member<IntWrapper>, WeakMember<IntWrapper> > PairStrongWeak;
1976 typedef std::pair<WeakMember<IntWrapper>, int> PairWeakUnwrapped;
1977 typedef std::pair<int, WeakMember<IntWrapper> > PairUnwrappedWeak;
1978
1979 class Container : public GarbageCollected<Container> {
1980 public:
create()1981 static Container* create() { return new Container(); }
1982 HeapHashMap<Member<IntWrapper>, Member<IntWrapper> > map;
1983 HeapHashSet<Member<IntWrapper> > set;
1984 HeapHashSet<Member<IntWrapper> > set2;
1985 HeapHashCountedSet<Member<IntWrapper> > set3;
1986 HeapVector<Member<IntWrapper>, 2> vector;
1987 HeapVector<PairWrappedUnwrapped, 2> vectorWU;
1988 HeapVector<PairUnwrappedWrapped, 2> vectorUW;
1989 HeapDeque<Member<IntWrapper>, 0> deque;
1990 HeapDeque<PairWrappedUnwrapped, 0> dequeWU;
1991 HeapDeque<PairUnwrappedWrapped, 0> dequeUW;
trace(Visitor * visitor)1992 void trace(Visitor* visitor)
1993 {
1994 visitor->trace(map);
1995 visitor->trace(set);
1996 visitor->trace(set2);
1997 visitor->trace(set3);
1998 visitor->trace(vector);
1999 visitor->trace(vectorWU);
2000 visitor->trace(vectorUW);
2001 visitor->trace(deque);
2002 visitor->trace(dequeWU);
2003 visitor->trace(dequeUW);
2004 }
2005 };
2006
2007 struct ShouldBeTraced {
ShouldBeTracedWebCore::ShouldBeTraced2008 explicit ShouldBeTraced(IntWrapper* wrapper) : m_wrapper(wrapper) { }
traceWebCore::ShouldBeTraced2009 void trace(Visitor* visitor) { visitor->trace(m_wrapper); }
2010 Member<IntWrapper> m_wrapper;
2011 };
2012
2013 class OffHeapContainer : public GarbageCollectedFinalized<OffHeapContainer> {
2014 public:
create()2015 static OffHeapContainer* create() { return new OffHeapContainer(); }
2016
2017 static const int iterations = 300;
2018 static const int deadWrappers = 2700;
2019
OffHeapContainer()2020 OffHeapContainer()
2021 {
2022 for (int i = 0; i < iterations; i++) {
2023 m_deque1.append(ShouldBeTraced(IntWrapper::create(i)));
2024 m_vector1.append(ShouldBeTraced(IntWrapper::create(i)));
2025 m_deque2.append(IntWrapper::create(i));
2026 m_vector2.append(IntWrapper::create(i));
2027 m_hashSet.add(IntWrapper::create(i));
2028 m_hashMap.add(i + 103, IntWrapper::create(i));
2029 m_listHashSet.add(IntWrapper::create(i));
2030 m_linkedHashSet.add(IntWrapper::create(i));
2031 m_ownedVector.append(adoptPtr(new ShouldBeTraced(IntWrapper::create(i))));
2032 }
2033
2034 Deque<ShouldBeTraced>::iterator d1Iterator(m_deque1.begin());
2035 Vector<ShouldBeTraced>::iterator v1Iterator(m_vector1.begin());
2036 Deque<Member<IntWrapper> >::iterator d2Iterator(m_deque2.begin());
2037 Vector<Member<IntWrapper> >::iterator v2Iterator(m_vector2.begin());
2038 HashSet<Member<IntWrapper> >::iterator setIterator(m_hashSet.begin());
2039 HashMap<int, Member<IntWrapper> >::iterator mapIterator(m_hashMap.begin());
2040 ListHashSet<Member<IntWrapper> >::iterator listSetIterator(m_listHashSet.begin());
2041 LinkedHashSet<Member<IntWrapper> >::iterator linkedSetIterator(m_linkedHashSet.begin());
2042 Vector<OwnPtr<ShouldBeTraced> >::iterator ownedVectorIterator(m_ownedVector.begin());
2043
2044 for (int i = 0; i < iterations; i++) {
2045 EXPECT_EQ(i, m_vector1[i].m_wrapper->value());
2046 EXPECT_EQ(i, m_vector2[i]->value());
2047 EXPECT_EQ(i, d1Iterator->m_wrapper->value());
2048 EXPECT_EQ(i, v1Iterator->m_wrapper->value());
2049 EXPECT_EQ(i, d2Iterator->get()->value());
2050 EXPECT_EQ(i, v2Iterator->get()->value());
2051 EXPECT_EQ(i, linkedSetIterator->get()->value());
2052 EXPECT_EQ(i, listSetIterator->get()->value());
2053 EXPECT_EQ(i, ownedVectorIterator->get()->m_wrapper->value());
2054 int value = setIterator->get()->value();
2055 EXPECT_LE(0, value);
2056 EXPECT_GT(iterations, value);
2057 value = mapIterator->value.get()->value();
2058 EXPECT_LE(0, value);
2059 EXPECT_GT(iterations, value);
2060 ++d1Iterator;
2061 ++v1Iterator;
2062 ++d2Iterator;
2063 ++v2Iterator;
2064 ++setIterator;
2065 ++mapIterator;
2066 ++listSetIterator;
2067 ++linkedSetIterator;
2068 ++ownedVectorIterator;
2069 }
2070 EXPECT_EQ(d1Iterator, m_deque1.end());
2071 EXPECT_EQ(v1Iterator, m_vector1.end());
2072 EXPECT_EQ(d2Iterator, m_deque2.end());
2073 EXPECT_EQ(v2Iterator, m_vector2.end());
2074 EXPECT_EQ(setIterator, m_hashSet.end());
2075 EXPECT_EQ(mapIterator, m_hashMap.end());
2076 EXPECT_EQ(listSetIterator, m_listHashSet.end());
2077 EXPECT_EQ(linkedSetIterator, m_linkedHashSet.end());
2078 EXPECT_EQ(ownedVectorIterator, m_ownedVector.end());
2079 }
2080
trace(Visitor * visitor)2081 void trace(Visitor* visitor)
2082 {
2083 visitor->trace(m_deque1);
2084 visitor->trace(m_vector1);
2085 visitor->trace(m_deque2);
2086 visitor->trace(m_vector2);
2087 visitor->trace(m_hashSet);
2088 visitor->trace(m_hashMap);
2089 visitor->trace(m_listHashSet);
2090 visitor->trace(m_linkedHashSet);
2091 visitor->trace(m_listHashSet);
2092 visitor->trace(m_ownedVector);
2093 }
2094
2095 Deque<ShouldBeTraced> m_deque1;
2096 Vector<ShouldBeTraced> m_vector1;
2097 Deque<Member<IntWrapper> > m_deque2;
2098 Vector<Member<IntWrapper> > m_vector2;
2099 HashSet<Member<IntWrapper> > m_hashSet;
2100 HashMap<int, Member<IntWrapper> > m_hashMap;
2101 ListHashSet<Member<IntWrapper> > m_listHashSet;
2102 LinkedHashSet<Member<IntWrapper> > m_linkedHashSet;
2103 Vector<OwnPtr<ShouldBeTraced> > m_ownedVector;
2104 };
2105
2106 const int OffHeapContainer::iterations;
2107 const int OffHeapContainer::deadWrappers;
2108
2109 // These class definitions test compile-time asserts with transition
2110 // types. They are therefore unused in test code and just need to
2111 // compile. This is intentional; do not delete the A and B classes below.
2112 class A : public WillBeGarbageCollectedMixin {
2113 };
2114
2115 class B : public NoBaseWillBeGarbageCollected<B>, public A {
2116 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(B);
2117 public:
trace(Visitor *)2118 void trace(Visitor*) { }
2119 };
2120
TEST(HeapTest,HeapVectorFilledWithValue)2121 TEST(HeapTest, HeapVectorFilledWithValue)
2122 {
2123 IntWrapper* val = IntWrapper::create(1);
2124 HeapVector<Member<IntWrapper> > vector(10, val);
2125 EXPECT_EQ(10u, vector.size());
2126 for (size_t i = 0; i < vector.size(); i++)
2127 EXPECT_EQ(val, vector[i]);
2128 }
2129
TEST(HeapTest,HeapVectorWithInlineCapacity)2130 TEST(HeapTest, HeapVectorWithInlineCapacity)
2131 {
2132 IntWrapper* one = IntWrapper::create(1);
2133 IntWrapper* two = IntWrapper::create(2);
2134 IntWrapper* three = IntWrapper::create(3);
2135 IntWrapper* four = IntWrapper::create(4);
2136 IntWrapper* five = IntWrapper::create(5);
2137 IntWrapper* six = IntWrapper::create(6);
2138 {
2139 HeapVector<Member<IntWrapper>, 2> vector;
2140 vector.append(one);
2141 vector.append(two);
2142 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2143 EXPECT_TRUE(vector.contains(one));
2144 EXPECT_TRUE(vector.contains(two));
2145
2146 vector.append(three);
2147 vector.append(four);
2148 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2149 EXPECT_TRUE(vector.contains(one));
2150 EXPECT_TRUE(vector.contains(two));
2151 EXPECT_TRUE(vector.contains(three));
2152 EXPECT_TRUE(vector.contains(four));
2153
2154 vector.shrink(1);
2155 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2156 EXPECT_TRUE(vector.contains(one));
2157 EXPECT_FALSE(vector.contains(two));
2158 EXPECT_FALSE(vector.contains(three));
2159 EXPECT_FALSE(vector.contains(four));
2160 }
2161 {
2162 HeapVector<Member<IntWrapper>, 2> vector1;
2163 HeapVector<Member<IntWrapper>, 2> vector2;
2164
2165 vector1.append(one);
2166 vector2.append(two);
2167 vector1.swap(vector2);
2168 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2169 EXPECT_TRUE(vector1.contains(two));
2170 EXPECT_TRUE(vector2.contains(one));
2171 }
2172 {
2173 HeapVector<Member<IntWrapper>, 2> vector1;
2174 HeapVector<Member<IntWrapper>, 2> vector2;
2175
2176 vector1.append(one);
2177 vector1.append(two);
2178 vector2.append(three);
2179 vector2.append(four);
2180 vector2.append(five);
2181 vector2.append(six);
2182 vector1.swap(vector2);
2183 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2184 EXPECT_TRUE(vector1.contains(three));
2185 EXPECT_TRUE(vector1.contains(four));
2186 EXPECT_TRUE(vector1.contains(five));
2187 EXPECT_TRUE(vector1.contains(six));
2188 EXPECT_TRUE(vector2.contains(one));
2189 EXPECT_TRUE(vector2.contains(two));
2190 }
2191 }
2192
2193 template<typename T, size_t inlineCapacity, typename U>
dequeContains(HeapDeque<T,inlineCapacity> & deque,U u)2194 bool dequeContains(HeapDeque<T, inlineCapacity>& deque, U u)
2195 {
2196 typedef typename HeapDeque<T, inlineCapacity>::iterator iterator;
2197 for (iterator it = deque.begin(); it != deque.end(); ++it) {
2198 if (*it == u)
2199 return true;
2200 }
2201 return false;
2202 }
2203
TEST(HeapTest,HeapCollectionTypes)2204 TEST(HeapTest, HeapCollectionTypes)
2205 {
2206 HeapStats initialHeapSize;
2207 IntWrapper::s_destructorCalls = 0;
2208
2209 typedef HeapHashMap<Member<IntWrapper>, Member<IntWrapper> > MemberMember;
2210 typedef HeapHashMap<Member<IntWrapper>, int> MemberPrimitive;
2211 typedef HeapHashMap<int, Member<IntWrapper> > PrimitiveMember;
2212
2213 typedef HeapHashSet<Member<IntWrapper> > MemberSet;
2214 typedef HeapHashCountedSet<Member<IntWrapper> > MemberCountedSet;
2215
2216 typedef HeapVector<Member<IntWrapper>, 2> MemberVector;
2217 typedef HeapDeque<Member<IntWrapper>, 0> MemberDeque;
2218
2219 typedef HeapVector<PairWrappedUnwrapped, 2> VectorWU;
2220 typedef HeapVector<PairUnwrappedWrapped, 2> VectorUW;
2221 typedef HeapDeque<PairWrappedUnwrapped, 0> DequeWU;
2222 typedef HeapDeque<PairUnwrappedWrapped, 0> DequeUW;
2223
2224 Persistent<MemberMember> memberMember = new MemberMember();
2225 Persistent<MemberMember> memberMember2 = new MemberMember();
2226 Persistent<MemberMember> memberMember3 = new MemberMember();
2227 Persistent<MemberPrimitive> memberPrimitive = new MemberPrimitive();
2228 Persistent<PrimitiveMember> primitiveMember = new PrimitiveMember();
2229 Persistent<MemberSet> set = new MemberSet();
2230 Persistent<MemberSet> set2 = new MemberSet();
2231 Persistent<MemberCountedSet> set3 = new MemberCountedSet();
2232 Persistent<MemberVector> vector = new MemberVector();
2233 Persistent<MemberVector> vector2 = new MemberVector();
2234 Persistent<VectorWU> vectorWU = new VectorWU();
2235 Persistent<VectorWU> vectorWU2 = new VectorWU();
2236 Persistent<VectorUW> vectorUW = new VectorUW();
2237 Persistent<VectorUW> vectorUW2 = new VectorUW();
2238 Persistent<MemberDeque> deque = new MemberDeque();
2239 Persistent<MemberDeque> deque2 = new MemberDeque();
2240 Persistent<DequeWU> dequeWU = new DequeWU();
2241 Persistent<DequeWU> dequeWU2 = new DequeWU();
2242 Persistent<DequeUW> dequeUW = new DequeUW();
2243 Persistent<DequeUW> dequeUW2 = new DequeUW();
2244 Persistent<Container> container = Container::create();
2245
2246 clearOutOldGarbage(&initialHeapSize);
2247 {
2248 Persistent<IntWrapper> one(IntWrapper::create(1));
2249 Persistent<IntWrapper> two(IntWrapper::create(2));
2250 Persistent<IntWrapper> oneB(IntWrapper::create(1));
2251 Persistent<IntWrapper> twoB(IntWrapper::create(2));
2252 Persistent<IntWrapper> oneC(IntWrapper::create(1));
2253 Persistent<IntWrapper> oneD(IntWrapper::create(1));
2254 Persistent<IntWrapper> oneE(IntWrapper::create(1));
2255 Persistent<IntWrapper> oneF(IntWrapper::create(1));
2256 {
2257 IntWrapper* threeB(IntWrapper::create(3));
2258 IntWrapper* threeC(IntWrapper::create(3));
2259 IntWrapper* threeD(IntWrapper::create(3));
2260 IntWrapper* threeE(IntWrapper::create(3));
2261 IntWrapper* threeF(IntWrapper::create(3));
2262 IntWrapper* three(IntWrapper::create(3));
2263 IntWrapper* fourB(IntWrapper::create(4));
2264 IntWrapper* fourC(IntWrapper::create(4));
2265 IntWrapper* fourD(IntWrapper::create(4));
2266 IntWrapper* fourE(IntWrapper::create(4));
2267 IntWrapper* fourF(IntWrapper::create(4));
2268 IntWrapper* four(IntWrapper::create(4));
2269 IntWrapper* fiveC(IntWrapper::create(5));
2270 IntWrapper* fiveD(IntWrapper::create(5));
2271 IntWrapper* fiveE(IntWrapper::create(5));
2272 IntWrapper* fiveF(IntWrapper::create(5));
2273
2274 // Member Collections.
2275 memberMember2->add(one, two);
2276 memberMember2->add(two, three);
2277 memberMember2->add(three, four);
2278 memberMember2->add(four, one);
2279 primitiveMember->add(1, two);
2280 primitiveMember->add(2, three);
2281 primitiveMember->add(3, four);
2282 primitiveMember->add(4, one);
2283 memberPrimitive->add(one, 2);
2284 memberPrimitive->add(two, 3);
2285 memberPrimitive->add(three, 4);
2286 memberPrimitive->add(four, 1);
2287 set2->add(one);
2288 set2->add(two);
2289 set2->add(three);
2290 set2->add(four);
2291 set->add(oneB);
2292 set3->add(oneB);
2293 set3->add(oneB);
2294 vector->append(oneB);
2295 deque->append(oneB);
2296 vector2->append(threeB);
2297 vector2->append(fourB);
2298 deque2->append(threeE);
2299 deque2->append(fourE);
2300 vectorWU->append(PairWrappedUnwrapped(&*oneC, 42));
2301 dequeWU->append(PairWrappedUnwrapped(&*oneE, 42));
2302 vectorWU2->append(PairWrappedUnwrapped(&*threeC, 43));
2303 vectorWU2->append(PairWrappedUnwrapped(&*fourC, 44));
2304 vectorWU2->append(PairWrappedUnwrapped(&*fiveC, 45));
2305 dequeWU2->append(PairWrappedUnwrapped(&*threeE, 43));
2306 dequeWU2->append(PairWrappedUnwrapped(&*fourE, 44));
2307 dequeWU2->append(PairWrappedUnwrapped(&*fiveE, 45));
2308 vectorUW->append(PairUnwrappedWrapped(1, &*oneD));
2309 vectorUW2->append(PairUnwrappedWrapped(103, &*threeD));
2310 vectorUW2->append(PairUnwrappedWrapped(104, &*fourD));
2311 vectorUW2->append(PairUnwrappedWrapped(105, &*fiveD));
2312 dequeUW->append(PairUnwrappedWrapped(1, &*oneF));
2313 dequeUW2->append(PairUnwrappedWrapped(103, &*threeF));
2314 dequeUW2->append(PairUnwrappedWrapped(104, &*fourF));
2315 dequeUW2->append(PairUnwrappedWrapped(105, &*fiveF));
2316
2317 EXPECT_TRUE(dequeContains(*deque, oneB));
2318
2319 // Collect garbage. This should change nothing since we are keeping
2320 // alive the IntWrapper objects with on-stack pointers.
2321 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2322
2323 EXPECT_TRUE(dequeContains(*deque, oneB));
2324
2325 EXPECT_EQ(0u, memberMember->size());
2326 EXPECT_EQ(4u, memberMember2->size());
2327 EXPECT_EQ(4u, primitiveMember->size());
2328 EXPECT_EQ(4u, memberPrimitive->size());
2329 EXPECT_EQ(1u, set->size());
2330 EXPECT_EQ(4u, set2->size());
2331 EXPECT_EQ(1u, set3->size());
2332 EXPECT_EQ(1u, vector->size());
2333 EXPECT_EQ(2u, vector2->size());
2334 EXPECT_EQ(1u, vectorWU->size());
2335 EXPECT_EQ(3u, vectorWU2->size());
2336 EXPECT_EQ(1u, vectorUW->size());
2337 EXPECT_EQ(3u, vectorUW2->size());
2338 EXPECT_EQ(1u, deque->size());
2339 EXPECT_EQ(2u, deque2->size());
2340 EXPECT_EQ(1u, dequeWU->size());
2341 EXPECT_EQ(3u, dequeWU2->size());
2342 EXPECT_EQ(1u, dequeUW->size());
2343 EXPECT_EQ(3u, dequeUW2->size());
2344
2345 MemberVector& cvec = container->vector;
2346 cvec.swap(*vector.get());
2347 vector2->swap(cvec);
2348 vector->swap(cvec);
2349
2350 VectorWU& cvecWU = container->vectorWU;
2351 cvecWU.swap(*vectorWU.get());
2352 vectorWU2->swap(cvecWU);
2353 vectorWU->swap(cvecWU);
2354
2355 VectorUW& cvecUW = container->vectorUW;
2356 cvecUW.swap(*vectorUW.get());
2357 vectorUW2->swap(cvecUW);
2358 vectorUW->swap(cvecUW);
2359
2360 MemberDeque& cDeque = container->deque;
2361 cDeque.swap(*deque.get());
2362 deque2->swap(cDeque);
2363 deque->swap(cDeque);
2364
2365 DequeWU& cDequeWU = container->dequeWU;
2366 cDequeWU.swap(*dequeWU.get());
2367 dequeWU2->swap(cDequeWU);
2368 dequeWU->swap(cDequeWU);
2369
2370 DequeUW& cDequeUW = container->dequeUW;
2371 cDequeUW.swap(*dequeUW.get());
2372 dequeUW2->swap(cDequeUW);
2373 dequeUW->swap(cDequeUW);
2374
2375 // Swap set and set2 in a roundabout way.
2376 MemberSet& cset1 = container->set;
2377 MemberSet& cset2 = container->set2;
2378 set->swap(cset1);
2379 set2->swap(cset2);
2380 set->swap(cset2);
2381 cset1.swap(cset2);
2382 cset2.swap(set2);
2383
2384 MemberCountedSet& cCountedSet = container->set3;
2385 set3->swap(cCountedSet);
2386 EXPECT_EQ(0u, set3->size());
2387 set3->swap(cCountedSet);
2388
2389 // Triple swap.
2390 container->map.swap(memberMember2);
2391 MemberMember& containedMap = container->map;
2392 memberMember3->swap(containedMap);
2393 memberMember3->swap(memberMember);
2394
2395 EXPECT_TRUE(memberMember->get(one) == two);
2396 EXPECT_TRUE(memberMember->get(two) == three);
2397 EXPECT_TRUE(memberMember->get(three) == four);
2398 EXPECT_TRUE(memberMember->get(four) == one);
2399 EXPECT_TRUE(primitiveMember->get(1) == two);
2400 EXPECT_TRUE(primitiveMember->get(2) == three);
2401 EXPECT_TRUE(primitiveMember->get(3) == four);
2402 EXPECT_TRUE(primitiveMember->get(4) == one);
2403 EXPECT_EQ(1, memberPrimitive->get(four));
2404 EXPECT_EQ(2, memberPrimitive->get(one));
2405 EXPECT_EQ(3, memberPrimitive->get(two));
2406 EXPECT_EQ(4, memberPrimitive->get(three));
2407 EXPECT_TRUE(set->contains(one));
2408 EXPECT_TRUE(set->contains(two));
2409 EXPECT_TRUE(set->contains(three));
2410 EXPECT_TRUE(set->contains(four));
2411 EXPECT_TRUE(set2->contains(oneB));
2412 EXPECT_TRUE(set3->contains(oneB));
2413 EXPECT_TRUE(vector->contains(threeB));
2414 EXPECT_TRUE(vector->contains(fourB));
2415 EXPECT_TRUE(dequeContains(*deque, threeE));
2416 EXPECT_TRUE(dequeContains(*deque, fourE));
2417 EXPECT_TRUE(vector2->contains(oneB));
2418 EXPECT_FALSE(vector2->contains(threeB));
2419 EXPECT_TRUE(dequeContains(*deque2, oneB));
2420 EXPECT_FALSE(dequeContains(*deque2, threeE));
2421 EXPECT_TRUE(vectorWU->contains(PairWrappedUnwrapped(&*threeC, 43)));
2422 EXPECT_TRUE(vectorWU->contains(PairWrappedUnwrapped(&*fourC, 44)));
2423 EXPECT_TRUE(vectorWU->contains(PairWrappedUnwrapped(&*fiveC, 45)));
2424 EXPECT_TRUE(vectorWU2->contains(PairWrappedUnwrapped(&*oneC, 42)));
2425 EXPECT_FALSE(vectorWU2->contains(PairWrappedUnwrapped(&*threeC, 43)));
2426 EXPECT_TRUE(vectorUW->contains(PairUnwrappedWrapped(103, &*threeD)));
2427 EXPECT_TRUE(vectorUW->contains(PairUnwrappedWrapped(104, &*fourD)));
2428 EXPECT_TRUE(vectorUW->contains(PairUnwrappedWrapped(105, &*fiveD)));
2429 EXPECT_TRUE(vectorUW2->contains(PairUnwrappedWrapped(1, &*oneD)));
2430 EXPECT_FALSE(vectorUW2->contains(PairUnwrappedWrapped(103, &*threeD)));
2431 EXPECT_TRUE(dequeContains(*dequeWU, PairWrappedUnwrapped(&*threeE, 43)));
2432 EXPECT_TRUE(dequeContains(*dequeWU, PairWrappedUnwrapped(&*fourE, 44)));
2433 EXPECT_TRUE(dequeContains(*dequeWU, PairWrappedUnwrapped(&*fiveE, 45)));
2434 EXPECT_TRUE(dequeContains(*dequeWU2, PairWrappedUnwrapped(&*oneE, 42)));
2435 EXPECT_FALSE(dequeContains(*dequeWU2, PairWrappedUnwrapped(&*threeE, 43)));
2436 EXPECT_TRUE(dequeContains(*dequeUW, PairUnwrappedWrapped(103, &*threeF)));
2437 EXPECT_TRUE(dequeContains(*dequeUW, PairUnwrappedWrapped(104, &*fourF)));
2438 EXPECT_TRUE(dequeContains(*dequeUW, PairUnwrappedWrapped(105, &*fiveF)));
2439 EXPECT_TRUE(dequeContains(*dequeUW2, PairUnwrappedWrapped(1, &*oneF)));
2440 EXPECT_FALSE(dequeContains(*dequeUW2, PairUnwrappedWrapped(103, &*threeF)));
2441 }
2442
2443 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2444
2445 EXPECT_EQ(4u, memberMember->size());
2446 EXPECT_EQ(0u, memberMember2->size());
2447 EXPECT_EQ(4u, primitiveMember->size());
2448 EXPECT_EQ(4u, memberPrimitive->size());
2449 EXPECT_EQ(4u, set->size());
2450 EXPECT_EQ(1u, set2->size());
2451 EXPECT_EQ(1u, set3->size());
2452 EXPECT_EQ(2u, vector->size());
2453 EXPECT_EQ(1u, vector2->size());
2454 EXPECT_EQ(3u, vectorUW->size());
2455 EXPECT_EQ(1u, vector2->size());
2456 EXPECT_EQ(2u, deque->size());
2457 EXPECT_EQ(1u, deque2->size());
2458 EXPECT_EQ(3u, dequeUW->size());
2459 EXPECT_EQ(1u, deque2->size());
2460
2461 EXPECT_TRUE(memberMember->get(one) == two);
2462 EXPECT_TRUE(primitiveMember->get(1) == two);
2463 EXPECT_TRUE(primitiveMember->get(4) == one);
2464 EXPECT_EQ(2, memberPrimitive->get(one));
2465 EXPECT_EQ(3, memberPrimitive->get(two));
2466 EXPECT_TRUE(set->contains(one));
2467 EXPECT_TRUE(set->contains(two));
2468 EXPECT_FALSE(set->contains(oneB));
2469 EXPECT_TRUE(set2->contains(oneB));
2470 EXPECT_TRUE(set3->contains(oneB));
2471 EXPECT_EQ(2u, set3->find(oneB)->value);
2472 EXPECT_EQ(3, vector->at(0)->value());
2473 EXPECT_EQ(4, vector->at(1)->value());
2474 EXPECT_EQ(3, deque->begin()->get()->value());
2475 }
2476
2477 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2478 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2479
2480 EXPECT_EQ(4u, memberMember->size());
2481 EXPECT_EQ(4u, primitiveMember->size());
2482 EXPECT_EQ(4u, memberPrimitive->size());
2483 EXPECT_EQ(4u, set->size());
2484 EXPECT_EQ(1u, set2->size());
2485 EXPECT_EQ(2u, vector->size());
2486 EXPECT_EQ(1u, vector2->size());
2487 EXPECT_EQ(3u, vectorWU->size());
2488 EXPECT_EQ(1u, vectorWU2->size());
2489 EXPECT_EQ(3u, vectorUW->size());
2490 EXPECT_EQ(1u, vectorUW2->size());
2491 EXPECT_EQ(2u, deque->size());
2492 EXPECT_EQ(1u, deque2->size());
2493 EXPECT_EQ(3u, dequeWU->size());
2494 EXPECT_EQ(1u, dequeWU2->size());
2495 EXPECT_EQ(3u, dequeUW->size());
2496 EXPECT_EQ(1u, dequeUW2->size());
2497 }
2498
2499 template<typename T>
MapIteratorCheck(T & it,const T & end,int expected)2500 void MapIteratorCheck(T& it, const T& end, int expected)
2501 {
2502 int found = 0;
2503 while (it != end) {
2504 found++;
2505 int key = it->key->value();
2506 int value = it->value->value();
2507 EXPECT_TRUE(key >= 0 && key < 1100);
2508 EXPECT_TRUE(value >= 0 && value < 1100);
2509 ++it;
2510 }
2511 EXPECT_EQ(expected, found);
2512 }
2513
2514 template<typename T>
SetIteratorCheck(T & it,const T & end,int expected)2515 void SetIteratorCheck(T& it, const T& end, int expected)
2516 {
2517 int found = 0;
2518 while (it != end) {
2519 found++;
2520 int value = (*it)->value();
2521 EXPECT_TRUE(value >= 0 && value < 1100);
2522 ++it;
2523 }
2524 EXPECT_EQ(expected, found);
2525 }
2526
TEST(HeapTest,HeapWeakCollectionSimple)2527 TEST(HeapTest, HeapWeakCollectionSimple)
2528 {
2529 HeapStats initialHeapStats;
2530 clearOutOldGarbage(&initialHeapStats);
2531 IntWrapper::s_destructorCalls = 0;
2532
2533 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive;
2534
2535 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakStrong;
2536 typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeak;
2537 typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper> > WeakWeak;
2538 typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet;
2539 typedef HeapHashCountedSet<WeakMember<IntWrapper> > WeakCountedSet;
2540
2541 Persistent<WeakStrong> weakStrong = new WeakStrong();
2542 Persistent<StrongWeak> strongWeak = new StrongWeak();
2543 Persistent<WeakWeak> weakWeak = new WeakWeak();
2544 Persistent<WeakSet> weakSet = new WeakSet();
2545 Persistent<WeakCountedSet> weakCountedSet = new WeakCountedSet();
2546
2547 Persistent<IntWrapper> two = IntWrapper::create(2);
2548
2549 keepNumbersAlive.append(IntWrapper::create(103));
2550 keepNumbersAlive.append(IntWrapper::create(10));
2551
2552 {
2553 weakStrong->add(IntWrapper::create(1), two);
2554 strongWeak->add(two, IntWrapper::create(1));
2555 weakWeak->add(two, IntWrapper::create(42));
2556 weakWeak->add(IntWrapper::create(42), two);
2557 weakSet->add(IntWrapper::create(0));
2558 weakSet->add(two);
2559 weakSet->add(keepNumbersAlive[0]);
2560 weakSet->add(keepNumbersAlive[1]);
2561 weakCountedSet->add(IntWrapper::create(0));
2562 weakCountedSet->add(two);
2563 weakCountedSet->add(two);
2564 weakCountedSet->add(two);
2565 weakCountedSet->add(keepNumbersAlive[0]);
2566 weakCountedSet->add(keepNumbersAlive[1]);
2567 EXPECT_EQ(1u, weakStrong->size());
2568 EXPECT_EQ(1u, strongWeak->size());
2569 EXPECT_EQ(2u, weakWeak->size());
2570 EXPECT_EQ(4u, weakSet->size());
2571 EXPECT_EQ(4u, weakCountedSet->size());
2572 EXPECT_EQ(3u, weakCountedSet->find(two)->value);
2573 weakCountedSet->remove(two);
2574 EXPECT_EQ(2u, weakCountedSet->find(two)->value);
2575 }
2576
2577 keepNumbersAlive[0] = nullptr;
2578
2579 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2580
2581 EXPECT_EQ(0u, weakStrong->size());
2582 EXPECT_EQ(0u, strongWeak->size());
2583 EXPECT_EQ(0u, weakWeak->size());
2584 EXPECT_EQ(2u, weakSet->size());
2585 EXPECT_EQ(2u, weakCountedSet->size());
2586 }
2587
2588 template<typename Set>
orderedSetHelper(bool strong)2589 void orderedSetHelper(bool strong)
2590 {
2591 HeapStats initialHeapStats;
2592 clearOutOldGarbage(&initialHeapStats);
2593 IntWrapper::s_destructorCalls = 0;
2594
2595 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive;
2596
2597 Persistent<Set> set1 = new Set();
2598 Persistent<Set> set2 = new Set();
2599
2600 const Set& constSet = *set1.get();
2601
2602 keepNumbersAlive.append(IntWrapper::create(2));
2603 keepNumbersAlive.append(IntWrapper::create(103));
2604 keepNumbersAlive.append(IntWrapper::create(10));
2605
2606 set1->add(IntWrapper::create(0));
2607 set1->add(keepNumbersAlive[0]);
2608 set1->add(keepNumbersAlive[1]);
2609 set1->add(keepNumbersAlive[2]);
2610
2611 set2->clear();
2612 set2->add(IntWrapper::create(42));
2613 set2->clear();
2614
2615 EXPECT_EQ(4u, set1->size());
2616 typename Set::iterator it(set1->begin());
2617 typename Set::reverse_iterator reverse(set1->rbegin());
2618 typename Set::const_iterator cit(constSet.begin());
2619 typename Set::const_reverse_iterator creverse(constSet.rbegin());
2620
2621 EXPECT_EQ(0, (*it)->value());
2622 EXPECT_EQ(0, (*cit)->value());
2623 ++it;
2624 ++cit;
2625 EXPECT_EQ(2, (*it)->value());
2626 EXPECT_EQ(2, (*cit)->value());
2627 --it;
2628 --cit;
2629 EXPECT_EQ(0, (*it)->value());
2630 EXPECT_EQ(0, (*cit)->value());
2631 ++it;
2632 ++cit;
2633 ++it;
2634 ++cit;
2635 EXPECT_EQ(103, (*it)->value());
2636 EXPECT_EQ(103, (*cit)->value());
2637 ++it;
2638 ++cit;
2639 EXPECT_EQ(10, (*it)->value());
2640 EXPECT_EQ(10, (*cit)->value());
2641 ++it;
2642 ++cit;
2643
2644 EXPECT_EQ(10, (*reverse)->value());
2645 EXPECT_EQ(10, (*creverse)->value());
2646 ++reverse;
2647 ++creverse;
2648 EXPECT_EQ(103, (*reverse)->value());
2649 EXPECT_EQ(103, (*creverse)->value());
2650 --reverse;
2651 --creverse;
2652 EXPECT_EQ(10, (*reverse)->value());
2653 EXPECT_EQ(10, (*creverse)->value());
2654 ++reverse;
2655 ++creverse;
2656 ++reverse;
2657 ++creverse;
2658 EXPECT_EQ(2, (*reverse)->value());
2659 EXPECT_EQ(2, (*creverse)->value());
2660 ++reverse;
2661 ++creverse;
2662 EXPECT_EQ(0, (*reverse)->value());
2663 EXPECT_EQ(0, (*creverse)->value());
2664 ++reverse;
2665 ++creverse;
2666
2667 EXPECT_EQ(set1->end(), it);
2668 EXPECT_EQ(constSet.end(), cit);
2669 EXPECT_EQ(set1->rend(), reverse);
2670 EXPECT_EQ(constSet.rend(), creverse);
2671
2672 typename Set::iterator iX(set2->begin());
2673 EXPECT_EQ(set2->end(), iX);
2674
2675 if (strong)
2676 set1->remove(keepNumbersAlive[0]);
2677
2678 keepNumbersAlive[0] = nullptr;
2679
2680 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2681
2682 EXPECT_EQ(2u + (strong ? 1u : 0u), set1->size());
2683
2684 EXPECT_EQ(2 + (strong ? 0 : 1), IntWrapper::s_destructorCalls);
2685
2686 typename Set::iterator i2(set1->begin());
2687 if (strong) {
2688 EXPECT_EQ(0, (*i2)->value());
2689 ++i2;
2690 EXPECT_NE(set1->end(), i2);
2691 }
2692 EXPECT_EQ(103, (*i2)->value());
2693 ++i2;
2694 EXPECT_NE(set1->end(), i2);
2695 EXPECT_EQ(10, (*i2)->value());
2696 ++i2;
2697 EXPECT_EQ(set1->end(), i2);
2698 }
2699
TEST(HeapTest,HeapWeakLinkedHashSet)2700 TEST(HeapTest, HeapWeakLinkedHashSet)
2701 {
2702 orderedSetHelper<HeapLinkedHashSet<Member<IntWrapper> > >(true);
2703 orderedSetHelper<HeapLinkedHashSet<WeakMember<IntWrapper> > >(false);
2704 orderedSetHelper<HeapListHashSet<Member<IntWrapper> > >(true);
2705 }
2706
2707 class ThingWithDestructor {
2708 public:
ThingWithDestructor()2709 ThingWithDestructor()
2710 : m_x(emptyValue)
2711 {
2712 s_liveThingsWithDestructor++;
2713 }
2714
ThingWithDestructor(int x)2715 ThingWithDestructor(int x)
2716 : m_x(x)
2717 {
2718 s_liveThingsWithDestructor++;
2719 }
2720
ThingWithDestructor(const ThingWithDestructor & other)2721 ThingWithDestructor(const ThingWithDestructor&other)
2722 {
2723 *this = other;
2724 s_liveThingsWithDestructor++;
2725 }
2726
~ThingWithDestructor()2727 ~ThingWithDestructor()
2728 {
2729 s_liveThingsWithDestructor--;
2730 }
2731
value()2732 int value() { return m_x; }
2733
2734 static int s_liveThingsWithDestructor;
2735
hash()2736 unsigned hash() { return IntHash<int>::hash(m_x); }
2737
2738 private:
2739 static const int emptyValue = 0;
2740 int m_x;
2741 };
2742
2743 int ThingWithDestructor::s_liveThingsWithDestructor;
2744
2745 struct ThingWithDestructorTraits : public HashTraits<ThingWithDestructor> {
2746 static const bool needsDestruction = true;
2747 };
2748
heapMapDestructorHelper(bool clearMaps)2749 static void heapMapDestructorHelper(bool clearMaps)
2750 {
2751 HeapStats initialHeapStats;
2752 clearOutOldGarbage(&initialHeapStats);
2753 ThingWithDestructor::s_liveThingsWithDestructor = 0;
2754
2755 typedef HeapHashMap<WeakMember<IntWrapper>, RefPtr<RefCountedAndGarbageCollected> > RefMap;
2756
2757 typedef HeapHashMap<
2758 WeakMember<IntWrapper>,
2759 ThingWithDestructor,
2760 DefaultHash<WeakMember<IntWrapper> >::Hash,
2761 HashTraits<WeakMember<IntWrapper> >,
2762 ThingWithDestructorTraits> Map;
2763
2764 Persistent<Map> map(new Map());
2765 Persistent<RefMap> refMap(new RefMap());
2766
2767 Persistent<IntWrapper> luck(IntWrapper::create(103));
2768
2769 int baseLine, refBaseLine;
2770
2771 {
2772 Map stackMap;
2773 RefMap stackRefMap;
2774
2775 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2776 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2777
2778 stackMap.add(IntWrapper::create(42), ThingWithDestructor(1729));
2779 stackMap.add(luck, ThingWithDestructor(8128));
2780 stackRefMap.add(IntWrapper::create(42), RefCountedAndGarbageCollected::create());
2781 stackRefMap.add(luck, RefCountedAndGarbageCollected::create());
2782
2783 baseLine = ThingWithDestructor::s_liveThingsWithDestructor;
2784 refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls;
2785
2786 // Although the heap maps are on-stack, we can't expect prompt
2787 // finalization of the elements, so when they go out of scope here we
2788 // will not necessarily have called the relevant destructors.
2789 }
2790
2791 // The RefCountedAndGarbageCollected things need an extra GC to discover
2792 // that they are no longer ref counted.
2793 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2794 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2795 EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor);
2796 EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls);
2797
2798 // Now use maps kept alive with persistents. Here we don't expect any
2799 // destructors to be called before there have been GCs.
2800
2801 map->add(IntWrapper::create(42), ThingWithDestructor(1729));
2802 map->add(luck, ThingWithDestructor(8128));
2803 refMap->add(IntWrapper::create(42), RefCountedAndGarbageCollected::create());
2804 refMap->add(luck, RefCountedAndGarbageCollected::create());
2805
2806 baseLine = ThingWithDestructor::s_liveThingsWithDestructor;
2807 refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls;
2808
2809 luck.clear();
2810 if (clearMaps) {
2811 map->clear(); // Clear map.
2812 refMap->clear(); // Clear map.
2813 } else {
2814 map.clear(); // Clear Persistent handle, not map.
2815 refMap.clear(); // Clear Persistent handle, not map.
2816 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2817 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2818 }
2819
2820 EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor);
2821
2822 // Need a GC to make sure that the RefCountedAndGarbageCollected thing
2823 // noticies it's been decremented to zero.
2824 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2825 EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls);
2826 }
2827
TEST(HeapTest,HeapMapDestructor)2828 TEST(HeapTest, HeapMapDestructor)
2829 {
2830 heapMapDestructorHelper(true);
2831 heapMapDestructorHelper(false);
2832 }
2833
2834 typedef HeapHashSet<PairWeakStrong> WeakStrongSet;
2835 typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet;
2836 typedef HeapHashSet<PairStrongWeak> StrongWeakSet;
2837 typedef HeapHashSet<PairUnwrappedWeak> UnwrappedWeakSet;
2838 typedef HeapLinkedHashSet<PairWeakStrong> WeakStrongLinkedSet;
2839 typedef HeapLinkedHashSet<PairWeakUnwrapped> WeakUnwrappedLinkedSet;
2840 typedef HeapLinkedHashSet<PairStrongWeak> StrongWeakLinkedSet;
2841 typedef HeapLinkedHashSet<PairUnwrappedWeak> UnwrappedWeakLinkedSet;
2842 typedef HeapHashCountedSet<PairWeakStrong> WeakStrongCountedSet;
2843 typedef HeapHashCountedSet<PairWeakUnwrapped> WeakUnwrappedCountedSet;
2844 typedef HeapHashCountedSet<PairStrongWeak> StrongWeakCountedSet;
2845 typedef HeapHashCountedSet<PairUnwrappedWeak> UnwrappedWeakCountedSet;
2846
2847 template<typename T>
iteratorExtractor(WTF::KeyValuePair<T,unsigned> & pair)2848 T& iteratorExtractor(WTF::KeyValuePair<T, unsigned>& pair)
2849 {
2850 return pair.key;
2851 }
2852
2853 template<typename T>
iteratorExtractor(T & notAPair)2854 T& iteratorExtractor(T& notAPair)
2855 {
2856 return notAPair;
2857 }
2858
2859 template<typename WSSet, typename SWSet, typename WUSet, typename UWSet>
checkPairSets(Persistent<WSSet> & weakStrong,Persistent<SWSet> & strongWeak,Persistent<WUSet> & weakUnwrapped,Persistent<UWSet> & unwrappedWeak,bool ones,Persistent<IntWrapper> & two)2860 void checkPairSets(
2861 Persistent<WSSet>& weakStrong,
2862 Persistent<SWSet>& strongWeak,
2863 Persistent<WUSet>& weakUnwrapped,
2864 Persistent<UWSet>& unwrappedWeak,
2865 bool ones,
2866 Persistent<IntWrapper>& two)
2867 {
2868 typename WSSet::iterator itWS = weakStrong->begin();
2869 typename SWSet::iterator itSW = strongWeak->begin();
2870 typename WUSet::iterator itWU = weakUnwrapped->begin();
2871 typename UWSet::iterator itUW = unwrappedWeak->begin();
2872
2873 EXPECT_EQ(2u, weakStrong->size());
2874 EXPECT_EQ(2u, strongWeak->size());
2875 EXPECT_EQ(2u, weakUnwrapped->size());
2876 EXPECT_EQ(2u, unwrappedWeak->size());
2877
2878 PairWeakStrong p = iteratorExtractor(*itWS);
2879 PairStrongWeak p2 = iteratorExtractor(*itSW);
2880 PairWeakUnwrapped p3 = iteratorExtractor(*itWU);
2881 PairUnwrappedWeak p4 = iteratorExtractor(*itUW);
2882 if (p.first == two && p.second == two)
2883 ++itWS;
2884 if (p2.first == two && p2.second == two)
2885 ++itSW;
2886 if (p3.first == two && p3.second == 2)
2887 ++itWU;
2888 if (p4.first == 2 && p4.second == two)
2889 ++itUW;
2890 p = iteratorExtractor(*itWS);
2891 p2 = iteratorExtractor(*itSW);
2892 p3 = iteratorExtractor(*itWU);
2893 p4 = iteratorExtractor(*itUW);
2894 IntWrapper* nullWrapper = 0;
2895 if (ones) {
2896 EXPECT_EQ(p.first->value(), 1);
2897 EXPECT_EQ(p2.second->value(), 1);
2898 EXPECT_EQ(p3.first->value(), 1);
2899 EXPECT_EQ(p4.second->value(), 1);
2900 } else {
2901 EXPECT_EQ(p.first, nullWrapper);
2902 EXPECT_EQ(p2.second, nullWrapper);
2903 EXPECT_EQ(p3.first, nullWrapper);
2904 EXPECT_EQ(p4.second, nullWrapper);
2905 }
2906
2907 EXPECT_EQ(p.second->value(), 2);
2908 EXPECT_EQ(p2.first->value(), 2);
2909 EXPECT_EQ(p3.second, 2);
2910 EXPECT_EQ(p4.first, 2);
2911
2912 EXPECT_TRUE(weakStrong->contains(PairWeakStrong(&*two, &*two)));
2913 EXPECT_TRUE(strongWeak->contains(PairStrongWeak(&*two, &*two)));
2914 EXPECT_TRUE(weakUnwrapped->contains(PairWeakUnwrapped(&*two, 2)));
2915 EXPECT_TRUE(unwrappedWeak->contains(PairUnwrappedWeak(2, &*two)));
2916 }
2917
2918 template<typename WSSet, typename SWSet, typename WUSet, typename UWSet>
weakPairsHelper()2919 void weakPairsHelper()
2920 {
2921 IntWrapper::s_destructorCalls = 0;
2922
2923 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive;
2924
2925 Persistent<WSSet> weakStrong = new WSSet();
2926 Persistent<SWSet> strongWeak = new SWSet();
2927 Persistent<WUSet> weakUnwrapped = new WUSet();
2928 Persistent<UWSet> unwrappedWeak = new UWSet();
2929
2930 Persistent<IntWrapper> two = IntWrapper::create(2);
2931
2932 weakStrong->add(PairWeakStrong(IntWrapper::create(1), &*two));
2933 weakStrong->add(PairWeakStrong(&*two, &*two));
2934 strongWeak->add(PairStrongWeak(&*two, IntWrapper::create(1)));
2935 strongWeak->add(PairStrongWeak(&*two, &*two));
2936 weakUnwrapped->add(PairWeakUnwrapped(IntWrapper::create(1), 2));
2937 weakUnwrapped->add(PairWeakUnwrapped(&*two, 2));
2938 unwrappedWeak->add(PairUnwrappedWeak(2, IntWrapper::create(1)));
2939 unwrappedWeak->add(PairUnwrappedWeak(2, &*two));
2940
2941 checkPairSets<WSSet, SWSet, WUSet, UWSet>(weakStrong, strongWeak, weakUnwrapped, unwrappedWeak, true, two);
2942
2943 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2944 checkPairSets<WSSet, SWSet, WUSet, UWSet>(weakStrong, strongWeak, weakUnwrapped, unwrappedWeak, false, two);
2945 }
2946
TEST(HeapTest,HeapWeakPairs)2947 TEST(HeapTest, HeapWeakPairs)
2948 {
2949 {
2950 typedef HeapHashSet<PairWeakStrong> WeakStrongSet;
2951 typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet;
2952 typedef HeapHashSet<PairStrongWeak> StrongWeakSet;
2953 typedef HeapHashSet<PairUnwrappedWeak> UnwrappedWeakSet;
2954 weakPairsHelper<WeakStrongSet, StrongWeakSet, WeakUnwrappedSet, UnwrappedWeakSet>();
2955 }
2956
2957 {
2958 typedef HeapListHashSet<PairWeakStrong> WeakStrongSet;
2959 typedef HeapListHashSet<PairWeakUnwrapped> WeakUnwrappedSet;
2960 typedef HeapListHashSet<PairStrongWeak> StrongWeakSet;
2961 typedef HeapListHashSet<PairUnwrappedWeak> UnwrappedWeakSet;
2962 weakPairsHelper<WeakStrongSet, StrongWeakSet, WeakUnwrappedSet, UnwrappedWeakSet>();
2963 }
2964
2965 {
2966 typedef HeapLinkedHashSet<PairWeakStrong> WeakStrongSet;
2967 typedef HeapLinkedHashSet<PairWeakUnwrapped> WeakUnwrappedSet;
2968 typedef HeapLinkedHashSet<PairStrongWeak> StrongWeakSet;
2969 typedef HeapLinkedHashSet<PairUnwrappedWeak> UnwrappedWeakSet;
2970 weakPairsHelper<WeakStrongSet, StrongWeakSet, WeakUnwrappedSet, UnwrappedWeakSet>();
2971 }
2972 }
2973
TEST(HeapTest,HeapWeakCollectionTypes)2974 TEST(HeapTest, HeapWeakCollectionTypes)
2975 {
2976 HeapStats initialHeapSize;
2977 IntWrapper::s_destructorCalls = 0;
2978
2979 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakStrong;
2980 typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeak;
2981 typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper> > WeakWeak;
2982 typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet;
2983 typedef HeapLinkedHashSet<WeakMember<IntWrapper> > WeakOrderedSet;
2984
2985 clearOutOldGarbage(&initialHeapSize);
2986
2987 const int weakStrongIndex = 0;
2988 const int strongWeakIndex = 1;
2989 const int weakWeakIndex = 2;
2990 const int numberOfMapIndices = 3;
2991 const int weakSetIndex = 3;
2992 const int weakOrderedSetIndex = 4;
2993 const int numberOfCollections = 5;
2994
2995 for (int testRun = 0; testRun < 4; testRun++) {
2996 for (int collectionNumber = 0; collectionNumber < numberOfCollections; collectionNumber++) {
2997 bool deleteAfterwards = (testRun == 1);
2998 bool addAfterwards = (testRun == 2);
2999 bool testThatIteratorsMakeStrong = (testRun == 3);
3000
3001 // The test doesn't work for strongWeak with deleting because we lost
3002 // the key from the keepNumbersAlive array, so we can't do the lookup.
3003 if (deleteAfterwards && collectionNumber == strongWeakIndex)
3004 continue;
3005
3006 unsigned added = addAfterwards ? 100 : 0;
3007
3008 Persistent<WeakStrong> weakStrong = new WeakStrong();
3009 Persistent<StrongWeak> strongWeak = new StrongWeak();
3010 Persistent<WeakWeak> weakWeak = new WeakWeak();
3011
3012 Persistent<WeakSet> weakSet = new WeakSet();
3013 Persistent<WeakOrderedSet> weakOrderedSet = new WeakOrderedSet();
3014
3015 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive;
3016 for (int i = 0; i < 128; i += 2) {
3017 IntWrapper* wrapped = IntWrapper::create(i);
3018 IntWrapper* wrapped2 = IntWrapper::create(i + 1);
3019 keepNumbersAlive.append(wrapped);
3020 keepNumbersAlive.append(wrapped2);
3021 weakStrong->add(wrapped, wrapped2);
3022 strongWeak->add(wrapped2, wrapped);
3023 weakWeak->add(wrapped, wrapped2);
3024 weakSet->add(wrapped);
3025 weakOrderedSet->add(wrapped);
3026 }
3027
3028 EXPECT_EQ(64u, weakStrong->size());
3029 EXPECT_EQ(64u, strongWeak->size());
3030 EXPECT_EQ(64u, weakWeak->size());
3031 EXPECT_EQ(64u, weakSet->size());
3032 EXPECT_EQ(64u, weakOrderedSet->size());
3033
3034 // Collect garbage. This should change nothing since we are keeping
3035 // alive the IntWrapper objects.
3036 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3037
3038 EXPECT_EQ(64u, weakStrong->size());
3039 EXPECT_EQ(64u, strongWeak->size());
3040 EXPECT_EQ(64u, weakWeak->size());
3041 EXPECT_EQ(64u, weakSet->size());
3042 EXPECT_EQ(64u, weakOrderedSet->size());
3043
3044 for (int i = 0; i < 128; i += 2) {
3045 IntWrapper* wrapped = keepNumbersAlive[i];
3046 IntWrapper* wrapped2 = keepNumbersAlive[i + 1];
3047 EXPECT_EQ(wrapped2, weakStrong->get(wrapped));
3048 EXPECT_EQ(wrapped, strongWeak->get(wrapped2));
3049 EXPECT_EQ(wrapped2, weakWeak->get(wrapped));
3050 EXPECT_TRUE(weakSet->contains(wrapped));
3051 EXPECT_TRUE(weakOrderedSet->contains(wrapped));
3052 }
3053
3054 for (int i = 0; i < 128; i += 3)
3055 keepNumbersAlive[i] = nullptr;
3056
3057 if (collectionNumber != weakStrongIndex)
3058 weakStrong->clear();
3059 if (collectionNumber != strongWeakIndex)
3060 strongWeak->clear();
3061 if (collectionNumber != weakWeakIndex)
3062 weakWeak->clear();
3063 if (collectionNumber != weakSetIndex)
3064 weakSet->clear();
3065 if (collectionNumber != weakOrderedSetIndex)
3066 weakOrderedSet->clear();
3067
3068 if (testThatIteratorsMakeStrong) {
3069 WeakStrong::iterator it1 = weakStrong->begin();
3070 StrongWeak::iterator it2 = strongWeak->begin();
3071 WeakWeak::iterator it3 = weakWeak->begin();
3072 WeakSet::iterator it4 = weakSet->begin();
3073 WeakOrderedSet::iterator it5 = weakOrderedSet->begin();
3074 // Collect garbage. This should change nothing since the
3075 // iterators make the collections strong.
3076 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3077 if (collectionNumber == weakStrongIndex) {
3078 EXPECT_EQ(64u, weakStrong->size());
3079 MapIteratorCheck(it1, weakStrong->end(), 64);
3080 } else if (collectionNumber == strongWeakIndex) {
3081 EXPECT_EQ(64u, strongWeak->size());
3082 MapIteratorCheck(it2, strongWeak->end(), 64);
3083 } else if (collectionNumber == weakWeakIndex) {
3084 EXPECT_EQ(64u, weakWeak->size());
3085 MapIteratorCheck(it3, weakWeak->end(), 64);
3086 } else if (collectionNumber == weakSetIndex) {
3087 EXPECT_EQ(64u, weakSet->size());
3088 SetIteratorCheck(it4, weakSet->end(), 64);
3089 } else if (collectionNumber == weakOrderedSetIndex) {
3090 EXPECT_EQ(64u, weakOrderedSet->size());
3091 SetIteratorCheck(it5, weakOrderedSet->end(), 64);
3092 }
3093 } else {
3094 // Collect garbage. This causes weak processing to remove
3095 // things from the collections.
3096 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3097 unsigned count = 0;
3098 for (int i = 0; i < 128; i += 2) {
3099 bool firstAlive = keepNumbersAlive[i];
3100 bool secondAlive = keepNumbersAlive[i + 1];
3101 if (firstAlive && (collectionNumber == weakStrongIndex || collectionNumber == strongWeakIndex))
3102 secondAlive = true;
3103 if (firstAlive && secondAlive && collectionNumber < numberOfMapIndices) {
3104 if (collectionNumber == weakStrongIndex) {
3105 if (deleteAfterwards)
3106 EXPECT_EQ(i + 1, weakStrong->take(keepNumbersAlive[i])->value());
3107 } else if (collectionNumber == strongWeakIndex) {
3108 if (deleteAfterwards)
3109 EXPECT_EQ(i, strongWeak->take(keepNumbersAlive[i + 1])->value());
3110 } else if (collectionNumber == weakWeakIndex) {
3111 if (deleteAfterwards)
3112 EXPECT_EQ(i + 1, weakWeak->take(keepNumbersAlive[i])->value());
3113 }
3114 if (!deleteAfterwards)
3115 count++;
3116 } else if (collectionNumber == weakSetIndex && firstAlive) {
3117 ASSERT_TRUE(weakSet->contains(keepNumbersAlive[i]));
3118 if (deleteAfterwards)
3119 weakSet->remove(keepNumbersAlive[i]);
3120 else
3121 count++;
3122 } else if (collectionNumber == weakOrderedSetIndex && firstAlive) {
3123 ASSERT_TRUE(weakOrderedSet->contains(keepNumbersAlive[i]));
3124 if (deleteAfterwards)
3125 weakOrderedSet->remove(keepNumbersAlive[i]);
3126 else
3127 count++;
3128 }
3129 }
3130 if (addAfterwards) {
3131 for (int i = 1000; i < 1100; i++) {
3132 IntWrapper* wrapped = IntWrapper::create(i);
3133 keepNumbersAlive.append(wrapped);
3134 weakStrong->add(wrapped, wrapped);
3135 strongWeak->add(wrapped, wrapped);
3136 weakWeak->add(wrapped, wrapped);
3137 weakSet->add(wrapped);
3138 weakOrderedSet->add(wrapped);
3139 }
3140 }
3141 if (collectionNumber == weakStrongIndex)
3142 EXPECT_EQ(count + added, weakStrong->size());
3143 else if (collectionNumber == strongWeakIndex)
3144 EXPECT_EQ(count + added, strongWeak->size());
3145 else if (collectionNumber == weakWeakIndex)
3146 EXPECT_EQ(count + added, weakWeak->size());
3147 else if (collectionNumber == weakSetIndex)
3148 EXPECT_EQ(count + added, weakSet->size());
3149 else if (collectionNumber == weakOrderedSetIndex)
3150 EXPECT_EQ(count + added, weakOrderedSet->size());
3151 WeakStrong::iterator it1 = weakStrong->begin();
3152 StrongWeak::iterator it2 = strongWeak->begin();
3153 WeakWeak::iterator it3 = weakWeak->begin();
3154 WeakSet::iterator it4 = weakSet->begin();
3155 WeakOrderedSet::iterator it5 = weakOrderedSet->begin();
3156 MapIteratorCheck(it1, weakStrong->end(), (collectionNumber == weakStrongIndex ? count : 0) + added);
3157 MapIteratorCheck(it2, strongWeak->end(), (collectionNumber == strongWeakIndex ? count : 0) + added);
3158 MapIteratorCheck(it3, weakWeak->end(), (collectionNumber == weakWeakIndex ? count : 0) + added);
3159 SetIteratorCheck(it4, weakSet->end(), (collectionNumber == weakSetIndex ? count : 0) + added);
3160 SetIteratorCheck(it5, weakOrderedSet->end(), (collectionNumber == weakOrderedSetIndex ? count : 0) + added);
3161 }
3162 for (unsigned i = 0; i < 128 + added; i++)
3163 keepNumbersAlive[i] = nullptr;
3164 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3165 EXPECT_EQ(added, weakStrong->size());
3166 EXPECT_EQ(added, strongWeak->size());
3167 EXPECT_EQ(added, weakWeak->size());
3168 EXPECT_EQ(added, weakSet->size());
3169 EXPECT_EQ(added, weakOrderedSet->size());
3170 }
3171 }
3172 }
3173
TEST(HeapTest,RefCountedGarbageCollected)3174 TEST(HeapTest, RefCountedGarbageCollected)
3175 {
3176 RefCountedAndGarbageCollected::s_destructorCalls = 0;
3177 {
3178 RefPtr<RefCountedAndGarbageCollected> refPtr3;
3179 {
3180 Persistent<RefCountedAndGarbageCollected> persistent;
3181 {
3182 RefPtr<RefCountedAndGarbageCollected> refPtr1 = RefCountedAndGarbageCollected::create();
3183 RefPtr<RefCountedAndGarbageCollected> refPtr2 = RefCountedAndGarbageCollected::create();
3184 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3185 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
3186 persistent = refPtr1.get();
3187 }
3188 // Reference count is zero for both objects but one of
3189 // them is kept alive by a persistent handle.
3190 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3191 EXPECT_EQ(1, RefCountedAndGarbageCollected::s_destructorCalls);
3192 refPtr3 = persistent.get();
3193 }
3194 // The persistent handle is gone but the ref count has been
3195 // increased to 1.
3196 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3197 EXPECT_EQ(1, RefCountedAndGarbageCollected::s_destructorCalls);
3198 }
3199 // Both persistent handle is gone and ref count is zero so the
3200 // object can be collected.
3201 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3202 EXPECT_EQ(2, RefCountedAndGarbageCollected::s_destructorCalls);
3203 }
3204
TEST(HeapTest,RefCountedGarbageCollectedWithStackPointers)3205 TEST(HeapTest, RefCountedGarbageCollectedWithStackPointers)
3206 {
3207 RefCountedAndGarbageCollected::s_destructorCalls = 0;
3208 RefCountedAndGarbageCollected2::s_destructorCalls = 0;
3209 {
3210 RefCountedAndGarbageCollected* pointer1 = 0;
3211 RefCountedAndGarbageCollected2* pointer2 = 0;
3212 {
3213 RefPtr<RefCountedAndGarbageCollected> object1 = RefCountedAndGarbageCollected::create();
3214 RefPtr<RefCountedAndGarbageCollected2> object2 = RefCountedAndGarbageCollected2::create();
3215 pointer1 = object1.get();
3216 pointer2 = object2.get();
3217 void* objects[2] = { object1.get(), object2.get() };
3218 RefCountedGarbageCollectedVisitor visitor(2, objects);
3219 ThreadState::current()->visitPersistents(&visitor);
3220 EXPECT_TRUE(visitor.validate());
3221
3222 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3223 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
3224 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
3225 }
3226 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3227 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
3228 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
3229
3230 // At this point, the reference counts of object1 and object2 are 0.
3231 // Only pointer1 and pointer2 keep references to object1 and object2.
3232 void* objects[] = { 0 };
3233 RefCountedGarbageCollectedVisitor visitor(0, objects);
3234 ThreadState::current()->visitPersistents(&visitor);
3235 EXPECT_TRUE(visitor.validate());
3236
3237 {
3238 RefPtr<RefCountedAndGarbageCollected> object1(pointer1);
3239 RefPtr<RefCountedAndGarbageCollected2> object2(pointer2);
3240 void* objects[2] = { object1.get(), object2.get() };
3241 RefCountedGarbageCollectedVisitor visitor(2, objects);
3242 ThreadState::current()->visitPersistents(&visitor);
3243 EXPECT_TRUE(visitor.validate());
3244
3245 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3246 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
3247 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
3248 }
3249
3250 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3251 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
3252 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
3253 }
3254
3255 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3256 EXPECT_EQ(1, RefCountedAndGarbageCollected::s_destructorCalls);
3257 EXPECT_EQ(1, RefCountedAndGarbageCollected2::s_destructorCalls);
3258 }
3259
TEST(HeapTest,WeakMembers)3260 TEST(HeapTest, WeakMembers)
3261 {
3262 Bar::s_live = 0;
3263 {
3264 Persistent<Bar> h1 = Bar::create();
3265 Persistent<Weak> h4;
3266 Persistent<WithWeakMember> h5;
3267 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3268 ASSERT_EQ(1u, Bar::s_live); // h1 is live.
3269 {
3270 Bar* h2 = Bar::create();
3271 Bar* h3 = Bar::create();
3272 h4 = Weak::create(h2, h3);
3273 h5 = WithWeakMember::create(h2, h3);
3274 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3275 EXPECT_EQ(5u, Bar::s_live); // The on-stack pointer keeps h3 alive.
3276 EXPECT_TRUE(h4->strongIsThere());
3277 EXPECT_TRUE(h4->weakIsThere());
3278 EXPECT_TRUE(h5->strongIsThere());
3279 EXPECT_TRUE(h5->weakIsThere());
3280 }
3281 // h3 is collected, weak pointers from h4 and h5 don't keep it alive.
3282 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3283 EXPECT_EQ(4u, Bar::s_live);
3284 EXPECT_TRUE(h4->strongIsThere());
3285 EXPECT_FALSE(h4->weakIsThere()); // h3 is gone from weak pointer.
3286 EXPECT_TRUE(h5->strongIsThere());
3287 EXPECT_FALSE(h5->weakIsThere()); // h3 is gone from weak pointer.
3288 h1.release(); // Zero out h1.
3289 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3290 EXPECT_EQ(3u, Bar::s_live); // Only h4, h5 and h2 are left.
3291 EXPECT_TRUE(h4->strongIsThere()); // h2 is still pointed to from h4.
3292 EXPECT_TRUE(h5->strongIsThere()); // h2 is still pointed to from h5.
3293 }
3294 // h4 and h5 have gone out of scope now and they were keeping h2 alive.
3295 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3296 EXPECT_EQ(0u, Bar::s_live); // All gone.
3297 }
3298
TEST(HeapTest,FinalizationObserver)3299 TEST(HeapTest, FinalizationObserver)
3300 {
3301 Persistent<FinalizationObserver<Observable> > o;
3302 {
3303 Observable* foo = Observable::create(Bar::create());
3304 // |o| observes |foo|.
3305 o = FinalizationObserver<Observable>::create(foo);
3306 }
3307 // FinalizationObserver doesn't have a strong reference to |foo|. So |foo|
3308 // and its member will be collected.
3309 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3310 EXPECT_EQ(0u, Bar::s_live);
3311 EXPECT_TRUE(o->didCallWillFinalize());
3312
3313 FinalizationObserverWithHashMap::s_didCallWillFinalize = false;
3314 Observable* foo = Observable::create(Bar::create());
3315 FinalizationObserverWithHashMap::ObserverMap& map = FinalizationObserverWithHashMap::observe(*foo);
3316 EXPECT_EQ(1u, map.size());
3317 foo = 0;
3318 // FinalizationObserverWithHashMap doesn't have a strong reference to
3319 // |foo|. So |foo| and its member will be collected.
3320 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3321 EXPECT_EQ(0u, Bar::s_live);
3322 EXPECT_EQ(0u, map.size());
3323 EXPECT_TRUE(FinalizationObserverWithHashMap::s_didCallWillFinalize);
3324 }
3325
TEST(HeapTest,Comparisons)3326 TEST(HeapTest, Comparisons)
3327 {
3328 Persistent<Bar> barPersistent = Bar::create();
3329 Persistent<Foo> fooPersistent = Foo::create(barPersistent);
3330 EXPECT_TRUE(barPersistent != fooPersistent);
3331 barPersistent = fooPersistent;
3332 EXPECT_TRUE(barPersistent == fooPersistent);
3333 }
3334
TEST(HeapTest,CheckAndMarkPointer)3335 TEST(HeapTest, CheckAndMarkPointer)
3336 {
3337 HeapStats initialHeapStats;
3338 clearOutOldGarbage(&initialHeapStats);
3339
3340 Vector<Address> objectAddresses;
3341 Vector<Address> endAddresses;
3342 Address largeObjectAddress;
3343 Address largeObjectEndAddress;
3344 CountingVisitor visitor;
3345 for (int i = 0; i < 10; i++) {
3346 SimpleObject* object = SimpleObject::create();
3347 Address objectAddress = reinterpret_cast<Address>(object);
3348 objectAddresses.append(objectAddress);
3349 endAddresses.append(objectAddress + sizeof(SimpleObject) - 1);
3350 }
3351 LargeObject* largeObject = LargeObject::create();
3352 largeObjectAddress = reinterpret_cast<Address>(largeObject);
3353 largeObjectEndAddress = largeObjectAddress + sizeof(LargeObject) - 1;
3354
3355 // This is a low-level test where we call checkAndMarkPointer. This method
3356 // causes the object start bitmap to be computed which requires the heap
3357 // to be in a consistent state (e.g. the free allocation area must be put
3358 // into a free list header). However when we call makeConsistentForGC it
3359 // also clears out the freelists so we have to rebuild those before trying
3360 // to allocate anything again. We do this by forcing a GC after doing the
3361 // checkAndMarkPointer tests.
3362 {
3363 TestGCScope scope(ThreadState::HeapPointersOnStack);
3364 EXPECT_TRUE(scope.allThreadsParked()); // Fail the test if we could not park all threads.
3365 Heap::makeConsistentForGC();
3366 for (size_t i = 0; i < objectAddresses.size(); i++) {
3367 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, objectAddresses[i]));
3368 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, endAddresses[i]));
3369 }
3370 EXPECT_EQ(objectAddresses.size() * 2, visitor.count());
3371 visitor.reset();
3372 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, largeObjectAddress));
3373 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress));
3374 EXPECT_EQ(2ul, visitor.count());
3375 visitor.reset();
3376 }
3377 // This forces a GC without stack scanning which results in the objects
3378 // being collected. This will also rebuild the above mentioned freelists,
3379 // however we don't rely on that below since we don't have any allocations.
3380 clearOutOldGarbage(&initialHeapStats);
3381 {
3382 TestGCScope scope(ThreadState::HeapPointersOnStack);
3383 EXPECT_TRUE(scope.allThreadsParked());
3384 Heap::makeConsistentForGC();
3385 for (size_t i = 0; i < objectAddresses.size(); i++) {
3386 // We would like to assert that checkAndMarkPointer returned false
3387 // here because the pointers no longer point into a valid object
3388 // (it's been freed by the GCs. But checkAndMarkPointer will return
3389 // true for any pointer that points into a heap page, regardless of
3390 // whether it points at a valid object (this ensures the
3391 // correctness of the page-based on-heap address caches), so we
3392 // can't make that assert.
3393 Heap::checkAndMarkPointer(&visitor, objectAddresses[i]);
3394 Heap::checkAndMarkPointer(&visitor, endAddresses[i]);
3395 }
3396 EXPECT_EQ(0ul, visitor.count());
3397 Heap::checkAndMarkPointer(&visitor, largeObjectAddress);
3398 Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress);
3399 EXPECT_EQ(0ul, visitor.count());
3400 }
3401 // This round of GC is important to make sure that the object start
3402 // bitmap are cleared out and that the free lists are rebuild.
3403 clearOutOldGarbage(&initialHeapStats);
3404 }
3405
TEST(HeapTest,VisitOffHeapCollections)3406 TEST(HeapTest, VisitOffHeapCollections)
3407 {
3408 HeapStats initialHeapStats;
3409 clearOutOldGarbage(&initialHeapStats);
3410 IntWrapper::s_destructorCalls = 0;
3411 Persistent<OffHeapContainer> container = OffHeapContainer::create();
3412 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3413 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3414 container = nullptr;
3415 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3416 EXPECT_EQ(OffHeapContainer::deadWrappers, IntWrapper::s_destructorCalls);
3417 }
3418
TEST(HeapTest,PersistentHeapCollectionTypes)3419 TEST(HeapTest, PersistentHeapCollectionTypes)
3420 {
3421 HeapStats initialHeapSize;
3422 IntWrapper::s_destructorCalls = 0;
3423
3424 typedef HeapVector<Member<IntWrapper> > Vec;
3425 typedef PersistentHeapVector<Member<IntWrapper> > PVec;
3426 typedef PersistentHeapHashSet<Member<IntWrapper> > PSet;
3427 typedef PersistentHeapListHashSet<Member<IntWrapper> > PListSet;
3428 typedef PersistentHeapLinkedHashSet<Member<IntWrapper> > PLinkedSet;
3429 typedef PersistentHeapHashMap<Member<IntWrapper>, Member<IntWrapper> > PMap;
3430 typedef PersistentHeapDeque<Member<IntWrapper> > PDeque;
3431
3432 clearOutOldGarbage(&initialHeapSize);
3433 {
3434 PVec pVec;
3435 PDeque pDeque;
3436 PSet pSet;
3437 PListSet pListSet;
3438 PLinkedSet pLinkedSet;
3439 PMap pMap;
3440
3441 IntWrapper* one(IntWrapper::create(1));
3442 IntWrapper* two(IntWrapper::create(2));
3443 IntWrapper* three(IntWrapper::create(3));
3444 IntWrapper* four(IntWrapper::create(4));
3445 IntWrapper* five(IntWrapper::create(5));
3446 IntWrapper* six(IntWrapper::create(6));
3447 IntWrapper* seven(IntWrapper::create(7));
3448 IntWrapper* eight(IntWrapper::create(8));
3449 IntWrapper* nine(IntWrapper::create(9));
3450
3451 pVec.append(one);
3452 pVec.append(two);
3453
3454 pDeque.append(seven);
3455 pDeque.append(two);
3456
3457 Vec* vec = new Vec();
3458 vec->swap(pVec);
3459
3460 pVec.append(two);
3461 pVec.append(three);
3462
3463 pSet.add(four);
3464 pListSet.add(eight);
3465 pLinkedSet.add(nine);
3466 pMap.add(five, six);
3467
3468 // Collect |vec| and |one|.
3469 vec = 0;
3470 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3471 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
3472
3473 EXPECT_EQ(2u, pVec.size());
3474 EXPECT_EQ(two, pVec.at(0));
3475 EXPECT_EQ(three, pVec.at(1));
3476
3477 EXPECT_EQ(2u, pDeque.size());
3478 EXPECT_EQ(seven, pDeque.first());
3479 EXPECT_EQ(seven, pDeque.takeFirst());
3480 EXPECT_EQ(two, pDeque.first());
3481
3482 EXPECT_EQ(1u, pDeque.size());
3483
3484 EXPECT_EQ(1u, pSet.size());
3485 EXPECT_TRUE(pSet.contains(four));
3486
3487 EXPECT_EQ(1u, pListSet.size());
3488 EXPECT_TRUE(pListSet.contains(eight));
3489
3490 EXPECT_EQ(1u, pLinkedSet.size());
3491 EXPECT_TRUE(pLinkedSet.contains(nine));
3492
3493 EXPECT_EQ(1u, pMap.size());
3494 EXPECT_EQ(six, pMap.get(five));
3495 }
3496
3497 // Collect previous roots.
3498 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3499 EXPECT_EQ(9, IntWrapper::s_destructorCalls);
3500 }
3501
TEST(HeapTest,CollectionNesting)3502 TEST(HeapTest, CollectionNesting)
3503 {
3504 HeapStats initialStats;
3505 clearOutOldGarbage(&initialStats);
3506 int* key = &IntWrapper::s_destructorCalls;
3507 IntWrapper::s_destructorCalls = 0;
3508 typedef HeapVector<Member<IntWrapper> > IntVector;
3509 typedef HeapDeque<Member<IntWrapper> > IntDeque;
3510 HeapHashMap<void*, IntVector>* map = new HeapHashMap<void*, IntVector>();
3511 HeapHashMap<void*, IntDeque>* map2 = new HeapHashMap<void*, IntDeque>();
3512
3513 map->add(key, IntVector());
3514 map2->add(key, IntDeque());
3515
3516 HeapHashMap<void*, IntVector>::iterator it = map->find(key);
3517 EXPECT_EQ(0u, map->get(key).size());
3518
3519 HeapHashMap<void*, IntDeque>::iterator it2 = map2->find(key);
3520 EXPECT_EQ(0u, map2->get(key).size());
3521
3522 it->value.append(IntWrapper::create(42));
3523 EXPECT_EQ(1u, map->get(key).size());
3524
3525 it2->value.append(IntWrapper::create(42));
3526 EXPECT_EQ(1u, map2->get(key).size());
3527
3528 Persistent<HeapHashMap<void*, IntVector> > keepAlive(map);
3529 Persistent<HeapHashMap<void*, IntDeque> > keepAlive2(map2);
3530
3531 for (int i = 0; i < 100; i++) {
3532 map->add(key + 1 + i, IntVector());
3533 map2->add(key + 1 + i, IntDeque());
3534 }
3535
3536 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3537
3538 EXPECT_EQ(1u, map->get(key).size());
3539 EXPECT_EQ(1u, map2->get(key).size());
3540 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3541
3542 keepAlive = nullptr;
3543 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3544 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
3545 }
3546
TEST(HeapTest,GarbageCollectedMixin)3547 TEST(HeapTest, GarbageCollectedMixin)
3548 {
3549 HeapStats initialHeapStats;
3550 clearOutOldGarbage(&initialHeapStats);
3551
3552 Persistent<UseMixin> usemixin = UseMixin::create();
3553 EXPECT_EQ(0, UseMixin::s_traceCount);
3554 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3555 EXPECT_EQ(1, UseMixin::s_traceCount);
3556
3557 Persistent<Mixin> mixin = usemixin;
3558 usemixin = nullptr;
3559 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3560 EXPECT_EQ(2, UseMixin::s_traceCount);
3561
3562 PersistentHeapHashSet<WeakMember<Mixin> > weakMap;
3563 weakMap.add(UseMixin::create());
3564 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3565 EXPECT_EQ(0u, weakMap.size());
3566 }
3567
TEST(HeapTest,CollectionNesting2)3568 TEST(HeapTest, CollectionNesting2)
3569 {
3570 HeapStats initialStats;
3571 clearOutOldGarbage(&initialStats);
3572 void* key = &IntWrapper::s_destructorCalls;
3573 IntWrapper::s_destructorCalls = 0;
3574 typedef HeapHashSet<Member<IntWrapper> > IntSet;
3575 HeapHashMap<void*, IntSet>* map = new HeapHashMap<void*, IntSet>();
3576
3577 map->add(key, IntSet());
3578
3579 HeapHashMap<void*, IntSet>::iterator it = map->find(key);
3580 EXPECT_EQ(0u, map->get(key).size());
3581
3582 it->value.add(IntWrapper::create(42));
3583 EXPECT_EQ(1u, map->get(key).size());
3584
3585 Persistent<HeapHashMap<void*, IntSet> > keepAlive(map);
3586 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3587 EXPECT_EQ(1u, map->get(key).size());
3588 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3589 }
3590
TEST(HeapTest,CollectionNesting3)3591 TEST(HeapTest, CollectionNesting3)
3592 {
3593 HeapStats initialStats;
3594 clearOutOldGarbage(&initialStats);
3595 IntWrapper::s_destructorCalls = 0;
3596 typedef HeapVector<Member<IntWrapper> > IntVector;
3597 typedef HeapDeque<Member<IntWrapper> > IntDeque;
3598 HeapVector<IntVector>* vector = new HeapVector<IntVector>();
3599 HeapDeque<IntDeque>* deque = new HeapDeque<IntDeque>();
3600
3601 vector->append(IntVector());
3602 deque->append(IntDeque());
3603
3604 HeapVector<IntVector>::iterator it = vector->begin();
3605 HeapDeque<IntDeque>::iterator it2 = deque->begin();
3606 EXPECT_EQ(0u, it->size());
3607 EXPECT_EQ(0u, it2->size());
3608
3609 it->append(IntWrapper::create(42));
3610 it2->append(IntWrapper::create(42));
3611 EXPECT_EQ(1u, it->size());
3612 EXPECT_EQ(1u, it2->size());
3613
3614 Persistent<HeapVector<IntVector> > keepAlive(vector);
3615 Persistent<HeapDeque<IntDeque> > keepAlive2(deque);
3616 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3617 EXPECT_EQ(1u, it->size());
3618 EXPECT_EQ(1u, it2->size());
3619 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3620 }
3621
TEST(HeapTest,EmbeddedInVector)3622 TEST(HeapTest, EmbeddedInVector)
3623 {
3624 HeapStats initialStats;
3625 clearOutOldGarbage(&initialStats);
3626 SimpleFinalizedObject::s_destructorCalls = 0;
3627 {
3628 PersistentHeapVector<VectorObject, 2> inlineVector;
3629 PersistentHeapVector<VectorObject> outlineVector;
3630 VectorObject i1, i2;
3631 inlineVector.append(i1);
3632 inlineVector.append(i2);
3633
3634 VectorObject o1, o2;
3635 outlineVector.append(o1);
3636 outlineVector.append(o2);
3637
3638 PersistentHeapVector<VectorObjectInheritedTrace> vectorInheritedTrace;
3639 VectorObjectInheritedTrace it1, it2;
3640 vectorInheritedTrace.append(it1);
3641 vectorInheritedTrace.append(it2);
3642
3643 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3644 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls);
3645
3646 // Since VectorObjectNoTrace has no trace method it will
3647 // not be traced and hence be collected when doing GC.
3648 // We trace items in a collection braced on the item's
3649 // having a trace method. This is determined via the
3650 // NeedsTracing trait in wtf/TypeTraits.h.
3651 PersistentHeapVector<VectorObjectNoTrace> vectorNoTrace;
3652 VectorObjectNoTrace n1, n2;
3653 vectorNoTrace.append(n1);
3654 vectorNoTrace.append(n2);
3655 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3656 EXPECT_EQ(2, SimpleFinalizedObject::s_destructorCalls);
3657 }
3658 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3659 EXPECT_EQ(8, SimpleFinalizedObject::s_destructorCalls);
3660 }
3661
TEST(HeapTest,EmbeddedInDeque)3662 TEST(HeapTest, EmbeddedInDeque)
3663 {
3664 HeapStats initialStats;
3665 clearOutOldGarbage(&initialStats);
3666 SimpleFinalizedObject::s_destructorCalls = 0;
3667 {
3668 PersistentHeapDeque<VectorObject, 2> inlineDeque;
3669 PersistentHeapDeque<VectorObject> outlineDeque;
3670 VectorObject i1, i2;
3671 inlineDeque.append(i1);
3672 inlineDeque.append(i2);
3673
3674 VectorObject o1, o2;
3675 outlineDeque.append(o1);
3676 outlineDeque.append(o2);
3677
3678 PersistentHeapDeque<VectorObjectInheritedTrace> dequeInheritedTrace;
3679 VectorObjectInheritedTrace it1, it2;
3680 dequeInheritedTrace.append(it1);
3681 dequeInheritedTrace.append(it2);
3682
3683 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3684 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls);
3685
3686 // Since VectorObjectNoTrace has no trace method it will
3687 // not be traced and hence be collected when doing GC.
3688 // We trace items in a collection braced on the item's
3689 // having a trace method. This is determined via the
3690 // NeedsTracing trait in wtf/TypeTraits.h.
3691 PersistentHeapDeque<VectorObjectNoTrace> dequeNoTrace;
3692 VectorObjectNoTrace n1, n2;
3693 dequeNoTrace.append(n1);
3694 dequeNoTrace.append(n2);
3695 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3696 EXPECT_EQ(2, SimpleFinalizedObject::s_destructorCalls);
3697 }
3698 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3699 EXPECT_EQ(8, SimpleFinalizedObject::s_destructorCalls);
3700 }
3701
3702 template<typename Set>
rawPtrInHashHelper()3703 void rawPtrInHashHelper()
3704 {
3705 Set set;
3706 set.add(new int(42));
3707 set.add(new int(42));
3708 EXPECT_EQ(2u, set.size());
3709 for (typename Set::iterator it = set.begin(); it != set.end(); ++it)
3710 EXPECT_EQ(42, **it);
3711 }
3712
TEST(HeapTest,RawPtrInHash)3713 TEST(HeapTest, RawPtrInHash)
3714 {
3715 rawPtrInHashHelper<HashSet<RawPtr<int> > >();
3716 rawPtrInHashHelper<ListHashSet<RawPtr<int> > >();
3717 rawPtrInHashHelper<LinkedHashSet<RawPtr<int> > >();
3718 }
3719
TEST(HeapTest,HeapTerminatedArray)3720 TEST(HeapTest, HeapTerminatedArray)
3721 {
3722 HeapStats initialHeapSize;
3723 clearOutOldGarbage(&initialHeapSize);
3724 IntWrapper::s_destructorCalls = 0;
3725
3726 HeapTerminatedArray<TerminatedArrayItem>* arr = 0;
3727
3728 const size_t prefixSize = 4;
3729 const size_t suffixSize = 4;
3730
3731 {
3732 HeapTerminatedArrayBuilder<TerminatedArrayItem> builder(arr);
3733 builder.grow(prefixSize);
3734 for (size_t i = 0; i < prefixSize; i++)
3735 builder.append(TerminatedArrayItem(IntWrapper::create(i)));
3736 arr = builder.release();
3737 }
3738
3739 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3740 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3741 EXPECT_EQ(prefixSize, arr->size());
3742 for (size_t i = 0; i < prefixSize; i++)
3743 EXPECT_EQ(i, static_cast<size_t>(arr->at(i).payload()->value()));
3744
3745 {
3746 HeapTerminatedArrayBuilder<TerminatedArrayItem> builder(arr);
3747 builder.grow(suffixSize);
3748 for (size_t i = 0; i < suffixSize; i++)
3749 builder.append(TerminatedArrayItem(IntWrapper::create(prefixSize + i)));
3750 arr = builder.release();
3751 }
3752
3753 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3754 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3755 EXPECT_EQ(prefixSize + suffixSize, arr->size());
3756 for (size_t i = 0; i < prefixSize + suffixSize; i++)
3757 EXPECT_EQ(i, static_cast<size_t>(arr->at(i).payload()->value()));
3758
3759 {
3760 Persistent<HeapTerminatedArray<TerminatedArrayItem> > persistentArr = arr;
3761 arr = 0;
3762 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3763 arr = persistentArr.get();
3764 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3765 EXPECT_EQ(prefixSize + suffixSize, arr->size());
3766 for (size_t i = 0; i < prefixSize + suffixSize; i++)
3767 EXPECT_EQ(i, static_cast<size_t>(arr->at(i).payload()->value()));
3768 }
3769
3770 arr = 0;
3771 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3772 EXPECT_EQ(8, IntWrapper::s_destructorCalls);
3773 }
3774
TEST(HeapTest,HeapLinkedStack)3775 TEST(HeapTest, HeapLinkedStack)
3776 {
3777 HeapStats initialHeapSize;
3778 clearOutOldGarbage(&initialHeapSize);
3779 IntWrapper::s_destructorCalls = 0;
3780
3781 HeapLinkedStack<TerminatedArrayItem>* stack = new HeapLinkedStack<TerminatedArrayItem>();
3782
3783 const size_t stackSize = 10;
3784
3785 for (size_t i = 0; i < stackSize; i++)
3786 stack->push(TerminatedArrayItem(IntWrapper::create(i)));
3787
3788 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3789 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3790 EXPECT_EQ(stackSize, stack->size());
3791 while (!stack->isEmpty()) {
3792 EXPECT_EQ(stack->size() - 1, static_cast<size_t>(stack->peek().payload()->value()));
3793 stack->pop();
3794 }
3795
3796 Persistent<HeapLinkedStack<TerminatedArrayItem> > pStack = stack;
3797
3798 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3799 EXPECT_EQ(stackSize, static_cast<size_t>(IntWrapper::s_destructorCalls));
3800 EXPECT_EQ(0u, pStack->size());
3801 }
3802
TEST(HeapTest,AllocationDuringFinalization)3803 TEST(HeapTest, AllocationDuringFinalization)
3804 {
3805 HeapStats initialHeapSize;
3806 clearOutOldGarbage(&initialHeapSize);
3807 IntWrapper::s_destructorCalls = 0;
3808 OneKiloByteObject::s_destructorCalls = 0;
3809
3810 Persistent<IntWrapper> wrapper;
3811 new FinalizationAllocator(&wrapper);
3812
3813 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3814 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3815 // Check that the wrapper allocated during finalization is not
3816 // swept away and zapped later in the same sweeping phase.
3817 EXPECT_EQ(42, wrapper->value());
3818
3819 wrapper.clear();
3820 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3821 EXPECT_EQ(10, IntWrapper::s_destructorCalls);
3822 EXPECT_EQ(512, OneKiloByteObject::s_destructorCalls);
3823 }
3824
3825 class SimpleClassWithDestructor {
3826 public:
SimpleClassWithDestructor()3827 SimpleClassWithDestructor() { }
~SimpleClassWithDestructor()3828 ~SimpleClassWithDestructor()
3829 {
3830 s_wasDestructed = true;
3831 }
3832 static bool s_wasDestructed;
3833 };
3834
3835 bool SimpleClassWithDestructor::s_wasDestructed;
3836
3837 class RefCountedWithDestructor : public RefCounted<RefCountedWithDestructor> {
3838 public:
RefCountedWithDestructor()3839 RefCountedWithDestructor() { }
~RefCountedWithDestructor()3840 ~RefCountedWithDestructor()
3841 {
3842 s_wasDestructed = true;
3843 }
3844 static bool s_wasDestructed;
3845 };
3846
3847 bool RefCountedWithDestructor::s_wasDestructed;
3848
3849 template<typename Set>
destructorsCalledOnGC(bool addLots)3850 void destructorsCalledOnGC(bool addLots)
3851 {
3852 RefCountedWithDestructor::s_wasDestructed = false;
3853 {
3854 Set set;
3855 RefCountedWithDestructor* hasDestructor = new RefCountedWithDestructor();
3856 set.add(adoptRef(hasDestructor));
3857 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed);
3858
3859 if (addLots) {
3860 for (int i = 0; i < 1000; i++) {
3861 set.add(adoptRef(new RefCountedWithDestructor()));
3862 }
3863 }
3864
3865 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed);
3866 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3867 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed);
3868 }
3869 // The destructors of the sets don't call the destructors of the elements
3870 // in the heap sets. You have to actually remove the elments, call clear()
3871 // or have a GC to get the destructors called.
3872 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed);
3873 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3874 EXPECT_TRUE(RefCountedWithDestructor::s_wasDestructed);
3875 }
3876
3877 template<typename Set>
destructorsCalledOnClear(bool addLots)3878 void destructorsCalledOnClear(bool addLots)
3879 {
3880 RefCountedWithDestructor::s_wasDestructed = false;
3881 Set set;
3882 RefCountedWithDestructor* hasDestructor = new RefCountedWithDestructor();
3883 set.add(adoptRef(hasDestructor));
3884 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed);
3885
3886 if (addLots) {
3887 for (int i = 0; i < 1000; i++) {
3888 set.add(adoptRef(new RefCountedWithDestructor()));
3889 }
3890 }
3891
3892 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed);
3893 set.clear();
3894 EXPECT_TRUE(RefCountedWithDestructor::s_wasDestructed);
3895 }
3896
TEST(HeapTest,DestructorsCalled)3897 TEST(HeapTest, DestructorsCalled)
3898 {
3899 HeapHashMap<SimpleClassWithDestructor*, OwnPtr<SimpleClassWithDestructor> > map;
3900 SimpleClassWithDestructor* hasDestructor = new SimpleClassWithDestructor();
3901 map.add(hasDestructor, adoptPtr(hasDestructor));
3902 SimpleClassWithDestructor::s_wasDestructed = false;
3903 map.clear();
3904 EXPECT_TRUE(SimpleClassWithDestructor::s_wasDestructed);
3905
3906 destructorsCalledOnClear<HeapHashSet<RefPtr<RefCountedWithDestructor> > >(false);
3907 destructorsCalledOnClear<HeapListHashSet<RefPtr<RefCountedWithDestructor> > >(false);
3908 destructorsCalledOnClear<HeapLinkedHashSet<RefPtr<RefCountedWithDestructor> > >(false);
3909 destructorsCalledOnClear<HeapHashSet<RefPtr<RefCountedWithDestructor> > >(true);
3910 destructorsCalledOnClear<HeapListHashSet<RefPtr<RefCountedWithDestructor> > >(true);
3911 destructorsCalledOnClear<HeapLinkedHashSet<RefPtr<RefCountedWithDestructor> > >(true);
3912
3913 destructorsCalledOnGC<HeapHashSet<RefPtr<RefCountedWithDestructor> > >(false);
3914 destructorsCalledOnGC<HeapListHashSet<RefPtr<RefCountedWithDestructor> > >(false);
3915 destructorsCalledOnGC<HeapLinkedHashSet<RefPtr<RefCountedWithDestructor> > >(false);
3916 destructorsCalledOnGC<HeapHashSet<RefPtr<RefCountedWithDestructor> > >(true);
3917 destructorsCalledOnGC<HeapListHashSet<RefPtr<RefCountedWithDestructor> > >(true);
3918 destructorsCalledOnGC<HeapLinkedHashSet<RefPtr<RefCountedWithDestructor> > >(true);
3919 }
3920
3921 class MixinA : public GarbageCollectedMixin {
3922 public:
MixinA()3923 MixinA() : m_obj(IntWrapper::create(100)) { }
trace(Visitor * visitor)3924 virtual void trace(Visitor* visitor)
3925 {
3926 visitor->trace(m_obj);
3927 }
3928 Member<IntWrapper> m_obj;
3929 };
3930
3931 class MixinB : public GarbageCollectedMixin {
3932 public:
MixinB()3933 MixinB() : m_obj(IntWrapper::create(101)) { }
trace(Visitor * visitor)3934 virtual void trace(Visitor* visitor)
3935 {
3936 visitor->trace(m_obj);
3937 }
3938 Member<IntWrapper> m_obj;
3939 };
3940
3941 class MultipleMixins : public GarbageCollected<MultipleMixins>, public MixinA, public MixinB {
3942 USING_GARBAGE_COLLECTED_MIXIN(MultipleMixins);
3943 public:
MultipleMixins()3944 MultipleMixins() : m_obj(IntWrapper::create(102)) { }
trace(Visitor * visitor)3945 virtual void trace(Visitor* visitor)
3946 {
3947 visitor->trace(m_obj);
3948 MixinA::trace(visitor);
3949 MixinB::trace(visitor);
3950 }
3951 Member<IntWrapper> m_obj;
3952 };
3953
3954 static const bool s_isMixinTrue = IsGarbageCollectedMixin<MultipleMixins>::value;
3955 static const bool s_isMixinFalse = IsGarbageCollectedMixin<IntWrapper>::value;
3956
TEST(HeapTest,MultipleMixins)3957 TEST(HeapTest, MultipleMixins)
3958 {
3959 EXPECT_TRUE(s_isMixinTrue);
3960 EXPECT_FALSE(s_isMixinFalse);
3961
3962 HeapStats initialHeapSize;
3963 clearOutOldGarbage(&initialHeapSize);
3964 IntWrapper::s_destructorCalls = 0;
3965 MultipleMixins* obj = new MultipleMixins();
3966 {
3967 Persistent<MixinA> a = obj;
3968 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3969 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3970 }
3971 {
3972 Persistent<MixinB> b = obj;
3973 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3974 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3975 }
3976 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3977 EXPECT_EQ(3, IntWrapper::s_destructorCalls);
3978 }
3979
3980 class GCParkingThreadTester {
3981 public:
test()3982 static void test()
3983 {
3984 createThread(&sleeperMainFunc, 0, "SleepingThread");
3985
3986 // Wait for the sleeper to run.
3987 while (!s_sleeperRunning) {
3988 yield();
3989 }
3990
3991 {
3992 // Expect the first attempt to park the sleeping thread to fail
3993 TestGCScope scope(ThreadState::NoHeapPointersOnStack);
3994 EXPECT_FALSE(scope.allThreadsParked());
3995 }
3996
3997 s_sleeperDone = true;
3998
3999 // Wait for the sleeper to finish.
4000 while (s_sleeperRunning) {
4001 // We enter the safepoint here since the sleeper thread will detach
4002 // causing it to GC.
4003 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
4004 yield();
4005 }
4006 {
4007 // Since the sleeper thread has detached this is the only thread.
4008 TestGCScope scope(ThreadState::NoHeapPointersOnStack);
4009 EXPECT_TRUE(scope.allThreadsParked());
4010 }
4011 }
4012
4013 private:
sleeperMainFunc(void * data)4014 static void sleeperMainFunc(void* data)
4015 {
4016 ThreadState::attach();
4017 s_sleeperRunning = true;
4018
4019 // Simulate a long running op that is not entering a safepoint.
4020 while (!s_sleeperDone) {
4021 yield();
4022 }
4023
4024 ThreadState::detach();
4025 s_sleeperRunning = false;
4026 }
4027
4028 static volatile bool s_sleeperRunning;
4029 static volatile bool s_sleeperDone;
4030 };
4031
4032 volatile bool GCParkingThreadTester::s_sleeperRunning = false;
4033 volatile bool GCParkingThreadTester::s_sleeperDone = false;
4034
TEST(HeapTest,GCParkingTimeout)4035 TEST(HeapTest, GCParkingTimeout)
4036 {
4037 GCParkingThreadTester::test();
4038 }
4039
TEST(HeapTest,NeedsAdjustAndMark)4040 TEST(HeapTest, NeedsAdjustAndMark)
4041 {
4042 // class Mixin : public GarbageCollectedMixin {};
4043 EXPECT_TRUE(NeedsAdjustAndMark<Mixin>::value);
4044 EXPECT_TRUE(NeedsAdjustAndMark<const Mixin>::value);
4045
4046 // class SimpleObject : public GarbageCollected<SimpleObject> {};
4047 EXPECT_FALSE(NeedsAdjustAndMark<SimpleObject>::value);
4048 EXPECT_FALSE(NeedsAdjustAndMark<const SimpleObject>::value);
4049
4050 // class UseMixin : public SimpleObject, public Mixin {};
4051 EXPECT_FALSE(NeedsAdjustAndMark<UseMixin>::value);
4052 EXPECT_FALSE(NeedsAdjustAndMark<const UseMixin>::value);
4053 }
4054
4055 template<typename Set>
setWithCustomWeaknessHandling()4056 void setWithCustomWeaknessHandling()
4057 {
4058 typedef typename Set::iterator Iterator;
4059 Persistent<IntWrapper> livingInt(IntWrapper::create(42));
4060 Persistent<Set> set1(new Set());
4061 {
4062 Set set2;
4063 Set* set3 = new Set();
4064 set2.add(PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create(1)));
4065 set3->add(PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create(3)));
4066 set1->add(PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create(5)));
4067 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4068 // The first set is pointed to from a persistent, so it's referenced, but
4069 // the weak processing may have taken place.
4070 if (set1->size()) {
4071 Iterator i1 = set1->begin();
4072 EXPECT_EQ(4, i1->first->value());
4073 EXPECT_EQ(5, i1->second->value());
4074 }
4075 // The second set is on-stack, so its backing store must be referenced from
4076 // the stack. That makes the weak references strong.
4077 Iterator i2 = set2.begin();
4078 EXPECT_EQ(0, i2->first->value());
4079 EXPECT_EQ(1, i2->second->value());
4080 // The third set is pointed to from the stack, so it's referenced, but the
4081 // weak processing may have taken place.
4082 if (set3->size()) {
4083 Iterator i3 = set3->begin();
4084 EXPECT_EQ(2, i3->first->value());
4085 EXPECT_EQ(3, i3->second->value());
4086 }
4087 }
4088 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4089 EXPECT_EQ(0u, set1->size());
4090 set1->add(PairWithWeakHandling(IntWrapper::create(103), livingInt));
4091 set1->add(PairWithWeakHandling(livingInt, IntWrapper::create(103))); // This one gets zapped at GC time because nothing holds the 103 alive.
4092 set1->add(PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(103))); // This one gets zapped too.
4093 set1->add(PairWithWeakHandling(livingInt, livingInt));
4094 set1->add(PairWithWeakHandling(livingInt, livingInt)); // This one is identical to the previous and doesn't add anything.
4095 EXPECT_EQ(4u, set1->size());
4096 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4097 EXPECT_EQ(2u, set1->size());
4098 Iterator i1 = set1->begin();
4099 EXPECT_TRUE(i1->first->value() == 103 || i1->first == livingInt);
4100 EXPECT_EQ(livingInt, i1->second);
4101 ++i1;
4102 EXPECT_TRUE(i1->first->value() == 103 || i1->first == livingInt);
4103 EXPECT_EQ(livingInt, i1->second);
4104 }
4105
TEST(HeapTest,SetWithCustomWeaknessHandling)4106 TEST(HeapTest, SetWithCustomWeaknessHandling)
4107 {
4108 setWithCustomWeaknessHandling<HeapHashSet<PairWithWeakHandling> >();
4109 setWithCustomWeaknessHandling<HeapLinkedHashSet<PairWithWeakHandling> >();
4110 }
4111
TEST(HeapTest,MapWithCustomWeaknessHandling)4112 TEST(HeapTest, MapWithCustomWeaknessHandling)
4113 {
4114 typedef HeapHashMap<PairWithWeakHandling, RefPtr<OffHeapInt> > Map;
4115 typedef Map::iterator Iterator;
4116 HeapStats initialHeapSize;
4117 clearOutOldGarbage(&initialHeapSize);
4118 OffHeapInt::s_destructorCalls = 0;
4119
4120 Persistent<Map> map1(new Map());
4121 Persistent<IntWrapper> livingInt(IntWrapper::create(42));
4122 {
4123 Map map2;
4124 Map* map3 = new Map();
4125 map2.add(PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create(1)), OffHeapInt::create(1001));
4126 map3->add(PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create(3)), OffHeapInt::create(1002));
4127 map1->add(PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create(5)), OffHeapInt::create(1003));
4128 EXPECT_EQ(0, OffHeapInt::s_destructorCalls);
4129
4130 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4131 // The first map2 is pointed to from a persistent, so it's referenced, but
4132 // the weak processing may have taken place.
4133 if (map1->size()) {
4134 Iterator i1 = map1->begin();
4135 EXPECT_EQ(4, i1->key.first->value());
4136 EXPECT_EQ(5, i1->key.second->value());
4137 EXPECT_EQ(1003, i1->value->value());
4138 }
4139 // The second map2 is on-stack, so its backing store must be referenced from
4140 // the stack. That makes the weak references strong.
4141 Iterator i2 = map2.begin();
4142 EXPECT_EQ(0, i2->key.first->value());
4143 EXPECT_EQ(1, i2->key.second->value());
4144 EXPECT_EQ(1001, i2->value->value());
4145 // The third map2 is pointed to from the stack, so it's referenced, but the
4146 // weak processing may have taken place.
4147 if (map3->size()) {
4148 Iterator i3 = map3->begin();
4149 EXPECT_EQ(2, i3->key.first->value());
4150 EXPECT_EQ(3, i3->key.second->value());
4151 EXPECT_EQ(1002, i3->value->value());
4152 }
4153 }
4154 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4155
4156 EXPECT_EQ(0u, map1->size());
4157 EXPECT_EQ(3, OffHeapInt::s_destructorCalls);
4158
4159 OffHeapInt::s_destructorCalls = 0;
4160
4161 map1->add(PairWithWeakHandling(IntWrapper::create(103), livingInt), OffHeapInt::create(2000));
4162 map1->add(PairWithWeakHandling(livingInt, IntWrapper::create(103)), OffHeapInt::create(2001)); // This one gets zapped at GC time because nothing holds the 103 alive.
4163 map1->add(PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(103)), OffHeapInt::create(2002)); // This one gets zapped too.
4164 RefPtr<OffHeapInt> dupeInt(OffHeapInt::create(2003));
4165 map1->add(PairWithWeakHandling(livingInt, livingInt), dupeInt);
4166 map1->add(PairWithWeakHandling(livingInt, livingInt), dupeInt); // This one is identical to the previous and doesn't add anything.
4167 dupeInt.clear();
4168
4169 EXPECT_EQ(0, OffHeapInt::s_destructorCalls);
4170 EXPECT_EQ(4u, map1->size());
4171 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4172 EXPECT_EQ(2, OffHeapInt::s_destructorCalls);
4173 EXPECT_EQ(2u, map1->size());
4174 Iterator i1 = map1->begin();
4175 EXPECT_TRUE(i1->key.first->value() == 103 || i1->key.first == livingInt);
4176 EXPECT_EQ(livingInt, i1->key.second);
4177 ++i1;
4178 EXPECT_TRUE(i1->key.first->value() == 103 || i1->key.first == livingInt);
4179 EXPECT_EQ(livingInt, i1->key.second);
4180 }
4181
TEST(HeapTest,MapWithCustomWeaknessHandling2)4182 TEST(HeapTest, MapWithCustomWeaknessHandling2)
4183 {
4184 typedef HeapHashMap<RefPtr<OffHeapInt>, PairWithWeakHandling> Map;
4185 typedef Map::iterator Iterator;
4186 HeapStats initialHeapSize;
4187 clearOutOldGarbage(&initialHeapSize);
4188 OffHeapInt::s_destructorCalls = 0;
4189
4190 Persistent<Map> map1(new Map());
4191 Persistent<IntWrapper> livingInt(IntWrapper::create(42));
4192
4193 {
4194 Map map2;
4195 Map* map3 = new Map();
4196 map2.add(OffHeapInt::create(1001), PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create(1)));
4197 map3->add(OffHeapInt::create(1002), PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create(3)));
4198 map1->add(OffHeapInt::create(1003), PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create(5)));
4199 EXPECT_EQ(0, OffHeapInt::s_destructorCalls);
4200
4201 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4202 // The first map2 is pointed to from a persistent, so it's referenced, but
4203 // the weak processing may have taken place.
4204 if (map1->size()) {
4205 Iterator i1 = map1->begin();
4206 EXPECT_EQ(4, i1->value.first->value());
4207 EXPECT_EQ(5, i1->value.second->value());
4208 EXPECT_EQ(1003, i1->key->value());
4209 }
4210 // The second map2 is on-stack, so its backing store must be referenced from
4211 // the stack. That makes the weak references strong.
4212 Iterator i2 = map2.begin();
4213 EXPECT_EQ(0, i2->value.first->value());
4214 EXPECT_EQ(1, i2->value.second->value());
4215 EXPECT_EQ(1001, i2->key->value());
4216 // The third map2 is pointed to from the stack, so it's referenced, but the
4217 // weak processing may have taken place.
4218 if (map3->size()) {
4219 Iterator i3 = map3->begin();
4220 EXPECT_EQ(2, i3->value.first->value());
4221 EXPECT_EQ(3, i3->value.second->value());
4222 EXPECT_EQ(1002, i3->key->value());
4223 }
4224 }
4225 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4226
4227 EXPECT_EQ(0u, map1->size());
4228 EXPECT_EQ(3, OffHeapInt::s_destructorCalls);
4229
4230 OffHeapInt::s_destructorCalls = 0;
4231
4232 map1->add(OffHeapInt::create(2000), PairWithWeakHandling(IntWrapper::create(103), livingInt));
4233 map1->add(OffHeapInt::create(2001), PairWithWeakHandling(livingInt, IntWrapper::create(103))); // This one gets zapped at GC time because nothing holds the 103 alive.
4234 map1->add(OffHeapInt::create(2002), PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(103))); // This one gets zapped too.
4235 RefPtr<OffHeapInt> dupeInt(OffHeapInt::create(2003));
4236 map1->add(dupeInt, PairWithWeakHandling(livingInt, livingInt));
4237 map1->add(dupeInt, PairWithWeakHandling(livingInt, livingInt)); // This one is identical to the previous and doesn't add anything.
4238 dupeInt.clear();
4239
4240 EXPECT_EQ(0, OffHeapInt::s_destructorCalls);
4241 EXPECT_EQ(4u, map1->size());
4242 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4243 EXPECT_EQ(2, OffHeapInt::s_destructorCalls);
4244 EXPECT_EQ(2u, map1->size());
4245 Iterator i1 = map1->begin();
4246 EXPECT_TRUE(i1->value.first->value() == 103 || i1->value.first == livingInt);
4247 EXPECT_EQ(livingInt, i1->value.second);
4248 ++i1;
4249 EXPECT_TRUE(i1->value.first->value() == 103 || i1->value.first == livingInt);
4250 EXPECT_EQ(livingInt, i1->value.second);
4251 }
4252
TEST(HeapTest,Bind)4253 TEST(HeapTest, Bind)
4254 {
4255 Closure closure = bind(&Bar::trace, Bar::create(), static_cast<Visitor*>(0));
4256 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4257 // The closure should have a persistent handle to the Bar.
4258 EXPECT_EQ(1u, Bar::s_live);
4259
4260 Closure closure2 = bind(&Bar::trace, RawPtr<Bar>(Bar::create()), static_cast<Visitor*>(0));
4261 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4262 // The closure should have a persistent handle to the Bar.
4263 EXPECT_EQ(2u, Bar::s_live);
4264 // RawPtr<OffHeapInt> should not make Persistent.
4265 Closure closure3 = bind(&OffHeapInt::voidFunction, RawPtr<OffHeapInt>(OffHeapInt::create(1).get()));
4266
4267 UseMixin::s_traceCount = 0;
4268 Mixin* mixin = UseMixin::create();
4269 Closure mixinClosure = bind(&Mixin::trace, mixin, static_cast<Visitor*>(0));
4270 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4271 // The closure should have a persistent handle to the mixin.
4272 EXPECT_EQ(1, UseMixin::s_traceCount);
4273 }
4274
4275 typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet;
4276
4277 // These special traits will remove a set from a map when the set is empty.
4278 struct EmptyClearingHastSetTraits : HashTraits<WeakSet> {
4279 static const WTF::WeakHandlingFlag weakHandlingFlag = WTF::WeakHandlingInCollections;
shouldRemoveFromCollectionWebCore::EmptyClearingHastSetTraits4280 static bool shouldRemoveFromCollection(Visitor* visitor, WeakSet& set)
4281 {
4282 return set.isEmpty(); // Remove this set from any maps it is in.
4283 }
traceInCollectionWebCore::EmptyClearingHastSetTraits4284 static void traceInCollection(Visitor* visitor, WeakSet& set, WebCore::ShouldWeakPointersBeMarkedStrongly strongify)
4285 {
4286 // We just trace normally, which will invoke the normal weak handling
4287 // of the set, removing individual items.
4288 set.trace(visitor);
4289 }
4290 };
4291
4292 // This is an example to show how you can remove entries from a T->WeakSet map
4293 // when the weak sets become empty. For this example we are using a type that
4294 // is given to use (HeapHashSet) rather than a type of our own. This means:
4295 // 1) We can't just override the HashTrait for the type since this would affect
4296 // all collections that use this kind of weak set. Instead we have our own
4297 // traits and use a map with custom traits for the value type. These traits
4298 // are the 5th template parameter, so we have to supply default values for
4299 // the 3rd and 4th template parameters
4300 // 2) We can't just inherit from WeakHandlingHashTraits, since that trait
4301 // assumes we can add methods to the type, but we can't add methods to
4302 // HeapHashSet.
TEST(HeapTest,RemoveEmptySets)4303 TEST(HeapTest, RemoveEmptySets)
4304 {
4305 HeapStats initialHeapSize;
4306 clearOutOldGarbage(&initialHeapSize);
4307 OffHeapInt::s_destructorCalls = 0;
4308
4309 Persistent<IntWrapper> livingInt(IntWrapper::create(42));
4310
4311 typedef RefPtr<OffHeapInt> Key;
4312 typedef HeapHashMap<Key, WeakSet, WTF::DefaultHash<Key>::Hash, HashTraits<Key>, EmptyClearingHastSetTraits> Map;
4313 Persistent<Map> map(new Map());
4314 map->add(OffHeapInt::create(1), WeakSet());
4315 {
4316 WeakSet& set = map->begin()->value;
4317 set.add(IntWrapper::create(103)); // Weak set can't hold this long.
4318 set.add(livingInt); // This prevents the set from being emptied.
4319 EXPECT_EQ(2u, set.size());
4320 }
4321
4322 // The set we add here is empty, so the entry will be removed from the map
4323 // at the next GC.
4324 map->add(OffHeapInt::create(2), WeakSet());
4325 EXPECT_EQ(2u, map->size());
4326
4327 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4328 EXPECT_EQ(1u, map->size()); // The one with key 2 was removed.
4329 EXPECT_EQ(1, OffHeapInt::s_destructorCalls);
4330 {
4331 WeakSet& set = map->begin()->value;
4332 EXPECT_EQ(1u, set.size());
4333 }
4334
4335 livingInt.clear(); // The weak set can no longer keep the '42' alive now.
4336 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4337 if (map->size() == 1u) {
4338 // If the weak processing for the set ran after the weak processing for
4339 // the map, then the set was not empty, and so the entry in the map was
4340 // not removed yet.
4341 WeakSet& set = map->begin()->value;
4342 EXPECT_EQ(0u, set.size());
4343 }
4344
4345 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4346 EXPECT_EQ(0u, map->size());
4347 }
4348
4349 } // WebCore namespace
4350