Commit 02ad0983 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Allow custom handling of classes that contain weak pointers that are embedded in collections.

This is currently tested with HeapHashSet. Extending it to other hash
collections is postponed to a later change. To have your type removed from
collections when weak pointers in it no longer point to live objects you need
to give it two methods and a special hash trait. See WeakHandlingHashTraits in
Heap.h for details and PairWithWeakHandling in HeapTest.cpp for an example.

R=ager@chromium.org, haraken@chromium.org, wibling@chromium.org, zerny@chromium.org
BUG=

Review URL: https://codereview.chromium.org/319593004

git-svn-id: svn://svn.chromium.org/blink/trunk@176009 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 96f7a81c
......@@ -612,7 +612,7 @@ protected:
T* m_raw;
template<bool x, bool y, ShouldWeakPointersBeMarkedStrongly z, typename U, typename V> friend struct CollectionBackingTraceTrait;
template<bool x, WTF::WeakHandlingFlag y, ShouldWeakPointersBeMarkedStrongly z, typename U, typename V> friend struct CollectionBackingTraceTrait;
friend class Visitor;
};
......@@ -1049,6 +1049,12 @@ template<typename T> struct HashTraits<WebCore::WeakMember<T> > : SimpleClassHas
static PeekOutType peek(const WebCore::WeakMember<T>& value) { return value; }
static PassOutType passOut(const WebCore::WeakMember<T>& value) { return value; }
static bool shouldRemoveFromCollection(WebCore::Visitor* visitor, WebCore::WeakMember<T>& value) { return !visitor->isAlive(value); }
static void traceInCollection(WebCore::Visitor* visitor, WebCore::WeakMember<T>& weakMember, WebCore::ShouldWeakPointersBeMarkedStrongly strongify)
{
if (strongify == WebCore::WeakPointersActStrong)
visitor->trace(reinterpret_cast<WebCore::Member<T>&>(weakMember)); // Strongified visit.
}
};
template<typename T> struct PtrHash<WebCore::Member<T> > : PtrHash<T*> {
......@@ -1095,11 +1101,6 @@ struct IsWeak<WebCore::WeakMember<T> > {
static const bool value = true;
};
template<typename Table>
struct IsWeak<WebCore::HeapHashTableBacking<Table> > {
static const bool value = Table::ValueTraits::isWeak;
};
template<typename T> inline T* getPtr(const WebCore::Member<T>& p)
{
return p.get();
......
......@@ -71,7 +71,7 @@ enum ShouldWeakPointersBeMarkedStrongly {
WeakPointersActWeak
};
template<bool needsTracing, bool isWeak, ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Traits> struct CollectionBackingTraceTrait;
template<bool needsTracing, WTF::WeakHandlingFlag weakHandlingFlag, ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Traits> struct CollectionBackingTraceTrait;
// The TraceMethodDelegate is used to convert a trace method for type T to a TraceCallback.
// This allows us to pass a type's trace method as a parameter to the PersistentNode
......@@ -238,6 +238,12 @@ public:
// Fallback method used only when we need to trace raw pointers of T.
// This is the case when a member is a union where we do not support members.
template<typename T>
void trace(const T* t)
{
mark(const_cast<T*>(t));
}
template<typename T>
void trace(T* t)
{
......@@ -246,16 +252,30 @@ public:
// WeakMember version of the templated trace method. It doesn't keep
// the traced thing alive, but will write null to the WeakMember later
// if the pointed-to object is dead.
// if the pointed-to object is dead. It's lying for this to be const,
// but the overloading resolver prioritizes constness too high when
// picking the correct overload, so all these trace methods have to have
// the same constness on their argument to allow the type to decide.
template<typename T>
void trace(const WeakMember<T>& t)
{
registerWeakCell(t.cell());
registerWeakCell(const_cast<WeakMember<T>&>(t).cell());
}
// Fallback trace method for part objects to allow individual
// trace methods to trace through a part object with
// visitor->trace(m_partObject).
template<typename T>
void traceInCollection(T& t, ShouldWeakPointersBeMarkedStrongly strongify)
{
HashTraits<T>::traceInCollection(this, t, strongify);
}
// Fallback trace method for part objects to allow individual trace methods
// to trace through a part object with visitor->trace(m_partObject). This
// takes a const argument, because otherwise it will match too eagerly: a
// non-const argument would match a non-const Vector<T>& argument better
// than the specialization that takes const Vector<T>&. For a similar reason,
// the other specializations take a const argument even though they are
// usually used with non-const arguments, otherwise this function would match
// too well.
template<typename T>
void trace(const T& t)
{
......@@ -264,15 +284,15 @@ public:
// The following trace methods are for off-heap collections.
template<typename T, size_t inlineCapacity>
void trace(const Vector<T, inlineCapacity, WTF::DefaultAllocator>& vector)
void trace(const Vector<T, inlineCapacity>& vector)
{
OffHeapCollectionTraceTrait<Vector<T, inlineCapacity, WTF::DefaultAllocator> >::trace(this, vector);
}
template<typename T, typename U, typename V>
void trace(const HashSet<T, U, V, WTF::DefaultAllocator>& hashSet)
void trace(const HashSet<T, U, V>& hashSet)
{
OffHeapCollectionTraceTrait<HashSet<T, U, V, WTF::DefaultAllocator> >::trace(this, hashSet);
OffHeapCollectionTraceTrait<HashSet<T, U, V> >::trace(this, hashSet);
}
template<typename T, size_t inlineCapacity, typename U>
......@@ -468,10 +488,12 @@ struct OffHeapCollectionTraceTrait<WTF::HashSet<T, HashFunctions, Traits, WTF::D
return;
if (WTF::ShouldBeTraced<Traits>::value) {
HashSet& iterSet = const_cast<HashSet&>(set);
for (typename HashSet::iterator it = iterSet.begin(), end = iterSet.end(); it != end; ++it)
CollectionBackingTraceTrait<WTF::ShouldBeTraced<Traits>::value, Traits::isWeak, WeakPointersActWeak, T, Traits>::trace(visitor, *it);
for (typename HashSet::iterator it = iterSet.begin(), end = iterSet.end(); it != end; ++it) {
const T& t = *it;
CollectionBackingTraceTrait<WTF::ShouldBeTraced<Traits>::value, Traits::weakHandlingFlag, WeakPointersActWeak, T, Traits>::trace(visitor, const_cast<T&>(t));
}
}
COMPILE_ASSERT(!Traits::isWeak, WeakOffHeapCollectionsConsideredDangerous0);
COMPILE_ASSERT(Traits::weakHandlingFlag == WTF::NoWeakHandlingInCollections, WeakOffHeapCollectionsConsideredDangerous0);
}
};
......@@ -514,12 +536,12 @@ struct OffHeapCollectionTraceTrait<WTF::HashMap<Key, Value, HashFunctions, KeyTr
if (WTF::ShouldBeTraced<KeyTraits>::value || WTF::ShouldBeTraced<ValueTraits>::value) {
HashMap& iterMap = const_cast<HashMap&>(map);
for (typename HashMap::iterator it = iterMap.begin(), end = iterMap.end(); it != end; ++it) {
CollectionBackingTraceTrait<WTF::ShouldBeTraced<KeyTraits>::value, KeyTraits::isWeak, WeakPointersActWeak, typename HashMap::KeyType, KeyTraits>::trace(visitor, it->key);
CollectionBackingTraceTrait<WTF::ShouldBeTraced<ValueTraits>::value, ValueTraits::isWeak, WeakPointersActWeak, typename HashMap::MappedType, ValueTraits>::trace(visitor, it->value);
CollectionBackingTraceTrait<WTF::ShouldBeTraced<KeyTraits>::value, KeyTraits::weakHandlingFlag, WeakPointersActWeak, typename HashMap::KeyType, KeyTraits>::trace(visitor, it->key);
CollectionBackingTraceTrait<WTF::ShouldBeTraced<ValueTraits>::value, ValueTraits::weakHandlingFlag, WeakPointersActWeak, typename HashMap::MappedType, ValueTraits>::trace(visitor, it->value);
}
}
COMPILE_ASSERT(!KeyTraits::isWeak, WeakOffHeapCollectionsConsideredDangerous1);
COMPILE_ASSERT(!ValueTraits::isWeak, WeakOffHeapCollectionsConsideredDangerous2);
COMPILE_ASSERT(KeyTraits::weakHandlingFlag == WTF::NoWeakHandlingInCollections, WeakOffHeapCollectionsConsideredDangerous1);
COMPILE_ASSERT(ValueTraits::weakHandlingFlag == WTF::NoWeakHandlingInCollections, WeakOffHeapCollectionsConsideredDangerous2);
}
};
......
......@@ -97,7 +97,7 @@ namespace WTF {
class HashTableConstIterator;
template<typename Value, typename HashFunctions, typename HashTraits, typename Allocator>
class LinkedHashSet;
template<bool x, typename T, typename U, typename V, typename W, typename X, typename Y, typename Z>
template<WeakHandlingFlag x, typename T, typename U, typename V, typename W, typename X, typename Y, typename Z>
struct WeakProcessingHashTableHelper;
typedef enum { HashItemKnownGood } HashItemKnownGoodTag;
......@@ -532,7 +532,7 @@ namespace WTF {
mutable OwnPtr<Stats> m_stats;
#endif
template<bool x, typename T, typename U, typename V, typename W, typename X, typename Y, typename Z> friend struct WeakProcessingHashTableHelper;
template<WeakHandlingFlag x, typename T, typename U, typename V, typename W, typename X, typename Y, typename Z> friend struct WeakProcessingHashTableHelper;
template<typename T, typename U, typename V, typename W> friend class LinkedHashSet;
};
......@@ -1097,16 +1097,16 @@ namespace WTF {
return *this;
}
template<bool isWeak, typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
template<WeakHandlingFlag weakHandlingFlag, typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
struct WeakProcessingHashTableHelper;
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
struct WeakProcessingHashTableHelper<false, Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> {
struct WeakProcessingHashTableHelper<NoWeakHandlingInCollections, Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> {
static void process(typename Allocator::Visitor* visitor, void* closure) { }
};
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
struct WeakProcessingHashTableHelper<true, Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> {
struct WeakProcessingHashTableHelper<WeakHandlingInCollections, Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> {
static void process(typename Allocator::Visitor* visitor, void* closure)
{
typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> HashTableType;
......@@ -1120,7 +1120,7 @@ namespace WTF {
// strongly).
for (typename HashTableType::ValueType* element = table->m_table + table->m_tableSize - 1; element >= table->m_table; element--) {
if (!HashTableType::isEmptyOrDeletedBucket(*element)) {
if (Allocator::hasDeadMember(visitor, *element)) {
if (Traits::shouldRemoveFromCollection(visitor, *element)) {
table->registerModification();
HashTableType::deleteBucket(*element); // Also calls the destructor.
table->m_deletedCount++;
......@@ -1156,10 +1156,10 @@ namespace WTF {
// while we are iterating over them. The weakProcessing callback will
// mark the backing as a void pointer, and will perform weak processing
// if needed.
if (!Traits::isWeak)
if (Traits::weakHandlingFlag == NoWeakHandlingInCollections)
Allocator::markNoTracing(visitor, m_table);
else
Allocator::registerWeakMembers(visitor, this, m_table, WeakProcessingHashTableHelper<Traits::isWeak, Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::process);
Allocator::registerWeakMembers(visitor, this, m_table, WeakProcessingHashTableHelper<Traits::weakHandlingFlag, Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::process);
if (ShouldBeTraced<Traits>::value) {
for (ValueType* element = m_table + m_tableSize - 1; element >= m_table; element--) {
if (!isEmptyOrDeletedBucket(*element))
......
......@@ -63,7 +63,9 @@ namespace WTF {
struct NeedsTracingLazily {
static const bool value = NeedsTracing<T>::value;
};
static const bool isWeak = IsWeak<T>::value;
static const WeakHandlingFlag weakHandlingFlag = IsWeak<T>::value ? WeakHandlingInCollections : NoWeakHandlingInCollections;
template<typename Visitor>
static bool shouldRemoveFromCollection(Visitor*, T&) { return false; }
};
// Default integer traits disallow both 0 and -1 as keys (max value instead of -1 for unsigned).
......@@ -270,12 +272,18 @@ namespace WTF {
struct NeedsTracingLazily {
static const bool value = ShouldBeTraced<KeyTraits>::value || ShouldBeTraced<ValueTraits>::value;
};
static const bool isWeak = KeyTraits::isWeak || ValueTraits::isWeak;
static const WeakHandlingFlag weakHandlingFlag = (KeyTraits::weakHandlingFlag == WeakHandlingInCollections || ValueTraits::weakHandlingFlag == WeakHandlingInCollections) ? WeakHandlingInCollections : NoWeakHandlingInCollections;
static const unsigned minimumTableSize = KeyTraits::minimumTableSize;
static void constructDeletedValue(TraitType& slot) { KeyTraits::constructDeletedValue(slot.key); }
static bool isDeletedValue(const TraitType& value) { return KeyTraits::isDeletedValue(value.key); }
template<typename Visitor>
static bool shouldRemoveFromCollection(Visitor* visitor, TraitType& pair)
{
return KeyTraits::shouldRemoveFromCollection(visitor, pair.key)
|| ValueTraits::shouldRemoveFromCollection(visitor, pair.value);
}
};
template<typename Key, typename Value>
......
......@@ -307,7 +307,7 @@ struct LinkedHashSetTraits : public SimpleClassHashTraits<LinkedHashSetNode<Valu
static const bool emptyValueIsZero = true;
static const bool hasIsEmptyValueFunction = true;
static bool isEmptyValue(const Node& value) { return !value.m_next; }
static bool isEmptyValue(const Node& node) { return !node.m_next; }
static const int deletedValue = -1;
......@@ -324,7 +324,12 @@ struct LinkedHashSetTraits : public SimpleClassHashTraits<LinkedHashSetNode<Valu
struct NeedsTracingLazily {
static const bool value = ValueTraits::template NeedsTracingLazily<>::value;
};
static const bool isWeak = ValueTraits::isWeak;
static const WeakHandlingFlag weakHandlingFlag = ValueTraits::weakHandlingFlag;
template<typename Visitor>
static bool shouldRemoveFromCollection(Visitor* visitor, LinkedHashSetNode<Value>& node)
{
return ValueTraits::shouldRemoveFromCollection(visitor, node.m_value);
}
};
template<typename LinkedHashSetType>
......@@ -670,11 +675,6 @@ inline void LinkedHashSet<T, U, V, W>::remove(ValuePeekInType value)
remove(find(value));
}
template<typename T>
struct IsWeak<LinkedHashSetNode<T> > {
static const bool value = IsWeak<T>::value;
};
inline void swap(LinkedHashSetNodeBase& a, LinkedHashSetNodeBase& b)
{
swap(a.m_prev, b.m_prev);
......
......@@ -996,6 +996,7 @@ namespace WTF {
template<typename T, size_t inlineCapacity, typename U, typename V>
void ListHashSet<T, inlineCapacity, U, V>::trace(typename Allocator::Visitor* visitor)
{
COMPILE_ASSERT(HashTraits<T>::weakHandlingFlag == NoWeakHandlingInCollections, ListHashSetDoesNotSupportWeakness);
// This marks all the nodes and their contents live that can be
// accessed through the HashTable.
m_impl.trace(visitor);
......
......@@ -72,6 +72,11 @@ namespace WTF {
template<typename T> struct IsWeak { static const bool value = false; };
enum WeakHandlingFlag {
NoWeakHandlingInCollections,
WeakHandlingInCollections
};
// IsPod is misnamed as it doesn't cover all plain old data (pod) types.
// Specifically, it doesn't allow for enums or for structs.
template <typename T> struct IsPod { static const bool value = IsArithmetic<T>::value; };
......
......@@ -305,7 +305,7 @@ static const size_t kInitialVectorSize = WTF_VECTOR_INITIAL_SIZE;
void clearUnusedSlots(T* from, T* to)
{
VectorUnusedSlotClearer<Allocator::isGarbageCollected && (VectorTraits<T>::needsDestruction || ShouldBeTraced<VectorTraits<T> >::value || VectorTraits<T>::isWeak), T>::clear(from, to);
VectorUnusedSlotClearer<Allocator::isGarbageCollected && (VectorTraits<T>::needsDestruction || ShouldBeTraced<VectorTraits<T> >::value), T>::clear(from, to);
}
protected:
......
......@@ -45,7 +45,7 @@ namespace WTF {
struct NeedsTracingLazily {
static const bool value = NeedsTracing<T>::value;
};
static const bool isWeak = IsWeak<T>::value;
static const WeakHandlingFlag weakHandlingFlag = NoWeakHandlingInCollections; // We don't support weak handling in vectors.
};
template<typename T>
......@@ -87,7 +87,7 @@ namespace WTF {
struct NeedsTracingLazily {
static const bool value = ShouldBeTraced<FirstTraits>::value || ShouldBeTraced<SecondTraits>::value;
};
static const bool isWeak = FirstTraits::isWeak || SecondTraits::isWeak;
static const WeakHandlingFlag weakHandlingFlag = NoWeakHandlingInCollections; // We don't support weak handling in vectors.
};
} // namespace WTF
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment