| Index: Source/heap/HeapTest.cpp
|
| diff --git a/Source/heap/HeapTest.cpp b/Source/heap/HeapTest.cpp
|
| index 005556e562003385ac64f26ec5a6ad3928879e74..5b9d450b0cd2ca77736bf2debacb03f96b544d09 100644
|
| --- a/Source/heap/HeapTest.cpp
|
| +++ b/Source/heap/HeapTest.cpp
|
| @@ -708,6 +708,11 @@ public:
|
| ++s_destructorCalls;
|
| }
|
|
|
| + // These are here with their default implementations so you can break in
|
| + // them in the debugger.
|
| + void ref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::ref(); }
|
| + void deref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::deref(); }
|
| +
|
| void trace(Visitor*) { }
|
|
|
| static int s_destructorCalls;
|
| @@ -2220,7 +2225,8 @@ void SetIteratorCheck(T& it, const T& end, int expected)
|
|
|
| TEST(HeapTest, HeapWeakCollectionSimple)
|
| {
|
| -
|
| + HeapStats initialHeapStats;
|
| + clearOutOldGarbage(&initialHeapStats);
|
| IntWrapper::s_destructorCalls = 0;
|
|
|
| PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive;
|
| @@ -2265,6 +2271,133 @@ TEST(HeapTest, HeapWeakCollectionSimple)
|
| EXPECT_EQ(2u, weakSet->size());
|
| }
|
|
|
| +class ThingWithDestructor {
|
| +public:
|
| + ThingWithDestructor()
|
| + : m_x(emptyValue)
|
| + {
|
| + s_liveThingsWithDestructor++;
|
| + }
|
| +
|
| + ThingWithDestructor(int x)
|
| + : m_x(x)
|
| + {
|
| + s_liveThingsWithDestructor++;
|
| + }
|
| +
|
| + ThingWithDestructor(const ThingWithDestructor&other)
|
| + {
|
| + *this = other;
|
| + s_liveThingsWithDestructor++;
|
| + }
|
| +
|
| + ~ThingWithDestructor()
|
| + {
|
| + s_liveThingsWithDestructor--;
|
| + }
|
| +
|
| + int value() { return m_x; }
|
| +
|
| + static int s_liveThingsWithDestructor;
|
| +
|
| + unsigned hash() { return IntHash<int>::hash(m_x); }
|
| +
|
| +private:
|
| + static const int emptyValue = 0;
|
| + int m_x;
|
| +};
|
| +
|
| +int ThingWithDestructor::s_liveThingsWithDestructor;
|
| +
|
| +struct ThingWithDestructorTraits : public HashTraits<ThingWithDestructor> {
|
| + static const bool needsDestruction = true;
|
| +};
|
| +
|
| +static void heapMapDestructorHelper(bool clearMaps)
|
| +{
|
| + HeapStats initialHeapStats;
|
| + clearOutOldGarbage(&initialHeapStats);
|
| + ThingWithDestructor::s_liveThingsWithDestructor = 0;
|
| +
|
| + typedef HeapHashMap<WeakMember<IntWrapper>, RefPtr<RefCountedAndGarbageCollected> > RefMap;
|
| +
|
| + typedef HeapHashMap<
|
| + WeakMember<IntWrapper>,
|
| + ThingWithDestructor,
|
| + DefaultHash<WeakMember<IntWrapper> >::Hash,
|
| + HashTraits<WeakMember<IntWrapper> >,
|
| + ThingWithDestructorTraits> Map;
|
| +
|
| + Persistent<Map> map(new Map());
|
| + Persistent<RefMap> refMap(new RefMap());
|
| +
|
| + Persistent<IntWrapper> luck(IntWrapper::create(103));
|
| +
|
| + int baseLine, refBaseLine;
|
| +
|
| + {
|
| + Map stackMap;
|
| + RefMap stackRefMap;
|
| +
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| +
|
| + stackMap.add(IntWrapper::create(42), ThingWithDestructor(1729));
|
| + stackMap.add(luck, ThingWithDestructor(8128));
|
| + stackRefMap.add(IntWrapper::create(42), RefCountedAndGarbageCollected::create());
|
| + stackRefMap.add(luck, RefCountedAndGarbageCollected::create());
|
| +
|
| + baseLine = ThingWithDestructor::s_liveThingsWithDestructor;
|
| + refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls;
|
| +
|
| + // Although the heap maps are on-stack, we can't expect prompt
|
| + // finalization of the elements, so when they go out of scope here we
|
| + // will not necessarily have called the relevant destructors.
|
| + }
|
| +
|
| + // The RefCountedAndGarbageCollected things need an extra GC to discover
|
| + // that they are no longer ref counted.
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| + EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor);
|
| + EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls);
|
| +
|
| + // Now use maps kept alive with persistents. Here we don't expect any
|
| + // destructors to be called before there have been GCs.
|
| +
|
| + map->add(IntWrapper::create(42), ThingWithDestructor(1729));
|
| + map->add(luck, ThingWithDestructor(8128));
|
| + refMap->add(IntWrapper::create(42), RefCountedAndGarbageCollected::create());
|
| + refMap->add(luck, RefCountedAndGarbageCollected::create());
|
| +
|
| + baseLine = ThingWithDestructor::s_liveThingsWithDestructor;
|
| + refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls;
|
| +
|
| + luck.clear();
|
| + if (clearMaps) {
|
| + map->clear(); // Clear map.
|
| + refMap->clear(); // Clear map.
|
| + } else {
|
| + map.clear(); // Clear Persistent handle, not map.
|
| + refMap.clear(); // Clear Persistent handle, not map.
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| + }
|
| +
|
| + EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor);
|
| +
|
| + // Need a GC to make sure that the RefCountedAndGarbageCollected thing
|
| + // noticies it's been decremented to zero.
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| + EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls);
|
| +}
|
| +
|
| +TEST(HeapTest, HeapMapDestructor)
|
| +{
|
| + heapMapDestructorHelper(true);
|
| + heapMapDestructorHelper(false);
|
| +}
|
| +
|
| typedef HeapHashSet<PairWeakStrong> WeakStrongSet;
|
| typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet;
|
| typedef HeapHashSet<PairStrongWeak> StrongWeakSet;
|
| @@ -2844,6 +2977,10 @@ TEST(HeapTest, CollectionNesting)
|
| Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| EXPECT_EQ(1u, map->get(key).size());
|
| EXPECT_EQ(0, IntWrapper::s_destructorCalls);
|
| +
|
| + keepAlive = nullptr;
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| + EXPECT_EQ(1, IntWrapper::s_destructorCalls);
|
| }
|
|
|
| TEST(heap, GarbageCollectedMixin)
|
| @@ -3062,4 +3199,27 @@ TEST(HeapTest, AllocationDuringFinalization)
|
| EXPECT_EQ(512, OneKiloByteObject::s_destructorCalls);
|
| }
|
|
|
| +class SimpleClassWithDestructor {
|
| +public:
|
| + SimpleClassWithDestructor() { }
|
| + ~SimpleClassWithDestructor()
|
| + {
|
| + ASSERT(!s_wasDestructed);
|
| + s_wasDestructed = true;
|
| + }
|
| + static bool s_wasDestructed;
|
| +};
|
| +
|
| +bool SimpleClassWithDestructor::s_wasDestructed;
|
| +
|
| +TEST(HeapTest, DestructorsCalledOnMapClear)
|
| +{
|
| + HeapHashMap<SimpleClassWithDestructor*, OwnPtr<SimpleClassWithDestructor> > map;
|
| + SimpleClassWithDestructor* hasDestructor = new SimpleClassWithDestructor();
|
| + map.add(hasDestructor, adoptPtr(hasDestructor));
|
| + SimpleClassWithDestructor::s_wasDestructed = false;
|
| + map.clear();
|
| + ASSERT(SimpleClassWithDestructor::s_wasDestructed);
|
| +}
|
| +
|
| } // WebCore namespace
|
|
|