| Index: Source/platform/heap/Handle.h
|
| diff --git a/Source/platform/heap/Handle.h b/Source/platform/heap/Handle.h
|
| index be0446348e8cf45e0c490c668f963b2f6b3f9159..9b0bbaa49433a2373edb9daf66be907a91a26250 100644
|
| --- a/Source/platform/heap/Handle.h
|
| +++ b/Source/platform/heap/Handle.h
|
| @@ -34,12 +34,14 @@
|
| #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"
|
| @@ -48,88 +50,6 @@ namespace blink {
|
|
|
| template<typename T> class HeapTerminatedArray;
|
|
|
| -class PersistentNode {
|
| -public:
|
| - explicit PersistentNode(TraceCallback trace)
|
| - : m_trace(trace)
|
| - {
|
| - }
|
| -
|
| - NO_LAZY_SWEEP_SANITIZE_ADDRESS
|
| - bool isHeapObjectAlive() { return m_trace; }
|
| -
|
| - // This operator= is important. Without having the operator=, m_next and
|
| - // m_prev are inproperly copied and it breaks the link list of the
|
| - // persistent handles.
|
| - inline PersistentNode& operator=(const PersistentNode& otherref) { return *this; }
|
| -
|
| -private:
|
| - // Ideally the trace method should be virtual and automatically dispatch
|
| - // to the most specific implementation. However having a virtual method
|
| - // on PersistentNode leads to too eager template instantiation with MSVC
|
| - // which leads to include cycles.
|
| - // Instead we call the constructor with a TraceCallback which knows the
|
| - // type of the most specific child and calls trace directly. See
|
| - // TraceMethodDelegate in Visitor.h for how this is done.
|
| - void tracePersistentNode(Visitor* visitor)
|
| - {
|
| - m_trace(visitor, this);
|
| - }
|
| -
|
| - ~PersistentNode()
|
| - {
|
| - }
|
| -
|
| - TraceCallback m_trace;
|
| - PersistentNode* m_next;
|
| - PersistentNode* m_prev;
|
| -
|
| - template<typename T> friend class CrossThreadPersistent;
|
| - template<typename T> friend class Persistent;
|
| - template<typename Collection> friend class PersistentHeapCollectionBase;
|
| - friend class PersistentAnchor;
|
| - friend class ThreadState;
|
| -};
|
| -
|
| -// A dummy Persistent handle that ensures the list of persistents is never null.
|
| -// This removes a test from a hot path.
|
| -class PersistentAnchor : public PersistentNode {
|
| -public:
|
| - void tracePersistentNodes(Visitor* visitor)
|
| - {
|
| - for (PersistentNode* current = m_next; current != this; current = current->m_next)
|
| - current->tracePersistentNode(visitor);
|
| - }
|
| -
|
| - int numberOfPersistents()
|
| - {
|
| - int numberOfPersistents = 0;
|
| - for (PersistentNode* current = m_next; current != this; current = current->m_next)
|
| - ++numberOfPersistents;
|
| - return numberOfPersistents;
|
| - }
|
| -
|
| - ~PersistentAnchor()
|
| - {
|
| - m_trace = nullptr;
|
| - }
|
| -
|
| - template<typename VisitorDispatcher>
|
| - void trace(VisitorDispatcher visitor)
|
| - {
|
| - ASSERT_NOT_REACHED();
|
| - }
|
| -
|
| -private:
|
| - PersistentAnchor() : PersistentNode(TraceMethodDelegate<PersistentAnchor, &PersistentAnchor::trace>::trampoline)
|
| - {
|
| - m_next = this;
|
| - m_prev = this;
|
| - }
|
| -
|
| - friend class ThreadState;
|
| -};
|
| -
|
| // Persistent handles are used to store pointers into the
|
| // managed heap. As long as the Persistent handle is alive
|
| // the GC will keep the object pointed to alive. Persistent
|
| @@ -144,33 +64,33 @@ private:
|
| //
|
| // We have to construct and destruct Persistent in the same thread.
|
| template<typename T>
|
| -class Persistent : public PersistentNode {
|
| +class Persistent final {
|
| public:
|
| - Persistent() : PersistentNode(TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline), m_raw(nullptr)
|
| + Persistent() : m_raw(nullptr)
|
| {
|
| initialize();
|
| }
|
|
|
| - Persistent(std::nullptr_t) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline), m_raw(nullptr)
|
| + Persistent(std::nullptr_t) : m_raw(nullptr)
|
| {
|
| initialize();
|
| }
|
|
|
| - Persistent(T* raw) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline), m_raw(raw)
|
| + Persistent(T* raw) : m_raw(raw)
|
| {
|
| initialize();
|
| checkPointer();
|
| recordBacktrace();
|
| }
|
|
|
| - Persistent(T& raw) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline), m_raw(&raw)
|
| + Persistent(T& raw) : m_raw(&raw)
|
| {
|
| initialize();
|
| checkPointer();
|
| recordBacktrace();
|
| }
|
|
|
| - Persistent(const Persistent& other) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline), m_raw(other)
|
| + Persistent(const Persistent& other) : m_raw(other)
|
| {
|
| initialize();
|
| checkPointer();
|
| @@ -178,7 +98,7 @@ public:
|
| }
|
|
|
| template<typename U>
|
| - Persistent(const Persistent<U>& other) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline), m_raw(other)
|
| + Persistent(const Persistent<U>& other) : m_raw(other)
|
| {
|
| initialize();
|
| checkPointer();
|
| @@ -186,7 +106,7 @@ public:
|
| }
|
|
|
| template<typename U>
|
| - Persistent(const Member<U>& other) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline), m_raw(other)
|
| + Persistent(const Member<U>& other) : m_raw(other)
|
| {
|
| initialize();
|
| checkPointer();
|
| @@ -194,7 +114,7 @@ public:
|
| }
|
|
|
| template<typename U>
|
| - Persistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline), m_raw(other.get())
|
| + Persistent(const RawPtr<U>& other) : m_raw(other.get())
|
| {
|
| initialize();
|
| checkPointer();
|
| @@ -207,7 +127,6 @@ public:
|
| {
|
| uninitialize();
|
| m_raw = nullptr;
|
| - m_trace = nullptr;
|
| }
|
|
|
| template<typename VisitorDispatcher>
|
| @@ -292,20 +211,14 @@ private:
|
| {
|
| ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
|
| state->checkThread();
|
| - m_prev = state->roots();
|
| - m_next = m_prev->m_next;
|
| - m_prev->m_next = this;
|
| - m_next->m_prev = this;
|
| + m_persistentNode = state->persistentRegion()->allocatePersistentNode(this, TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline);
|
| }
|
|
|
| - NO_LAZY_SWEEP_SANITIZE_ADDRESS
|
| void uninitialize()
|
| {
|
| - ASSERT(isHeapObjectAlive());
|
| - ASSERT(m_next->isHeapObjectAlive());
|
| - ASSERT(m_prev->isHeapObjectAlive());
|
| - m_next->m_prev = m_prev;
|
| - m_prev->m_next = m_next;
|
| + ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
|
| + state->checkThread();
|
| + state->persistentRegion()->freePersistentNode(m_persistentNode);
|
| }
|
|
|
| void checkPointer()
|
| @@ -337,39 +250,41 @@ private:
|
| #else
|
| inline void recordBacktrace() const { }
|
| #endif
|
| + // m_raw is accessed most, so put it at the first field.
|
| T* m_raw;
|
| + PersistentNode* m_persistentNode;
|
| };
|
|
|
| // Unlike Persistent, we can destruct a CrossThreadPersistent in a thread
|
| // different from the construction thread.
|
| template<typename T>
|
| -class CrossThreadPersistent : public PersistentNode {
|
| +class CrossThreadPersistent final {
|
| public:
|
| - CrossThreadPersistent() : PersistentNode(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(nullptr)
|
| + CrossThreadPersistent() : m_raw(nullptr)
|
| {
|
| initialize();
|
| }
|
|
|
| - CrossThreadPersistent(std::nullptr_t) : PersistentNode(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(nullptr)
|
| + CrossThreadPersistent(std::nullptr_t) : m_raw(nullptr)
|
| {
|
| initialize();
|
| }
|
|
|
| - CrossThreadPersistent(T* raw) : PersistentNode(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(raw)
|
| + CrossThreadPersistent(T* raw) : m_raw(raw)
|
| {
|
| initialize();
|
| checkPointer();
|
| recordBacktrace();
|
| }
|
|
|
| - CrossThreadPersistent(T& raw) : PersistentNode(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(&raw)
|
| + CrossThreadPersistent(T& raw) : m_raw(&raw)
|
| {
|
| initialize();
|
| checkPointer();
|
| recordBacktrace();
|
| }
|
|
|
| - CrossThreadPersistent(const CrossThreadPersistent& other) : PersistentNode(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(other)
|
| + CrossThreadPersistent(const CrossThreadPersistent& other) : m_raw(other)
|
| {
|
| initialize();
|
| checkPointer();
|
| @@ -377,7 +292,7 @@ public:
|
| }
|
|
|
| template<typename U>
|
| - CrossThreadPersistent(const CrossThreadPersistent<U>& other) : PersistentNode(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(other)
|
| + CrossThreadPersistent(const CrossThreadPersistent<U>& other) : m_raw(other)
|
| {
|
| initialize();
|
| checkPointer();
|
| @@ -385,7 +300,7 @@ public:
|
| }
|
|
|
| template<typename U>
|
| - CrossThreadPersistent(const Member<U>& other) : PersistentNode(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(other)
|
| + CrossThreadPersistent(const Member<U>& other) : m_raw(other)
|
| {
|
| initialize();
|
| checkPointer();
|
| @@ -393,7 +308,7 @@ public:
|
| }
|
|
|
| template<typename U>
|
| - CrossThreadPersistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(other.get())
|
| + CrossThreadPersistent(const RawPtr<U>& other) : m_raw(other.get())
|
| {
|
| initialize();
|
| checkPointer();
|
| @@ -406,7 +321,6 @@ public:
|
| {
|
| uninitialize();
|
| m_raw = nullptr;
|
| - m_trace = nullptr;
|
| }
|
|
|
| template<typename VisitorDispatcher>
|
| @@ -489,22 +403,12 @@ private:
|
| NO_LAZY_SWEEP_SANITIZE_ADDRESS
|
| void initialize()
|
| {
|
| - MutexLocker m_locker(ThreadState::globalRootsMutex());
|
| - m_prev = &ThreadState::globalRoots();
|
| - m_next = m_prev->m_next;
|
| - m_prev->m_next = this;
|
| - m_next->m_prev = this;
|
| + m_persistentNode = ThreadState::crossThreadPersistentRegion().allocatePersistentNode(this, TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline);
|
| }
|
|
|
| - NO_LAZY_SWEEP_SANITIZE_ADDRESS
|
| void uninitialize()
|
| {
|
| - MutexLocker m_locker(ThreadState::globalRootsMutex());
|
| - ASSERT(isHeapObjectAlive());
|
| - ASSERT(m_next->isHeapObjectAlive());
|
| - ASSERT(m_prev->isHeapObjectAlive());
|
| - m_next->m_prev = m_prev;
|
| - m_prev->m_next = m_next;
|
| + ThreadState::crossThreadPersistentRegion().freePersistentNode(m_persistentNode);
|
| }
|
|
|
| void checkPointer()
|
| @@ -535,31 +439,33 @@ private:
|
| #else
|
| inline void recordBacktrace() const { }
|
| #endif
|
| + // m_raw is accessed most, so put it at the first field.
|
| T* m_raw;
|
| + PersistentNode* m_persistentNode;
|
| };
|
|
|
| // PersistentNode must be the left-most class to let the
|
| // visitor->trace(static_cast<Collection*>(this)) trace the correct position.
|
| // FIXME: derive affinity based on the collection.
|
| template<typename Collection>
|
| -class PersistentHeapCollectionBase : public PersistentNode, public 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() : PersistentNode(TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::trace>::trampoline)
|
| + PersistentHeapCollectionBase()
|
| {
|
| initialize();
|
| }
|
|
|
| - PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : PersistentNode(TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::trace>::trampoline), Collection(other)
|
| + PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : Collection(other)
|
| {
|
| initialize();
|
| }
|
|
|
| template<typename OtherCollection>
|
| - PersistentHeapCollectionBase(const OtherCollection& other) : PersistentNode(TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::trace>::trampoline), Collection(other)
|
| + PersistentHeapCollectionBase(const OtherCollection& other) : Collection(other)
|
| {
|
| initialize();
|
| }
|
| @@ -567,7 +473,6 @@ public:
|
| ~PersistentHeapCollectionBase()
|
| {
|
| uninitialize();
|
| - m_trace = nullptr;
|
| }
|
|
|
| template<typename VisitorDispatcher>
|
| @@ -582,21 +487,18 @@ private:
|
| void initialize()
|
| {
|
| ThreadState* state = ThreadState::current();
|
| - m_prev = state->roots();
|
| - m_next = m_prev->m_next;
|
| - m_prev->m_next = this;
|
| - m_next->m_prev = this;
|
| + state->checkThread();
|
| + m_persistentNode = state->persistentRegion()->allocatePersistentNode(this, TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::trace>::trampoline);
|
| }
|
|
|
| - NO_LAZY_SWEEP_SANITIZE_ADDRESS
|
| void uninitialize()
|
| {
|
| - ASSERT(isHeapObjectAlive());
|
| - ASSERT(m_next->isHeapObjectAlive());
|
| - ASSERT(m_prev->isHeapObjectAlive());
|
| - m_next->m_prev = m_prev;
|
| - m_prev->m_next = m_next;
|
| + ThreadState* state = ThreadState::current();
|
| + state->checkThread();
|
| + state->persistentRegion()->freePersistentNode(m_persistentNode);
|
| }
|
| +
|
| + PersistentNode* m_persistentNode;
|
| };
|
|
|
| template<
|
|
|