blob: 9f0b0abe70acc4f4963865aaa4f778f01ca750b6 [file] [log] [blame]
/*
* Copyright (C) 2014 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Handle_h
#define Handle_h
#include "platform/heap/Heap.h"
#include "platform/heap/HeapAllocator.h"
#include "platform/heap/InlinedGlobalMarkingVisitor.h"
#include "platform/heap/PersistentNode.h"
#include "platform/heap/ThreadState.h"
#include "platform/heap/TraceTraits.h"
#include "platform/heap/Visitor.h"
#include "wtf/Allocator.h"
#include "wtf/Atomics.h"
#include "wtf/HashFunctions.h"
#include "wtf/TypeTraits.h"
#if defined(LEAK_SANITIZER)
#include "wtf/LeakAnnotations.h"
#endif
namespace blink {
// Marker used to annotate persistent objects and collections with,
// so as to enable reliable testing for persistent references via
// a type trait (see TypeTraits.h's IsPersistentReferenceType<>.)
#define IS_PERSISTENT_REFERENCE_TYPE() \
public: \
using IsPersistentReferenceTypeMarker = int; \
private:
enum WeaknessPersistentConfiguration {
NonWeakPersistentConfiguration,
WeakPersistentConfiguration
};
enum CrossThreadnessPersistentConfiguration {
SingleThreadPersistentConfiguration,
CrossThreadPersistentConfiguration
};
template<typename T, WeaknessPersistentConfiguration weaknessConfiguration, CrossThreadnessPersistentConfiguration crossThreadnessConfiguration>
class PersistentBase {
USING_FAST_MALLOC(PersistentBase);
IS_PERSISTENT_REFERENCE_TYPE();
public:
PersistentBase() : m_raw(nullptr)
{
initialize();
}
PersistentBase(std::nullptr_t) : m_raw(nullptr)
{
initialize();
}
PersistentBase(T* raw) : m_raw(raw)
{
initialize();
checkPointer();
}
PersistentBase(T& raw) : m_raw(&raw)
{
initialize();
checkPointer();
}
PersistentBase(const PersistentBase& other) : m_raw(other)
{
initialize();
checkPointer();
}
template<typename U>
PersistentBase(const PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>& other) : m_raw(other)
{
initialize();
checkPointer();
}
template<typename U>
PersistentBase(const Member<U>& other) : m_raw(other)
{
initialize();
checkPointer();
}
~PersistentBase()
{
uninitialize();
m_raw = nullptr;
}
template<typename VisitorDispatcher>
void trace(VisitorDispatcher visitor)
{
static_assert(sizeof(T), "T must be fully defined");
static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage collected object");
if (weaknessConfiguration == WeakPersistentConfiguration) {
visitor->registerWeakCell(&m_raw);
} else {
visitor->mark(m_raw);
}
}
T* release()
{
T* result = m_raw;
assign(nullptr);
return result;
}
void clear() { assign(nullptr); }
T& operator*() const { return *m_raw; }
explicit operator bool() const { return m_raw; }
operator T*() const { return m_raw; }
T* operator->() const { return *this; }
T* get() const { return m_raw; }
template<typename U>
PersistentBase& operator=(U* other)
{
assign(other);
return *this;
}
PersistentBase& operator=(std::nullptr_t)
{
assign(nullptr);
return *this;
}
PersistentBase& operator=(const PersistentBase& other)
{
assign(other);
return *this;
}
template<typename U>
PersistentBase& operator=(const PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>& other)
{
assign(other);
return *this;
}
template<typename U>
PersistentBase& operator=(const Member<U>& other)
{
assign(other);
return *this;
}
// Register the persistent node as a 'static reference',
// belonging to the current thread and a persistent that must
// be cleared when the ThreadState itself is cleared out and
// destructed.
//
// Static singletons arrange for this to happen, either to ensure
// clean LSan leak reports or to register a thread-local persistent
// needing to be cleared out before the thread is terminated.
PersistentBase* registerAsStaticReference()
{
if (m_persistentNode) {
ASSERT(ThreadState::current());
ThreadState::current()->registerStaticPersistentNode(m_persistentNode, nullptr);
LEAK_SANITIZER_IGNORE_OBJECT(this);
}
return this;
}
protected:
T* atomicGet() { return reinterpret_cast<T*>(acquireLoad(reinterpret_cast<void* volatile*>(&m_raw))); }
private:
NO_LAZY_SWEEP_SANITIZE_ADDRESS
void assign(T* ptr)
{
if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration)
releaseStore(reinterpret_cast<void* volatile*>(&m_raw), ptr);
else
m_raw = ptr;
checkPointer();
if (m_raw) {
if (!m_persistentNode)
initialize();
return;
}
uninitialize();
}
NO_LAZY_SWEEP_SANITIZE_ADDRESS
void initialize()
{
ASSERT(!m_persistentNode);
if (!m_raw)
return;
TraceCallback traceCallback = TraceMethodDelegate<PersistentBase<T, weaknessConfiguration, crossThreadnessConfiguration>, &PersistentBase<T, weaknessConfiguration, crossThreadnessConfiguration>::trace>::trampoline;
if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) {
ProcessHeap::crossThreadPersistentRegion().allocatePersistentNode(m_persistentNode, this, traceCallback);
return;
}
ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
ASSERT(state->checkThread());
m_persistentNode = state->getPersistentRegion()->allocatePersistentNode(this, traceCallback);
#if ENABLE(ASSERT)
m_state = state;
#endif
}
void uninitialize()
{
if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) {
if (acquireLoad(reinterpret_cast<void* volatile*>(&m_persistentNode)))
ProcessHeap::crossThreadPersistentRegion().freePersistentNode(m_persistentNode);
return;
}
if (!m_persistentNode)
return;
ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
ASSERT(state->checkThread());
// Persistent handle must be created and destructed in the same thread.
ASSERT(m_state == state);
state->freePersistentNode(m_persistentNode);
m_persistentNode = nullptr;
}
void checkPointer()
{
#if ENABLE(ASSERT) && defined(ADDRESS_SANITIZER)
if (!m_raw)
return;
// ThreadHeap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable
// object. In other words, it checks that the pointer is either of:
//
// (a) a pointer to the head of an on-heap object.
// (b) a pointer to the head of an on-heap mixin object.
//
// Otherwise, ThreadHeap::isHeapObjectAlive will crash when it calls
// header->checkHeader().
ThreadHeap::isHeapObjectAlive(m_raw);
#endif
}
// m_raw is accessed most, so put it at the first field.
T* m_raw;
PersistentNode* m_persistentNode = nullptr;
#if ENABLE(ASSERT)
ThreadState* m_state = nullptr;
#endif
};
// Persistent is a way to create a strong pointer from an off-heap object
// to another on-heap object. As long as the Persistent handle is alive
// the GC will keep the object pointed to alive. The Persistent handle is
// always a GC root from the point of view of the GC.
//
// We have to construct and destruct Persistent in the same thread.
template<typename T>
class Persistent : public PersistentBase<T, NonWeakPersistentConfiguration, SingleThreadPersistentConfiguration> {
typedef PersistentBase<T, NonWeakPersistentConfiguration, SingleThreadPersistentConfiguration> Parent;
public:
Persistent() : Parent() { }
Persistent(std::nullptr_t) : Parent(nullptr) { }
Persistent(T* raw) : Parent(raw) { }
Persistent(T& raw) : Parent(raw) { }
Persistent(const Persistent& other) : Parent(other) { }
template<typename U>
Persistent(const Persistent<U>& other) : Parent(other) { }
template<typename U>
Persistent(const Member<U>& other) : Parent(other) { }
template<typename U>
Persistent& operator=(U* other)
{
Parent::operator=(other);
return *this;
}
Persistent& operator=(std::nullptr_t)
{
Parent::operator=(nullptr);
return *this;
}
Persistent& operator=(const Persistent& other)
{
Parent::operator=(other);
return *this;
}
template<typename U>
Persistent& operator=(const Persistent<U>& other)
{
Parent::operator=(other);
return *this;
}
template<typename U>
Persistent& operator=(const Member<U>& other)
{
Parent::operator=(other);
return *this;
}
};
// WeakPersistent is a way to create a weak pointer from an off-heap object
// to an on-heap object. The m_raw is automatically cleared when the pointee
// gets collected.
//
// We have to construct and destruct WeakPersistent in the same thread.
//
// Note that collections of WeakPersistents are not supported. Use a persistent
// collection of WeakMembers instead.
//
// HashSet<WeakPersistent<T>> m_set; // wrong
// PersistentHeapHashSet<WeakMember<T>> m_set; // correct
template<typename T>
class WeakPersistent : public PersistentBase<T, WeakPersistentConfiguration, SingleThreadPersistentConfiguration> {
typedef PersistentBase<T, WeakPersistentConfiguration, SingleThreadPersistentConfiguration> Parent;
public:
WeakPersistent() : Parent() { }
WeakPersistent(std::nullptr_t) : Parent(nullptr) { }
WeakPersistent(T* raw) : Parent(raw) { }
WeakPersistent(T& raw) : Parent(raw) { }
WeakPersistent(const WeakPersistent& other) : Parent(other) { }
template<typename U>
WeakPersistent(const WeakPersistent<U>& other) : Parent(other) { }
template<typename U>
WeakPersistent(const Member<U>& other) : Parent(other) { }
template<typename U>
WeakPersistent& operator=(U* other)
{
Parent::operator=(other);
return *this;
}
WeakPersistent& operator=(std::nullptr_t)
{
Parent::operator=(nullptr);
return *this;
}
WeakPersistent& operator=(const WeakPersistent& other)
{
Parent::operator=(other);
return *this;
}
template<typename U>
WeakPersistent& operator=(const WeakPersistent<U>& other)
{
Parent::operator=(other);
return *this;
}
template<typename U>
WeakPersistent& operator=(const Member<U>& other)
{
Parent::operator=(other);
return *this;
}
};
// Unlike Persistent, we can destruct a CrossThreadPersistent in a thread
// different from the construction thread.
template<typename T>
class CrossThreadPersistent : public PersistentBase<T, NonWeakPersistentConfiguration, CrossThreadPersistentConfiguration> {
typedef PersistentBase<T, NonWeakPersistentConfiguration, CrossThreadPersistentConfiguration> Parent;
public:
CrossThreadPersistent() : Parent() { }
CrossThreadPersistent(std::nullptr_t) : Parent(nullptr) { }
CrossThreadPersistent(T* raw) : Parent(raw) { }
CrossThreadPersistent(T& raw) : Parent(raw) { }
CrossThreadPersistent(const CrossThreadPersistent& other) : Parent(other) { }
template<typename U>
CrossThreadPersistent(const CrossThreadPersistent<U>& other) : Parent(other) { }
template<typename U>
CrossThreadPersistent(const Member<U>& other) : Parent(other) { }
T* atomicGet() { return Parent::atomicGet(); }
template<typename U>
CrossThreadPersistent& operator=(U* other)
{
Parent::operator=(other);
return *this;
}
CrossThreadPersistent& operator=(std::nullptr_t)
{
Parent::operator=(nullptr);
return *this;
}
CrossThreadPersistent& operator=(const CrossThreadPersistent& other)
{
Parent::operator=(other);
return *this;
}
template<typename U>
CrossThreadPersistent& operator=(const CrossThreadPersistent<U>& other)
{
Parent::operator=(other);
return *this;
}
template<typename U>
CrossThreadPersistent& operator=(const Member<U>& other)
{
Parent::operator=(other);
return *this;
}
};
// Combines the behavior of CrossThreadPersistent and WeakPersistent.
template<typename T>
class CrossThreadWeakPersistent : public PersistentBase<T, WeakPersistentConfiguration, CrossThreadPersistentConfiguration> {
typedef PersistentBase<T, WeakPersistentConfiguration, CrossThreadPersistentConfiguration> Parent;
public:
CrossThreadWeakPersistent() : Parent() { }
CrossThreadWeakPersistent(std::nullptr_t) : Parent(nullptr) { }
CrossThreadWeakPersistent(T* raw) : Parent(raw) { }
CrossThreadWeakPersistent(T& raw) : Parent(raw) { }
CrossThreadWeakPersistent(const CrossThreadWeakPersistent& other) : Parent(other) { }
template<typename U>
CrossThreadWeakPersistent(const CrossThreadWeakPersistent<U>& other) : Parent(other) { }
template<typename U>
CrossThreadWeakPersistent(const Member<U>& other) : Parent(other) { }
template<typename U>
CrossThreadWeakPersistent& operator=(U* other)
{
Parent::operator=(other);
return *this;
}
CrossThreadWeakPersistent& operator=(std::nullptr_t)
{
Parent::operator=(nullptr);
return *this;
}
CrossThreadWeakPersistent& operator=(const CrossThreadWeakPersistent& other)
{
Parent::operator=(other);
return *this;
}
template<typename U>
CrossThreadWeakPersistent& operator=(const CrossThreadWeakPersistent<U>& other)
{
Parent::operator=(other);
return *this;
}
template<typename U>
CrossThreadWeakPersistent& operator=(const Member<U>& other)
{
Parent::operator=(other);
return *this;
}
};
template<typename Collection>
class PersistentHeapCollectionBase : public Collection {
// We overload the various new and delete operators with using the WTF PartitionAllocator to ensure persistent
// heap collections are always allocated off-heap. This allows persistent collections to be used in
// DEFINE_STATIC_LOCAL et. al.
WTF_USE_ALLOCATOR(PersistentHeapCollectionBase, WTF::PartitionAllocator);
IS_PERSISTENT_REFERENCE_TYPE();
public:
PersistentHeapCollectionBase()
{
initialize();
}
PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : Collection(other)
{
initialize();
}
template<typename OtherCollection>
PersistentHeapCollectionBase(const OtherCollection& other) : Collection(other)
{
initialize();
}
~PersistentHeapCollectionBase()
{
uninitialize();
}
template<typename VisitorDispatcher>
void trace(VisitorDispatcher visitor)
{
static_assert(sizeof(Collection), "Collection must be fully defined");
visitor->trace(*static_cast<Collection*>(this));
}
// See PersistentBase::registerAsStaticReference() comment.
PersistentHeapCollectionBase* registerAsStaticReference()
{
if (m_persistentNode) {
ASSERT(ThreadState::current());
ThreadState::current()->registerStaticPersistentNode(m_persistentNode, &PersistentHeapCollectionBase<Collection>::clearPersistentNode);
LEAK_SANITIZER_IGNORE_OBJECT(this);
}
return this;
}
private:
// Used when the registered PersistentNode of this object is
// released during ThreadState shutdown, clearing the association.
static void clearPersistentNode(void *self)
{
PersistentHeapCollectionBase<Collection>* collection = (reinterpret_cast<PersistentHeapCollectionBase<Collection>*>(self));
collection->uninitialize();
collection->clear();
}
NO_LAZY_SWEEP_SANITIZE_ADDRESS
void initialize()
{
// FIXME: Derive affinity based on the collection.
ThreadState* state = ThreadState::current();
ASSERT(state->checkThread());
m_persistentNode = state->getPersistentRegion()->allocatePersistentNode(this, TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::trace>::trampoline);
#if ENABLE(ASSERT)
m_state = state;
#endif
}
void uninitialize()
{
if (!m_persistentNode)
return;
ThreadState* state = ThreadState::current();
ASSERT(state->checkThread());
// Persistent handle must be created and destructed in the same thread.
ASSERT(m_state == state);
state->freePersistentNode(m_persistentNode);
m_persistentNode = nullptr;
}
PersistentNode* m_persistentNode;
#if ENABLE(ASSERT)
ThreadState* m_state;
#endif
};
template<
typename KeyArg,
typename MappedArg,
typename HashArg = typename DefaultHash<KeyArg>::Hash,
typename KeyTraitsArg = HashTraits<KeyArg>,
typename MappedTraitsArg = HashTraits<MappedArg>>
class PersistentHeapHashMap : public PersistentHeapCollectionBase<HeapHashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>> { };
template<
typename ValueArg,
typename HashArg = typename DefaultHash<ValueArg>::Hash,
typename TraitsArg = HashTraits<ValueArg>>
class PersistentHeapHashSet : public PersistentHeapCollectionBase<HeapHashSet<ValueArg, HashArg, TraitsArg>> { };
template<
typename ValueArg,
typename HashArg = typename DefaultHash<ValueArg>::Hash,
typename TraitsArg = HashTraits<ValueArg>>
class PersistentHeapLinkedHashSet : public PersistentHeapCollectionBase<HeapLinkedHashSet<ValueArg, HashArg, TraitsArg>> { };
template<
typename ValueArg,
size_t inlineCapacity = 0,
typename HashArg = typename DefaultHash<ValueArg>::Hash>
class PersistentHeapListHashSet : public PersistentHeapCollectionBase<HeapListHashSet<ValueArg, inlineCapacity, HashArg>> { };
template<
typename ValueArg,
typename HashFunctions = typename DefaultHash<ValueArg>::Hash,
typename Traits = HashTraits<ValueArg>>
class PersistentHeapHashCountedSet : public PersistentHeapCollectionBase<HeapHashCountedSet<ValueArg, HashFunctions, Traits>> { };
template<typename T, size_t inlineCapacity = 0>
class PersistentHeapVector : public PersistentHeapCollectionBase<HeapVector<T, inlineCapacity>> {
public:
PersistentHeapVector()
{
initializeUnusedSlots();
}
explicit PersistentHeapVector(size_t size)
: PersistentHeapCollectionBase<HeapVector<T, inlineCapacity>>(size)
{
initializeUnusedSlots();
}
PersistentHeapVector(const PersistentHeapVector& other)
: PersistentHeapCollectionBase<HeapVector<T, inlineCapacity>>(other)
{
initializeUnusedSlots();
}
template<size_t otherCapacity>
PersistentHeapVector(const HeapVector<T, otherCapacity>& other)
: PersistentHeapCollectionBase<HeapVector<T, inlineCapacity>>(other)
{
initializeUnusedSlots();
}
private:
void initializeUnusedSlots()
{
// The PersistentHeapVector is allocated off heap along with its
// inline buffer (if any.) Maintain the invariant that unused
// slots are cleared for the off-heap inline buffer also.
size_t unusedSlots = this->capacity() - this->size();
if (unusedSlots)
this->clearUnusedSlots(this->end(), this->end() + unusedSlots);
}
};
template<typename T, size_t inlineCapacity = 0>
class PersistentHeapDeque : public PersistentHeapCollectionBase<HeapDeque<T, inlineCapacity>> {
public:
PersistentHeapDeque() { }
template<size_t otherCapacity>
PersistentHeapDeque(const HeapDeque<T, otherCapacity>& other)
: PersistentHeapCollectionBase<HeapDeque<T, inlineCapacity>>(other)
{
}
};
// Members are used in classes to contain strong pointers to other oilpan heap
// allocated objects.
// All Member fields of a class must be traced in the class' trace method.
// During the mark phase of the GC all live objects are marked as live and
// all Member fields of a live object will be traced marked as live as well.
template<typename T>
class Member {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
public:
Member() : m_raw(nullptr)
{
}
Member(std::nullptr_t) : m_raw(nullptr)
{
}
Member(T* raw) : m_raw(raw)
{
checkPointer();
}
explicit Member(T& raw) : m_raw(&raw)
{
checkPointer();
}
Member(WTF::HashTableDeletedValueType) : m_raw(reinterpret_cast<T*>(-1))
{
}
bool isHashTableDeletedValue() const { return m_raw == reinterpret_cast<T*>(-1); }
template<typename U>
Member(const Persistent<U>& other) : m_raw(other)
{
checkPointer();
}
Member(const Member& other) : m_raw(other)
{
checkPointer();
}
template<typename U>
Member(const Member<U>& other) : m_raw(other)
{
checkPointer();
}
T* release()
{
T* result = m_raw;
m_raw = nullptr;
return result;
}
explicit operator bool() const { return m_raw; }
operator T*() const { return m_raw; }
T* operator->() const { return m_raw; }
T& operator*() const { return *m_raw; }
template<typename U>
Member& operator=(const Persistent<U>& other)
{
m_raw = other;
checkPointer();
return *this;
}
template<typename U>
Member& operator=(const Member<U>& other)
{
m_raw = other;
checkPointer();
return *this;
}
template<typename U>
Member& operator=(U* other)
{
m_raw = other;
checkPointer();
return *this;
}
Member& operator=(std::nullptr_t)
{
m_raw = nullptr;
return *this;
}
void swap(Member<T>& other)
{
std::swap(m_raw, other.m_raw);
checkPointer();
}
T* get() const { return m_raw; }
void clear() { m_raw = nullptr; }
protected:
void checkPointer()
{
#if ENABLE(ASSERT) && defined(ADDRESS_SANITIZER)
if (!m_raw)
return;
// HashTable can store a special value (which is not aligned to the
// allocation granularity) to Member<> to represent a deleted entry.
// Thus we treat a pointer that is not aligned to the granularity
// as a valid pointer.
if (reinterpret_cast<intptr_t>(m_raw) % allocationGranularity)
return;
// TODO(haraken): What we really want to check here is that the pointer
// is a traceable object. In other words, the pointer is either of:
//
// (a) a pointer to the head of an on-heap object.
// (b) a pointer to the head of an on-heap mixin object.
//
// We can check it by calling ThreadHeap::isHeapObjectAlive(m_raw),
// but we cannot call it here because it requires to include T.h.
// So we currently only try to implement the check for (a), but do
// not insist that T's definition is in scope.
if (IsFullyDefined<T>::value && !IsGarbageCollectedMixin<T>::value)
ASSERT(HeapObjectHeader::fromPayload(m_raw)->checkHeader());
#endif
}
T* m_raw;
template<bool x, WTF::WeakHandlingFlag y, WTF::ShouldWeakPointersBeMarkedStrongly z, typename U, typename V> friend struct CollectionBackingTraceTrait;
friend class Visitor;
};
// WeakMember is similar to Member in that it is used to point to other oilpan
// heap allocated objects.
// However instead of creating a strong pointer to the object, the WeakMember creates
// a weak pointer, which does not keep the pointee alive. Hence if all pointers to
// to a heap allocated object are weak the object will be garbage collected. At the
// time of GC the weak pointers will automatically be set to null.
template<typename T>
class WeakMember : public Member<T> {
public:
WeakMember() : Member<T>() { }
WeakMember(std::nullptr_t) : Member<T>(nullptr) { }
WeakMember(T* raw) : Member<T>(raw) { }
WeakMember(WTF::HashTableDeletedValueType x) : Member<T>(x) { }
template<typename U>
WeakMember(const Persistent<U>& other) : Member<T>(other) { }
template<typename U>
WeakMember(const Member<U>& other) : Member<T>(other) { }
template<typename U>
WeakMember& operator=(const Persistent<U>& other)
{
this->m_raw = other;
this->checkPointer();
return *this;
}
template<typename U>
WeakMember& operator=(const Member<U>& other)
{
this->m_raw = other;
this->checkPointer();
return *this;
}
template<typename U>
WeakMember& operator=(U* other)
{
this->m_raw = other;
this->checkPointer();
return *this;
}
WeakMember& operator=(std::nullptr_t)
{
this->m_raw = nullptr;
return *this;
}
private:
T** cell() const { return const_cast<T**>(&this->m_raw); }
template<typename Derived> friend class VisitorHelper;
};
// UntracedMember is a pointer to an on-heap object that is not traced for some
// reason. Please don't use this unless you understand what you're doing.
// Basically, all pointers to on-heap objects must be stored in either of
// Persistent, Member or WeakMember. It is not allowed to leave raw pointers to
// on-heap objects. However, there can be scenarios where you have to use raw
// pointers for some reason, and in that case you can use UntracedMember. Of
// course, it must be guaranteed that the pointing on-heap object is kept alive
// while the raw pointer is pointing to the object.
template<typename T>
class UntracedMember final : public Member<T> {
public:
UntracedMember() : Member<T>() { }
UntracedMember(std::nullptr_t) : Member<T>(nullptr) { }
UntracedMember(T* raw) : Member<T>(raw) { }
template<typename U>
UntracedMember(const Persistent<U>& other) : Member<T>(other) { }
template<typename U>
UntracedMember(const Member<U>& other) : Member<T>(other) { }
UntracedMember(WTF::HashTableDeletedValueType x) : Member<T>(x) { }
template<typename U>
UntracedMember& operator=(const Persistent<U>& other)
{
this->m_raw = other;
this->checkPointer();
return *this;
}
template<typename U>
UntracedMember& operator=(const Member<U>& other)
{
this->m_raw = other;
this->checkPointer();
return *this;
}
template<typename U>
UntracedMember& operator=(U* other)
{
this->m_raw = other;
this->checkPointer();
return *this;
}
UntracedMember& operator=(std::nullptr_t)
{
this->m_raw = nullptr;
return *this;
}
};
// Comparison operators between (Weak)Members, Persistents, and UntracedMembers.
template<typename T, typename U> inline bool operator==(const Member<T>& a, const Member<U>& b) { return a.get() == b.get(); }
template<typename T, typename U> inline bool operator!=(const Member<T>& a, const Member<U>& b) { return a.get() != b.get(); }
template<typename T, typename U> inline bool operator==(const Persistent<T>& a, const Persistent<U>& b) { return a.get() == b.get(); }
template<typename T, typename U> inline bool operator!=(const Persistent<T>& a, const Persistent<U>& b) { return a.get() != b.get(); }
template<typename T, typename U> inline bool operator==(const Member<T>& a, const Persistent<U>& b) { return a.get() == b.get(); }
template<typename T, typename U> inline bool operator!=(const Member<T>& a, const Persistent<U>& b) { return a.get() != b.get(); }
template<typename T, typename U> inline bool operator==(const Persistent<T>& a, const Member<U>& b) { return a.get() == b.get(); }
template<typename T, typename U> inline bool operator!=(const Persistent<T>& a, const Member<U>& b) { return a.get() != b.get(); }
template<typename T, bool = IsGarbageCollectedType<T>::value>
class RawPtrOrMemberTrait {
STATIC_ONLY(RawPtrOrMemberTrait)
public:
using Type = T*;
};
template<typename T>
class RawPtrOrMemberTrait<T, true> {
STATIC_ONLY(RawPtrOrMemberTrait)
public:
using Type = Member<T>;
};
// Abstraction for injecting calls to an object's 'dispose()' method
// on leaving a stack scope, ensuring earlier release of resources
// than waiting until the object is eventually GCed.
template<typename T, void (T::*Disposer)() = (&T::dispose)>
class ScopedDisposal {
STACK_ALLOCATED();
public:
ScopedDisposal(T* object)
: m_object(object)
{
}
~ScopedDisposal()
{
if (m_object)
(m_object->*Disposer)();
}
void clear() { m_object.clear(); }
private:
typename RawPtrOrMemberTrait<T>::Type m_object;
};
// SelfKeepAlive<Object> is the idiom to use for objects that have to keep
// themselves temporarily alive and cannot rely on there being some
// external reference in that interval:
//
// class Opener {
// public:
// ...
// void open()
// {
// // Retain a self-reference while in an open()ed state:
// m_keepAlive = this;
// ....
// }
//
// void close()
// {
// // Clear self-reference that ensured we were kept alive while opened.
// m_keepAlive.clear();
// ....
// }
//
// private:
// ...
// SelfKeepAlive m_keepAlive;
// };
//
// The responsibility to call clear() in a timely fashion resides with the implementation
// of the object.
//
//
template<typename Self>
class SelfKeepAlive final {
DISALLOW_NEW();
public:
SelfKeepAlive()
{
}
explicit SelfKeepAlive(Self* self)
{
assign(self);
}
SelfKeepAlive& operator=(Self* self)
{
assign(self);
return *this;
}
void clear()
{
m_keepAlive.clear();
}
typedef Persistent<Self> (SelfKeepAlive::*UnspecifiedBoolType);
operator UnspecifiedBoolType() const { return m_keepAlive ? &SelfKeepAlive::m_keepAlive : 0; }
private:
void assign(Self* self)
{
ASSERT(!m_keepAlive || m_keepAlive.get() == self);
m_keepAlive = self;
}
GC_PLUGIN_IGNORE("420515")
Persistent<Self> m_keepAlive;
};
// Only a very reduced form of weak heap object references can currently be held
// by WTF::Closure<>s. i.e., bound as a 'this' pointer only.
//
// TODO(sof): once wtf/Functional.h is able to work over platform/heap/ types
// (like CrossThreadWeakPersistent<>), drop the restriction on weak persistent
// use by function closures (and rename this ad-hoc type.)
template<typename T>
class WeakPersistentThisPointer {
STACK_ALLOCATED();
public:
explicit WeakPersistentThisPointer(T* value) : m_value(value) { }
WeakPersistent<T> value() const { return m_value; }
private:
WeakPersistent<T> m_value;
};
template<typename T>
class CrossThreadWeakPersistentThisPointer {
STACK_ALLOCATED();
public:
explicit CrossThreadWeakPersistentThisPointer(T* value) : m_value(value) { }
CrossThreadWeakPersistent<T> value() const { return m_value; }
private:
CrossThreadWeakPersistent<T> m_value;
};
template <typename T>
Persistent<T> wrapPersistent(T* value)
{
return Persistent<T>(value);
}
template <typename T>
CrossThreadPersistent<T> wrapCrossThreadPersistent(T* value)
{
return CrossThreadPersistent<T>(value);
}
// LEAK_SANITIZER_DISABLED_SCOPE: all allocations made in the current scope
// will be exempted from LSan consideration.
//
// TODO(sof): move this to wtf/LeakAnnotations.h (LeakSanitizer.h?) once
// wtf/ can freely call upon Oilpan functionality.
#if defined(LEAK_SANITIZER)
class LeakSanitizerDisableScope {
STACK_ALLOCATED();
WTF_MAKE_NONCOPYABLE(LeakSanitizerDisableScope);
public:
LeakSanitizerDisableScope()
{
__lsan_disable();
if (ThreadState::current())
ThreadState::current()->enterStaticReferenceRegistrationDisabledScope();
}
~LeakSanitizerDisableScope()
{
__lsan_enable();
if (ThreadState::current())
ThreadState::current()->leaveStaticReferenceRegistrationDisabledScope();
}
};
#define LEAK_SANITIZER_DISABLED_SCOPE LeakSanitizerDisableScope lsanDisabledScope
#else
#define LEAK_SANITIZER_DISABLED_SCOPE
#endif
} // namespace blink
namespace WTF {
template <typename T>
struct MemberHash : PtrHash<T> {
STATIC_ONLY(MemberHash);
template <typename U>
static unsigned hash(const U& key) { return PtrHash<T>::hash(key); }
template <typename U, typename V>
static bool equal(const U& a, const V& b) { return a == b; }
};
template <typename T>
struct WeakMemberHash : MemberHash<T> {
STATIC_ONLY(WeakMemberHash);
};
template <typename T>
struct UntracedMemberHash : MemberHash<T> {
STATIC_ONLY(UntracedMemberHash);
};
// PtrHash is the default hash for hash tables with members.
template <typename T>
struct DefaultHash<blink::Member<T>> {
STATIC_ONLY(DefaultHash);
using Hash = MemberHash<T>;
};
template <typename T>
struct DefaultHash<blink::WeakMember<T>> {
STATIC_ONLY(DefaultHash);
using Hash = WeakMemberHash<T>;
};
template <typename T>
struct DefaultHash<blink::UntracedMember<T>> {
STATIC_ONLY(DefaultHash);
using Hash = UntracedMemberHash<T>;
};
template<typename T>
struct NeedsTracing<blink::Member<T>> {
STATIC_ONLY(NeedsTracing);
static const bool value = true;
};
template<typename T>
struct IsWeak<blink::WeakMember<T>> {
STATIC_ONLY(IsWeak);
static const bool value = true;
};
// For wtf/Functional.h
template<typename T, bool isGarbageCollected> struct PointerParamStorageTraits;
// The condition of 'T must be fully defined' (except for void) is checked in
// blink::IsGarbageCollectedType<T>::value.
template<typename T>
struct PointerParamStorageTraits<T*, false> {
STATIC_ONLY(PointerParamStorageTraits);
using StorageType = T*;
static StorageType wrap(T* value) { return value; }
static T* unwrap(const StorageType& value) { return value; }
};
template<typename T>
struct PointerParamStorageTraits<T*, true> {
STATIC_ONLY(PointerParamStorageTraits);
using StorageType = blink::CrossThreadPersistent<T>;
static StorageType wrap(T* value) { return value; }
static T* unwrap(const StorageType& value) { return value.get(); }
};
template<typename T>
struct ParamStorageTraits<T*> : public PointerParamStorageTraits<T*, blink::IsGarbageCollectedType<T>::value> {
STATIC_ONLY(ParamStorageTraits);
};
template<typename T>
struct ParamStorageTraits<blink::WeakPersistentThisPointer<T>> {
STATIC_ONLY(ParamStorageTraits);
static_assert(sizeof(T), "T must be fully defined");
using StorageType = blink::WeakPersistent<T>;
static StorageType wrap(const blink::WeakPersistentThisPointer<T>& value) { return value.value(); }
// WTF::FunctionWrapper<> handles WeakPtr<>, so recast this weak persistent
// into it.
//
// TODO(sof): remove this hack once wtf/Functional.h can also work with a type like
// WeakPersistent<>.
static WeakPtr<T> unwrap(const StorageType& value) { return WeakPtr<T>(WeakReference<T>::create(value.get())); }
};
template<typename T>
struct ParamStorageTraits<blink::CrossThreadWeakPersistentThisPointer<T>> {
STATIC_ONLY(ParamStorageTraits);
static_assert(sizeof(T), "T must be fully defined");
using StorageType = blink::CrossThreadWeakPersistent<T>;
static StorageType wrap(const blink::CrossThreadWeakPersistentThisPointer<T>& value) { return value.value(); }
// WTF::FunctionWrapper<> handles WeakPtr<>, so recast this weak persistent
// into it.
//
// TODO(sof): remove this hack once wtf/Functional.h can also work with a type like
// CrossThreadWeakPersistent<>.
static WeakPtr<T> unwrap(const StorageType& value) { return WeakPtr<T>(WeakReference<T>::create(value.get())); }
};
} // namespace WTF
#endif