| Index: Source/platform/heap/HeapTest.cpp
|
| diff --git a/Source/platform/heap/HeapTest.cpp b/Source/platform/heap/HeapTest.cpp
|
| index 114078c1032f37b661463e63e1bc6217b08bcf4f..567c0483f0244acff44cb219fc278328149d885f 100644
|
| --- a/Source/platform/heap/HeapTest.cpp
|
| +++ b/Source/platform/heap/HeapTest.cpp
|
| @@ -4272,4 +4272,78 @@ TEST(HeapTest, Bind)
|
| EXPECT_EQ(1, UseMixin::s_traceCount);
|
| }
|
|
|
| +typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet;
|
| +
|
| +// These special traits will remove a set from a map when the set is empty.
|
| +struct EmptyClearingHastSetTraits : HashTraits<WeakSet> {
|
| + static const WTF::WeakHandlingFlag weakHandlingFlag = WTF::WeakHandlingInCollections;
|
| + static bool shouldRemoveFromCollection(Visitor* visitor, WeakSet& set)
|
| + {
|
| + return set.isEmpty(); // Remove this set from any maps it is in.
|
| + }
|
| + static void traceInCollection(Visitor* visitor, WeakSet& set, WebCore::ShouldWeakPointersBeMarkedStrongly strongify)
|
| + {
|
| + // We just trace normally, which will invoke the normal weak handling
|
| + // of the set, removing individual items.
|
| + set.trace(visitor);
|
| + }
|
| +};
|
| +
|
| +// This is an example to show how you can remove entries from a T->WeakSet map
|
| +// when the weak sets become empty. For this example we are using a type that
|
| +// is given to use (HeapHashSet) rather than a type of our own. This means:
|
| +// 1) We can't just override the HashTrait for the type since this would affect
|
| +// all collections that use this kind of weak set. Instead we have our own
|
| +// traits and use a map with custom traits for the value type. These traits
|
| +// are the 5th template parameter, so we have to supply default values for
|
| +// the 3rd and 4th template parameters
|
| +// 2) We can't just inherit from WeakHandlingHashTraits, since that trait
|
| +// assumes we can add methods to the type, but we can't add methods to
|
| +// HeapHashSet.
|
| +TEST(HeapTest, RemoveEmptySets)
|
| +{
|
| + HeapStats initialHeapSize;
|
| + clearOutOldGarbage(&initialHeapSize);
|
| + OffHeapInt::s_destructorCalls = 0;
|
| +
|
| + Persistent<IntWrapper> livingInt(IntWrapper::create(42));
|
| +
|
| + typedef RefPtr<OffHeapInt> Key;
|
| + typedef HeapHashMap<Key, WeakSet, WTF::DefaultHash<Key>::Hash, HashTraits<Key>, EmptyClearingHastSetTraits> Map;
|
| + Persistent<Map> map(new Map());
|
| + map->add(OffHeapInt::create(1), WeakSet());
|
| + {
|
| + WeakSet& set = map->begin()->value;
|
| + set.add(IntWrapper::create(103)); // Weak set can't hold this long.
|
| + set.add(livingInt); // This prevents the set from being emptied.
|
| + EXPECT_EQ(2u, set.size());
|
| + }
|
| +
|
| + // The set we add here is empty, so the entry will be removed from the map
|
| + // at the next GC.
|
| + map->add(OffHeapInt::create(2), WeakSet());
|
| + EXPECT_EQ(2u, map->size());
|
| +
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| + EXPECT_EQ(1u, map->size()); // The one with key 2 was removed.
|
| + EXPECT_EQ(1, OffHeapInt::s_destructorCalls);
|
| + {
|
| + WeakSet& set = map->begin()->value;
|
| + EXPECT_EQ(1u, set.size());
|
| + }
|
| +
|
| + livingInt.clear(); // The weak set can no longer keep the '42' alive now.
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| + if (map->size() == 1u) {
|
| + // If the weak processing for the set ran after the weak processing for
|
| + // the map, then the set was not empty, and so the entry in the map was
|
| + // not removed yet.
|
| + WeakSet& set = map->begin()->value;
|
| + EXPECT_EQ(0u, set.size());
|
| + }
|
| +
|
| + Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
|
| + EXPECT_EQ(0u, map->size());
|
| +}
|
| +
|
| } // WebCore namespace
|
|
|