| /* |
| * 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/ThreadState.h" |
| #include "platform/heap/Visitor.h" |
| #include "wtf/Functional.h" |
| #include "wtf/HashFunctions.h" |
| #include "wtf/Locker.h" |
| #include "wtf/RawPtr.h" |
| #include "wtf/RefCounted.h" |
| #include "wtf/TypeTraits.h" |
| |
| namespace blink { |
| |
| template<typename T> class HeapTerminatedArray; |
| |
| // Template to determine if a class is a GarbageCollectedMixin by checking if it |
| // has adjustAndMark and isAlive. We can't check directly if the class is a |
| // GarbageCollectedMixin because casting to it is potentially ambiguous. |
| template<typename T> |
| struct IsGarbageCollectedMixin { |
| typedef char TrueType; |
| struct FalseType { |
| char dummy[2]; |
| }; |
| |
| #if COMPILER(MSVC) |
| template<typename U> static TrueType hasAdjustAndMark(char[&U::adjustAndMark != 0]); |
| template<typename U> static TrueType hasIsHeapObjectAlive(char[&U::isHeapObjectAlive != 0]); |
| #else |
| template<size_t> struct F; |
| template<typename U> static TrueType hasAdjustAndMark(F<sizeof(&U::adjustAndMark)>*); |
| template<typename U> static TrueType hasIsHeapObjectAlive(F<sizeof(&U::isHeapObjectAlive)>*); |
| #endif |
| template<typename U> static FalseType hasIsHeapObjectAlive(...); |
| template<typename U> static FalseType hasAdjustAndMark(...); |
| |
| static bool const value = (sizeof(TrueType) == sizeof(hasAdjustAndMark<T>(0))) && (sizeof(TrueType) == sizeof(hasIsHeapObjectAlive<T>(0))); |
| }; |
| |
| template <typename T> |
| struct IsGarbageCollectedType { |
| typedef char TrueType; |
| struct FalseType { |
| char dummy[2]; |
| }; |
| |
| typedef typename WTF::RemoveConst<T>::Type NonConstType; |
| typedef WTF::IsSubclassOfTemplate<NonConstType, GarbageCollected> GarbageCollectedSubclass; |
| typedef IsGarbageCollectedMixin<NonConstType> GarbageCollectedMixinSubclass; |
| typedef WTF::IsSubclassOfTemplate<NonConstType, HeapHashSet> HeapHashSetSubclass; |
| typedef WTF::IsSubclassOfTemplate<NonConstType, HeapLinkedHashSet> HeapLinkedHashSetSubclass; |
| typedef WTF::IsSubclassOfTemplateTypenameSizeTypename<NonConstType, HeapListHashSet> HeapListHashSetSubclass; |
| typedef WTF::IsSubclassOfTemplate<NonConstType, HeapHashMap> HeapHashMapSubclass; |
| typedef WTF::IsSubclassOfTemplateTypenameSize<NonConstType, HeapVector> HeapVectorSubclass; |
| typedef WTF::IsSubclassOfTemplateTypenameSize<NonConstType, HeapDeque> HeapDequeSubclass; |
| typedef WTF::IsSubclassOfTemplate<NonConstType, HeapHashCountedSet> HeapHashCountedSetSubclass; |
| typedef WTF::IsSubclassOfTemplate<NonConstType, HeapTerminatedArray> HeapTerminatedArraySubclass; |
| |
| template<typename U, size_t inlineCapacity> static TrueType listHashSetNodeIsHeapAllocated(WTF::ListHashSetNode<U, HeapListHashSetAllocator<U, inlineCapacity> >*); |
| static FalseType listHashSetNodeIsHeapAllocated(...); |
| static const bool isHeapAllocatedListHashSetNode = sizeof(TrueType) == sizeof(listHashSetNodeIsHeapAllocated(reinterpret_cast<NonConstType*>(0))); |
| |
| static const bool value = |
| GarbageCollectedSubclass::value |
| || GarbageCollectedMixinSubclass::value |
| || HeapHashSetSubclass::value |
| || HeapLinkedHashSetSubclass::value |
| || HeapListHashSetSubclass::value |
| || HeapHashMapSubclass::value |
| || HeapVectorSubclass::value |
| || HeapDequeSubclass::value |
| || HeapHashCountedSetSubclass::value |
| || HeapTerminatedArraySubclass::value |
| || isHeapAllocatedListHashSetNode; |
| }; |
| |
| #define COMPILE_ASSERT_IS_GARBAGE_COLLECTED(T, ErrorMessage) \ |
| COMPILE_ASSERT(IsGarbageCollectedType<T>::value, ErrorMessage) |
| |
| template<typename T> class Member; |
| |
| class PersistentNode { |
| public: |
| explicit PersistentNode(TraceCallback trace) |
| : m_trace(trace) |
| { |
| } |
| |
| bool isAlive() { return m_trace; } |
| |
| virtual ~PersistentNode() |
| { |
| ASSERT(isAlive()); |
| m_trace = 0; |
| } |
| |
| // 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 trace(Visitor* visitor) |
| { |
| m_trace(visitor, this); |
| } |
| |
| protected: |
| TraceCallback m_trace; |
| |
| private: |
| PersistentNode* m_next; |
| PersistentNode* m_prev; |
| |
| template<typename RootsAccessor, typename Owner> friend class PersistentBase; |
| friend class PersistentAnchor; |
| friend class ThreadState; |
| }; |
| |
| // RootsAccessor for Persistent that provides access to thread-local list |
| // of persistent handles. Can only be used to create handles that |
| // are constructed and destructed on the same thread. |
| template<ThreadAffinity Affinity> |
| class ThreadLocalPersistents { |
| public: |
| static PersistentNode* roots() { return state()->roots(); } |
| |
| // No locking required. Just check that we are at the right thread. |
| class Lock { |
| public: |
| Lock() { state()->checkThread(); } |
| }; |
| |
| private: |
| static ThreadState* state() { return ThreadStateFor<Affinity>::state(); } |
| }; |
| |
| // RootsAccessor for Persistent that provides synchronized access to global |
| // list of persistent handles. Can be used for persistent handles that are |
| // passed between threads. |
| class GlobalPersistents { |
| public: |
| static PersistentNode* roots() { return ThreadState::globalRoots(); } |
| |
| class Lock { |
| public: |
| Lock() : m_locker(ThreadState::globalRootsMutex()) { } |
| private: |
| MutexLocker m_locker; |
| }; |
| }; |
| |
| // Base class for persistent handles. RootsAccessor specifies which list to |
| // link resulting handle into. Owner specifies the class containing trace |
| // method. |
| template<typename RootsAccessor, typename Owner> |
| class PersistentBase : public PersistentNode { |
| public: |
| ~PersistentBase() |
| { |
| typename RootsAccessor::Lock lock; |
| ASSERT(m_roots == RootsAccessor::roots()); // Check that the thread is using the same roots list. |
| ASSERT(isAlive()); |
| ASSERT(m_next->isAlive()); |
| ASSERT(m_prev->isAlive()); |
| m_next->m_prev = m_prev; |
| m_prev->m_next = m_next; |
| } |
| |
| protected: |
| inline PersistentBase() |
| : PersistentNode(TraceMethodDelegate<Owner, &Owner::trace>::trampoline) |
| #if ENABLE(ASSERT) |
| , m_roots(RootsAccessor::roots()) |
| #endif |
| { |
| typename RootsAccessor::Lock lock; |
| m_prev = RootsAccessor::roots(); |
| m_next = m_prev->m_next; |
| m_prev->m_next = this; |
| m_next->m_prev = this; |
| } |
| |
| inline explicit PersistentBase(const PersistentBase& otherref) |
| : PersistentNode(otherref.m_trace) |
| #if ENABLE(ASSERT) |
| , m_roots(RootsAccessor::roots()) |
| #endif |
| { |
| // We don't support allocation of thread local Persistents while doing |
| // thread shutdown/cleanup. |
| ASSERT(!ThreadState::current()->isTerminating()); |
| typename RootsAccessor::Lock lock; |
| ASSERT(otherref.m_roots == m_roots); // Handles must belong to the same list. |
| PersistentBase* other = const_cast<PersistentBase*>(&otherref); |
| m_prev = other; |
| m_next = other->m_next; |
| other->m_next = this; |
| m_next->m_prev = this; |
| } |
| |
| inline PersistentBase& operator=(const PersistentBase& otherref) { return *this; } |
| |
| #if ENABLE(ASSERT) |
| private: |
| PersistentNode* m_roots; |
| #endif |
| }; |
| |
| // 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 trace(Visitor* visitor) |
| { |
| for (PersistentNode* current = m_next; current != this; current = current->m_next) |
| current->trace(visitor); |
| } |
| |
| int numberOfPersistents() |
| { |
| int numberOfPersistents = 0; |
| for (PersistentNode* current = m_next; current != this; current = current->m_next) |
| ++numberOfPersistents; |
| return numberOfPersistents; |
| } |
| |
| virtual ~PersistentAnchor() |
| { |
| // FIXME: oilpan: Ideally we should have no left-over persistents at this point. However currently there is a |
| // large number of objects leaked when we tear down the main thread. Since some of these might contain a |
| // persistent or e.g. be RefCountedGarbageCollected we cannot guarantee there are no remaining Persistents at |
| // this point. |
| } |
| |
| private: |
| PersistentAnchor() : PersistentNode(TraceMethodDelegate<PersistentAnchor, &PersistentAnchor::trace>::trampoline) |
| { |
| m_next = this; |
| m_prev = this; |
| } |
| |
| friend class ThreadState; |
| }; |
| |
| #if ENABLE(ASSERT) |
| // For global persistent handles we cannot check that the |
| // pointer is in the heap because that would involve |
| // inspecting the heap of running threads. |
| #define ASSERT_IS_VALID_PERSISTENT_POINTER(pointer) \ |
| bool isGlobalPersistent = WTF::IsSubclass<RootsAccessor, GlobalPersistents>::value; \ |
| ASSERT(!pointer || isGlobalPersistent || ThreadStateFor<ThreadingTrait<T>::Affinity>::state()->contains(pointer)) |
| #else |
| #define ASSERT_IS_VALID_PERSISTENT_POINTER(pointer) |
| #endif |
| |
| template<typename T> |
| class CrossThreadPersistent; |
| |
| // 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 |
| // handles can be stored in objects and they are not scoped. |
| // Persistent handles must not be used to contain pointers |
| // between objects that are in the managed heap. They are only |
| // meant to point to managed heap objects from variables/members |
| // outside the managed heap. |
| // |
| // A Persistent is always a GC root from the point of view of |
| // the garbage collector. |
| // |
| // We have to construct and destruct Persistent with default RootsAccessor in |
| // the same thread. |
| template<typename T, typename RootsAccessor /* = ThreadLocalPersistents<ThreadingTrait<T>::Affinity > */ > |
| class Persistent : public PersistentBase<RootsAccessor, Persistent<T, RootsAccessor> > { |
| public: |
| Persistent() : m_raw(0) { } |
| |
| Persistent(std::nullptr_t) : m_raw(0) { } |
| |
| Persistent(T* raw) : m_raw(raw) |
| { |
| ASSERT_IS_VALID_PERSISTENT_POINTER(m_raw); |
| recordBacktrace(); |
| } |
| |
| explicit Persistent(T& raw) : m_raw(&raw) |
| { |
| ASSERT_IS_VALID_PERSISTENT_POINTER(m_raw); |
| recordBacktrace(); |
| } |
| |
| Persistent(const Persistent& other) : m_raw(other) { recordBacktrace(); } |
| |
| template<typename U> |
| Persistent(const Persistent<U, RootsAccessor>& other) : m_raw(other) { recordBacktrace(); } |
| |
| template<typename U> |
| Persistent(const Member<U>& other) : m_raw(other) { recordBacktrace(); } |
| |
| template<typename U> |
| Persistent(const RawPtr<U>& other) : m_raw(other.get()) { recordBacktrace(); } |
| |
| template<typename U> |
| Persistent& operator=(U* other) |
| { |
| m_raw = other; |
| recordBacktrace(); |
| return *this; |
| } |
| |
| Persistent& operator=(std::nullptr_t) |
| { |
| m_raw = 0; |
| return *this; |
| } |
| |
| void clear() { m_raw = 0; } |
| |
| virtual ~Persistent() |
| { |
| m_raw = 0; |
| } |
| |
| template<typename U> |
| U* as() const |
| { |
| return static_cast<U*>(m_raw); |
| } |
| |
| void trace(Visitor* visitor) |
| { |
| COMPILE_ASSERT_IS_GARBAGE_COLLECTED(T, NonGarbageCollectedObjectInPersistent); |
| #if ENABLE(GC_PROFILE_MARKING) |
| visitor->setHostInfo(this, m_tracingName.isEmpty() ? "Persistent" : m_tracingName); |
| #endif |
| visitor->mark(m_raw); |
| } |
| |
| RawPtr<T> release() |
| { |
| RawPtr<T> result = m_raw; |
| m_raw = 0; |
| return result; |
| } |
| |
| 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; } |
| |
| Persistent& operator=(const Persistent& other) |
| { |
| m_raw = other; |
| recordBacktrace(); |
| return *this; |
| } |
| |
| template<typename U> |
| Persistent& operator=(const Persistent<U, RootsAccessor>& other) |
| { |
| m_raw = other; |
| recordBacktrace(); |
| return *this; |
| } |
| |
| template<typename U> |
| Persistent& operator=(const Member<U>& other) |
| { |
| m_raw = other; |
| recordBacktrace(); |
| return *this; |
| } |
| |
| template<typename U> |
| Persistent& operator=(const RawPtr<U>& other) |
| { |
| m_raw = other; |
| recordBacktrace(); |
| return *this; |
| } |
| |
| T* get() const { return m_raw; } |
| |
| private: |
| #if ENABLE(GC_PROFILE_MARKING) |
| void recordBacktrace() |
| { |
| if (m_raw) |
| m_tracingName = Heap::createBacktraceString(); |
| } |
| |
| String m_tracingName; |
| #else |
| inline void recordBacktrace() const { } |
| #endif |
| T* m_raw; |
| |
| friend class CrossThreadPersistent<T>; |
| }; |
| |
| // Unlike Persistent, we can destruct a CrossThreadPersistent in a thread |
| // different from the construction thread. |
| template<typename T> |
| class CrossThreadPersistent : public Persistent<T, GlobalPersistents> { |
| public: |
| CrossThreadPersistent(T* raw) : Persistent<T, GlobalPersistents>(raw) { } |
| |
| using Persistent<T, GlobalPersistents>::operator=; |
| }; |
| |
| // FIXME: derive affinity based on the collection. |
| template<typename Collection, ThreadAffinity Affinity = AnyThread> |
| class PersistentHeapCollectionBase |
| : public Collection |
| , public PersistentBase<ThreadLocalPersistents<Affinity>, PersistentHeapCollectionBase<Collection, Affinity> > { |
| // 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() { } |
| |
| template<typename OtherCollection> |
| PersistentHeapCollectionBase(const OtherCollection& other) : Collection(other) { } |
| |
| void trace(Visitor* visitor) |
| { |
| #if ENABLE(GC_PROFILE_MARKING) |
| visitor->setHostInfo(this, "PersistentHeapCollectionBase"); |
| #endif |
| visitor->trace(*static_cast<Collection*>(this)); |
| } |
| }; |
| |
| 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(0) |
| { |
| } |
| |
| Member(std::nullptr_t) : m_raw(0) |
| { |
| } |
| |
| Member(T* raw) : m_raw(raw) |
| { |
| } |
| |
| explicit Member(T& raw) : m_raw(&raw) |
| { |
| } |
| |
| template<typename U> |
| Member(const RawPtr<U>& other) : m_raw(other.get()) |
| { |
| } |
| |
| 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) { } |
| |
| Member(const Member& other) : m_raw(other) { } |
| |
| template<typename U> |
| Member(const Member<U>& other) : m_raw(other) { } |
| |
| T* release() |
| { |
| T* result = m_raw; |
| m_raw = 0; |
| return result; |
| } |
| |
| template<typename U> |
| U* as() const |
| { |
| return static_cast<U*>(m_raw); |
| } |
| |
| 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; |
| return *this; |
| } |
| |
| template<typename U> |
| Member& operator=(const Member<U>& other) |
| { |
| m_raw = other; |
| return *this; |
| } |
| |
| template<typename U> |
| Member& operator=(U* other) |
| { |
| m_raw = other; |
| return *this; |
| } |
| |
| template<typename U> |
| Member& operator=(RawPtr<U> other) |
| { |
| m_raw = other; |
| return *this; |
| } |
| |
| Member& operator=(std::nullptr_t) |
| { |
| m_raw = 0; |
| return *this; |
| } |
| |
| void swap(Member<T>& other) { std::swap(m_raw, other.m_raw); } |
| |
| T* get() const { return m_raw; } |
| |
| void clear() { m_raw = 0; } |
| |
| |
| protected: |
| void verifyTypeIsGarbageCollected() const |
| { |
| COMPILE_ASSERT_IS_GARBAGE_COLLECTED(T, NonGarbageCollectedObjectInMember); |
| } |
| |
| T* m_raw; |
| |
| template<bool x, WTF::WeakHandlingFlag y, WTF::ShouldWeakPointersBeMarkedStrongly z, typename U, typename V> friend struct CollectionBackingTraceTrait; |
| friend class Visitor; |
| }; |
| |
| template<typename T> |
| class TraceTrait<Member<T> > { |
| public: |
| static void trace(Visitor* visitor, void* self) |
| { |
| TraceTrait<T>::mark(visitor, *static_cast<Member<T>*>(self)); |
| } |
| }; |
| |
| // TraceTrait to allow compilation of trace method bodies when oilpan is disabled. |
| // This should never be called, but is needed to compile. |
| template<typename T> |
| class TraceTrait<RefPtr<T> > { |
| public: |
| static void trace(Visitor*, void*) |
| { |
| ASSERT_NOT_REACHED(); |
| } |
| }; |
| |
| template<typename T> |
| class TraceTrait<OwnPtr<T> > { |
| public: |
| static void trace(Visitor* visitor, OwnPtr<T>* ptr) |
| { |
| ASSERT_NOT_REACHED(); |
| } |
| }; |
| |
| template<typename T, bool needsTracing> |
| struct TraceIfEnabled; |
| |
| template<typename T> |
| struct TraceIfEnabled<T, false> { |
| static void trace(Visitor*, T*) { } |
| }; |
| |
| template<typename T> |
| struct TraceIfEnabled<T, true> { |
| static void trace(Visitor* visitor, T* t) |
| { |
| visitor->trace(*t); |
| } |
| }; |
| |
| template <typename T> struct RemoveHeapPointerWrapperTypes { |
| typedef typename WTF::RemoveTemplate<typename WTF::RemoveTemplate<typename WTF::RemoveTemplate<T, Member>::Type, WeakMember>::Type, RawPtr>::Type Type; |
| }; |
| |
| // FIXME: Oilpan: TraceIfNeeded should be implemented ala: |
| // NeedsTracing<T>::value || IsWeakMember<T>::value. It should not need to test |
| // raw pointer types. To remove these tests, we may need support for |
| // instantiating a template with a RawPtrOrMember'ish template. |
| template<typename T> |
| struct TraceIfNeeded : public TraceIfEnabled<T, WTF::NeedsTracing<T>::value || blink::IsGarbageCollectedType<typename RemoveHeapPointerWrapperTypes<typename WTF::RemovePointer<T>::Type>::Type>::value> { }; |
| |
| // This trace trait for std::pair will null weak members if their referent is |
| // collected. If you have a collection that contain weakness it does not remove |
| // entries from the collection that contain nulled weak members. |
| template<typename T, typename U> |
| class TraceTrait<std::pair<T, U> > { |
| public: |
| static const bool firstNeedsTracing = WTF::NeedsTracing<T>::value || WTF::IsWeak<T>::value; |
| static const bool secondNeedsTracing = WTF::NeedsTracing<U>::value || WTF::IsWeak<U>::value; |
| static void trace(Visitor* visitor, std::pair<T, U>* pair) |
| { |
| TraceIfEnabled<T, firstNeedsTracing>::trace(visitor, &pair->first); |
| TraceIfEnabled<U, secondNeedsTracing>::trace(visitor, &pair->second); |
| } |
| }; |
| |
| // 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; |
| return *this; |
| } |
| |
| template<typename U> |
| WeakMember& operator=(const Member<U>& other) |
| { |
| this->m_raw = other; |
| return *this; |
| } |
| |
| template<typename U> |
| WeakMember& operator=(U* other) |
| { |
| this->m_raw = other; |
| return *this; |
| } |
| |
| template<typename U> |
| WeakMember& operator=(const RawPtr<U>& other) |
| { |
| this->m_raw = other; |
| return *this; |
| } |
| |
| WeakMember& operator=(std::nullptr_t) |
| { |
| this->m_raw = 0; |
| return *this; |
| } |
| |
| private: |
| T** cell() const { return const_cast<T**>(&this->m_raw); } |
| |
| friend class Visitor; |
| }; |
| |
| // 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(); } |
| |
| // 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 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 RefPtrWillBeCrossThreadPersistent blink::CrossThreadPersistent |
| #define RawPtrWillBeMember blink::Member |
| #define RawPtrWillBePersistent blink::Persistent |
| #define RawPtrWillBeWeakMember blink::WeakMember |
| #define OwnPtrWillBeMember blink::Member |
| #define OwnPtrWillBePersistent blink::Persistent |
| #define OwnPtrWillBeRawPtr WTF::RawPtr |
| #define PassOwnPtrWillBeRawPtr WTF::RawPtr |
| #define WeakPtrWillBeMember blink::Member |
| #define WeakPtrWillBeRawPtr WTF::RawPtr |
| #define WeakPtrWillBeMember blink::Member |
| #define WeakPtrWillBeWeakMember blink::WeakMember |
| #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; |
| COMPILE_ASSERT(notRefCounted, youMustAdopt); |
| return ptr; |
| } |
| |
| template<typename T> T* adoptPtrWillBeNoop(T* ptr) |
| { |
| static const bool notRefCounted = !WTF::IsSubclassOfTemplate<typename WTF::RemoveConst<T>::Type, RefCounted>::value; |
| COMPILE_ASSERT(notRefCounted, youMustAdopt); |
| return ptr; |
| } |
| |
| #define WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED // 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) |
| |
| template<typename T> |
| class DummyBase { |
| public: |
| DummyBase() { } |
| ~DummyBase() { } |
| }; |
| |
| #define PassRefPtrWillBeRawPtr WTF::PassRefPtr |
| #define RefCountedWillBeGarbageCollected WTF::RefCounted |
| #define RefCountedWillBeGarbageCollectedFinalized WTF::RefCounted |
| #define RefCountedWillBeRefCountedGarbageCollected WTF::RefCounted |
| #define RefCountedGarbageCollectedWillBeGarbageCollectedFinalized 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 RefPtrWillBeCrossThreadPersistent WTF::RefPtr |
| #define RawPtrWillBeMember WTF::RawPtr |
| #define RawPtrWillBePersistent WTF::RawPtr |
| #define RawPtrWillBeWeakMember WTF::RawPtr |
| #define OwnPtrWillBeMember WTF::OwnPtr |
| #define OwnPtrWillBePersistent WTF::OwnPtr |
| #define OwnPtrWillBeRawPtr WTF::OwnPtr |
| #define PassOwnPtrWillBeRawPtr WTF::PassOwnPtr |
| #define WeakPtrWillBeMember WTF::WeakPtr |
| #define WeakPtrWillBeRawPtr WTF::WeakPtr |
| #define WeakPtrWillBeMember WTF::WeakPtr |
| #define WeakPtrWillBeWeakMember 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 WTF_MAKE_FAST_ALLOCATED |
| #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) |
| |
| } // 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 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 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 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 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 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 canMoveWithMemcpy = VectorTraits<T>::canMoveWithMemcpy; |
| }; |
| |
| template<typename T> struct HashTraits<blink::Member<T> > : SimpleClassHashTraits<blink::Member<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. |
| typedef RawPtr<T> PeekInType; |
| typedef RawPtr<T> PassInType; |
| typedef blink::Member<T>* IteratorGetType; |
| typedef const blink::Member<T>* IteratorConstGetType; |
| typedef blink::Member<T>& IteratorReferenceType; |
| typedef T* const IteratorConstReferenceType; |
| static IteratorReferenceType getToReferenceConversion(IteratorGetType x) { return *x; } |
| static IteratorConstReferenceType getToReferenceConstConversion(IteratorConstGetType x) { return x->get(); } |
| // FIXME: Similarly, there is no need for a distinction between PeekOutType |
| // and PassOutType without reference counting. |
| typedef T* PeekOutType; |
| typedef T* PassOutType; |
| |
| 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. |
| typedef RawPtr<T> PeekInType; |
| typedef RawPtr<T> PassInType; |
| typedef blink::WeakMember<T>* IteratorGetType; |
| typedef const blink::WeakMember<T>* IteratorConstGetType; |
| typedef blink::WeakMember<T>& IteratorReferenceType; |
| typedef T* const IteratorConstReferenceType; |
| static IteratorReferenceType getToReferenceConversion(IteratorGetType x) { return *x; } |
| static IteratorConstReferenceType getToReferenceConstConversion(IteratorConstGetType x) { return x->get(); } |
| // FIXME: Similarly, there is no need for a distinction between PeekOutType |
| // and PassOutType without reference counting. |
| typedef T* PeekOutType; |
| typedef T* PassOutType; |
| |
| 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; } |
| static bool traceInCollection(blink::Visitor* visitor, blink::WeakMember<T>& weakMember, ShouldWeakPointersBeMarkedStrongly strongify) |
| { |
| if (strongify == WeakPointersActStrong) { |
| visitor->trace(reinterpret_cast<blink::Member<T>&>(weakMember)); // Strongified visit. |
| return false; |
| } |
| return !visitor->isAlive(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> > { |
| }; |
| |
| template<typename P> struct PtrHash<blink::Persistent<P> > : PtrHash<P*> { |
| using PtrHash<P*>::hash; |
| static unsigned hash(const RefPtr<P>& key) { return hash(key.get()); } |
| using PtrHash<P*>::equal; |
| static bool equal(const RefPtr<P>& a, const RefPtr<P>& b) { return a == b; } |
| static bool equal(P* a, const RefPtr<P>& b) { return a == b; } |
| static bool equal(const RefPtr<P>& a, P* b) { return a == b; } |
| }; |
| |
| // PtrHash is the default hash for hash tables with members. |
| template<typename T> struct DefaultHash<blink::Member<T> > { |
| typedef PtrHash<blink::Member<T> > Hash; |
| }; |
| |
| template<typename T> struct DefaultHash<blink::WeakMember<T> > { |
| typedef PtrHash<blink::WeakMember<T> > Hash; |
| }; |
| |
| template<typename T> struct DefaultHash<blink::Persistent<T> > { |
| typedef PtrHash<blink::Persistent<T> > Hash; |
| }; |
| |
| 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> > *> { |
| // 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> { |
| typedef T* StorageType; |
| |
| static StorageType wrap(T* value) { return value; } |
| static T* unwrap(const StorageType& value) { return value; } |
| }; |
| |
| template<typename T> |
| struct PointerParamStorageTraits<T*, true> { |
| typedef blink::CrossThreadPersistent<T> StorageType; |
| |
| 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> { |
| }; |
| |
| template<typename T> |
| struct ParamStorageTraits<RawPtr<T> > : public PointerParamStorageTraits<T*, blink::IsGarbageCollectedType<T>::value> { |
| }; |
| |
| } // namespace WTF |
| |
| #endif |