blob: f1bbe104fdfd41094719fef93bc9a15c7321083e [file] [log] [blame]
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00001/*
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
Torne (Richard Coles)09380292014-02-21 12:17:33 +000033#include "heap/Handle.h"
Torne (Richard Coles)a854de02013-12-18 16:25:25 +000034#include "heap/Heap.h"
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +000035#include "heap/HeapLinkedStack.h"
36#include "heap/HeapTerminatedArrayBuilder.h"
Torne (Richard Coles)09380292014-02-21 12:17:33 +000037#include "heap/ThreadState.h"
38#include "heap/Visitor.h"
Torne (Richard Coles)a854de02013-12-18 16:25:25 +000039
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +000040#include "wtf/HashTraits.h"
41
Torne (Richard Coles)a854de02013-12-18 16:25:25 +000042#include <gtest/gtest.h>
43
Torne (Richard Coles)09380292014-02-21 12:17:33 +000044namespace WebCore {
Torne (Richard Coles)a854de02013-12-18 16:25:25 +000045
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +000046class ThreadMarker {
47public:
48 ThreadMarker() : m_creatingThread(reinterpret_cast<ThreadState*>(0)), m_num(0) { }
49 ThreadMarker(unsigned i) : m_creatingThread(ThreadState::current()), m_num(i) { }
50 ThreadMarker(WTF::HashTableDeletedValueType deleted) : m_creatingThread(reinterpret_cast<ThreadState*>(-1)), m_num(0) { }
51 ~ThreadMarker()
52 {
53 EXPECT_TRUE((m_creatingThread == ThreadState::current())
54 || (m_creatingThread == reinterpret_cast<ThreadState*>(0))
55 || (m_creatingThread == reinterpret_cast<ThreadState*>(-1)));
56 }
57 bool isHashTableDeletedValue() const { return m_creatingThread == reinterpret_cast<ThreadState*>(-1); }
58 bool operator==(const ThreadMarker& other) const { return other.m_creatingThread == m_creatingThread && other.m_num == m_num; }
59 ThreadState* m_creatingThread;
60 unsigned m_num;
61};
62
63struct ThreadMarkerHash {
64 static unsigned hash(const ThreadMarker& key)
65 {
66 return static_cast<unsigned>(reinterpret_cast<uintptr_t>(key.m_creatingThread) + key.m_num);
67 }
68
69 static bool equal(const ThreadMarker& a, const ThreadMarker& b)
70 {
71 return a == b;
72 }
73
74 static const bool safeToCompareToEmptyOrDeleted = false;
75};
76
77}
78
79namespace WTF {
80
81template<typename T> struct DefaultHash;
82template<> struct DefaultHash<WebCore::ThreadMarker> {
83 typedef WebCore::ThreadMarkerHash Hash;
84};
85
86// ThreadMarkerHash is the default hash for ThreadMarker
87template<> struct HashTraits<WebCore::ThreadMarker> : GenericHashTraits<WebCore::ThreadMarker> {
88 static const bool emptyValueIsZero = true;
89 static void constructDeletedValue(WebCore::ThreadMarker& slot) { new (NotNull, &slot) WebCore::ThreadMarker(HashTableDeletedValue); }
90 static bool isDeletedValue(const WebCore::ThreadMarker& slot) { return slot.isHashTableDeletedValue(); }
91};
92
93}
94
95namespace WebCore {
96
Torne (Richard Coles)09380292014-02-21 12:17:33 +000097class TestGCScope {
98public:
99 explicit TestGCScope(ThreadState::StackState state)
100 : m_state(ThreadState::current())
101 , m_safePointScope(state)
102 {
103 m_state->checkThread();
104 ASSERT(!m_state->isInGC());
105 ThreadState::stopThreads();
106 m_state->enterGC();
107 }
Torne (Richard Coles)a854de02013-12-18 16:25:25 +0000108
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000109 ~TestGCScope()
110 {
111 m_state->leaveGC();
112 ASSERT(!m_state->isInGC());
113 ThreadState::resumeThreads();
114 }
115
116private:
117 ThreadState* m_state;
118 ThreadState::SafePointScope m_safePointScope;
119};
120
121static void getHeapStats(HeapStats* stats)
Torne (Richard Coles)a854de02013-12-18 16:25:25 +0000122{
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000123 TestGCScope scope(ThreadState::NoHeapPointersOnStack);
124 Heap::getStats(stats);
Torne (Richard Coles)a854de02013-12-18 16:25:25 +0000125}
126
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000127#define DEFINE_VISITOR_METHODS(Type) \
128 virtual void mark(const Type* object, TraceCallback callback) OVERRIDE \
129 { \
130 if (object) \
131 m_count++; \
132 } \
133 virtual bool isMarked(const Type*) OVERRIDE { return false; }
134
135class CountingVisitor : public Visitor {
136public:
137 CountingVisitor()
138 : m_count(0)
139 {
140 }
141
142 virtual void mark(const void* object, TraceCallback) OVERRIDE
143 {
144 if (object)
145 m_count++;
146 }
147
148 virtual void mark(HeapObjectHeader* header, TraceCallback callback) OVERRIDE
149 {
150 ASSERT(header->payload());
151 m_count++;
152 }
153
154 virtual void mark(FinalizedHeapObjectHeader* header, TraceCallback callback) OVERRIDE
155 {
156 ASSERT(header->payload());
157 m_count++;
158 }
159
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000160 virtual void registerWeakMembers(const void*, const void*, WeakPointerCallback) OVERRIDE { }
161 virtual void registerWeakCell(void**, WeakPointerCallback) OVERRIDE { }
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000162 virtual bool isMarked(const void*) OVERRIDE { return false; }
163
164 FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS)
165
166 size_t count() { return m_count; }
167 void reset() { m_count = 0; }
168
169private:
170 size_t m_count;
171};
172
173class SimpleObject : public GarbageCollected<SimpleObject> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000174public:
175 static SimpleObject* create() { return new SimpleObject(); }
176 void trace(Visitor*) { }
177 char getPayload(int i) { return payload[i]; }
Ben Murdochaafa69c2014-04-03 12:30:15 +0100178 // This virtual method is unused but it is here to make sure
179 // that this object has a vtable. This object is used
180 // as the super class for objects that also have garbage
181 // collected mixins and having a virtual here makes sure
182 // that adjustment is needed both for marking and for isAlive
183 // checks.
184 virtual void virtualMethod() { }
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000185protected:
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000186 SimpleObject() { }
187 char payload[64];
188};
189
190#undef DEFINE_VISITOR_METHODS
191
192class HeapTestSuperClass : public GarbageCollectedFinalized<HeapTestSuperClass> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000193public:
194 static HeapTestSuperClass* create()
195 {
196 return new HeapTestSuperClass();
197 }
198
199 virtual ~HeapTestSuperClass()
200 {
201 ++s_destructorCalls;
202 }
203
204 static int s_destructorCalls;
205 void trace(Visitor*) { }
206
207protected:
208 HeapTestSuperClass() { }
209};
210
211int HeapTestSuperClass::s_destructorCalls = 0;
212
213class HeapTestOtherSuperClass {
214public:
215 int payload;
216};
217
218static const size_t classMagic = 0xABCDDBCA;
219
220class HeapTestSubClass : public HeapTestOtherSuperClass, public HeapTestSuperClass {
221public:
222 static HeapTestSubClass* create()
223 {
224 return new HeapTestSubClass();
225 }
226
227 virtual ~HeapTestSubClass()
228 {
229 EXPECT_EQ(classMagic, m_magic);
230 ++s_destructorCalls;
231 }
232
233 static int s_destructorCalls;
234
235private:
236
237 HeapTestSubClass() : m_magic(classMagic) { }
238
239 const size_t m_magic;
240};
241
242int HeapTestSubClass::s_destructorCalls = 0;
243
244class HeapAllocatedArray : public GarbageCollected<HeapAllocatedArray> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000245public:
246 HeapAllocatedArray()
247 {
248 for (int i = 0; i < s_arraySize; ++i) {
249 m_array[i] = i % 128;
250 }
251 }
252
253 int8_t at(size_t i) { return m_array[i]; }
254 void trace(Visitor*) { }
255private:
256 static const int s_arraySize = 1000;
257 int8_t m_array[s_arraySize];
258};
259
260// Do several GCs to make sure that later GCs don't free up old memory from
261// previously run tests in this process.
262static void clearOutOldGarbage(HeapStats* heapStats)
263{
264 while (true) {
265 getHeapStats(heapStats);
266 size_t used = heapStats->totalObjectSpace();
267 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
268 getHeapStats(heapStats);
269 if (heapStats->totalObjectSpace() >= used)
270 break;
271 }
272}
273
274class IntWrapper : public GarbageCollectedFinalized<IntWrapper> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000275public:
276 static IntWrapper* create(int x)
277 {
278 return new IntWrapper(x);
279 }
280
281 virtual ~IntWrapper()
282 {
283 ++s_destructorCalls;
284 }
285
286 static int s_destructorCalls;
287 static void trace(Visitor*) { }
288
289 int value() const { return m_x; }
290
291 bool operator==(const IntWrapper& other) const { return other.value() == value(); }
292
293 unsigned hash() { return IntHash<int>::hash(m_x); }
294
295protected:
296 IntWrapper(int x) : m_x(x) { }
297
298private:
299 IntWrapper();
300 int m_x;
301};
302
303USED_FROM_MULTIPLE_THREADS(IntWrapper);
304
305int IntWrapper::s_destructorCalls = 0;
306
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000307class ThreadedTesterBase {
308protected:
309 static void test(ThreadedTesterBase* tester)
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000310 {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000311 for (int i = 0; i < numberOfThreads; i++)
312 createThread(&threadFunc, tester, "testing thread");
313 while (tester->m_threadsToFinish) {
314 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
315 yield();
316 }
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000317 delete tester;
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000318 }
319
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000320 virtual void runThread() = 0;
321
322protected:
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000323 static const int numberOfThreads = 10;
324 static const int gcPerThread = 5;
325 static const int numberOfAllocations = 50;
326
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000327 ThreadedTesterBase() : m_gcCount(0), m_threadsToFinish(numberOfThreads)
328 {
329 }
330
331 virtual ~ThreadedTesterBase()
332 {
333 }
334
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000335 inline bool done() const { return m_gcCount >= numberOfThreads * gcPerThread; }
336
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000337 volatile int m_gcCount;
338 volatile int m_threadsToFinish;
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000339
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000340private:
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000341 static void threadFunc(void* data)
342 {
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000343 reinterpret_cast<ThreadedTesterBase*>(data)->runThread();
344 }
345};
346
347class ThreadedHeapTester : public ThreadedTesterBase {
348public:
349 static void test()
350 {
351 ThreadedTesterBase::test(new ThreadedHeapTester);
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000352 }
353
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000354protected:
355 virtual void runThread() OVERRIDE
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000356 {
357 ThreadState::attach();
358
359 int gcCount = 0;
360 while (!done()) {
361 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
362 {
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000363 Persistent<IntWrapper> wrapper;
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000364
365 typedef Persistent<IntWrapper, GlobalPersistents> GlobalIntWrapperPersistent;
366 OwnPtr<GlobalIntWrapperPersistent> globalPersistent = adoptPtr(new GlobalIntWrapperPersistent(IntWrapper::create(0x0ed0cabb)));
367
368 for (int i = 0; i < numberOfAllocations; i++) {
369 wrapper = IntWrapper::create(0x0bbac0de);
370 if (!(i % 10)) {
371 globalPersistent = adoptPtr(new GlobalIntWrapperPersistent(IntWrapper::create(0x0ed0cabb)));
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000372 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000373 }
374 yield();
375 }
376
377 if (gcCount < gcPerThread) {
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000378 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000379 gcCount++;
380 atomicIncrement(&m_gcCount);
381 }
382
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000383 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000384 EXPECT_EQ(wrapper->value(), 0x0bbac0de);
385 EXPECT_EQ((*globalPersistent)->value(), 0x0ed0cabb);
386 }
387 yield();
388 }
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000389 ThreadState::detach();
390 atomicDecrement(&m_threadsToFinish);
391 }
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000392};
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000393
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000394class ThreadedWeaknessTester : public ThreadedTesterBase {
395public:
396 static void test()
397 {
398 ThreadedTesterBase::test(new ThreadedWeaknessTester);
399 }
400
401private:
402 virtual void runThread() OVERRIDE
403 {
404 ThreadState::attach();
405
406 int gcCount = 0;
407 while (!done()) {
408 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
409 {
410 Persistent<HeapHashMap<ThreadMarker, WeakMember<IntWrapper> > > weakMap = new HeapHashMap<ThreadMarker, WeakMember<IntWrapper> >;
411 PersistentHeapHashMap<ThreadMarker, WeakMember<IntWrapper> > weakMap2;
412
413 for (int i = 0; i < numberOfAllocations; i++) {
414 weakMap->add(static_cast<unsigned>(i), IntWrapper::create(0));
415 weakMap2.add(static_cast<unsigned>(i), IntWrapper::create(0));
416 if (!(i % 10)) {
417 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
418 }
419 yield();
420 }
421
422 if (gcCount < gcPerThread) {
423 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
424 gcCount++;
425 atomicIncrement(&m_gcCount);
426 }
427
428 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
429 EXPECT_TRUE(weakMap->isEmpty());
430 EXPECT_TRUE(weakMap2.isEmpty());
431 }
432 yield();
433 }
434 ThreadState::detach();
435 atomicDecrement(&m_threadsToFinish);
436 }
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000437};
438
439// The accounting for memory includes the memory used by rounding up object
440// sizes. This is done in a different way on 32 bit and 64 bit, so we have to
441// have some slack in the tests.
442template<typename T>
443void CheckWithSlack(T expected, T actual, int slack)
444{
445 EXPECT_LE(expected, actual);
446 EXPECT_GE((intptr_t)expected + slack, (intptr_t)actual);
447}
448
449class TraceCounter : public GarbageCollectedFinalized<TraceCounter> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000450public:
451 static TraceCounter* create()
452 {
453 return new TraceCounter();
454 }
455
456 void trace(Visitor*) { m_traceCount++; }
457
458 int traceCount() { return m_traceCount; }
459
460private:
461 TraceCounter()
462 : m_traceCount(0)
463 {
464 }
465
466 int m_traceCount;
467};
468
469class ClassWithMember : public GarbageCollected<ClassWithMember> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000470public:
471 static ClassWithMember* create()
472 {
473 return new ClassWithMember();
474 }
475
476 void trace(Visitor* visitor)
477 {
478 EXPECT_TRUE(visitor->isMarked(this));
479 if (!traceCount())
480 EXPECT_FALSE(visitor->isMarked(m_traceCounter));
481 else
482 EXPECT_TRUE(visitor->isMarked(m_traceCounter));
483
484 visitor->trace(m_traceCounter);
485 }
486
487 int traceCount() { return m_traceCounter->traceCount(); }
488
489private:
490 ClassWithMember()
491 : m_traceCounter(TraceCounter::create())
492 { }
493
494 Member<TraceCounter> m_traceCounter;
495};
496
497class SimpleFinalizedObject : public GarbageCollectedFinalized<SimpleFinalizedObject> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000498public:
499 static SimpleFinalizedObject* create()
500 {
501 return new SimpleFinalizedObject();
502 }
503
504 ~SimpleFinalizedObject()
505 {
506 ++s_destructorCalls;
507 }
508
509 static int s_destructorCalls;
510
511 void trace(Visitor*) { }
512
513private:
514 SimpleFinalizedObject() { }
515};
516
517int SimpleFinalizedObject::s_destructorCalls = 0;
518
519class TestTypedHeapClass : public GarbageCollected<TestTypedHeapClass> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000520public:
521 static TestTypedHeapClass* create()
522 {
523 return new TestTypedHeapClass();
524 }
525
526 void trace(Visitor*) { }
527
528private:
529 TestTypedHeapClass() { }
530};
531
532class Bar : public GarbageCollectedFinalized<Bar> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000533public:
534 static Bar* create()
535 {
536 return new Bar();
537 }
538
Torne (Richard Coles)43e75022014-03-21 14:26:12 +0000539 void finalizeGarbageCollectedObject()
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000540 {
541 EXPECT_TRUE(m_magic == magic);
542 m_magic = 0;
543 s_live--;
544 }
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000545 bool hasBeenFinalized() const { return !m_magic; }
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000546
547 virtual void trace(Visitor* visitor) { }
548 static unsigned s_live;
549
550protected:
551 static const int magic = 1337;
552 int m_magic;
553
554 Bar()
555 : m_magic(magic)
556 {
557 s_live++;
558 }
559};
560
561unsigned Bar::s_live = 0;
562
563class Baz : public GarbageCollected<Baz> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000564public:
565 static Baz* create(Bar* bar)
566 {
567 return new Baz(bar);
568 }
569
570 void trace(Visitor* visitor)
571 {
572 visitor->trace(m_bar);
573 }
574
575 void clear() { m_bar.release(); }
576
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000577 // willFinalize is called by FinalizationObserver.
578 void willFinalize()
579 {
580 EXPECT_TRUE(!m_bar->hasBeenFinalized());
581 }
582
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000583private:
584 explicit Baz(Bar* bar)
585 : m_bar(bar)
586 {
587 }
588
589 Member<Bar> m_bar;
590};
591
592class Foo : public Bar {
593public:
594 static Foo* create(Bar* bar)
595 {
596 return new Foo(bar);
597 }
598
599 static Foo* create(Foo* foo)
600 {
601 return new Foo(foo);
602 }
603
604 virtual void trace(Visitor* visitor) OVERRIDE
605 {
606 if (m_pointsToFoo)
607 visitor->mark(static_cast<Foo*>(m_bar));
608 else
609 visitor->mark(m_bar);
610 }
611
612private:
613 Foo(Bar* bar)
614 : Bar()
615 , m_bar(bar)
616 , m_pointsToFoo(false)
617 {
618 }
619
620 Foo(Foo* foo)
621 : Bar()
622 , m_bar(foo)
623 , m_pointsToFoo(true)
624 {
625 }
626
627 Bar* m_bar;
628 bool m_pointsToFoo;
629};
630
631class Bars : public Bar {
632public:
633 static Bars* create()
634 {
635 return new Bars();
636 }
637
638 virtual void trace(Visitor* visitor) OVERRIDE
639 {
640 for (unsigned i = 0; i < m_width; i++)
641 visitor->trace(m_bars[i]);
642 }
643
644 unsigned getWidth() const
645 {
646 return m_width;
647 }
648
649 static const unsigned width = 7500;
650private:
651 Bars() : m_width(0)
652 {
653 for (unsigned i = 0; i < width; i++) {
654 m_bars[i] = Bar::create();
655 m_width++;
656 }
657 }
658
659 unsigned m_width;
660 Member<Bar> m_bars[width];
661};
662
663class ConstructorAllocation : public GarbageCollected<ConstructorAllocation> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000664public:
665 static ConstructorAllocation* create() { return new ConstructorAllocation(); }
666
667 void trace(Visitor* visitor) { visitor->trace(m_intWrapper); }
668
669private:
670 ConstructorAllocation()
671 {
672 m_intWrapper = IntWrapper::create(42);
673 }
674
675 Member<IntWrapper> m_intWrapper;
676};
677
678class LargeObject : public GarbageCollectedFinalized<LargeObject> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000679public:
680 ~LargeObject()
681 {
682 s_destructorCalls++;
683 }
684 static LargeObject* create() { return new LargeObject(); }
685 char get(size_t i) { return m_data[i]; }
686 void set(size_t i, char c) { m_data[i] = c; }
687 size_t length() { return s_length; }
688 void trace(Visitor* visitor)
689 {
690 visitor->trace(m_intWrapper);
691 }
692 static int s_destructorCalls;
693
694private:
695 static const size_t s_length = 1024*1024;
696 LargeObject()
697 {
698 m_intWrapper = IntWrapper::create(23);
699 }
700 Member<IntWrapper> m_intWrapper;
701 char m_data[s_length];
702};
703
704int LargeObject::s_destructorCalls = 0;
705
706class RefCountedAndGarbageCollected : public RefCountedGarbageCollected<RefCountedAndGarbageCollected> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000707public:
708 static PassRefPtr<RefCountedAndGarbageCollected> create()
709 {
710 return adoptRef(new RefCountedAndGarbageCollected());
711 }
712
713 ~RefCountedAndGarbageCollected()
714 {
715 ++s_destructorCalls;
716 }
717
Ben Murdochaafa69c2014-04-03 12:30:15 +0100718 // These are here with their default implementations so you can break in
719 // them in the debugger.
720 void ref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::ref(); }
721 void deref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::deref(); }
722
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000723 void trace(Visitor*) { }
724
725 static int s_destructorCalls;
726
727private:
728 RefCountedAndGarbageCollected()
729 {
730 }
731};
732
733int RefCountedAndGarbageCollected::s_destructorCalls = 0;
734
735class RefCountedAndGarbageCollected2 : public HeapTestOtherSuperClass, public RefCountedGarbageCollected<RefCountedAndGarbageCollected2> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000736public:
737 static RefCountedAndGarbageCollected2* create()
738 {
739 return adoptRefCountedGarbageCollected(new RefCountedAndGarbageCollected2());
740 }
741
742 ~RefCountedAndGarbageCollected2()
743 {
744 ++s_destructorCalls;
745 }
746
747 void trace(Visitor*) { }
748
749 static int s_destructorCalls;
750
751private:
752 RefCountedAndGarbageCollected2()
753 {
754 }
755};
756
757int RefCountedAndGarbageCollected2::s_destructorCalls = 0;
758
759#define DEFINE_VISITOR_METHODS(Type) \
760 virtual void mark(const Type* object, TraceCallback callback) OVERRIDE \
761 { \
762 mark(object); \
763 } \
764
765class RefCountedGarbageCollectedVisitor : public CountingVisitor {
766public:
767 RefCountedGarbageCollectedVisitor(int expected, void** objects)
768 : m_count(0)
769 , m_expectedCount(expected)
770 , m_expectedObjects(objects)
771 {
772 }
773
774 void mark(const void* ptr) { markNoTrace(ptr); }
775
776 virtual void markNoTrace(const void* ptr)
777 {
778 if (!ptr)
779 return;
780 if (m_count < m_expectedCount)
781 EXPECT_TRUE(expectedObject(ptr));
782 else
783 EXPECT_FALSE(expectedObject(ptr));
784 m_count++;
785 }
786
787 virtual void mark(const void* ptr, TraceCallback) OVERRIDE
788 {
789 mark(ptr);
790 }
791
792 virtual void mark(HeapObjectHeader* header, TraceCallback callback) OVERRIDE
793 {
794 mark(header->payload());
795 }
796
797 virtual void mark(FinalizedHeapObjectHeader* header, TraceCallback callback) OVERRIDE
798 {
799 mark(header->payload());
800 }
801
802 bool validate() { return m_count >= m_expectedCount; }
803 void reset() { m_count = 0; }
804
805 FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS)
806
807private:
808 bool expectedObject(const void* ptr)
809 {
810 for (int i = 0; i < m_expectedCount; i++) {
811 if (m_expectedObjects[i] == ptr)
812 return true;
813 }
814 return false;
815 }
816
817 int m_count;
818 int m_expectedCount;
819 void** m_expectedObjects;
820};
821
822#undef DEFINE_VISITOR_METHODS
823
824class Weak : public Bar {
825public:
826 static Weak* create(Bar* strong, Bar* weak)
827 {
828 return new Weak(strong, weak);
829 }
830
831 virtual void trace(Visitor* visitor) OVERRIDE
832 {
833 visitor->trace(m_strongBar);
834 visitor->registerWeakMembers(this, zapWeakMembers);
835 }
836
837 static void zapWeakMembers(Visitor* visitor, void* self)
838 {
839 reinterpret_cast<Weak*>(self)->zapWeakMembers(visitor);
840 }
841
842 bool strongIsThere() { return !!m_strongBar; }
843 bool weakIsThere() { return !!m_weakBar; }
844
845private:
846 Weak(Bar* strongBar, Bar* weakBar)
847 : Bar()
848 , m_strongBar(strongBar)
849 , m_weakBar(weakBar)
850 {
851 }
852
853 void zapWeakMembers(Visitor* visitor)
854 {
855 if (m_weakBar && !visitor->isAlive(m_weakBar))
856 m_weakBar = 0;
857 }
858
859 Member<Bar> m_strongBar;
860 Bar* m_weakBar;
861};
862
863class WithWeakMember : public Bar {
864public:
865 static WithWeakMember* create(Bar* strong, Bar* weak)
866 {
867 return new WithWeakMember(strong, weak);
868 }
869
870 virtual void trace(Visitor* visitor) OVERRIDE
871 {
872 visitor->trace(m_strongBar);
873 visitor->trace(m_weakBar);
874 }
875
876 bool strongIsThere() { return !!m_strongBar; }
877 bool weakIsThere() { return !!m_weakBar; }
878
879private:
880 WithWeakMember(Bar* strongBar, Bar* weakBar)
881 : Bar()
882 , m_strongBar(strongBar)
883 , m_weakBar(weakBar)
884 {
885 }
886
887 Member<Bar> m_strongBar;
888 WeakMember<Bar> m_weakBar;
889};
890
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +0000891class Observable : public GarbageCollectedFinalized<Observable> {
892public:
893 static Observable* create(Bar* bar) { return new Observable(bar); }
894 ~Observable() { m_wasDestructed = true; }
895 void trace(Visitor* visitor) { visitor->trace(m_bar); }
896
897 // willFinalize is called by FinalizationObserver. willFinalize can touch
898 // other on-heap objects.
899 void willFinalize()
900 {
901 EXPECT_FALSE(m_wasDestructed);
902 EXPECT_FALSE(m_bar->hasBeenFinalized());
903 }
904
905private:
906 explicit Observable(Bar* bar)
907 : m_bar(bar)
908 , m_wasDestructed(false)
909 {
910 }
911
912 Member<Bar> m_bar;
913 bool m_wasDestructed;
914};
915
916template <typename T> class FinalizationObserver : public GarbageCollected<FinalizationObserver<T> > {
917public:
918 static FinalizationObserver* create(T* data) { return new FinalizationObserver(data); }
919 bool didCallWillFinalize() const { return m_didCallWillFinalize; }
920
921 void trace(Visitor* visitor)
922 {
923 visitor->registerWeakMembers(this, zapWeakMembers);
924 }
925
926private:
927 FinalizationObserver(T* data)
928 : m_data(data)
929 , m_didCallWillFinalize(false)
930 {
931 }
932
933 static void zapWeakMembers(Visitor* visitor, void* self)
934 {
935 FinalizationObserver* o = reinterpret_cast<FinalizationObserver*>(self);
936 if (o->m_data && !visitor->isAlive(o->m_data)) {
937 o->m_data->willFinalize();
938 o->m_data = nullptr;
939 o->m_didCallWillFinalize = true;
940 }
941 }
942
943 WeakMember<T> m_data;
944 bool m_didCallWillFinalize;
945};
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000946
Ben Murdoch07a852d2014-03-31 11:51:52 +0100947class FinalizationObserverWithHashMap {
948public:
949 typedef HeapHashMap<WeakMember<Observable>, OwnPtr<FinalizationObserverWithHashMap> > ObserverMap;
950
951 explicit FinalizationObserverWithHashMap(Observable& target) : m_target(target) { }
952 ~FinalizationObserverWithHashMap()
953 {
954 m_target.willFinalize();
955 s_didCallWillFinalize = true;
956 }
957
958 static ObserverMap& observe(Observable& target)
959 {
960 ObserverMap& map = observers();
961 ObserverMap::AddResult result = map.add(&target, nullptr);
962 if (result.isNewEntry)
963 result.storedValue->value = adoptPtr(new FinalizationObserverWithHashMap(target));
964 else
965 ASSERT(result.storedValue->value);
966 return map;
967 }
968
969 static bool s_didCallWillFinalize;
970
971private:
972 static ObserverMap& observers()
973 {
974 DEFINE_STATIC_LOCAL(Persistent<ObserverMap>, observerMap, ());
975 if (!observerMap)
976 observerMap = new ObserverMap();
977 return *observerMap;
978 }
979
980 Observable& m_target;
981};
982
983bool FinalizationObserverWithHashMap::s_didCallWillFinalize = false;
984
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000985class SuperClass;
986
987class PointsBack : public RefCountedWillBeGarbageCollectedFinalized<PointsBack> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +0000988public:
989 static PassRefPtrWillBeRawPtr<PointsBack> create()
990 {
991 return adoptRefWillBeNoop(new PointsBack());
992 }
993
994 ~PointsBack()
995 {
996 --s_aliveCount;
997 }
998
999 void setBackPointer(SuperClass* backPointer)
1000 {
1001 m_backPointer = backPointer;
1002 }
1003
1004 SuperClass* backPointer() const { return m_backPointer; }
1005
1006 void trace(Visitor* visitor)
1007 {
1008#if ENABLE_OILPAN
1009 visitor->trace(m_backPointer);
1010#endif
1011 }
1012
1013 static int s_aliveCount;
1014private:
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001015 PointsBack() : m_backPointer(nullptr)
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001016 {
1017 ++s_aliveCount;
1018 }
1019
1020 RawPtrWillBeWeakMember<SuperClass> m_backPointer;
1021};
1022
1023int PointsBack::s_aliveCount = 0;
1024
1025class SuperClass : public RefCountedWillBeGarbageCollectedFinalized<SuperClass> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001026public:
1027 static PassRefPtrWillBeRawPtr<SuperClass> create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
1028 {
1029 return adoptRefWillBeNoop(new SuperClass(pointsBack));
1030 }
1031
1032 virtual ~SuperClass()
1033 {
1034#if !ENABLE_OILPAN
1035 m_pointsBack->setBackPointer(0);
1036#endif
1037 --s_aliveCount;
1038 }
1039
1040 void doStuff(PassRefPtrWillBeRawPtr<SuperClass> targetPass, PointsBack* pointsBack, int superClassCount)
1041 {
1042 RefPtrWillBeRawPtr<SuperClass> target = targetPass;
1043 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1044 EXPECT_EQ(pointsBack, target->pointsBack());
1045 EXPECT_EQ(superClassCount, SuperClass::s_aliveCount);
1046 }
1047
1048 virtual void trace(Visitor* visitor)
1049 {
1050#if ENABLE_OILPAN
1051 visitor->trace(m_pointsBack);
1052#endif
1053 }
1054
1055 PointsBack* pointsBack() const { return m_pointsBack.get(); }
1056
1057 static int s_aliveCount;
1058protected:
1059 explicit SuperClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
1060 : m_pointsBack(pointsBack)
1061 {
1062 m_pointsBack->setBackPointer(this);
1063 ++s_aliveCount;
1064 }
1065
1066private:
1067 RefPtrWillBeMember<PointsBack> m_pointsBack;
1068};
1069
1070int SuperClass::s_aliveCount = 0;
1071class SubData : public NoBaseWillBeGarbageCollectedFinalized<SubData> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001072public:
1073 SubData() { ++s_aliveCount; }
1074 ~SubData() { --s_aliveCount; }
1075
1076 void trace(Visitor*) { }
1077
1078 static int s_aliveCount;
1079};
1080
1081int SubData::s_aliveCount = 0;
1082
1083class SubClass : public SuperClass {
1084public:
1085 static PassRefPtrWillBeRawPtr<SubClass> create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
1086 {
1087 return adoptRefWillBeNoop(new SubClass(pointsBack));
1088 }
1089
1090 virtual ~SubClass()
1091 {
1092 --s_aliveCount;
1093 }
1094
1095 virtual void trace(Visitor* visitor)
1096 {
1097#if ENABLE_OILPAN
1098 SuperClass::trace(visitor);
1099 visitor->trace(m_data);
1100#endif
1101 }
1102
1103 static int s_aliveCount;
1104private:
1105 explicit SubClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
1106 : SuperClass(pointsBack)
1107 , m_data(adoptPtrWillBeNoop(new SubData()))
1108 {
1109 ++s_aliveCount;
1110 }
1111
1112private:
1113 OwnPtrWillBeMember<SubData> m_data;
1114};
1115
1116int SubClass::s_aliveCount = 0;
1117
1118class TransitionRefCounted : public RefCountedWillBeRefCountedGarbageCollected<TransitionRefCounted> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001119public:
1120 static PassRefPtrWillBeRawPtr<TransitionRefCounted> create()
1121 {
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001122 return adoptRefWillBeRefCountedGarbageCollected(new TransitionRefCounted());
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001123 }
1124
1125 ~TransitionRefCounted()
1126 {
1127 --s_aliveCount;
1128 }
1129
1130 void trace(Visitor* visitor) { }
1131
1132 static int s_aliveCount;
1133
1134private:
1135 TransitionRefCounted()
1136 {
1137 ++s_aliveCount;
1138 }
1139};
1140
1141int TransitionRefCounted::s_aliveCount = 0;
1142
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001143class Mixin : public GarbageCollectedMixin {
1144public:
1145 virtual void trace(Visitor* visitor) { }
1146
Ben Murdochaafa69c2014-04-03 12:30:15 +01001147 virtual char getPayload(int i) { return m_padding[i]; }
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001148
1149protected:
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001150 int m_padding[8];
1151};
1152
1153class UseMixin : public SimpleObject, public Mixin {
1154 USING_GARBAGE_COLLECTED_MIXIN(UseMixin)
1155public:
1156 static UseMixin* create()
1157 {
1158 return new UseMixin();
1159 }
1160
1161 static int s_traceCount;
1162 virtual void trace(Visitor* visitor)
1163 {
1164 SimpleObject::trace(visitor);
1165 Mixin::trace(visitor);
1166 ++s_traceCount;
1167 }
1168
1169private:
1170 UseMixin()
1171 {
1172 s_traceCount = 0;
1173 }
1174};
1175
1176int UseMixin::s_traceCount = 0;
1177
1178class VectorObject {
1179 ALLOW_ONLY_INLINE_ALLOCATION();
1180public:
1181 VectorObject()
1182 {
1183 m_value = SimpleFinalizedObject::create();
1184 }
1185
1186 void trace(Visitor* visitor)
1187 {
1188 visitor->trace(m_value);
1189 }
1190
1191private:
1192 Member<SimpleFinalizedObject> m_value;
1193};
1194
1195class VectorObjectInheritedTrace : public VectorObject { };
1196
1197class VectorObjectNoTrace {
1198 ALLOW_ONLY_INLINE_ALLOCATION();
1199public:
1200 VectorObjectNoTrace()
1201 {
1202 m_value = SimpleFinalizedObject::create();
1203 }
1204
1205private:
1206 Member<SimpleFinalizedObject> m_value;
1207};
1208
1209class TerminatedArrayItem {
1210 ALLOW_ONLY_INLINE_ALLOCATION();
1211public:
1212 TerminatedArrayItem(IntWrapper* payload) : m_payload(payload), m_isLast(false) { }
1213
1214 void trace(Visitor* visitor) { visitor->trace(m_payload); }
1215
1216 bool isLastInArray() const { return m_isLast; }
1217 void setLastInArray(bool value) { m_isLast = value; }
1218
1219 IntWrapper* payload() const { return m_payload; }
1220
1221private:
1222 Member<IntWrapper> m_payload;
1223 bool m_isLast;
1224};
1225
1226} // WebCore namespace
1227
1228namespace WTF {
1229
1230// We need the below vector trait specialization for the above HeapVectors to behave correctly wrt. memset, memcmp etc.
1231template<> struct VectorTraits<WebCore::VectorObject> : public SimpleClassVectorTraits<WebCore::VectorObject> { };
1232template<> struct VectorTraits<WebCore::VectorObjectInheritedTrace> : public SimpleClassVectorTraits<WebCore::VectorObjectInheritedTrace> { };
1233template<> struct VectorTraits<WebCore::VectorObjectNoTrace> : public SimpleClassVectorTraits<WebCore::VectorObjectNoTrace> { };
1234
1235} // WTF namespace
1236
1237namespace WebCore {
1238
1239class OneKiloByteObject : public GarbageCollectedFinalized<OneKiloByteObject> {
1240public:
1241 ~OneKiloByteObject() { s_destructorCalls++; }
1242 char* data() { return m_data; }
1243 void trace(Visitor* visitor) { }
1244 static int s_destructorCalls;
1245
1246private:
1247 static const size_t s_length = 1024;
1248 char m_data[s_length];
1249};
1250
1251int OneKiloByteObject::s_destructorCalls = 0;
1252
1253class DynamicallySizedObject : public GarbageCollected<DynamicallySizedObject> {
1254public:
1255 static DynamicallySizedObject* create(size_t size)
1256 {
1257 void* slot = Heap::allocate<DynamicallySizedObject>(size);
1258 return new (slot) DynamicallySizedObject();
1259 }
1260
1261 void* operator new(std::size_t, void* location)
1262 {
1263 return location;
1264 }
1265
1266 uint8_t get(int i)
1267 {
1268 return *(reinterpret_cast<uint8_t*>(this) + i);
1269 }
1270
1271 void trace(Visitor*) { }
1272
1273private:
1274 DynamicallySizedObject() { }
1275};
1276
1277class FinalizationAllocator : public GarbageCollectedFinalized<FinalizationAllocator> {
1278public:
1279 FinalizationAllocator(Persistent<IntWrapper>* wrapper)
1280 : m_wrapper(wrapper)
1281 {
1282 }
1283
1284 ~FinalizationAllocator()
1285 {
1286 for (int i = 0; i < 10; ++i)
1287 *m_wrapper = IntWrapper::create(42);
1288 for (int i = 0; i < 512; ++i)
1289 new OneKiloByteObject();
1290 }
1291
1292 void trace(Visitor*) { }
1293
1294private:
1295 Persistent<IntWrapper>* m_wrapper;
1296};
1297
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001298TEST(HeapTest, Transition)
1299{
1300 {
1301 RefPtr<TransitionRefCounted> refCounted = TransitionRefCounted::create();
1302 EXPECT_EQ(1, TransitionRefCounted::s_aliveCount);
1303 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1304 EXPECT_EQ(1, TransitionRefCounted::s_aliveCount);
1305 }
1306 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1307 EXPECT_EQ(0, TransitionRefCounted::s_aliveCount);
1308
1309 RefPtrWillBePersistent<PointsBack> pointsBack1 = PointsBack::create();
1310 RefPtrWillBePersistent<PointsBack> pointsBack2 = PointsBack::create();
1311 RefPtrWillBePersistent<SuperClass> superClass = SuperClass::create(pointsBack1);
1312 RefPtrWillBePersistent<SubClass> subClass = SubClass::create(pointsBack2);
1313 EXPECT_EQ(2, PointsBack::s_aliveCount);
1314 EXPECT_EQ(2, SuperClass::s_aliveCount);
1315 EXPECT_EQ(1, SubClass::s_aliveCount);
1316 EXPECT_EQ(1, SubData::s_aliveCount);
1317
1318 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1319 EXPECT_EQ(0, TransitionRefCounted::s_aliveCount);
1320 EXPECT_EQ(2, PointsBack::s_aliveCount);
1321 EXPECT_EQ(2, SuperClass::s_aliveCount);
1322 EXPECT_EQ(1, SubClass::s_aliveCount);
1323 EXPECT_EQ(1, SubData::s_aliveCount);
1324
1325 superClass->doStuff(superClass.release(), pointsBack1.get(), 2);
1326 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1327 EXPECT_EQ(2, PointsBack::s_aliveCount);
1328 EXPECT_EQ(1, SuperClass::s_aliveCount);
1329 EXPECT_EQ(1, SubClass::s_aliveCount);
1330 EXPECT_EQ(1, SubData::s_aliveCount);
1331 EXPECT_EQ(0, pointsBack1->backPointer());
1332
1333 pointsBack1.release();
1334 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1335 EXPECT_EQ(1, PointsBack::s_aliveCount);
1336 EXPECT_EQ(1, SuperClass::s_aliveCount);
1337 EXPECT_EQ(1, SubClass::s_aliveCount);
1338 EXPECT_EQ(1, SubData::s_aliveCount);
1339
1340 subClass->doStuff(subClass.release(), pointsBack2.get(), 1);
1341 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1342 EXPECT_EQ(1, PointsBack::s_aliveCount);
1343 EXPECT_EQ(0, SuperClass::s_aliveCount);
1344 EXPECT_EQ(0, SubClass::s_aliveCount);
1345 EXPECT_EQ(0, SubData::s_aliveCount);
1346 EXPECT_EQ(0, pointsBack2->backPointer());
1347
1348 pointsBack2.release();
1349 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1350 EXPECT_EQ(0, PointsBack::s_aliveCount);
1351 EXPECT_EQ(0, SuperClass::s_aliveCount);
1352 EXPECT_EQ(0, SubClass::s_aliveCount);
1353 EXPECT_EQ(0, SubData::s_aliveCount);
1354
1355 EXPECT_TRUE(superClass == subClass);
1356}
1357
1358TEST(HeapTest, Threading)
1359{
1360 ThreadedHeapTester::test();
1361}
1362
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001363TEST(HeapTest, ThreadedWeakness)
1364{
1365 ThreadedWeaknessTester::test();
1366}
1367
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001368TEST(HeapTest, BasicFunctionality)
1369{
1370 HeapStats heapStats;
1371 clearOutOldGarbage(&heapStats);
1372 {
1373 size_t slack = 0;
1374
1375 // When the test starts there may already have been leaked some memory
1376 // on the heap, so we establish a base line.
1377 size_t baseLevel = heapStats.totalObjectSpace();
1378 bool testPagesAllocated = !baseLevel;
1379 if (testPagesAllocated)
1380 EXPECT_EQ(heapStats.totalAllocatedSpace(), 0ul);
1381
1382 // This allocates objects on the general heap which should add a page of memory.
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001383 DynamicallySizedObject* alloc32 = DynamicallySizedObject::create(32);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001384 slack += 4;
1385 memset(alloc32, 40, 32);
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001386 DynamicallySizedObject* alloc64 = DynamicallySizedObject::create(64);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001387 slack += 4;
1388 memset(alloc64, 27, 64);
1389
1390 size_t total = 96;
1391
1392 getHeapStats(&heapStats);
1393 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack);
1394 if (testPagesAllocated)
1395 EXPECT_EQ(heapStats.totalAllocatedSpace(), blinkPageSize);
1396
1397 CheckWithSlack(alloc32 + 32 + sizeof(HeapObjectHeader), alloc64, slack);
1398
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001399 EXPECT_EQ(alloc32->get(0), 40);
1400 EXPECT_EQ(alloc32->get(31), 40);
1401 EXPECT_EQ(alloc64->get(0), 27);
1402 EXPECT_EQ(alloc64->get(63), 27);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001403
1404 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1405
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001406 EXPECT_EQ(alloc32->get(0), 40);
1407 EXPECT_EQ(alloc32->get(31), 40);
1408 EXPECT_EQ(alloc64->get(0), 27);
1409 EXPECT_EQ(alloc64->get(63), 27);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001410 }
1411
1412 clearOutOldGarbage(&heapStats);
1413 size_t total = 0;
1414 size_t slack = 0;
1415 size_t baseLevel = heapStats.totalObjectSpace();
1416 bool testPagesAllocated = !baseLevel;
1417 if (testPagesAllocated)
1418 EXPECT_EQ(heapStats.totalAllocatedSpace(), 0ul);
1419
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001420 size_t big = 1008;
1421 Persistent<DynamicallySizedObject> bigArea = DynamicallySizedObject::create(big);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001422 total += big;
1423 slack += 4;
1424
1425 size_t persistentCount = 0;
1426 const size_t numPersistents = 100000;
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001427 Persistent<DynamicallySizedObject>* persistents[numPersistents];
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001428
1429 for (int i = 0; i < 1000; i++) {
1430 size_t size = 128 + i * 8;
1431 total += size;
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001432 persistents[persistentCount++] = new Persistent<DynamicallySizedObject>(DynamicallySizedObject::create(size));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001433 slack += 4;
1434 getHeapStats(&heapStats);
1435 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack);
1436 if (testPagesAllocated)
1437 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
1438 }
1439
1440 {
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001441 DynamicallySizedObject* alloc32b(DynamicallySizedObject::create(32));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001442 slack += 4;
1443 memset(alloc32b, 40, 32);
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001444 DynamicallySizedObject* alloc64b(DynamicallySizedObject::create(64));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001445 slack += 4;
1446 memset(alloc64b, 27, 64);
1447 EXPECT_TRUE(alloc32b != alloc64b);
1448
1449 total += 96;
1450 getHeapStats(&heapStats);
1451 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack);
1452 if (testPagesAllocated)
1453 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
1454 }
1455
1456 clearOutOldGarbage(&heapStats);
1457 total -= 96;
1458 slack -= 8;
1459 if (testPagesAllocated)
1460 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
1461
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001462 DynamicallySizedObject* bigAreaRaw = bigArea;
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001463 // Clear the persistent, so that the big area will be garbage collected.
1464 bigArea.release();
1465 clearOutOldGarbage(&heapStats);
1466
1467 total -= big;
1468 slack -= 4;
1469 getHeapStats(&heapStats);
1470 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack);
1471 if (testPagesAllocated)
1472 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
1473
1474 // Endless loop unless we eventually get the memory back that we just freed.
1475 while (true) {
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001476 Persistent<DynamicallySizedObject>* alloc = new Persistent<DynamicallySizedObject>(DynamicallySizedObject::create(big / 2));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001477 slack += 4;
1478 persistents[persistentCount++] = alloc;
1479 EXPECT_LT(persistentCount, numPersistents);
1480 total += big / 2;
1481 if (bigAreaRaw == alloc->get())
1482 break;
1483 }
1484
1485 getHeapStats(&heapStats);
1486 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack);
1487 if (testPagesAllocated)
1488 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
1489
1490 for (size_t i = 0; i < persistentCount; i++) {
1491 delete persistents[i];
1492 persistents[i] = 0;
1493 }
1494
Torne (Richard Coles)43e75022014-03-21 14:26:12 +00001495 uint8_t* address = reinterpret_cast<uint8_t*>(Heap::reallocate<DynamicallySizedObject>(0, 100));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001496 for (int i = 0; i < 100; i++)
1497 address[i] = i;
Torne (Richard Coles)43e75022014-03-21 14:26:12 +00001498 address = reinterpret_cast<uint8_t*>(Heap::reallocate<DynamicallySizedObject>(address, 100000));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001499 for (int i = 0; i < 100; i++)
1500 EXPECT_EQ(address[i], i);
Torne (Richard Coles)43e75022014-03-21 14:26:12 +00001501 address = reinterpret_cast<uint8_t*>(Heap::reallocate<DynamicallySizedObject>(address, 50));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001502 for (int i = 0; i < 50; i++)
1503 EXPECT_EQ(address[i], i);
1504 // This should be equivalent to free(address).
Torne (Richard Coles)43e75022014-03-21 14:26:12 +00001505 EXPECT_EQ(reinterpret_cast<uintptr_t>(Heap::reallocate<DynamicallySizedObject>(address, 0)), 0ul);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001506 // This should be equivalent to malloc(0).
Torne (Richard Coles)43e75022014-03-21 14:26:12 +00001507 EXPECT_EQ(reinterpret_cast<uintptr_t>(Heap::reallocate<DynamicallySizedObject>(0, 0)), 0ul);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001508}
1509
1510TEST(HeapTest, SimpleAllocation)
1511{
1512 HeapStats initialHeapStats;
1513 clearOutOldGarbage(&initialHeapStats);
1514 EXPECT_EQ(0ul, initialHeapStats.totalObjectSpace());
1515
1516 // Allocate an object in the heap.
1517 HeapAllocatedArray* array = new HeapAllocatedArray();
1518 HeapStats statsAfterAllocation;
1519 getHeapStats(&statsAfterAllocation);
1520 EXPECT_TRUE(statsAfterAllocation.totalObjectSpace() >= sizeof(HeapAllocatedArray));
1521
1522 // Sanity check of the contents in the heap.
1523 EXPECT_EQ(0, array->at(0));
1524 EXPECT_EQ(42, array->at(42));
1525 EXPECT_EQ(0, array->at(128));
1526 EXPECT_EQ(999 % 128, array->at(999));
1527}
1528
1529TEST(HeapTest, SimplePersistent)
1530{
1531 Persistent<TraceCounter> traceCounter = TraceCounter::create();
1532 EXPECT_EQ(0, traceCounter->traceCount());
1533
1534 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1535 EXPECT_EQ(1, traceCounter->traceCount());
1536
1537 Persistent<ClassWithMember> classWithMember = ClassWithMember::create();
1538 EXPECT_EQ(0, classWithMember->traceCount());
1539
1540 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1541 EXPECT_EQ(1, classWithMember->traceCount());
1542 EXPECT_EQ(2, traceCounter->traceCount());
1543}
1544
1545TEST(HeapTest, SimpleFinalization)
1546{
1547 {
1548 Persistent<SimpleFinalizedObject> finalized = SimpleFinalizedObject::create();
1549 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls);
1550 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1551 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls);
1552 }
1553
1554 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1555 EXPECT_EQ(1, SimpleFinalizedObject::s_destructorCalls);
1556}
1557
1558TEST(HeapTest, Finalization)
1559{
1560 {
1561 HeapTestSubClass* t1 = HeapTestSubClass::create();
1562 HeapTestSubClass* t2 = HeapTestSubClass::create();
1563 HeapTestSuperClass* t3 = HeapTestSuperClass::create();
1564 // FIXME(oilpan): Ignore unused variables.
1565 (void)t1;
1566 (void)t2;
1567 (void)t3;
1568 }
1569 // Nothing is marked so the GC should free everything and call
1570 // the finalizer on all three objects.
1571 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1572 EXPECT_EQ(2, HeapTestSubClass::s_destructorCalls);
1573 EXPECT_EQ(3, HeapTestSuperClass::s_destructorCalls);
1574 // Destructors not called again when GCing again.
1575 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1576 EXPECT_EQ(2, HeapTestSubClass::s_destructorCalls);
1577 EXPECT_EQ(3, HeapTestSuperClass::s_destructorCalls);
1578}
1579
1580TEST(HeapTest, TypedHeapSanity)
1581{
1582 // We use TraceCounter for allocating an object on the general heap.
1583 Persistent<TraceCounter> generalHeapObject = TraceCounter::create();
1584 Persistent<TestTypedHeapClass> typedHeapObject = TestTypedHeapClass::create();
1585 EXPECT_NE(pageHeaderAddress(reinterpret_cast<Address>(generalHeapObject.get())),
1586 pageHeaderAddress(reinterpret_cast<Address>(typedHeapObject.get())));
1587}
1588
1589TEST(HeapTest, NoAllocation)
1590{
1591 EXPECT_TRUE(ThreadState::current()->isAllocationAllowed());
1592 {
1593 // Disallow allocation
1594 NoAllocationScope<AnyThread> noAllocationScope;
1595 EXPECT_FALSE(ThreadState::current()->isAllocationAllowed());
1596 }
1597 EXPECT_TRUE(ThreadState::current()->isAllocationAllowed());
1598}
1599
1600TEST(HeapTest, Members)
1601{
1602 Bar::s_live = 0;
1603 {
1604 Persistent<Baz> h1;
1605 Persistent<Baz> h2;
1606 {
1607 h1 = Baz::create(Bar::create());
1608 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1609 EXPECT_EQ(1u, Bar::s_live);
1610 h2 = Baz::create(Bar::create());
1611 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1612 EXPECT_EQ(2u, Bar::s_live);
1613 }
1614 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1615 EXPECT_EQ(2u, Bar::s_live);
1616 h1->clear();
1617 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1618 EXPECT_EQ(1u, Bar::s_live);
1619 }
1620 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1621 EXPECT_EQ(0u, Bar::s_live);
1622}
1623
1624TEST(HeapTest, MarkTest)
1625{
1626 {
1627 Bar::s_live = 0;
1628 Persistent<Bar> bar = Bar::create();
1629 EXPECT_TRUE(ThreadState::current()->contains(bar));
1630 EXPECT_EQ(1u, Bar::s_live);
1631 {
1632 Foo* foo = Foo::create(bar);
1633 EXPECT_TRUE(ThreadState::current()->contains(foo));
1634 EXPECT_EQ(2u, Bar::s_live);
1635 EXPECT_TRUE(reinterpret_cast<Address>(foo) != reinterpret_cast<Address>(bar.get()));
1636 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1637 EXPECT_TRUE(foo != bar); // To make sure foo is kept alive.
1638 EXPECT_EQ(2u, Bar::s_live);
1639 }
1640 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1641 EXPECT_EQ(1u, Bar::s_live);
1642 }
1643 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1644 EXPECT_EQ(0u, Bar::s_live);
1645}
1646
1647TEST(HeapTest, DeepTest)
1648{
1649 const unsigned depth = 100000;
1650 Bar::s_live = 0;
1651 {
1652 Bar* bar = Bar::create();
1653 EXPECT_TRUE(ThreadState::current()->contains(bar));
1654 Foo* foo = Foo::create(bar);
1655 EXPECT_TRUE(ThreadState::current()->contains(foo));
1656 EXPECT_EQ(2u, Bar::s_live);
1657 for (unsigned i = 0; i < depth; i++) {
1658 Foo* foo2 = Foo::create(foo);
1659 foo = foo2;
1660 EXPECT_TRUE(ThreadState::current()->contains(foo));
1661 }
1662 EXPECT_EQ(depth + 2, Bar::s_live);
1663 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1664 EXPECT_TRUE(foo != bar); // To make sure foo and bar are kept alive.
1665 EXPECT_EQ(depth + 2, Bar::s_live);
1666 }
1667 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1668 EXPECT_EQ(0u, Bar::s_live);
1669}
1670
1671TEST(HeapTest, WideTest)
1672{
1673 Bar::s_live = 0;
1674 {
1675 Bars* bars = Bars::create();
1676 unsigned width = Bars::width;
1677 EXPECT_EQ(width + 1, Bar::s_live);
1678 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1679 EXPECT_EQ(width + 1, Bar::s_live);
1680 // Use bars here to make sure that it will be on the stack
1681 // for the conservative stack scan to find.
1682 EXPECT_EQ(width, bars->getWidth());
1683 }
1684 EXPECT_EQ(Bars::width + 1, Bar::s_live);
1685 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1686 EXPECT_EQ(0u, Bar::s_live);
1687}
1688
1689TEST(HeapTest, HashMapOfMembers)
1690{
1691 HeapStats initialHeapSize;
1692 IntWrapper::s_destructorCalls = 0;
1693
1694 clearOutOldGarbage(&initialHeapSize);
1695 {
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001696 typedef HeapHashMap<
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001697 Member<IntWrapper>,
1698 Member<IntWrapper>,
1699 DefaultHash<Member<IntWrapper> >::Hash,
1700 HashTraits<Member<IntWrapper> >,
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001701 HashTraits<Member<IntWrapper> > > HeapObjectIdentityMap;
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001702
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001703 Persistent<HeapObjectIdentityMap> map = new HeapObjectIdentityMap();
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001704
1705 map->clear();
1706 HeapStats afterSetWasCreated;
1707 getHeapStats(&afterSetWasCreated);
1708 EXPECT_TRUE(afterSetWasCreated.totalObjectSpace() > initialHeapSize.totalObjectSpace());
1709
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001710 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001711 HeapStats afterGC;
1712 getHeapStats(&afterGC);
1713 EXPECT_EQ(afterGC.totalObjectSpace(), afterSetWasCreated.totalObjectSpace());
1714
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001715 // If the additions below cause garbage collections, these
1716 // pointers should be found by conservative stack scanning.
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001717 IntWrapper* one(IntWrapper::create(1));
1718 IntWrapper* anotherOne(IntWrapper::create(1));
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001719
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001720 map->add(one, one);
1721
1722 HeapStats afterOneAdd;
1723 getHeapStats(&afterOneAdd);
1724 EXPECT_TRUE(afterOneAdd.totalObjectSpace() > afterGC.totalObjectSpace());
1725
1726 HeapObjectIdentityMap::iterator it(map->begin());
1727 HeapObjectIdentityMap::iterator it2(map->begin());
1728 ++it;
1729 ++it2;
1730
1731 map->add(anotherOne, one);
1732
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001733 // The addition above can cause an allocation of a new
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001734 // backing store. We therefore garbage collect before
1735 // taking the heap stats in order to get rid of the old
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001736 // backing store. We make sure to not use conservative
1737 // stack scanning as that could find a pointer to the
1738 // old backing.
1739 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001740 HeapStats afterAddAndGC;
1741 getHeapStats(&afterAddAndGC);
1742 EXPECT_TRUE(afterAddAndGC.totalObjectSpace() >= afterOneAdd.totalObjectSpace());
1743
1744 EXPECT_EQ(map->size(), 2u); // Two different wrappings of '1' are distinct.
1745
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001746 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001747 EXPECT_TRUE(map->contains(one));
1748 EXPECT_TRUE(map->contains(anotherOne));
1749
1750 IntWrapper* gotten(map->get(one));
1751 EXPECT_EQ(gotten->value(), one->value());
1752 EXPECT_EQ(gotten, one);
1753
1754 HeapStats afterGC2;
1755 getHeapStats(&afterGC2);
1756 EXPECT_EQ(afterGC2.totalObjectSpace(), afterAddAndGC.totalObjectSpace());
1757
1758 IntWrapper* dozen = 0;
1759
1760 for (int i = 1; i < 1000; i++) { // 999 iterations.
1761 IntWrapper* iWrapper(IntWrapper::create(i));
1762 IntWrapper* iSquared(IntWrapper::create(i * i));
1763 map->add(iWrapper, iSquared);
1764 if (i == 12)
1765 dozen = iWrapper;
1766 }
1767 HeapStats afterAdding1000;
1768 getHeapStats(&afterAdding1000);
1769 EXPECT_TRUE(afterAdding1000.totalObjectSpace() > afterGC2.totalObjectSpace());
1770
1771 IntWrapper* gross(map->get(dozen));
1772 EXPECT_EQ(gross->value(), 144);
1773
1774 // This should clear out junk created by all the adds.
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001775 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001776 HeapStats afterGC3;
1777 getHeapStats(&afterGC3);
1778 EXPECT_TRUE(afterGC3.totalObjectSpace() < afterAdding1000.totalObjectSpace());
1779 }
1780
1781 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1782 // The objects 'one', anotherOne, and the 999 other pairs.
1783 EXPECT_EQ(IntWrapper::s_destructorCalls, 2000);
1784 HeapStats afterGC4;
1785 getHeapStats(&afterGC4);
1786 EXPECT_EQ(afterGC4.totalObjectSpace(), initialHeapSize.totalObjectSpace());
1787}
1788
1789TEST(HeapTest, NestedAllocation)
1790{
1791 HeapStats initialHeapSize;
1792 clearOutOldGarbage(&initialHeapSize);
1793 {
1794 Persistent<ConstructorAllocation> constructorAllocation = ConstructorAllocation::create();
1795 }
1796 HeapStats afterFree;
1797 clearOutOldGarbage(&afterFree);
1798 EXPECT_TRUE(initialHeapSize == afterFree);
1799}
1800
1801TEST(HeapTest, LargeObjects)
1802{
1803 HeapStats initialHeapSize;
1804 clearOutOldGarbage(&initialHeapSize);
1805 IntWrapper::s_destructorCalls = 0;
1806 LargeObject::s_destructorCalls = 0;
1807 {
1808 int slack = 8; // LargeObject points to an IntWrapper that is also allocated.
1809 Persistent<LargeObject> object = LargeObject::create();
1810 HeapStats afterAllocation;
1811 clearOutOldGarbage(&afterAllocation);
1812 {
1813 object->set(0, 'a');
1814 EXPECT_EQ('a', object->get(0));
1815 object->set(object->length() - 1, 'b');
1816 EXPECT_EQ('b', object->get(object->length() - 1));
1817 size_t expectedObjectSpace = sizeof(LargeObject) + sizeof(IntWrapper);
1818 size_t actualObjectSpace =
1819 afterAllocation.totalObjectSpace() - initialHeapSize.totalObjectSpace();
1820 CheckWithSlack(expectedObjectSpace, actualObjectSpace, slack);
1821 // There is probably space for the IntWrapper in a heap page without
1822 // allocating extra pages. However, the IntWrapper allocation might cause
1823 // the addition of a heap page.
1824 size_t largeObjectAllocationSize =
1825 sizeof(LargeObject) + sizeof(LargeHeapObject<FinalizedHeapObjectHeader>) + sizeof(FinalizedHeapObjectHeader);
1826 size_t allocatedSpaceLowerBound =
1827 initialHeapSize.totalAllocatedSpace() + largeObjectAllocationSize;
1828 size_t allocatedSpaceUpperBound = allocatedSpaceLowerBound + slack + blinkPageSize;
1829 EXPECT_LE(allocatedSpaceLowerBound, afterAllocation.totalAllocatedSpace());
1830 EXPECT_LE(afterAllocation.totalAllocatedSpace(), allocatedSpaceUpperBound);
1831 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
1832 EXPECT_EQ(0, LargeObject::s_destructorCalls);
1833 for (int i = 0; i < 10; i++)
1834 object = LargeObject::create();
1835 }
1836 HeapStats oneLargeObject;
1837 clearOutOldGarbage(&oneLargeObject);
1838 EXPECT_TRUE(oneLargeObject == afterAllocation);
1839 EXPECT_EQ(10, IntWrapper::s_destructorCalls);
1840 EXPECT_EQ(10, LargeObject::s_destructorCalls);
1841 }
1842 HeapStats backToInitial;
1843 clearOutOldGarbage(&backToInitial);
1844 EXPECT_TRUE(initialHeapSize == backToInitial);
1845 EXPECT_EQ(11, IntWrapper::s_destructorCalls);
1846 EXPECT_EQ(11, LargeObject::s_destructorCalls);
1847 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1848}
1849
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001850typedef std::pair<Member<IntWrapper>, int> PairWrappedUnwrapped;
1851typedef std::pair<int, Member<IntWrapper> > PairUnwrappedWrapped;
1852typedef std::pair<WeakMember<IntWrapper>, Member<IntWrapper> > PairWeakStrong;
1853typedef std::pair<Member<IntWrapper>, WeakMember<IntWrapper> > PairStrongWeak;
1854typedef std::pair<WeakMember<IntWrapper>, int> PairWeakUnwrapped;
1855typedef std::pair<int, WeakMember<IntWrapper> > PairUnwrappedWeak;
1856
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001857class Container : public GarbageCollected<Container> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001858public:
1859 static Container* create() { return new Container(); }
1860 HeapHashMap<Member<IntWrapper>, Member<IntWrapper> > map;
1861 HeapHashSet<Member<IntWrapper> > set;
1862 HeapHashSet<Member<IntWrapper> > set2;
1863 HeapVector<Member<IntWrapper>, 2> vector;
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001864 HeapVector<PairWrappedUnwrapped, 2> vectorWU;
1865 HeapVector<PairUnwrappedWrapped, 2> vectorUW;
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001866 void trace(Visitor* visitor)
1867 {
1868 visitor->trace(map);
1869 visitor->trace(set);
1870 visitor->trace(set2);
1871 visitor->trace(vector);
1872 }
1873};
1874
1875struct ShouldBeTraced {
1876 explicit ShouldBeTraced(IntWrapper* wrapper) : m_wrapper(wrapper) { }
1877 void trace(Visitor* visitor) { visitor->trace(m_wrapper); }
1878 Member<IntWrapper> m_wrapper;
1879};
1880
1881class OffHeapContainer : public GarbageCollectedFinalized<OffHeapContainer> {
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001882public:
1883 static OffHeapContainer* create() { return new OffHeapContainer(); }
1884
1885 OffHeapContainer()
1886 {
1887 m_deque1.append(ShouldBeTraced(IntWrapper::create(1)));
1888 m_vector1.append(ShouldBeTraced(IntWrapper::create(2)));
1889 m_deque2.append(IntWrapper::create(3));
1890 m_vector2.append(IntWrapper::create(4));
1891 m_hashSet.add(IntWrapper::create(5));
1892 m_hashMap.add(this, IntWrapper::create(6));
1893 m_listHashSet.add(IntWrapper::create(7));
1894 }
1895
1896 void trace(Visitor* visitor)
1897 {
1898 visitor->trace(m_deque1);
1899 visitor->trace(m_vector1);
1900 visitor->trace(m_deque2);
1901 visitor->trace(m_vector2);
1902 visitor->trace(m_hashSet);
1903 visitor->trace(m_hashMap);
1904 visitor->trace(m_listHashSet);
1905 }
1906
1907 Deque<ShouldBeTraced> m_deque1;
1908 Vector<ShouldBeTraced> m_vector1;
1909 Deque<Member<IntWrapper> > m_deque2;
1910 Vector<Member<IntWrapper> > m_vector2;
1911 HashSet<Member<IntWrapper> > m_hashSet;
1912 HashMap<void*, Member<IntWrapper> > m_hashMap;
1913 ListHashSet<Member<IntWrapper> > m_listHashSet;
1914};
1915
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00001916
1917// These class definitions test compile-time asserts with transition
1918// types. They are therefore unused in test code and just need to
1919// compile. This is intentional; do not delete the A and B classes below.
1920class A : public WillBeGarbageCollectedMixin {
1921};
1922
1923class B : public NoBaseWillBeGarbageCollected<B>, public A {
1924 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(B);
1925public:
1926 void trace(Visitor*) { }
1927};
1928
1929TEST(HeapTest, HeapVectorFilledWithValue)
1930{
1931 IntWrapper* val = IntWrapper::create(1);
1932 HeapVector<Member<IntWrapper> > vector(10, val);
1933 EXPECT_EQ(10u, vector.size());
1934 for (size_t i = 0; i < vector.size(); i++)
1935 EXPECT_EQ(val, vector[i]);
1936}
1937
Torne (Richard Coles)09380292014-02-21 12:17:33 +00001938TEST(HeapTest, HeapVectorWithInlineCapacity)
1939{
1940 IntWrapper* one = IntWrapper::create(1);
1941 IntWrapper* two = IntWrapper::create(2);
1942 IntWrapper* three = IntWrapper::create(3);
1943 IntWrapper* four = IntWrapper::create(4);
1944 IntWrapper* five = IntWrapper::create(5);
1945 IntWrapper* six = IntWrapper::create(6);
1946 {
1947 HeapVector<Member<IntWrapper>, 2> vector;
1948 vector.append(one);
1949 vector.append(two);
1950 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1951 EXPECT_TRUE(vector.contains(one));
1952 EXPECT_TRUE(vector.contains(two));
1953
1954 vector.append(three);
1955 vector.append(four);
1956 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1957 EXPECT_TRUE(vector.contains(one));
1958 EXPECT_TRUE(vector.contains(two));
1959 EXPECT_TRUE(vector.contains(three));
1960 EXPECT_TRUE(vector.contains(four));
1961
1962 vector.shrink(1);
1963 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1964 EXPECT_TRUE(vector.contains(one));
1965 EXPECT_FALSE(vector.contains(two));
1966 EXPECT_FALSE(vector.contains(three));
1967 EXPECT_FALSE(vector.contains(four));
1968 }
1969 {
1970 HeapVector<Member<IntWrapper>, 2> vector1;
1971 HeapVector<Member<IntWrapper>, 2> vector2;
1972
1973 vector1.append(one);
1974 vector2.append(two);
1975 vector1.swap(vector2);
1976 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1977 EXPECT_TRUE(vector1.contains(two));
1978 EXPECT_TRUE(vector2.contains(one));
1979 }
1980 {
1981 HeapVector<Member<IntWrapper>, 2> vector1;
1982 HeapVector<Member<IntWrapper>, 2> vector2;
1983
1984 vector1.append(one);
1985 vector1.append(two);
1986 vector2.append(three);
1987 vector2.append(four);
1988 vector2.append(five);
1989 vector2.append(six);
1990 vector1.swap(vector2);
1991 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
1992 EXPECT_TRUE(vector1.contains(three));
1993 EXPECT_TRUE(vector1.contains(four));
1994 EXPECT_TRUE(vector1.contains(five));
1995 EXPECT_TRUE(vector1.contains(six));
1996 EXPECT_TRUE(vector2.contains(one));
1997 EXPECT_TRUE(vector2.contains(two));
1998 }
1999}
2000
2001TEST(HeapTest, HeapCollectionTypes)
2002{
2003 HeapStats initialHeapSize;
2004 IntWrapper::s_destructorCalls = 0;
2005
2006 typedef HeapHashMap<Member<IntWrapper>, Member<IntWrapper> > MemberMember;
2007 typedef HeapHashMap<Member<IntWrapper>, int> MemberPrimitive;
2008 typedef HeapHashMap<int, Member<IntWrapper> > PrimitiveMember;
2009
2010 typedef HeapHashSet<Member<IntWrapper> > MemberSet;
2011 typedef HeapHashSet<WeakMember<IntWrapper> > WeakMemberSet;
2012
2013 typedef HeapVector<Member<IntWrapper>, 2> MemberVector;
2014
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002015 typedef HeapVector<PairWrappedUnwrapped, 2> VectorWU;
2016 typedef HeapVector<PairUnwrappedWrapped, 2> VectorUW;
2017
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002018 Persistent<MemberMember> memberMember = new MemberMember();
2019 Persistent<MemberMember> memberMember2 = new MemberMember();
2020 Persistent<MemberMember> memberMember3 = new MemberMember();
2021 Persistent<MemberPrimitive> memberPrimitive = new MemberPrimitive();
2022 Persistent<PrimitiveMember> primitiveMember = new PrimitiveMember();
2023 Persistent<MemberSet> set = new MemberSet();
2024 Persistent<MemberSet> set2 = new MemberSet();
2025 Persistent<MemberVector> vector = new MemberVector();
2026 Persistent<MemberVector> vector2 = new MemberVector();
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002027 Persistent<VectorWU> vectorWU = new VectorWU();
2028 Persistent<VectorWU> vectorWU2 = new VectorWU();
2029 Persistent<VectorUW> vectorUW = new VectorUW();
2030 Persistent<VectorUW> vectorUW2 = new VectorUW();
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002031 Persistent<Container> container = Container::create();
2032
2033 clearOutOldGarbage(&initialHeapSize);
2034 {
2035 Persistent<IntWrapper> one(IntWrapper::create(1));
2036 Persistent<IntWrapper> two(IntWrapper::create(2));
2037 Persistent<IntWrapper> oneB(IntWrapper::create(1));
2038 Persistent<IntWrapper> twoB(IntWrapper::create(2));
2039 Persistent<IntWrapper> oneC(IntWrapper::create(1));
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002040 Persistent<IntWrapper> oneD(IntWrapper::create(1));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002041 {
2042 IntWrapper* three(IntWrapper::create(3));
2043 IntWrapper* four(IntWrapper::create(4));
2044 IntWrapper* threeB(IntWrapper::create(3));
2045 IntWrapper* fourB(IntWrapper::create(4));
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002046 IntWrapper* threeC(IntWrapper::create(3));
2047 IntWrapper* fourC(IntWrapper::create(4));
2048 IntWrapper* fiveC(IntWrapper::create(5));
2049 IntWrapper* threeD(IntWrapper::create(3));
2050 IntWrapper* fourD(IntWrapper::create(4));
2051 IntWrapper* fiveD(IntWrapper::create(5));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002052
2053 // Member Collections.
2054 memberMember2->add(one, two);
2055 memberMember2->add(two, three);
2056 memberMember2->add(three, four);
2057 memberMember2->add(four, one);
2058 primitiveMember->add(1, two);
2059 primitiveMember->add(2, three);
2060 primitiveMember->add(3, four);
2061 primitiveMember->add(4, one);
2062 memberPrimitive->add(one, 2);
2063 memberPrimitive->add(two, 3);
2064 memberPrimitive->add(three, 4);
2065 memberPrimitive->add(four, 1);
2066 set2->add(one);
2067 set2->add(two);
2068 set2->add(three);
2069 set2->add(four);
2070 set->add(oneB);
2071 vector->append(oneB);
2072 vector2->append(threeB);
2073 vector2->append(fourB);
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002074 vectorWU->append(PairWrappedUnwrapped(&*oneC, 42));
2075 vectorWU2->append(PairWrappedUnwrapped(&*threeC, 43));
2076 vectorWU2->append(PairWrappedUnwrapped(&*fourC, 44));
2077 vectorWU2->append(PairWrappedUnwrapped(&*fiveC, 45));
2078 vectorUW->append(PairUnwrappedWrapped(1, &*oneD));
2079 vectorUW2->append(PairUnwrappedWrapped(103, &*threeD));
2080 vectorUW2->append(PairUnwrappedWrapped(104, &*fourD));
2081 vectorUW2->append(PairUnwrappedWrapped(105, &*fiveD));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002082
2083 // Collect garbage. This should change nothing since we are keeping
2084 // alive the IntWrapper objects with on-stack pointers.
2085 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2086 EXPECT_EQ(0u, memberMember->size());
2087 EXPECT_EQ(4u, memberMember2->size());
2088 EXPECT_EQ(4u, primitiveMember->size());
2089 EXPECT_EQ(4u, memberPrimitive->size());
2090 EXPECT_EQ(1u, set->size());
2091 EXPECT_EQ(4u, set2->size());
2092 EXPECT_EQ(1u, vector->size());
2093 EXPECT_EQ(2u, vector2->size());
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002094 EXPECT_EQ(1u, vectorWU->size());
2095 EXPECT_EQ(3u, vectorWU2->size());
2096 EXPECT_EQ(1u, vectorUW->size());
2097 EXPECT_EQ(3u, vectorUW2->size());
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002098
2099 MemberVector& cvec = container->vector;
2100 cvec.swap(*vector.get());
2101 vector2->swap(cvec);
2102 vector->swap(cvec);
2103
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002104 VectorWU& cvecWU = container->vectorWU;
2105 cvecWU.swap(*vectorWU.get());
2106 vectorWU2->swap(cvecWU);
2107 vectorWU->swap(cvecWU);
2108
2109 VectorUW& cvecUW = container->vectorUW;
2110 cvecUW.swap(*vectorUW.get());
2111 vectorUW2->swap(cvecUW);
2112 vectorUW->swap(cvecUW);
2113
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002114 // Swap set and set2 in a roundabout way.
2115 MemberSet& cset1 = container->set;
2116 MemberSet& cset2 = container->set2;
2117 set->swap(cset1);
2118 set2->swap(cset2);
2119 set->swap(cset2);
2120 cset1.swap(cset2);
2121 cset2.swap(set2);
2122
2123 // Triple swap.
2124 container->map.swap(memberMember2);
2125 MemberMember& containedMap = container->map;
2126 memberMember3->swap(containedMap);
2127 memberMember3->swap(memberMember);
2128
2129 EXPECT_TRUE(memberMember->get(one) == two);
2130 EXPECT_TRUE(memberMember->get(two) == three);
2131 EXPECT_TRUE(memberMember->get(three) == four);
2132 EXPECT_TRUE(memberMember->get(four) == one);
2133 EXPECT_TRUE(primitiveMember->get(1) == two);
2134 EXPECT_TRUE(primitiveMember->get(2) == three);
2135 EXPECT_TRUE(primitiveMember->get(3) == four);
2136 EXPECT_TRUE(primitiveMember->get(4) == one);
2137 EXPECT_EQ(1, memberPrimitive->get(four));
2138 EXPECT_EQ(2, memberPrimitive->get(one));
2139 EXPECT_EQ(3, memberPrimitive->get(two));
2140 EXPECT_EQ(4, memberPrimitive->get(three));
2141 EXPECT_TRUE(set->contains(one));
2142 EXPECT_TRUE(set->contains(two));
2143 EXPECT_TRUE(set->contains(three));
2144 EXPECT_TRUE(set->contains(four));
2145 EXPECT_TRUE(set2->contains(oneB));
2146 EXPECT_TRUE(vector->contains(threeB));
2147 EXPECT_TRUE(vector->contains(fourB));
2148 EXPECT_TRUE(vector2->contains(oneB));
2149 EXPECT_FALSE(vector2->contains(threeB));
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002150 EXPECT_TRUE(vectorWU->contains(PairWrappedUnwrapped(&*threeC, 43)));
2151 EXPECT_TRUE(vectorWU->contains(PairWrappedUnwrapped(&*fourC, 44)));
2152 EXPECT_TRUE(vectorWU->contains(PairWrappedUnwrapped(&*fiveC, 45)));
2153 EXPECT_TRUE(vectorWU2->contains(PairWrappedUnwrapped(&*oneC, 42)));
2154 EXPECT_FALSE(vectorWU2->contains(PairWrappedUnwrapped(&*threeC, 43)));
2155 EXPECT_TRUE(vectorUW->contains(PairUnwrappedWrapped(103, &*threeD)));
2156 EXPECT_TRUE(vectorUW->contains(PairUnwrappedWrapped(104, &*fourD)));
2157 EXPECT_TRUE(vectorUW->contains(PairUnwrappedWrapped(105, &*fiveD)));
2158 EXPECT_TRUE(vectorUW2->contains(PairUnwrappedWrapped(1, &*oneD)));
2159 EXPECT_FALSE(vectorUW2->contains(PairUnwrappedWrapped(103, &*threeD)));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002160 }
2161
2162 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2163
2164 EXPECT_EQ(4u, memberMember->size());
2165 EXPECT_EQ(0u, memberMember2->size());
2166 EXPECT_EQ(4u, primitiveMember->size());
2167 EXPECT_EQ(4u, memberPrimitive->size());
2168 EXPECT_EQ(4u, set->size());
2169 EXPECT_EQ(1u, set2->size());
2170 EXPECT_EQ(2u, vector->size());
2171 EXPECT_EQ(1u, vector2->size());
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002172 EXPECT_EQ(3u, vectorUW->size());
2173 EXPECT_EQ(1u, vector2->size());
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002174
2175 EXPECT_TRUE(memberMember->get(one) == two);
2176 EXPECT_TRUE(primitiveMember->get(1) == two);
2177 EXPECT_TRUE(primitiveMember->get(4) == one);
2178 EXPECT_EQ(2, memberPrimitive->get(one));
2179 EXPECT_EQ(3, memberPrimitive->get(two));
2180 EXPECT_TRUE(set->contains(one));
2181 EXPECT_TRUE(set->contains(two));
2182 EXPECT_FALSE(set->contains(oneB));
2183 EXPECT_TRUE(set2->contains(oneB));
2184 EXPECT_EQ(3, vector->at(0)->value());
2185 EXPECT_EQ(4, vector->at(1)->value());
2186 }
2187
2188 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2189 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2190
2191 EXPECT_EQ(4u, memberMember->size());
2192 EXPECT_EQ(4u, primitiveMember->size());
2193 EXPECT_EQ(4u, memberPrimitive->size());
2194 EXPECT_EQ(4u, set->size());
2195 EXPECT_EQ(1u, set2->size());
2196 EXPECT_EQ(2u, vector->size());
2197 EXPECT_EQ(1u, vector2->size());
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002198 EXPECT_EQ(3u, vectorWU->size());
2199 EXPECT_EQ(1u, vectorWU2->size());
2200 EXPECT_EQ(3u, vectorUW->size());
2201 EXPECT_EQ(1u, vectorUW2->size());
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002202}
2203
2204template<typename T>
2205void MapIteratorCheck(T& it, const T& end, int expected)
2206{
2207 int found = 0;
2208 while (it != end) {
2209 found++;
2210 int key = it->key->value();
2211 int value = it->value->value();
2212 EXPECT_TRUE(key >= 0 && key < 1100);
2213 EXPECT_TRUE(value >= 0 && value < 1100);
2214 ++it;
2215 }
2216 EXPECT_EQ(expected, found);
2217}
2218
2219template<typename T>
2220void SetIteratorCheck(T& it, const T& end, int expected)
2221{
2222 int found = 0;
2223 while (it != end) {
2224 found++;
2225 int value = (*it)->value();
2226 EXPECT_TRUE(value >= 0 && value < 1100);
2227 ++it;
2228 }
2229 EXPECT_EQ(expected, found);
2230}
2231
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002232TEST(HeapTest, HeapWeakCollectionSimple)
2233{
Ben Murdochaafa69c2014-04-03 12:30:15 +01002234 HeapStats initialHeapStats;
2235 clearOutOldGarbage(&initialHeapStats);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002236 IntWrapper::s_destructorCalls = 0;
2237
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002238 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive;
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002239
2240 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakStrong;
2241 typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeak;
2242 typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper> > WeakWeak;
2243 typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet;
2244
2245 Persistent<WeakStrong> weakStrong = new WeakStrong();
2246 Persistent<StrongWeak> strongWeak = new StrongWeak();
2247 Persistent<WeakWeak> weakWeak = new WeakWeak();
2248 Persistent<WeakSet> weakSet = new WeakSet();
2249
2250 Persistent<IntWrapper> two = IntWrapper::create(2);
2251
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002252 keepNumbersAlive.append(IntWrapper::create(103));
2253 keepNumbersAlive.append(IntWrapper::create(10));
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002254
2255 {
2256 weakStrong->add(IntWrapper::create(1), two);
2257 strongWeak->add(two, IntWrapper::create(1));
2258 weakWeak->add(two, IntWrapper::create(42));
2259 weakWeak->add(IntWrapper::create(42), two);
2260 weakSet->add(IntWrapper::create(0));
2261 weakSet->add(two);
2262 weakSet->add(keepNumbersAlive[0]);
2263 weakSet->add(keepNumbersAlive[1]);
2264 EXPECT_EQ(1u, weakStrong->size());
2265 EXPECT_EQ(1u, strongWeak->size());
2266 EXPECT_EQ(2u, weakWeak->size());
2267 EXPECT_EQ(4u, weakSet->size());
2268 }
2269
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002270 keepNumbersAlive[0] = nullptr;
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002271
2272 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2273
2274 EXPECT_EQ(0u, weakStrong->size());
2275 EXPECT_EQ(0u, strongWeak->size());
2276 EXPECT_EQ(0u, weakWeak->size());
2277 EXPECT_EQ(2u, weakSet->size());
2278}
2279
Ben Murdochaafa69c2014-04-03 12:30:15 +01002280class ThingWithDestructor {
2281public:
2282 ThingWithDestructor()
2283 : m_x(emptyValue)
2284 {
2285 s_liveThingsWithDestructor++;
2286 }
2287
2288 ThingWithDestructor(int x)
2289 : m_x(x)
2290 {
2291 s_liveThingsWithDestructor++;
2292 }
2293
2294 ThingWithDestructor(const ThingWithDestructor&other)
2295 {
2296 *this = other;
2297 s_liveThingsWithDestructor++;
2298 }
2299
2300 ~ThingWithDestructor()
2301 {
2302 s_liveThingsWithDestructor--;
2303 }
2304
2305 int value() { return m_x; }
2306
2307 static int s_liveThingsWithDestructor;
2308
2309 unsigned hash() { return IntHash<int>::hash(m_x); }
2310
2311private:
2312 static const int emptyValue = 0;
2313 int m_x;
2314};
2315
2316int ThingWithDestructor::s_liveThingsWithDestructor;
2317
2318struct ThingWithDestructorTraits : public HashTraits<ThingWithDestructor> {
2319 static const bool needsDestruction = true;
2320};
2321
2322static void heapMapDestructorHelper(bool clearMaps)
2323{
2324 HeapStats initialHeapStats;
2325 clearOutOldGarbage(&initialHeapStats);
2326 ThingWithDestructor::s_liveThingsWithDestructor = 0;
2327
2328 typedef HeapHashMap<WeakMember<IntWrapper>, RefPtr<RefCountedAndGarbageCollected> > RefMap;
2329
2330 typedef HeapHashMap<
2331 WeakMember<IntWrapper>,
2332 ThingWithDestructor,
2333 DefaultHash<WeakMember<IntWrapper> >::Hash,
2334 HashTraits<WeakMember<IntWrapper> >,
2335 ThingWithDestructorTraits> Map;
2336
2337 Persistent<Map> map(new Map());
2338 Persistent<RefMap> refMap(new RefMap());
2339
2340 Persistent<IntWrapper> luck(IntWrapper::create(103));
2341
2342 int baseLine, refBaseLine;
2343
2344 {
2345 Map stackMap;
2346 RefMap stackRefMap;
2347
2348 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2349 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2350
2351 stackMap.add(IntWrapper::create(42), ThingWithDestructor(1729));
2352 stackMap.add(luck, ThingWithDestructor(8128));
2353 stackRefMap.add(IntWrapper::create(42), RefCountedAndGarbageCollected::create());
2354 stackRefMap.add(luck, RefCountedAndGarbageCollected::create());
2355
2356 baseLine = ThingWithDestructor::s_liveThingsWithDestructor;
2357 refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls;
2358
2359 // Although the heap maps are on-stack, we can't expect prompt
2360 // finalization of the elements, so when they go out of scope here we
2361 // will not necessarily have called the relevant destructors.
2362 }
2363
2364 // The RefCountedAndGarbageCollected things need an extra GC to discover
2365 // that they are no longer ref counted.
2366 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2367 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2368 EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor);
2369 EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls);
2370
2371 // Now use maps kept alive with persistents. Here we don't expect any
2372 // destructors to be called before there have been GCs.
2373
2374 map->add(IntWrapper::create(42), ThingWithDestructor(1729));
2375 map->add(luck, ThingWithDestructor(8128));
2376 refMap->add(IntWrapper::create(42), RefCountedAndGarbageCollected::create());
2377 refMap->add(luck, RefCountedAndGarbageCollected::create());
2378
2379 baseLine = ThingWithDestructor::s_liveThingsWithDestructor;
2380 refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls;
2381
2382 luck.clear();
2383 if (clearMaps) {
2384 map->clear(); // Clear map.
2385 refMap->clear(); // Clear map.
2386 } else {
2387 map.clear(); // Clear Persistent handle, not map.
2388 refMap.clear(); // Clear Persistent handle, not map.
2389 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2390 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2391 }
2392
2393 EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor);
2394
2395 // Need a GC to make sure that the RefCountedAndGarbageCollected thing
2396 // noticies it's been decremented to zero.
2397 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2398 EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls);
2399}
2400
2401TEST(HeapTest, HeapMapDestructor)
2402{
2403 heapMapDestructorHelper(true);
2404 heapMapDestructorHelper(false);
2405}
2406
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002407typedef HeapHashSet<PairWeakStrong> WeakStrongSet;
2408typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet;
2409typedef HeapHashSet<PairStrongWeak> StrongWeakSet;
2410typedef HeapHashSet<PairUnwrappedWeak> UnwrappedWeakSet;
2411
2412void checkPairSets(
2413 Persistent<WeakStrongSet>& weakStrong,
2414 Persistent<StrongWeakSet>& strongWeak,
2415 Persistent<WeakUnwrappedSet>& weakUnwrapped,
2416 Persistent<UnwrappedWeakSet>& unwrappedWeak,
2417 bool ones,
2418 Persistent<IntWrapper>& two)
2419{
2420 WeakStrongSet::iterator itWS = weakStrong->begin();
2421 StrongWeakSet::iterator itSW = strongWeak->begin();
2422 WeakUnwrappedSet::iterator itWU = weakUnwrapped->begin();
2423 UnwrappedWeakSet::iterator itUW = unwrappedWeak->begin();
2424
2425 EXPECT_EQ(2u, weakStrong->size());
2426 EXPECT_EQ(2u, strongWeak->size());
2427 EXPECT_EQ(2u, weakUnwrapped->size());
2428 EXPECT_EQ(2u, unwrappedWeak->size());
2429
2430 PairWeakStrong p = *itWS;
2431 PairStrongWeak p2 = *itSW;
2432 PairWeakUnwrapped p3 = *itWU;
2433 PairUnwrappedWeak p4 = *itUW;
2434 if (p.first == two && p.second == two)
2435 ++itWS;
2436 if (p2.first == two && p2.second == two)
2437 ++itSW;
2438 if (p3.first == two && p3.second == 2)
2439 ++itWU;
2440 if (p4.first == 2 && p4.second == two)
2441 ++itUW;
2442 p = *itWS;
2443 p2 = *itSW;
2444 p3 = *itWU;
2445 p4 = *itUW;
2446 IntWrapper* nullWrapper = 0;
2447 if (ones) {
2448 EXPECT_EQ(p.first->value(), 1);
2449 EXPECT_EQ(p2.second->value(), 1);
2450 EXPECT_EQ(p3.first->value(), 1);
2451 EXPECT_EQ(p4.second->value(), 1);
2452 } else {
2453 EXPECT_EQ(p.first, nullWrapper);
2454 EXPECT_EQ(p2.second, nullWrapper);
2455 EXPECT_EQ(p3.first, nullWrapper);
2456 EXPECT_EQ(p4.second, nullWrapper);
2457 }
2458
2459 EXPECT_EQ(p.second->value(), 2);
2460 EXPECT_EQ(p2.first->value(), 2);
2461 EXPECT_EQ(p3.second, 2);
2462 EXPECT_EQ(p4.first, 2);
2463
2464 EXPECT_TRUE(weakStrong->contains(PairWeakStrong(&*two, &*two)));
2465 EXPECT_TRUE(strongWeak->contains(PairStrongWeak(&*two, &*two)));
2466 EXPECT_TRUE(weakUnwrapped->contains(PairWeakUnwrapped(&*two, 2)));
2467 EXPECT_TRUE(unwrappedWeak->contains(PairUnwrappedWeak(2, &*two)));
2468}
2469
2470TEST(HeapTest, HeapWeakPairs)
2471{
2472 IntWrapper::s_destructorCalls = 0;
2473
2474 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive;
2475
2476 Persistent<WeakStrongSet> weakStrong = new WeakStrongSet();
2477 Persistent<StrongWeakSet> strongWeak = new StrongWeakSet();
2478 Persistent<WeakUnwrappedSet> weakUnwrapped = new WeakUnwrappedSet();
2479 Persistent<UnwrappedWeakSet> unwrappedWeak = new UnwrappedWeakSet();
2480
2481 Persistent<IntWrapper> two = IntWrapper::create(2);
2482
2483 weakStrong->add(PairWeakStrong(IntWrapper::create(1), &*two));
2484 weakStrong->add(PairWeakStrong(&*two, &*two));
2485 strongWeak->add(PairStrongWeak(&*two, IntWrapper::create(1)));
2486 strongWeak->add(PairStrongWeak(&*two, &*two));
2487 weakUnwrapped->add(PairWeakUnwrapped(IntWrapper::create(1), 2));
2488 weakUnwrapped->add(PairWeakUnwrapped(&*two, 2));
2489 unwrappedWeak->add(PairUnwrappedWeak(2, IntWrapper::create(1)));
2490 unwrappedWeak->add(PairUnwrappedWeak(2, &*two));
2491
2492 checkPairSets(weakStrong, strongWeak, weakUnwrapped, unwrappedWeak, true, two);
2493
2494 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2495 checkPairSets(weakStrong, strongWeak, weakUnwrapped, unwrappedWeak, false, two);
2496}
2497
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002498TEST(HeapTest, HeapWeakCollectionTypes)
2499{
2500 HeapStats initialHeapSize;
2501 IntWrapper::s_destructorCalls = 0;
2502
2503 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakStrong;
2504 typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeak;
2505 typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper> > WeakWeak;
2506 typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet;
2507
2508 clearOutOldGarbage(&initialHeapSize);
2509
2510 const int weakStrongIndex = 0;
2511 const int strongWeakIndex = 1;
2512 const int weakWeakIndex = 2;
2513 const int numberOfMapIndices = 3;
2514 const int weakSetIndex = 3;
2515 const int numberOfCollections = 4;
2516
2517 for (int testRun = 0; testRun < 4; testRun++) {
2518 for (int collectionNumber = 0; collectionNumber < numberOfCollections; collectionNumber++) {
2519 bool testThatIteratorsMakeStrong = (testRun == weakSetIndex);
2520 bool deleteAfterwards = (testRun == 1);
2521 bool addAfterwards = (testRun == weakWeakIndex);
2522
2523 // The test doesn't work for strongWeak with deleting because we lost
2524 // the key from the keepNumbersAlive array, so we can't do the lookup.
2525 if (deleteAfterwards && collectionNumber == strongWeakIndex)
2526 continue;
2527
2528 unsigned added = addAfterwards ? 100 : 0;
2529
2530 Persistent<WeakStrong> weakStrong = new WeakStrong();
2531 Persistent<StrongWeak> strongWeak = new StrongWeak();
2532 Persistent<WeakWeak> weakWeak = new WeakWeak();
2533
2534 Persistent<WeakSet> weakSet = new WeakSet();
2535
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002536 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive;
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002537 for (int i = 0; i < 128; i += 2) {
2538 IntWrapper* wrapped = IntWrapper::create(i);
2539 IntWrapper* wrapped2 = IntWrapper::create(i + 1);
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002540 keepNumbersAlive.append(wrapped);
2541 keepNumbersAlive.append(wrapped2);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002542 weakStrong->add(wrapped, wrapped2);
2543 strongWeak->add(wrapped2, wrapped);
2544 weakWeak->add(wrapped, wrapped2);
2545 weakSet->add(wrapped);
2546 }
2547
2548 EXPECT_EQ(64u, weakStrong->size());
2549 EXPECT_EQ(64u, strongWeak->size());
2550 EXPECT_EQ(64u, weakWeak->size());
2551 EXPECT_EQ(64u, weakSet->size());
2552
2553 // Collect garbage. This should change nothing since we are keeping
2554 // alive the IntWrapper objects.
2555 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2556
2557 EXPECT_EQ(64u, weakStrong->size());
2558 EXPECT_EQ(64u, strongWeak->size());
2559 EXPECT_EQ(64u, weakWeak->size());
2560 EXPECT_EQ(64u, weakSet->size());
2561
2562 for (int i = 0; i < 128; i += 2) {
2563 IntWrapper* wrapped = keepNumbersAlive[i];
2564 IntWrapper* wrapped2 = keepNumbersAlive[i + 1];
2565 EXPECT_EQ(wrapped2, weakStrong->get(wrapped));
2566 EXPECT_EQ(wrapped, strongWeak->get(wrapped2));
2567 EXPECT_EQ(wrapped2, weakWeak->get(wrapped));
2568 EXPECT_TRUE(weakSet->contains(wrapped));
2569 }
2570
2571 for (int i = 0; i < 128; i += 3)
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002572 keepNumbersAlive[i] = nullptr;
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002573
2574 if (collectionNumber != weakStrongIndex)
2575 weakStrong->clear();
2576 if (collectionNumber != strongWeakIndex)
2577 strongWeak->clear();
2578 if (collectionNumber != weakWeakIndex)
2579 weakWeak->clear();
2580 if (collectionNumber != weakSetIndex)
2581 weakSet->clear();
2582
2583 if (testThatIteratorsMakeStrong) {
2584 WeakStrong::iterator it1 = weakStrong->begin();
2585 StrongWeak::iterator it2 = strongWeak->begin();
2586 WeakWeak::iterator it3 = weakWeak->begin();
2587 WeakSet::iterator it4 = weakSet->begin();
2588 // Collect garbage. This should change nothing since the
2589 // iterators make the collections strong.
2590 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2591 if (collectionNumber == weakStrongIndex) {
2592 EXPECT_EQ(64u, weakStrong->size());
2593 MapIteratorCheck(it1, weakStrong->end(), 64);
2594 } else if (collectionNumber == strongWeakIndex) {
2595 EXPECT_EQ(64u, strongWeak->size());
2596 MapIteratorCheck(it2, strongWeak->end(), 64);
2597 } else if (collectionNumber == weakWeakIndex) {
2598 EXPECT_EQ(64u, weakWeak->size());
2599 MapIteratorCheck(it3, weakWeak->end(), 64);
2600 } else if (collectionNumber == weakSetIndex) {
2601 EXPECT_EQ(64u, weakSet->size());
2602 SetIteratorCheck(it4, weakSet->end(), 64);
2603 }
2604 } else {
2605 // Collect garbage. This causes weak processing to remove
2606 // things from the collections.
2607 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2608 unsigned count = 0;
2609 for (int i = 0; i < 128; i += 2) {
2610 bool firstAlive = keepNumbersAlive[i];
2611 bool secondAlive = keepNumbersAlive[i + 1];
2612 if (firstAlive && (collectionNumber == weakStrongIndex || collectionNumber == strongWeakIndex))
2613 secondAlive = true;
2614 if (firstAlive && secondAlive && collectionNumber < numberOfMapIndices) {
2615 if (collectionNumber == weakStrongIndex) {
2616 if (deleteAfterwards)
2617 EXPECT_EQ(i + 1, weakStrong->take(keepNumbersAlive[i])->value());
2618 } else if (collectionNumber == strongWeakIndex) {
2619 if (deleteAfterwards)
2620 EXPECT_EQ(i, strongWeak->take(keepNumbersAlive[i + 1])->value());
2621 } else if (collectionNumber == weakWeakIndex) {
2622 if (deleteAfterwards)
2623 EXPECT_EQ(i + 1, weakWeak->take(keepNumbersAlive[i])->value());
2624 }
2625 if (!deleteAfterwards)
2626 count++;
2627 } else if (collectionNumber == weakSetIndex && firstAlive) {
2628 ASSERT_TRUE(weakSet->contains(keepNumbersAlive[i]));
2629 if (deleteAfterwards)
2630 weakSet->remove(keepNumbersAlive[i]);
2631 else
2632 count++;
2633 }
2634 }
2635 if (addAfterwards) {
2636 for (int i = 1000; i < 1100; i++) {
2637 IntWrapper* wrapped = IntWrapper::create(i);
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002638 keepNumbersAlive.append(wrapped);
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002639 weakStrong->add(wrapped, wrapped);
2640 strongWeak->add(wrapped, wrapped);
2641 weakWeak->add(wrapped, wrapped);
2642 weakSet->add(wrapped);
2643 }
2644 }
2645 if (collectionNumber == weakStrongIndex)
2646 EXPECT_EQ(count + added, weakStrong->size());
2647 else if (collectionNumber == strongWeakIndex)
2648 EXPECT_EQ(count + added, strongWeak->size());
2649 else if (collectionNumber == weakWeakIndex)
2650 EXPECT_EQ(count + added, weakWeak->size());
2651 else if (collectionNumber == weakSetIndex)
2652 EXPECT_EQ(count + added, weakSet->size());
2653 WeakStrong::iterator it1 = weakStrong->begin();
2654 StrongWeak::iterator it2 = strongWeak->begin();
2655 WeakWeak::iterator it3 = weakWeak->begin();
2656 WeakSet::iterator it4 = weakSet->begin();
2657 MapIteratorCheck(it1, weakStrong->end(), (collectionNumber == weakStrongIndex ? count : 0) + added);
2658 MapIteratorCheck(it2, strongWeak->end(), (collectionNumber == strongWeakIndex ? count : 0) + added);
2659 MapIteratorCheck(it3, weakWeak->end(), (collectionNumber == weakWeakIndex ? count : 0) + added);
2660 SetIteratorCheck(it4, weakSet->end(), (collectionNumber == weakSetIndex ? count : 0) + added);
2661 }
2662 for (unsigned i = 0; i < 128 + added; i++)
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002663 keepNumbersAlive[i] = nullptr;
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002664 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2665 EXPECT_EQ(added, weakStrong->size());
2666 EXPECT_EQ(added, strongWeak->size());
2667 EXPECT_EQ(added, weakWeak->size());
2668 EXPECT_EQ(added, weakSet->size());
2669 }
2670 }
2671}
2672
2673TEST(HeapTest, RefCountedGarbageCollected)
2674{
2675 RefCountedAndGarbageCollected::s_destructorCalls = 0;
2676 {
2677 RefPtr<RefCountedAndGarbageCollected> refPtr3;
2678 {
2679 Persistent<RefCountedAndGarbageCollected> persistent;
2680 {
2681 RefPtr<RefCountedAndGarbageCollected> refPtr1 = RefCountedAndGarbageCollected::create();
2682 RefPtr<RefCountedAndGarbageCollected> refPtr2 = RefCountedAndGarbageCollected::create();
2683 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2684 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
2685 persistent = refPtr1.get();
2686 }
2687 // Reference count is zero for both objects but one of
2688 // them is kept alive by a persistent handle.
2689 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2690 EXPECT_EQ(1, RefCountedAndGarbageCollected::s_destructorCalls);
2691 refPtr3 = persistent;
2692 }
2693 // The persistent handle is gone but the ref count has been
2694 // increased to 1.
2695 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2696 EXPECT_EQ(1, RefCountedAndGarbageCollected::s_destructorCalls);
2697 }
2698 // Both persistent handle is gone and ref count is zero so the
2699 // object can be collected.
2700 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2701 EXPECT_EQ(2, RefCountedAndGarbageCollected::s_destructorCalls);
2702}
2703
2704TEST(HeapTest, RefCountedGarbageCollectedWithStackPointers)
2705{
2706 RefCountedAndGarbageCollected::s_destructorCalls = 0;
2707 RefCountedAndGarbageCollected2::s_destructorCalls = 0;
2708 {
2709 RefCountedAndGarbageCollected* pointer1 = 0;
2710 RefCountedAndGarbageCollected2* pointer2 = 0;
2711 {
2712 RefPtr<RefCountedAndGarbageCollected> object1 = RefCountedAndGarbageCollected::create();
2713 RefPtr<RefCountedAndGarbageCollected2> object2 = RefCountedAndGarbageCollected2::create();
2714 pointer1 = object1.get();
2715 pointer2 = object2.get();
2716 void* objects[2] = { object1.get(), object2.get() };
2717 RefCountedGarbageCollectedVisitor visitor(2, objects);
2718 ThreadState::current()->visitPersistents(&visitor);
2719 EXPECT_TRUE(visitor.validate());
2720
2721 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2722 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
2723 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
2724 }
2725 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2726 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
2727 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
2728
2729 // At this point, the reference counts of object1 and object2 are 0.
2730 // Only pointer1 and pointer2 keep references to object1 and object2.
2731 void* objects[] = { 0 };
2732 RefCountedGarbageCollectedVisitor visitor(0, objects);
2733 ThreadState::current()->visitPersistents(&visitor);
2734 EXPECT_TRUE(visitor.validate());
2735
2736 {
2737 RefPtr<RefCountedAndGarbageCollected> object1(pointer1);
2738 RefPtr<RefCountedAndGarbageCollected2> object2(pointer2);
2739 void* objects[2] = { object1.get(), object2.get() };
2740 RefCountedGarbageCollectedVisitor visitor(2, objects);
2741 ThreadState::current()->visitPersistents(&visitor);
2742 EXPECT_TRUE(visitor.validate());
2743
2744 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2745 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
2746 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
2747 }
2748
2749 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2750 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
2751 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
2752 }
2753
2754 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2755 EXPECT_EQ(1, RefCountedAndGarbageCollected::s_destructorCalls);
2756 EXPECT_EQ(1, RefCountedAndGarbageCollected2::s_destructorCalls);
2757}
2758
2759TEST(HeapTest, WeakMembers)
2760{
2761 Bar::s_live = 0;
2762 {
2763 Persistent<Bar> h1 = Bar::create();
2764 Persistent<Weak> h4;
2765 Persistent<WithWeakMember> h5;
2766 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2767 ASSERT_EQ(1u, Bar::s_live); // h1 is live.
2768 {
2769 Bar* h2 = Bar::create();
2770 Bar* h3 = Bar::create();
2771 h4 = Weak::create(h2, h3);
2772 h5 = WithWeakMember::create(h2, h3);
2773 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
2774 EXPECT_EQ(5u, Bar::s_live); // The on-stack pointer keeps h3 alive.
2775 EXPECT_TRUE(h4->strongIsThere());
2776 EXPECT_TRUE(h4->weakIsThere());
2777 EXPECT_TRUE(h5->strongIsThere());
2778 EXPECT_TRUE(h5->weakIsThere());
2779 }
2780 // h3 is collected, weak pointers from h4 and h5 don't keep it alive.
2781 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2782 EXPECT_EQ(4u, Bar::s_live);
2783 EXPECT_TRUE(h4->strongIsThere());
2784 EXPECT_FALSE(h4->weakIsThere()); // h3 is gone from weak pointer.
2785 EXPECT_TRUE(h5->strongIsThere());
2786 EXPECT_FALSE(h5->weakIsThere()); // h3 is gone from weak pointer.
2787 h1.release(); // Zero out h1.
2788 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2789 EXPECT_EQ(3u, Bar::s_live); // Only h4, h5 and h2 are left.
2790 EXPECT_TRUE(h4->strongIsThere()); // h2 is still pointed to from h4.
2791 EXPECT_TRUE(h5->strongIsThere()); // h2 is still pointed to from h5.
2792 }
2793 // h4 and h5 have gone out of scope now and they were keeping h2 alive.
2794 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2795 EXPECT_EQ(0u, Bar::s_live); // All gone.
2796}
2797
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002798TEST(HeapTest, FinalizationObserver)
2799{
2800 Persistent<FinalizationObserver<Observable> > o;
2801 {
2802 Observable* foo = Observable::create(Bar::create());
2803 // |o| observes |foo|.
2804 o = FinalizationObserver<Observable>::create(foo);
2805 }
2806 // FinalizationObserver doesn't have a strong reference to |foo|. So |foo|
2807 // and its member will be collected.
2808 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2809 EXPECT_EQ(0u, Bar::s_live);
2810 EXPECT_TRUE(o->didCallWillFinalize());
Ben Murdoch07a852d2014-03-31 11:51:52 +01002811
2812 FinalizationObserverWithHashMap::s_didCallWillFinalize = false;
2813 Observable* foo = Observable::create(Bar::create());
2814 FinalizationObserverWithHashMap::ObserverMap& map = FinalizationObserverWithHashMap::observe(*foo);
2815 EXPECT_EQ(1u, map.size());
2816 foo = 0;
2817 // FinalizationObserverWithHashMap doesn't have a strong reference to
2818 // |foo|. So |foo| and its member will be collected.
2819 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2820 EXPECT_EQ(0u, Bar::s_live);
2821 EXPECT_EQ(0u, map.size());
2822 EXPECT_TRUE(FinalizationObserverWithHashMap::s_didCallWillFinalize);
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002823}
2824
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002825TEST(HeapTest, Comparisons)
2826{
2827 Persistent<Bar> barPersistent = Bar::create();
2828 Persistent<Foo> fooPersistent = Foo::create(barPersistent);
2829 EXPECT_TRUE(barPersistent != fooPersistent);
2830 barPersistent = fooPersistent;
2831 EXPECT_TRUE(barPersistent == fooPersistent);
2832}
2833
2834TEST(HeapTest, CheckAndMarkPointer)
2835{
2836 HeapStats initialHeapStats;
2837 clearOutOldGarbage(&initialHeapStats);
2838
2839 Vector<Address> objectAddresses;
2840 Vector<Address> endAddresses;
2841 Address largeObjectAddress;
2842 Address largeObjectEndAddress;
2843 CountingVisitor visitor;
2844 for (int i = 0; i < 10; i++) {
2845 SimpleObject* object = SimpleObject::create();
2846 Address objectAddress = reinterpret_cast<Address>(object);
2847 objectAddresses.append(objectAddress);
2848 endAddresses.append(objectAddress + sizeof(SimpleObject) - 1);
2849 }
2850 LargeObject* largeObject = LargeObject::create();
2851 largeObjectAddress = reinterpret_cast<Address>(largeObject);
2852 largeObjectEndAddress = largeObjectAddress + sizeof(LargeObject) - 1;
2853
2854 // This is a low-level test where we call checkAndMarkPointer. This method
2855 // causes the object start bitmap to be computed which requires the heap
2856 // to be in a consistent state (e.g. the free allocation area must be put
2857 // into a free list header). However when we call makeConsistentForGC it
2858 // also clears out the freelists so we have to rebuild those before trying
2859 // to allocate anything again. We do this by forcing a GC after doing the
2860 // checkAndMarkPointer tests.
2861 {
2862 TestGCScope scope(ThreadState::HeapPointersOnStack);
2863 Heap::makeConsistentForGC();
2864 for (size_t i = 0; i < objectAddresses.size(); i++) {
2865 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, objectAddresses[i]));
2866 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, endAddresses[i]));
2867 }
2868 EXPECT_EQ(objectAddresses.size() * 2, visitor.count());
2869 visitor.reset();
2870 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, largeObjectAddress));
2871 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress));
2872 EXPECT_EQ(2ul, visitor.count());
2873 visitor.reset();
2874 }
2875 // This forces a GC without stack scanning which results in the objects
2876 // being collected. This will also rebuild the above mentioned freelists,
2877 // however we don't rely on that below since we don't have any allocations.
2878 clearOutOldGarbage(&initialHeapStats);
2879 {
2880 TestGCScope scope(ThreadState::HeapPointersOnStack);
2881 Heap::makeConsistentForGC();
2882 for (size_t i = 0; i < objectAddresses.size(); i++) {
2883 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, objectAddresses[i]));
2884 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, endAddresses[i]));
2885 }
2886 EXPECT_EQ(0ul, visitor.count());
2887 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, largeObjectAddress));
2888 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress));
2889 EXPECT_EQ(0ul, visitor.count());
2890 }
2891 // This round of GC is important to make sure that the object start
2892 // bitmap are cleared out and that the free lists are rebuild.
2893 clearOutOldGarbage(&initialHeapStats);
2894}
2895
2896TEST(HeapTest, VisitOffHeapCollections)
2897{
2898 HeapStats initialHeapStats;
2899 clearOutOldGarbage(&initialHeapStats);
2900 IntWrapper::s_destructorCalls = 0;
2901 Persistent<OffHeapContainer> container = OffHeapContainer::create();
2902 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2903 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002904 container = nullptr;
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002905 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2906 EXPECT_EQ(7, IntWrapper::s_destructorCalls);
2907}
2908
2909TEST(HeapTest, PersistentHeapCollectionTypes)
2910{
2911 HeapStats initialHeapSize;
2912 IntWrapper::s_destructorCalls = 0;
2913
2914 typedef HeapVector<Member<IntWrapper> > Vec;
2915 typedef PersistentHeapVector<Member<IntWrapper> > PVec;
2916 typedef PersistentHeapHashSet<Member<IntWrapper> > PSet;
2917 typedef PersistentHeapHashMap<Member<IntWrapper>, Member<IntWrapper> > PMap;
2918
2919 clearOutOldGarbage(&initialHeapSize);
2920 {
2921 PVec pVec;
2922 PSet pSet;
2923 PMap pMap;
2924
2925 IntWrapper* one(IntWrapper::create(1));
2926 IntWrapper* two(IntWrapper::create(2));
2927 IntWrapper* three(IntWrapper::create(3));
2928 IntWrapper* four(IntWrapper::create(4));
2929 IntWrapper* five(IntWrapper::create(5));
2930 IntWrapper* six(IntWrapper::create(6));
2931
2932 pVec.append(one);
2933 pVec.append(two);
2934
2935 Vec* vec = new Vec();
2936 vec->swap(pVec);
2937
2938 pVec.append(two);
2939 pVec.append(three);
2940
2941 pSet.add(four);
2942 pMap.add(five, six);
2943
2944 // Collect |vec| and |one|.
2945 vec = 0;
2946 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2947 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
2948
2949 EXPECT_EQ(2u, pVec.size());
2950 EXPECT_TRUE(pVec.at(0) == two);
2951 EXPECT_TRUE(pVec.at(1) == three);
2952
2953 EXPECT_EQ(1u, pSet.size());
2954 EXPECT_TRUE(pSet.contains(four));
2955
2956 EXPECT_EQ(1u, pMap.size());
2957 EXPECT_TRUE(pMap.get(five) == six);
2958 }
2959
2960 // Collect previous roots.
2961 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2962 EXPECT_EQ(6, IntWrapper::s_destructorCalls);
2963}
2964
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002965TEST(HeapTest, CollectionNesting)
2966{
2967 HeapStats initialStats;
2968 clearOutOldGarbage(&initialStats);
2969 void* key = &IntWrapper::s_destructorCalls;
2970 IntWrapper::s_destructorCalls = 0;
2971 typedef HeapVector<Member<IntWrapper> > IntVector;
2972 HeapHashMap<void*, IntVector>* map = new HeapHashMap<void*, IntVector>();
Torne (Richard Coles)09380292014-02-21 12:17:33 +00002973
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002974 map->add(key, IntVector());
2975
2976 HeapHashMap<void*, IntVector>::iterator it = map->find(key);
2977 EXPECT_EQ(0u, map->get(key).size());
2978
2979 it->value.append(IntWrapper::create(42));
2980 EXPECT_EQ(1u, map->get(key).size());
2981
2982 Persistent<HeapHashMap<void*, IntVector> > keepAlive(map);
2983 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2984 EXPECT_EQ(1u, map->get(key).size());
2985 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
Ben Murdochaafa69c2014-04-03 12:30:15 +01002986
2987 keepAlive = nullptr;
2988 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2989 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002990}
2991
Ben Murdochaafa69c2014-04-03 12:30:15 +01002992TEST(HeapTest, GarbageCollectedMixin)
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002993{
2994 HeapStats initialHeapStats;
2995 clearOutOldGarbage(&initialHeapStats);
2996
2997 Persistent<UseMixin> usemixin = UseMixin::create();
Ben Murdochaafa69c2014-04-03 12:30:15 +01002998 EXPECT_EQ(0, UseMixin::s_traceCount);
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00002999 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
Ben Murdochaafa69c2014-04-03 12:30:15 +01003000 EXPECT_EQ(1, UseMixin::s_traceCount);
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00003001
3002 Persistent<Mixin> mixin = usemixin;
3003 usemixin = nullptr;
3004 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
Ben Murdochaafa69c2014-04-03 12:30:15 +01003005 EXPECT_EQ(2, UseMixin::s_traceCount);
3006
3007 PersistentHeapHashSet<WeakMember<Mixin> > weakMap;
3008 weakMap.add(UseMixin::create());
3009 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3010 EXPECT_EQ(0u, weakMap.size());
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00003011}
3012
3013TEST(HeapTest, CollectionNesting2)
3014{
3015 HeapStats initialStats;
3016 clearOutOldGarbage(&initialStats);
3017 void* key = &IntWrapper::s_destructorCalls;
3018 IntWrapper::s_destructorCalls = 0;
3019 typedef HeapHashSet<Member<IntWrapper> > IntSet;
3020 HeapHashMap<void*, IntSet>* map = new HeapHashMap<void*, IntSet>();
3021
3022 map->add(key, IntSet());
3023
3024 HeapHashMap<void*, IntSet>::iterator it = map->find(key);
3025 EXPECT_EQ(0u, map->get(key).size());
3026
3027 it->value.add(IntWrapper::create(42));
3028 EXPECT_EQ(1u, map->get(key).size());
3029
3030 Persistent<HeapHashMap<void*, IntSet> > keepAlive(map);
3031 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3032 EXPECT_EQ(1u, map->get(key).size());
3033 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3034}
3035
3036TEST(HeapTest, CollectionNesting3)
3037{
3038 HeapStats initialStats;
3039 clearOutOldGarbage(&initialStats);
3040 IntWrapper::s_destructorCalls = 0;
3041 typedef HeapVector<Member<IntWrapper> > IntVector;
3042 HeapVector<IntVector>* vector = new HeapVector<IntVector>();
3043
3044 vector->append(IntVector());
3045
3046 HeapVector<IntVector>::iterator it = vector->begin();
3047 EXPECT_EQ(0u, it->size());
3048
3049 it->append(IntWrapper::create(42));
3050 EXPECT_EQ(1u, it->size());
3051
3052 Persistent<HeapVector<IntVector> > keepAlive(vector);
3053 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3054 EXPECT_EQ(1u, it->size());
3055 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3056}
3057
3058TEST(HeapTest, EmbeddedInVector)
3059{
3060 HeapStats initialStats;
3061 clearOutOldGarbage(&initialStats);
3062 SimpleFinalizedObject::s_destructorCalls = 0;
3063 {
3064 PersistentHeapVector<VectorObject, 2> inlineVector;
3065 PersistentHeapVector<VectorObject> outlineVector;
3066 VectorObject i1, i2;
3067 inlineVector.append(i1);
3068 inlineVector.append(i2);
3069
3070 VectorObject o1, o2;
3071 outlineVector.append(o1);
3072 outlineVector.append(o2);
3073
3074 PersistentHeapVector<VectorObjectInheritedTrace> vectorInheritedTrace;
3075 VectorObjectInheritedTrace it1, it2;
3076 vectorInheritedTrace.append(it1);
3077 vectorInheritedTrace.append(it2);
3078
3079 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3080 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls);
3081
3082 // Since VectorObjectNoTrace has no trace method it will
3083 // not be traced and hence be collected when doing GC.
3084 // We trace items in a collection braced on the item's
3085 // having a trace method. This is determined via the
3086 // NeedsTracing trait in wtf/TypeTraits.h.
3087 PersistentHeapVector<VectorObjectNoTrace> vectorNoTrace;
3088 VectorObjectNoTrace n1, n2;
3089 vectorNoTrace.append(n1);
3090 vectorNoTrace.append(n2);
3091 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3092 EXPECT_EQ(2, SimpleFinalizedObject::s_destructorCalls);
3093 }
3094 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3095 EXPECT_EQ(8, SimpleFinalizedObject::s_destructorCalls);
3096}
3097
3098TEST(HeapTest, RawPtrInHash)
3099{
3100 HashSet<RawPtr<int> > set;
3101 set.add(new int(42));
3102 set.add(new int(42));
3103 EXPECT_EQ(2u, set.size());
3104 for (HashSet<RawPtr<int> >::iterator it = set.begin(); it != set.end(); ++it)
3105 EXPECT_EQ(42, **it);
3106}
3107
3108TEST(HeapTest, HeapTerminatedArray)
3109{
3110 HeapStats initialHeapSize;
3111 clearOutOldGarbage(&initialHeapSize);
3112 IntWrapper::s_destructorCalls = 0;
3113
3114 HeapTerminatedArray<TerminatedArrayItem>* arr = 0;
3115
3116 const size_t prefixSize = 4;
3117 const size_t suffixSize = 4;
3118
3119 {
3120 HeapTerminatedArrayBuilder<TerminatedArrayItem> builder(arr);
3121 builder.grow(prefixSize);
3122 for (size_t i = 0; i < prefixSize; i++)
3123 builder.append(TerminatedArrayItem(IntWrapper::create(i)));
3124 arr = builder.release();
3125 }
3126
3127 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3128 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3129 EXPECT_EQ(prefixSize, arr->size());
3130 for (size_t i = 0; i < prefixSize; i++)
3131 EXPECT_EQ(i, static_cast<size_t>(arr->at(i).payload()->value()));
3132
3133 {
3134 HeapTerminatedArrayBuilder<TerminatedArrayItem> builder(arr);
3135 builder.grow(suffixSize);
3136 for (size_t i = 0; i < suffixSize; i++)
3137 builder.append(TerminatedArrayItem(IntWrapper::create(prefixSize + i)));
3138 arr = builder.release();
3139 }
3140
3141 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3142 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3143 EXPECT_EQ(prefixSize + suffixSize, arr->size());
3144 for (size_t i = 0; i < prefixSize + suffixSize; i++)
3145 EXPECT_EQ(i, static_cast<size_t>(arr->at(i).payload()->value()));
3146
3147 {
3148 Persistent<HeapTerminatedArray<TerminatedArrayItem> > persistentArr = arr;
3149 arr = 0;
3150 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3151 arr = persistentArr.get();
3152 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3153 EXPECT_EQ(prefixSize + suffixSize, arr->size());
3154 for (size_t i = 0; i < prefixSize + suffixSize; i++)
3155 EXPECT_EQ(i, static_cast<size_t>(arr->at(i).payload()->value()));
3156 }
3157
3158 arr = 0;
3159 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3160 EXPECT_EQ(8, IntWrapper::s_destructorCalls);
3161}
3162
3163TEST(HeapTest, HeapLinkedStack)
3164{
3165 HeapStats initialHeapSize;
3166 clearOutOldGarbage(&initialHeapSize);
3167 IntWrapper::s_destructorCalls = 0;
3168
3169 HeapLinkedStack<TerminatedArrayItem>* stack = new HeapLinkedStack<TerminatedArrayItem>();
3170
3171 const size_t stackSize = 10;
3172
3173 for (size_t i = 0; i < stackSize; i++)
3174 stack->push(TerminatedArrayItem(IntWrapper::create(i)));
3175
3176 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
3177 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3178 EXPECT_EQ(stackSize, stack->size());
3179 while (!stack->isEmpty()) {
3180 EXPECT_EQ(stack->size() - 1, static_cast<size_t>(stack->peek().payload()->value()));
3181 stack->pop();
3182 }
3183
3184 Persistent<HeapLinkedStack<TerminatedArrayItem> > pStack = stack;
3185
3186 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3187 EXPECT_EQ(stackSize, static_cast<size_t>(IntWrapper::s_destructorCalls));
3188 EXPECT_EQ(0u, pStack->size());
3189}
3190
3191TEST(HeapTest, AllocationDuringFinalization)
3192{
3193 HeapStats initialHeapSize;
3194 clearOutOldGarbage(&initialHeapSize);
3195 IntWrapper::s_destructorCalls = 0;
3196 OneKiloByteObject::s_destructorCalls = 0;
3197
3198 Persistent<IntWrapper> wrapper;
3199 new FinalizationAllocator(&wrapper);
3200
3201 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3202 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
3203 // Check that the wrapper allocated during finalization is not
3204 // swept away and zapped later in the same sweeping phase.
3205 EXPECT_EQ(42, wrapper->value());
3206
3207 wrapper.clear();
3208 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3209 EXPECT_EQ(10, IntWrapper::s_destructorCalls);
3210 EXPECT_EQ(512, OneKiloByteObject::s_destructorCalls);
3211}
3212
Ben Murdochaafa69c2014-04-03 12:30:15 +01003213class SimpleClassWithDestructor {
3214public:
3215 SimpleClassWithDestructor() { }
3216 ~SimpleClassWithDestructor()
3217 {
3218 ASSERT(!s_wasDestructed);
3219 s_wasDestructed = true;
3220 }
3221 static bool s_wasDestructed;
3222};
3223
3224bool SimpleClassWithDestructor::s_wasDestructed;
3225
3226TEST(HeapTest, DestructorsCalledOnMapClear)
3227{
3228 HeapHashMap<SimpleClassWithDestructor*, OwnPtr<SimpleClassWithDestructor> > map;
3229 SimpleClassWithDestructor* hasDestructor = new SimpleClassWithDestructor();
3230 map.add(hasDestructor, adoptPtr(hasDestructor));
3231 SimpleClassWithDestructor::s_wasDestructed = false;
3232 map.clear();
3233 ASSERT(SimpleClassWithDestructor::s_wasDestructed);
3234}
3235
Torne (Richard Coles)d5428f32014-03-18 10:21:16 +00003236} // WebCore namespace