blob: 9f5054639238ac610cdb9ddde3f912119268e26c [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/Functional.h"
#include "wtf/HashFunctions.h"
#include "wtf/Locker.h"
#include "wtf/MainThread.h"
#include "wtf/RawPtr.h"
#include "wtf/RefCounted.h"
#include "wtf/TypeTraits.h"
namespace blink {
enum WeaknessPersistentConfiguration {
NonWeakPersistentConfiguration,
WeakPersistentConfiguration
};
enum CrossThreadnessPersistentConfiguration {
SingleThreadPersistentConfiguration,
CrossThreadPersistentConfiguration
};
template<typename T, WeaknessPersistentConfiguration weaknessConfiguration, CrossThreadnessPersistentConfiguration crossThreadnessConfiguration>
class PersistentBase {
public:
PersistentBase() : m_raw(nullptr)
{
initialize();
}
PersistentBase(std::nullptr_t) : m_raw(nullptr)
{
initialize();
}
PersistentBase(T* raw) : m_raw(raw)
{
initialize();
checkPointer();
recordBacktrace();
}
PersistentBase(T& raw) : m_raw(&raw)
{
initialize();
checkPointer();
recordBacktrace();
}
PersistentBase(const PersistentBase& other) : m_raw(other)
{
initialize();
checkPointer();
recordBacktrace();
}
template<typename U>
PersistentBase(const PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>& other) : m_raw(other)
{
initialize();
checkPointer();
recordBacktrace();
}
template<typename U>
PersistentBase(const Member<U>& other) : m_raw(other)
{
initialize();
checkPointer();
recordBacktrace();
}
template<typename U>
PersistentBase(const RawPtr<U>& other) : m_raw(other.get())
{
initialize();
checkPointer();
recordBacktrace();
}
~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);
}
}
RawPtr<T> release()
{
RawPtr<T> result = m_raw;
assign(nullptr);
return result;
}
void clear() { assign(nullptr); }
T& operator*() const { return *m_raw; }
bool operator!() const { return !m_raw; }
operator T*() const { return m_raw; }
operator RawPtr<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;
}
template<typename U>
PersistentBase& operator=(const RawPtr<U>& other)
{
assign(other);
return *this;
}
private:
NO_LAZY_SWEEP_SANITIZE_ADDRESS
void assign(T* ptr)
{
m_raw = ptr;
checkPointer();
recordBacktrace();
if (m_raw) {
if (!m_persistentNode)
initialize();
return;
}
if (m_persistentNode && crossThreadnessConfiguration != CrossThreadPersistentConfiguration)
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) {
m_persistentNode = ThreadState::crossThreadPersistentRegion().allocatePersistentNode(this, traceCallback);
} else {
ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
ASSERT(state->checkThread());
m_persistentNode = state->persistentRegion()->allocatePersistentNode(this, traceCallback);
#if ENABLE(ASSERT)
m_state = state;
#endif
}
}
void uninitialize()
{
if (!m_persistentNode)
return;
if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) {
ThreadState::crossThreadPersistentRegion().freePersistentNode(m_persistentNode);
} else {
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->persistentRegion()->freePersistentNode(m_persistentNode);
}
m_persistentNode = nullptr;
}
void checkPointer()
{
#if ENABLE(ASSERT)
if (!m_raw)
return;
// Heap::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, Heap::isHeapObjectAlive will crash when it calls
// header->checkHeader().
Heap::isHeapObjectAlive(m_raw);
#endif
}
#if ENABLE(GC_PROFILING)
void recordBacktrace()
{
if (m_raw)
m_tracingName = Heap::createBacktraceString();
}
String m_tracingName;
#else
inline void recordBacktrace() const { }
#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(const RawPtr<U>& other) : Parent(other.get()) { }
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;
}
template<typename U>
Persistent& operator=(const RawPtr<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(const RawPtr<U>& other) : Parent(other.get()) { }
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;
}
template<typename U>
WeakPersistent& operator=(const RawPtr<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) { }
template<typename U>
CrossThreadPersistent(const RawPtr<U>& other) : Parent(other.get()) { }
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;
}
template<typename U>
CrossThreadPersistent& operator=(const RawPtr<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(const RawPtr<U>& other) : Parent(other.get()) { }
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 U>
CrossThreadWeakPersistent& operator=(const RawPtr<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 DefaultAllocator 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::DefaultAllocator);
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));
}
private:
NO_LAZY_SWEEP_SANITIZE_ADDRESS
void initialize()
{
// FIXME: Derive affinity based on the collection.
ThreadState* state = ThreadState::current();
ASSERT(state->checkThread());
m_persistentNode = state->persistentRegion()->allocatePersistentNode(this, TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::trace>::trampoline);
state->persistentAllocated();
#if ENABLE(ASSERT)
m_state = state;
#endif
}
void uninitialize()
{
ThreadState* state = ThreadState::current();
ASSERT(state->checkThread());
// Persistent handle must be created and destructed in the same thread.
ASSERT(m_state == state);
state->persistentRegion()->freePersistentNode(m_persistentNode);
state->persistentFreed();
}
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 T, typename U, typename V>
class PersistentHeapHashCountedSet : public PersistentHeapCollectionBase<HeapHashCountedSet<T, U, V>> { };
template<typename T, size_t inlineCapacity = 0>
class PersistentHeapVector : public PersistentHeapCollectionBase<HeapVector<T, inlineCapacity>> {
public:
PersistentHeapVector() { }
template<size_t otherCapacity>
PersistentHeapVector(const HeapVector<T, otherCapacity>& other)
: PersistentHeapCollectionBase<HeapVector<T, inlineCapacity>>(other)
{
}
};
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 {
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();
}
template<typename U>
Member(const RawPtr<U>& other) : m_raw(other.get())
{
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;
}
bool operator!() 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>
operator RawPtr<U>() 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;
}
template<typename U>
Member& operator=(RawPtr<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)
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 Heap::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;
}
template<typename U>
WeakMember& operator=(const RawPtr<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;
};
// Comparison operators between (Weak)Members and Persistents
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 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, 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>
class DummyBase {
public:
DummyBase() { }
~DummyBase() { }
};
// CPP-defined type names for the transition period where we want to
// support both reference counting and garbage collection based on a
// compile-time flag.
//
// C++11 template aliases were initially used (with clang only, not
// with GCC nor MSVC.) However, supporting both CPP defines and
// template aliases is problematic from outside a WebCore namespace
// when Oilpan is disabled: e.g.,
// blink::RefCountedWillBeGarbageCollected as a template alias would
// uniquely resolve from within any namespace, but if it is backed by
// a CPP #define, it would expand to blink::RefCounted, and not the
// required WTF::RefCounted.
//
// Having the CPP expansion instead be fully namespace qualified, and the
// transition type be unqualified, would dually not work for template
// aliases. So, slightly unfortunately, fall back/down to the lowest
// commmon denominator of using CPP macros only.
#if ENABLE(OILPAN)
#define PassRefPtrWillBeRawPtr WTF::RawPtr
#define RefCountedWillBeGarbageCollected blink::GarbageCollected
#define RefCountedWillBeGarbageCollectedFinalized blink::GarbageCollectedFinalized
#define RefCountedWillBeRefCountedGarbageCollected blink::RefCountedGarbageCollected
#define RefCountedGarbageCollectedWillBeGarbageCollectedFinalized blink::GarbageCollectedFinalized
#define RefCountedWillBeNoBase blink::DummyBase
#define RefCountedGarbageCollectedWillBeNoBase blink::DummyBase
#define ThreadSafeRefCountedWillBeGarbageCollected blink::GarbageCollected
#define ThreadSafeRefCountedWillBeGarbageCollectedFinalized blink::GarbageCollectedFinalized
#define PersistentWillBeMember blink::Member
#define CrossThreadPersistentWillBeMember blink::Member
#define RefPtrWillBePersistent blink::Persistent
#define RefPtrWillBeRawPtr WTF::RawPtr
#define RefPtrWillBeMember blink::Member
#define RefPtrWillBeWeakMember blink::WeakMember
#define RefPtrWillBeWeakPersistent blink::WeakPersistent
#define RefPtrWillBeCrossThreadPersistent blink::CrossThreadPersistent
#define RawPtrWillBeMember blink::Member
#define RawPtrWillBePersistent blink::Persistent
#define RawPtrWillBeWeakMember blink::WeakMember
#define RawPtrWillBeWeakPersistent blink::WeakPersistent
#define OwnPtrWillBeCrossThreadPersistent blink::CrossThreadPersistent
#define OwnPtrWillBeMember blink::Member
#define OwnPtrWillBePersistent blink::Persistent
#define OwnPtrWillBeRawPtr WTF::RawPtr
#define PassOwnPtrWillBeRawPtr WTF::RawPtr
#define WeakPtrWillBeCrossThreadWeakPersistent blink::CrossThreadWeakPersistent
#define WeakPtrWillBeMember blink::Member
#define WeakPtrWillBeRawPtr WTF::RawPtr
#define WeakPtrWillBeWeakMember blink::WeakMember
#define WeakPtrWillBeWeakPersistent blink::WeakPersistent
#define NoBaseWillBeGarbageCollected blink::GarbageCollected
#define NoBaseWillBeGarbageCollectedFinalized blink::GarbageCollectedFinalized
#define NoBaseWillBeRefCountedGarbageCollected blink::RefCountedGarbageCollected
#define WillBeHeapHashMap blink::HeapHashMap
#define WillBePersistentHeapHashMap blink::PersistentHeapHashMap
#define WillBeHeapHashSet blink::HeapHashSet
#define WillBePersistentHeapHashSet blink::PersistentHeapHashSet
#define WillBeHeapLinkedHashSet blink::HeapLinkedHashSet
#define WillBePersistentHeapLinkedHashSet blink::PersistentHeapLinkedHashSet
#define WillBeHeapListHashSet blink::HeapListHashSet
#define WillBePersistentHeapListHashSet blink::PersistentHeapListHashSet
#define WillBeHeapVector blink::HeapVector
#define WillBePersistentHeapVector blink::PersistentHeapVector
#define WillBeHeapDeque blink::HeapDeque
#define WillBePersistentHeapDeque blink::PersistentHeapDeque
#define WillBeHeapHashCountedSet blink::HeapHashCountedSet
#define WillBePersistentHeapHashCountedSet blink::PersistentHeapHashCountedSet
#define WillBeGarbageCollectedMixin blink::GarbageCollectedMixin
#define WillBeHeapSupplement blink::HeapSupplement
#define WillBeHeapSupplementable blink::HeapSupplementable
#define WillBeHeapTerminatedArray blink::HeapTerminatedArray
#define WillBeHeapTerminatedArrayBuilder blink::HeapTerminatedArrayBuilder
#define WillBeHeapLinkedStack blink::HeapLinkedStack
#define PersistentHeapHashMapWillBeHeapHashMap blink::HeapHashMap
#define PersistentHeapHashSetWillBeHeapHashSet blink::HeapHashSet
#define PersistentHeapDequeWillBeHeapDeque blink::HeapDeque
#define PersistentHeapVectorWillBeHeapVector blink::HeapVector
template<typename T> T* adoptRefWillBeNoop(T* ptr)
{
static const bool notRefCounted = !WTF::IsSubclassOfTemplate<typename WTF::RemoveConst<T>::Type, RefCounted>::value;
static_assert(notRefCounted, "you must adopt");
return ptr;
}
template<typename T> T* adoptPtrWillBeNoop(T* ptr)
{
static const bool notRefCounted = !WTF::IsSubclassOfTemplate<typename WTF::RemoveConst<T>::Type, RefCounted>::value;
static_assert(notRefCounted, "you must adopt");
return ptr;
}
#define WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED(type) // do nothing when oilpan is enabled.
#define DECLARE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(type) // do nothing
#define DECLARE_EMPTY_VIRTUAL_DESTRUCTOR_WILL_BE_REMOVED(type) // do nothing
#define DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(type) // do nothing
#define DEFINE_STATIC_REF_WILL_BE_PERSISTENT(type, name, arguments) \
static type* name = (new Persistent<type>(arguments))->get();
#else // !ENABLE(OILPAN)
#define PassRefPtrWillBeRawPtr WTF::PassRefPtr
#define RefCountedWillBeGarbageCollected WTF::RefCounted
#define RefCountedWillBeGarbageCollectedFinalized WTF::RefCounted
#define RefCountedWillBeRefCountedGarbageCollected WTF::RefCounted
#define RefCountedGarbageCollectedWillBeGarbageCollectedFinalized blink::RefCountedGarbageCollected
#define RefCountedWillBeNoBase WTF::RefCounted
#define RefCountedGarbageCollectedWillBeNoBase blink::RefCountedGarbageCollected
#define ThreadSafeRefCountedWillBeGarbageCollected WTF::ThreadSafeRefCounted
#define ThreadSafeRefCountedWillBeGarbageCollectedFinalized WTF::ThreadSafeRefCounted
#define PersistentWillBeMember blink::Persistent
#define CrossThreadPersistentWillBeMember blink::CrossThreadPersistent
#define RefPtrWillBePersistent WTF::RefPtr
#define RefPtrWillBeRawPtr WTF::RefPtr
#define RefPtrWillBeMember WTF::RefPtr
#define RefPtrWillBeWeakMember WTF::RefPtr
#define RefPtrWillBeWeakPersistent WTF::RefPtr
#define RefPtrWillBeCrossThreadPersistent WTF::RefPtr
#define RawPtrWillBeMember WTF::RawPtr
#define RawPtrWillBePersistent WTF::RawPtr
#define RawPtrWillBeWeakMember WTF::RawPtr
#define RawPtrWillBeWeakPersistent WTF::RawPtr
#define OwnPtrWillBeCrossThreadPersistent WTF::OwnPtr
#define OwnPtrWillBeMember WTF::OwnPtr
#define OwnPtrWillBePersistent WTF::OwnPtr
#define OwnPtrWillBeRawPtr WTF::OwnPtr
#define PassOwnPtrWillBeRawPtr WTF::PassOwnPtr
#define WeakPtrWillBeCrossThreadWeakPersistent WTF::WeakPtr
#define WeakPtrWillBeMember WTF::WeakPtr
#define WeakPtrWillBeRawPtr WTF::WeakPtr
#define WeakPtrWillBeWeakMember WTF::WeakPtr
#define WeakPtrWillBeWeakPersistent WTF::WeakPtr
#define NoBaseWillBeGarbageCollected blink::DummyBase
#define NoBaseWillBeGarbageCollectedFinalized blink::DummyBase
#define NoBaseWillBeRefCountedGarbageCollected blink::DummyBase
#define WillBeHeapHashMap WTF::HashMap
#define WillBePersistentHeapHashMap WTF::HashMap
#define WillBeHeapHashSet WTF::HashSet
#define WillBePersistentHeapHashSet WTF::HashSet
#define WillBeHeapLinkedHashSet WTF::LinkedHashSet
#define WillBePersistentLinkedHeapHashSet WTF::LinkedHashSet
#define WillBeHeapListHashSet WTF::ListHashSet
#define WillBePersistentListHeapHashSet WTF::ListHashSet
#define WillBeHeapVector WTF::Vector
#define WillBePersistentHeapVector WTF::Vector
#define WillBeHeapDeque WTF::Deque
#define WillBePersistentHeapDeque WTF::Deque
#define WillBeHeapHashCountedSet WTF::HashCountedSet
#define WillBePersistentHeapHashCountedSet WTF::HashCountedSet
#define WillBeGarbageCollectedMixin blink::DummyBase<void>
#define WillBeHeapSupplement blink::Supplement
#define WillBeHeapSupplementable blink::Supplementable
#define WillBeHeapTerminatedArray WTF::TerminatedArray
#define WillBeHeapTerminatedArrayBuilder WTF::TerminatedArrayBuilder
#define WillBeHeapLinkedStack WTF::LinkedStack
#define PersistentHeapHashMapWillBeHeapHashMap blink::PersistentHeapHashMap
#define PersistentHeapHashSetWillBeHeapHashSet blink::PersistentHeapHashSet
#define PersistentHeapDequeWillBeHeapDeque blink::PersistentHeapDeque
#define PersistentHeapVectorWillBeHeapVector blink::PersistentHeapVector
template<typename T> PassRefPtrWillBeRawPtr<T> adoptRefWillBeNoop(T* ptr) { return adoptRef(ptr); }
template<typename T> PassOwnPtrWillBeRawPtr<T> adoptPtrWillBeNoop(T* ptr) { return adoptPtr(ptr); }
#define WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED(type) WTF_MAKE_FAST_ALLOCATED(type)
#define DECLARE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(type) \
public: \
~type(); \
private:
#define DECLARE_EMPTY_VIRTUAL_DESTRUCTOR_WILL_BE_REMOVED(type) \
public: \
virtual ~type(); \
private:
#define DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(type) \
type::~type() { }
#define DEFINE_STATIC_REF_WILL_BE_PERSISTENT(type, name, arguments) \
DEFINE_STATIC_REF(type, name, arguments)
#endif // ENABLE(OILPAN)
template<typename T, bool = IsGarbageCollectedType<T>::value>
class PointerFieldStorageTrait {
public:
using Type = RawPtr<T>;
};
template<typename T>
class PointerFieldStorageTrait<T, true> {
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 PointerFieldStorageTrait<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 {
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;
};
template<typename T>
class AllowCrossThreadWeakPersistent {
STACK_ALLOCATED();
public:
explicit AllowCrossThreadWeakPersistent(T* value) : m_value(value) { }
CrossThreadWeakPersistent<T> value() const { return m_value; }
private:
CrossThreadWeakPersistent<T> m_value;
};
} // namespace blink
namespace WTF {
template <typename T> struct VectorTraits<blink::Member<T>> : VectorTraitsBase<blink::Member<T>> {
static const bool needsDestruction = false;
static const bool canInitializeWithMemset = true;
static const bool canClearUnusedSlotsWithMemset = true;
static const bool canMoveWithMemcpy = true;
};
template <typename T> struct VectorTraits<blink::WeakMember<T>> : VectorTraitsBase<blink::WeakMember<T>> {
static const bool needsDestruction = false;
static const bool canInitializeWithMemset = true;
static const bool canClearUnusedSlotsWithMemset = true;
static const bool canMoveWithMemcpy = true;
};
template <typename T> struct VectorTraits<blink::HeapVector<T, 0>> : VectorTraitsBase<blink::HeapVector<T, 0>> {
static const bool needsDestruction = false;
static const bool canInitializeWithMemset = true;
static const bool canClearUnusedSlotsWithMemset = true;
static const bool canMoveWithMemcpy = true;
};
template <typename T> struct VectorTraits<blink::HeapDeque<T, 0>> : VectorTraitsBase<blink::HeapDeque<T, 0>> {
static const bool needsDestruction = false;
static const bool canInitializeWithMemset = true;
static const bool canClearUnusedSlotsWithMemset = true;
static const bool canMoveWithMemcpy = true;
};
template <typename T, size_t inlineCapacity> struct VectorTraits<blink::HeapVector<T, inlineCapacity>> : VectorTraitsBase<blink::HeapVector<T, inlineCapacity>> {
static const bool needsDestruction = VectorTraits<T>::needsDestruction;
static const bool canInitializeWithMemset = VectorTraits<T>::canInitializeWithMemset;
static const bool canClearUnusedSlotsWithMemset = VectorTraits<T>::canClearUnusedSlotsWithMemset;
static const bool canMoveWithMemcpy = VectorTraits<T>::canMoveWithMemcpy;
};
template <typename T, size_t inlineCapacity> struct VectorTraits<blink::HeapDeque<T, inlineCapacity>> : VectorTraitsBase<blink::HeapDeque<T, inlineCapacity>> {
static const bool needsDestruction = VectorTraits<T>::needsDestruction;
static const bool canInitializeWithMemset = VectorTraits<T>::canInitializeWithMemset;
static const bool canClearUnusedSlotsWithMemset = VectorTraits<T>::canClearUnusedSlotsWithMemset;
static const bool canMoveWithMemcpy = VectorTraits<T>::canMoveWithMemcpy;
};
template<typename T> struct HashTraits<blink::Member<T>> : SimpleClassHashTraits<blink::Member<T>> {
// FIXME: The distinction between PeekInType and PassInType is there for
// the sake of the reference counting handles. When they are gone the two
// types can be merged into PassInType.
// FIXME: Implement proper const'ness for iterator types. Requires support
// in the marking Visitor.
using PeekInType = RawPtr<T>;
using PassInType = RawPtr<T>;
using IteratorGetType = blink::Member<T>*;
using IteratorConstGetType = const blink::Member<T>*;
using IteratorReferenceType = blink::Member<T>&;
using IteratorConstReferenceType = const blink::Member<T>&;
static IteratorReferenceType getToReferenceConversion(IteratorGetType x) { return *x; }
static IteratorConstReferenceType getToReferenceConstConversion(IteratorConstGetType x) { return *x; }
// FIXME: Similarly, there is no need for a distinction between PeekOutType
// and PassOutType without reference counting.
using PeekOutType = T*;
using PassOutType = T*;
template<typename U>
static void store(const U& value, blink::Member<T>& storage) { storage = value; }
static PeekOutType peek(const blink::Member<T>& value) { return value; }
static PassOutType passOut(const blink::Member<T>& value) { return value; }
};
template<typename T> struct HashTraits<blink::WeakMember<T>> : SimpleClassHashTraits<blink::WeakMember<T>> {
static const bool needsDestruction = false;
// FIXME: The distinction between PeekInType and PassInType is there for
// the sake of the reference counting handles. When they are gone the two
// types can be merged into PassInType.
// FIXME: Implement proper const'ness for iterator types. Requires support
// in the marking Visitor.
using PeekInType = RawPtr<T>;
using PassInType = RawPtr<T>;
using IteratorGetType = blink::WeakMember<T>*;
using IteratorConstGetType = const blink::WeakMember<T>*;
using IteratorReferenceType = blink::WeakMember<T>&;
using IteratorConstReferenceType = const blink::WeakMember<T>&;
static IteratorReferenceType getToReferenceConversion(IteratorGetType x) { return *x; }
static IteratorConstReferenceType getToReferenceConstConversion(IteratorConstGetType x) { return *x; }
// FIXME: Similarly, there is no need for a distinction between PeekOutType
// and PassOutType without reference counting.
using PeekOutType = T*;
using PassOutType = T*;
template<typename U>
static void store(const U& value, blink::WeakMember<T>& storage) { storage = value; }
static PeekOutType peek(const blink::WeakMember<T>& value) { return value; }
static PassOutType passOut(const blink::WeakMember<T>& value) { return value; }
template<typename VisitorDispatcher>
static bool traceInCollection(VisitorDispatcher visitor, blink::WeakMember<T>& weakMember, ShouldWeakPointersBeMarkedStrongly strongify)
{
if (strongify == WeakPointersActStrong) {
visitor->trace(weakMember.get()); // Strongified visit.
return false;
}
return !blink::Heap::isHeapObjectAlive(weakMember);
}
};
template<typename T> struct PtrHash<blink::Member<T>> : PtrHash<T*> {
template<typename U>
static unsigned hash(const U& key) { return PtrHash<T*>::hash(key); }
static bool equal(T* a, const blink::Member<T>& b) { return a == b; }
static bool equal(const blink::Member<T>& a, T* b) { return a == b; }
template<typename U, typename V>
static bool equal(const U& a, const V& b) { return a == b; }
};
template<typename T> struct PtrHash<blink::WeakMember<T>> : PtrHash<blink::Member<T>> {
};
// PtrHash is the default hash for hash tables with members.
template<typename T> struct DefaultHash<blink::Member<T>> {
using Hash = PtrHash<blink::Member<T>>;
};
template<typename T> struct DefaultHash<blink::WeakMember<T>> {
using Hash = PtrHash<blink::WeakMember<T>>;
};
template<typename T>
struct NeedsTracing<blink::Member<T>> {
static const bool value = true;
};
template<typename T>
struct IsWeak<blink::WeakMember<T>> {
static const bool value = true;
};
template<typename T> inline T* getPtr(const blink::Member<T>& p)
{
return p.get();
}
template<typename T> inline T* getPtr(const blink::Persistent<T>& p)
{
return p.get();
}
template<typename T, size_t inlineCapacity>
struct NeedsTracing<ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>> *> {
static_assert(sizeof(T), "T must be fully defined");
// All heap allocated node pointers need visiting to keep the nodes alive,
// regardless of whether they contain pointers to other heap allocated
// objects.
static const bool value = true;
};
// For wtf/Functional.h
template<typename T, bool isGarbageCollected> struct PointerParamStorageTraits;
template<typename T>
struct PointerParamStorageTraits<T*, false> {
static_assert(sizeof(T), "T must be fully defined");
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_assert(sizeof(T), "T must be fully defined");
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_assert(sizeof(T), "T must be fully defined");
};
template<typename T>
struct ParamStorageTraits<RawPtr<T>> : public PointerParamStorageTraits<T*, blink::IsGarbageCollectedType<T>::value> {
static_assert(sizeof(T), "T must be fully defined");
};
template<typename T>
struct ParamStorageTraits<blink::AllowCrossThreadWeakPersistent<T>> {
static_assert(sizeof(T), "T must be fully defined");
using StorageType = blink::CrossThreadWeakPersistent<T>;
static StorageType wrap(const blink::AllowCrossThreadWeakPersistent<T>& value) { return value.value(); }
// Currently assume that the call sites of this unwrap() account for cleared weak references also.
// TODO(sof): extend WTF::FunctionWrapper call overloading to also handle (CrossThread)WeakPersistent.
static T* unwrap(const StorageType& value) { return value.get(); }
};
template<typename T>
PassRefPtr<T> adoptRef(blink::RefCountedGarbageCollected<T>*) = delete;
} // namespace WTF
#endif