// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_ #include "build/build_config.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap_buildflags.h" #include "third_party/blink/renderer/platform/heap/marking_visitor.h" #include "third_party/blink/renderer/platform/heap/trace_traits.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/construct_traits.h" #include "third_party/blink/renderer/platform/wtf/deque.h" #include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h" #include "third_party/blink/renderer/platform/wtf/hash_counted_set.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/hash_table.h" #include "third_party/blink/renderer/platform/wtf/linked_hash_set.h" #include "third_party/blink/renderer/platform/wtf/list_hash_set.h" #include "third_party/blink/renderer/platform/wtf/type_traits.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { template > class HeapVectorBacking { DISALLOW_NEW(); IS_GARBAGE_COLLECTED_TYPE(); public: static void Finalize(void* pointer); void FinalizeGarbageCollectedObject() { Finalize(this); } }; template class HeapHashTableBacking { DISALLOW_NEW(); IS_GARBAGE_COLLECTED_TYPE(); public: static void Finalize(void* pointer); void FinalizeGarbageCollectedObject() { Finalize(this); } }; // This is a static-only class used as a trait on collections to make them heap // allocated. However see also HeapListHashSetAllocator. class PLATFORM_EXPORT HeapAllocator { STATIC_ONLY(HeapAllocator); public: using Visitor = blink::Visitor; static constexpr bool kIsGarbageCollected = true; template static size_t MaxElementCountInBackingStore() { return kMaxHeapObjectSize / sizeof(T); } template static size_t QuantizedSize(size_t count) { CHECK(count <= MaxElementCountInBackingStore()); return ThreadHeap::AllocationSizeFromSize(count * sizeof(T)) - sizeof(HeapObjectHeader); } template static T* AllocateVectorBacking(size_t size) { ThreadState* state = ThreadStateFor::kAffinity>::GetState(); DCHECK(state->IsAllocationAllowed()); uint32_t gc_info_index = GCInfoTrait>::Index(); NormalPageArena* arena = static_cast( state->Heap().VectorBackingArena(gc_info_index)); return reinterpret_cast(arena->AllocateObject( ThreadHeap::AllocationSizeFromSize(size), gc_info_index)); } template static T* AllocateExpandedVectorBacking(size_t size) { ThreadState* state = ThreadStateFor::kAffinity>::GetState(); DCHECK(state->IsAllocationAllowed()); uint32_t gc_info_index = GCInfoTrait>::Index(); NormalPageArena* arena = static_cast( state->Heap().ExpandedVectorBackingArena(gc_info_index)); return reinterpret_cast(arena->AllocateObject( ThreadHeap::AllocationSizeFromSize(size), gc_info_index)); } static void FreeVectorBacking(void*); static bool ExpandVectorBacking(void*, size_t); static bool ShrinkVectorBacking(void* address, size_t quantized_current_size, size_t quantized_shrunk_size); template static T* AllocateInlineVectorBacking(size_t size) { uint32_t gc_info_index = GCInfoTrait>::Index(); ThreadState* state = ThreadStateFor::kAffinity>::GetState(); const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(HeapVectorBacking); return reinterpret_cast(state->Heap().AllocateOnArenaIndex( state, size, BlinkGC::kInlineVectorArenaIndex, gc_info_index, type_name)); } static void FreeInlineVectorBacking(void*); static bool ExpandInlineVectorBacking(void*, size_t); static bool ShrinkInlineVectorBacking(void* address, size_t quantized_current_size, size_t quantized_shrunk_size); template static T* AllocateHashTableBacking(size_t size) { uint32_t gc_info_index = GCInfoTrait>::Index(); ThreadState* state = ThreadStateFor::kAffinity>::GetState(); const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(HeapHashTableBacking); return reinterpret_cast(state->Heap().AllocateOnArenaIndex( state, size, BlinkGC::kHashTableArenaIndex, gc_info_index, type_name)); } template static T* AllocateZeroedHashTableBacking(size_t size) { return AllocateHashTableBacking(size); } static void FreeHashTableBacking(void* address); static bool ExpandHashTableBacking(void*, size_t); static void TraceMarkedBackingStore(void* address) { MarkingVisitor::TraceMarkedBackingStore(address); } static void BackingWriteBarrier(void* address) { MarkingVisitor::WriteBarrier(address); } template static void BackingWriteBarrier(TraceWrapperMember* address, size_t size) { MarkingVisitor::WriteBarrier(address); ScriptWrappableMarkingVisitor::WriteBarrier(address, size); } template static void BackingWriteBarrier(T* address, size_t size) { MarkingVisitor::WriteBarrier(address); } template static Return Malloc(size_t size, const char* type_name) { return reinterpret_cast(ThreadHeap::Allocate( size, IsEagerlyFinalizedType::value)); } // Compilers sometimes eagerly instantiates the unused 'operator delete', so // we provide a version that asserts and fails at run-time if used. static void Free(void*) { NOTREACHED(); } template static void* NewArray(size_t bytes) { NOTREACHED(); return nullptr; } static void DeleteArray(void* ptr) { NOTREACHED(); } static bool IsAllocationAllowed() { return ThreadState::Current()->IsAllocationAllowed(); } static bool IsObjectResurrectionForbidden() { return ThreadState::Current()->IsObjectResurrectionForbidden(); } static bool IsSweepForbidden() { return ThreadState::Current()->SweepForbidden(); } template static bool IsHeapObjectAlive(T* object) { return ThreadHeap::IsHeapObjectAlive(object); } template static void Trace(VisitorDispatcher visitor, T& t) { TraceCollectionIfEnabled::Trace( visitor, t); } template static bool RegisterWeakTable(VisitorDispatcher visitor, const void* closure, EphemeronCallback iteration_callback) { return visitor->RegisterWeakTable(closure, iteration_callback); } template static void RegisterBackingStoreCallback(VisitorDispatcher visitor, T** backing_store_slot, MovingObjectCallback callback, void* callback_data) { visitor->RegisterBackingStoreCallback( reinterpret_cast(backing_store_slot), callback, callback_data); } static void EnterGCForbiddenScope() { ThreadState::Current()->EnterGCForbiddenScope(); } static void LeaveGCForbiddenScope() { ThreadState::Current()->LeaveGCForbiddenScope(); } template static void NotifyNewObject(T* object) { #if BUILDFLAG(BLINK_HEAP_INCREMENTAL_MARKING) if (!ThreadState::IsAnyIncrementalMarking()) return; // The object may have been in-place constructed as part of a large object. // It is not safe to retrieve the page from the object here. ThreadState* const thread_state = ThreadState::Current(); if (thread_state->IsIncrementalMarking()) { // Eagerly trace the object ensuring that the object and all its children // are discovered by the marker. ThreadState::NoAllocationScope no_allocation_scope(thread_state); DCHECK(thread_state->CurrentVisitor()); // This check ensures that the visitor will not eagerly recurse into // children but rather push all blink::GarbageCollected objects and only // eagerly trace non-managed objects. DCHECK(!thread_state->Heap().GetStackFrameDepth().IsEnabled()); // No weak handling for write barriers. Modifying weakly reachable objects // strongifies them for the current cycle. DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*object)); TraceCollectionIfEnabled< WTF::kNoWeakHandling, T, Traits>::Trace(thread_state ->CurrentVisitor(), *object); } #endif // BUILDFLAG(BLINK_HEAP_INCREMENTAL_MARKING) } template static void NotifyNewObjects(T* array, size_t len) { #if BUILDFLAG(BLINK_HEAP_INCREMENTAL_MARKING) if (!ThreadState::IsAnyIncrementalMarking()) return; // The object may have been in-place constructed as part of a large object. // It is not safe to retrieve the page from the object here. ThreadState* const thread_state = ThreadState::Current(); if (thread_state->IsIncrementalMarking()) { // See |NotifyNewObject| for details. ThreadState::NoAllocationScope no_allocation_scope(thread_state); DCHECK(thread_state->CurrentVisitor()); DCHECK(!thread_state->Heap().GetStackFrameDepth().IsEnabled()); // No weak handling for write barriers. Modifying weakly reachable objects // strongifies them for the current cycle. while (len-- > 0) { DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*array)); TraceCollectionIfEnabled< WTF::kNoWeakHandling, T, Traits>::Trace(thread_state ->CurrentVisitor(), *array); array++; } } #endif // BUILDFLAG(BLINK_HEAP_INCREMENTAL_MARKING) } template static void TraceVectorBacking(Visitor* visitor, T* backing, T** backing_slot) { visitor->TraceBackingStoreStrongly( reinterpret_cast*>(backing), reinterpret_cast**>(backing_slot)); } template static void TraceHashTableBackingStrongly(Visitor* visitor, T* backing, T** backing_slot) { visitor->TraceBackingStoreStrongly( reinterpret_cast*>(backing), reinterpret_cast**>(backing_slot)); } template static void TraceHashTableBackingWeakly(Visitor* visitor, T* backing, T** backing_slot, WeakCallback callback, void* parameter) { visitor->TraceBackingStoreWeakly( reinterpret_cast*>(backing), reinterpret_cast**>(backing_slot), callback, parameter); } template static void TraceHashTableBackingOnly(Visitor* visitor, T* backing, T** backing_slot) { visitor->TraceBackingStoreOnly( reinterpret_cast*>(backing), reinterpret_cast**>(backing_slot)); } private: static void BackingFree(void*); static bool BackingExpand(void*, size_t); static bool BackingShrink(void*, size_t quantized_current_size, size_t quantized_shrunk_size); template friend class WTF::Vector; template friend class WTF::HashSet; template friend class WTF::HashMap; }; template static void TraceListHashSetValue(VisitorDispatcher visitor, Value& value) { // We use the default hash traits for the value in the node, because // ListHashSet does not let you specify any specific ones. // We don't allow ListHashSet of WeakMember, so we set that one false // (there's an assert elsewhere), but we have to specify some value for the // strongify template argument, so we specify WTF::WeakPointersActWeak, // arbitrarily. TraceCollectionIfEnabled>::Trace(visitor, value); } // The inline capacity is just a dummy template argument to match the off-heap // allocator. // This inherits from the static-only HeapAllocator trait class, but we do // declare pointers to instances. These pointers are always null, and no // objects are instantiated. template class HeapListHashSetAllocator : public HeapAllocator { DISALLOW_NEW(); public: using TableAllocator = HeapAllocator; using Node = WTF::ListHashSetNode; class AllocatorProvider { DISALLOW_NEW(); public: // For the heap allocation we don't need an actual allocator object, so // we just return null. HeapListHashSetAllocator* Get() const { return nullptr; } // No allocator object is needed. void CreateAllocatorIfNeeded() {} void ReleaseAllocator() {} // There is no allocator object in the HeapListHashSet (unlike in the // regular ListHashSet) so there is nothing to swap. void Swap(AllocatorProvider& other) {} }; void Deallocate(void* dummy) {} // This is not a static method even though it could be, because it needs to // match the one that the (off-heap) ListHashSetAllocator has. The 'this' // pointer will always be null. void* AllocateNode() { // Consider using a LinkedHashSet instead if this compile-time assert fails: static_assert(!WTF::IsWeak::value, "weak pointers in a ListHashSet will result in null entries " "in the set"); return Malloc( sizeof(Node), nullptr /* Oilpan does not use the heap profiler at the moment. */); } template static void TraceValue(VisitorDispatcher visitor, Node* node) { TraceListHashSetValue(visitor, node->value_); } }; template void HeapVectorBacking::Finalize(void* pointer) { static_assert(Traits::kNeedsDestruction, "Only vector buffers with items requiring destruction should " "be finalized"); // See the comment in HeapVectorBacking::trace. static_assert( Traits::kCanClearUnusedSlotsWithMemset || std::is_polymorphic::value, "HeapVectorBacking doesn't support objects that cannot be cleared as " "unused with memset or don't have a vtable"); static_assert( !std::is_trivially_destructible::value, "Finalization of trivially destructible classes should not happen."); HeapObjectHeader* header = HeapObjectHeader::FromPayload(pointer); // Use the payload size as recorded by the heap to determine how many // elements to finalize. size_t length = header->PayloadSize() / sizeof(T); char* payload = static_cast(pointer); #ifdef ANNOTATE_CONTIGUOUS_CONTAINER ANNOTATE_CHANGE_SIZE(payload, length * sizeof(T), 0, length * sizeof(T)); #endif // As commented above, HeapVectorBacking calls finalizers for unused slots // (which are already zeroed out). if (std::is_polymorphic::value) { for (unsigned i = 0; i < length; ++i) { char* element = payload + i * sizeof(T); if (blink::VTableInitialized(element)) reinterpret_cast(element)->~T(); } } else { T* buffer = reinterpret_cast(payload); for (unsigned i = 0; i < length; ++i) buffer[i].~T(); } } template void HeapHashTableBacking::Finalize(void* pointer) { using Value = typename Table::ValueType; static_assert( !std::is_trivially_destructible::value, "Finalization of trivially destructible classes should not happen."); HeapObjectHeader* header = HeapObjectHeader::FromPayload(pointer); // Use the payload size as recorded by the heap to determine how many // elements to finalize. size_t length = header->PayloadSize() / sizeof(Value); Value* table = reinterpret_cast(pointer); for (unsigned i = 0; i < length; ++i) { if (!Table::IsEmptyOrDeletedBucket(table[i])) table[i].~Value(); } } template ::Hash, typename KeyTraitsArg = HashTraits, typename MappedTraitsArg = HashTraits> class HeapHashMap : public HashMap { IS_GARBAGE_COLLECTED_TYPE(); using Base = HashMap; static_assert(WTF::IsTraceable::value || WTF::IsTraceable::value, "For hash maps without traceable elements, use HashMap<> " "instead of HeapHashMap<>"); public: static void* AllocateObject(size_t size, bool eagerly_sweep) { return ThreadHeap::Allocate< HeapHashMap>( size, eagerly_sweep); } void* operator new(size_t size) = delete; void operator delete(void* p) = delete; void* operator new[](size_t size) = delete; void operator delete[](void* p) = delete; void* operator new(size_t size, NotNullTag null_tag, void* location) { return Base::operator new(size, null_tag, location); } void* operator new(size_t size, void* location) { return Base::operator new(size, location); } }; template ::Hash, typename TraitsArg = HashTraits> class HeapHashSet : public HashSet { IS_GARBAGE_COLLECTED_TYPE(); using Base = HashSet; static_assert(WTF::IsTraceable::value, "For hash sets without traceable elements, use HashSet<> " "instead of HeapHashSet<>"); public: static void* AllocateObject(size_t size, bool eagerly_sweep) { return ThreadHeap::Allocate>( size, eagerly_sweep); } void* operator new(size_t size) = delete; void operator delete(void* p) = delete; void* operator new[](size_t size) = delete; void operator delete[](void* p) = delete; void* operator new(size_t size, NotNullTag null_tag, void* location) { return Base::operator new(size, null_tag, location); } void* operator new(size_t size, void* location) { return Base::operator new(size, location); } }; template ::Hash, typename TraitsArg = HashTraits> class HeapLinkedHashSet : public LinkedHashSet { IS_GARBAGE_COLLECTED_TYPE(); using Base = LinkedHashSet; static_assert(WTF::IsTraceable::value, "For sets without traceable elements, use LinkedHashSet<> " "instead of HeapLinkedHashSet<>"); public: static void* AllocateObject(size_t size, bool eagerly_sweep) { return ThreadHeap::Allocate< HeapLinkedHashSet>(size, eagerly_sweep); } void* operator new(size_t size) = delete; void operator delete(void* p) = delete; void* operator new[](size_t size) = delete; void operator delete[](void* p) = delete; void* operator new(size_t size, NotNullTag null_tag, void* location) { return Base::operator new(size, null_tag, location); } void* operator new(size_t size, void* location) { return Base::operator new(size, location); } }; template ::Hash> class HeapListHashSet : public ListHashSet> { IS_GARBAGE_COLLECTED_TYPE(); using Base = ListHashSet; static_assert(WTF::IsTraceable::value, "For sets without traceable elements, use ListHashSet<> " "instead of HeapListHashSet<>"); public: static void* AllocateObject(size_t size, bool eagerly_sweep) { return ThreadHeap::Allocate< HeapListHashSet>(size, eagerly_sweep); } void* operator new(size_t size) = delete; void operator delete(void* p) = delete; void* operator new[](size_t size) = delete; void operator delete[](void* p) = delete; void* operator new(size_t size, NotNullTag null_tag, void* location) { return Base::operator new(size, null_tag, location); } void* operator new(size_t size, void* location) { return Base::operator new(size, location); } }; template ::Hash, typename Traits = HashTraits> class HeapHashCountedSet : public HashCountedSet { IS_GARBAGE_COLLECTED_TYPE(); static_assert(WTF::IsTraceable::value, "For counted sets without traceable elements, use " "HashCountedSet<> instead of HeapHashCountedSet<>"); }; template class HeapVector : public Vector { IS_GARBAGE_COLLECTED_TYPE(); using Base = Vector; public: HeapVector() { static_assert(WTF::IsTraceable::value, "For vectors without traceable elements, use Vector<> " "instead of HeapVector<>"); } static void* AllocateObject(size_t size, bool eagerly_sweep) { // On-heap HeapVectors generally should not have inline capacity, but it is // hard to avoid when using a type alias. Hence we only disallow the // VectorTraits::kNeedsDestruction case for now. static_assert(inlineCapacity == 0 || !VectorTraits::kNeedsDestruction, "on-heap HeapVector<> should not have an inline capacity"); return ThreadHeap::Allocate>(size, eagerly_sweep); } void* operator new(size_t size) = delete; void operator delete(void* p) = delete; void* operator new[](size_t size) = delete; void operator delete[](void* p) = delete; void* operator new(size_t size, NotNullTag null_tag, void* location) { return Base::operator new(size, null_tag, location); } void* operator new(size_t size, void* location) { return Base::operator new(size, location); } explicit HeapVector(wtf_size_t size) : Vector(size) {} HeapVector(wtf_size_t size, const T& val) : Vector(size, val) {} template HeapVector(const HeapVector& other) : Vector(other) {} }; template class HeapDeque : public Deque { IS_GARBAGE_COLLECTED_TYPE(); using Base = Deque; public: HeapDeque() { static_assert(WTF::IsTraceable::value, "For vectors without traceable elements, use Deque<> instead " "of HeapDeque<>"); } static void* AllocateObject(size_t size, bool eagerly_sweep) { // On-heap HeapDeques generally should not have inline capacity, but it is // hard to avoid when using a type alias. Hence we only disallow the // VectorTraits::kNeedsDestruction case for now. static_assert(inlineCapacity == 0 || !VectorTraits::kNeedsDestruction, "on-heap HeapDeque<> should not have an inline capacity"); return ThreadHeap::Allocate>(size, eagerly_sweep); } void* operator new(size_t size) = delete; void operator delete(void* p) = delete; void* operator new[](size_t size) = delete; void operator delete[](void* p) = delete; void* operator new(size_t size, NotNullTag null_tag, void* location) { return Base::operator new(size, null_tag, location); } void* operator new(size_t size, void* location) { return Base::operator new(size, location); } explicit HeapDeque(wtf_size_t size) : Deque(size) {} HeapDeque(wtf_size_t size, const T& val) : Deque(size, val) {} HeapDeque& operator=(const HeapDeque& other) { HeapDeque copy(other); Deque::Swap(copy); return *this; } template HeapDeque(const HeapDeque& other) : Deque(other) {} }; template class HeapDoublyLinkedList : public DoublyLinkedList> { IS_GARBAGE_COLLECTED_TYPE(); DISALLOW_NEW(); public: HeapDoublyLinkedList() { static_assert(WTF::IsGarbageCollectedType::value, "This should only be used for garbage collected types."); } void Trace(Visitor* visitor) { visitor->Trace(this->head_); visitor->Trace(this->tail_); } }; } // namespace blink namespace WTF { template struct VectorTraits> : VectorTraitsBase> { STATIC_ONLY(VectorTraits); static const bool kNeedsDestruction = false; static const bool kCanInitializeWithMemset = true; static const bool kCanClearUnusedSlotsWithMemset = true; static const bool kCanCopyWithMemcpy = true; static const bool kCanMoveWithMemcpy = true; }; template struct VectorTraits> : VectorTraitsBase> { STATIC_ONLY(VectorTraits); static const bool kNeedsDestruction = false; static const bool kCanInitializeWithMemset = true; static const bool kCanClearUnusedSlotsWithMemset = true; static const bool kCanMoveWithMemcpy = true; static const bool kCanSwapUsingCopyOrMove = false; }; template struct VectorTraits> : VectorTraitsBase> { STATIC_ONLY(VectorTraits); static const bool kNeedsDestruction = false; static const bool kCanInitializeWithMemset = true; static const bool kCanClearUnusedSlotsWithMemset = true; static const bool kCanMoveWithMemcpy = true; static const bool kCanCopyWithMemcpy = true; static const bool kCanSwapUsingCopyOrMove = true; }; template struct VectorTraits> : VectorTraitsBase> { STATIC_ONLY(VectorTraits); static const bool kNeedsDestruction = false; static const bool kCanInitializeWithMemset = true; static const bool kCanClearUnusedSlotsWithMemset = true; static const bool kCanMoveWithMemcpy = true; }; template struct VectorTraits> : VectorTraitsBase> { STATIC_ONLY(VectorTraits); static const bool kNeedsDestruction = false; static const bool kCanInitializeWithMemset = true; static const bool kCanClearUnusedSlotsWithMemset = true; static const bool kCanMoveWithMemcpy = true; }; template struct VectorTraits> : VectorTraitsBase> { STATIC_ONLY(VectorTraits); static const bool kNeedsDestruction = false; static const bool kCanInitializeWithMemset = true; static const bool kCanClearUnusedSlotsWithMemset = true; static const bool kCanMoveWithMemcpy = true; }; template struct VectorTraits> : VectorTraitsBase> { STATIC_ONLY(VectorTraits); static const bool kNeedsDestruction = false; static const bool kCanInitializeWithMemset = true; static const bool kCanClearUnusedSlotsWithMemset = true; static const bool kCanMoveWithMemcpy = true; }; template struct VectorTraits> : VectorTraitsBase> { STATIC_ONLY(VectorTraits); static const bool kNeedsDestruction = VectorTraits::kNeedsDestruction; static const bool kCanInitializeWithMemset = VectorTraits::kCanInitializeWithMemset; static const bool kCanClearUnusedSlotsWithMemset = VectorTraits::kCanClearUnusedSlotsWithMemset; static const bool kCanMoveWithMemcpy = VectorTraits::kCanMoveWithMemcpy; }; template struct VectorTraits> : VectorTraitsBase> { STATIC_ONLY(VectorTraits); static const bool kNeedsDestruction = VectorTraits::kNeedsDestruction; static const bool kCanInitializeWithMemset = VectorTraits::kCanInitializeWithMemset; static const bool kCanClearUnusedSlotsWithMemset = VectorTraits::kCanClearUnusedSlotsWithMemset; static const bool kCanMoveWithMemcpy = VectorTraits::kCanMoveWithMemcpy; }; template struct HashTraits> : SimpleClassHashTraits> { STATIC_ONLY(HashTraits); // FIXME: Implement proper const'ness for iterator types. Requires support // in the marking Visitor. using PeekInType = T*; using IteratorGetType = blink::Member*; using IteratorConstGetType = const blink::Member*; using IteratorReferenceType = blink::Member&; using IteratorConstReferenceType = const blink::Member&; static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { return *x; } static IteratorConstReferenceType GetToReferenceConstConversion( IteratorConstGetType x) { return *x; } using PeekOutType = T*; template static void Store(const U& value, blink::Member& storage) { storage = value; } static PeekOutType Peek(const blink::Member& value) { return value; } static void ConstructDeletedValue(blink::Member& slot, bool) { slot = WTF::kHashTableDeletedValue; } static bool IsDeletedValue(const blink::Member& value) { return value.IsHashTableDeletedValue(); } }; template struct HashTraits> : SimpleClassHashTraits> { STATIC_ONLY(HashTraits); // FIXME: Implement proper const'ness for iterator types. Requires support // in the marking Visitor. using PeekInType = T*; using IteratorGetType = blink::SameThreadCheckedMember*; using IteratorConstGetType = const blink::SameThreadCheckedMember*; using IteratorReferenceType = blink::SameThreadCheckedMember&; using IteratorConstReferenceType = const blink::SameThreadCheckedMember&; static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { return *x; } static IteratorConstReferenceType GetToReferenceConstConversion( IteratorConstGetType x) { return *x; } using PeekOutType = T*; template static void Store(const U& value, blink::SameThreadCheckedMember& storage) { storage = value; } static PeekOutType Peek(const blink::SameThreadCheckedMember& value) { return value; } static blink::SameThreadCheckedMember EmptyValue() { return blink::SameThreadCheckedMember(nullptr, nullptr); } }; template struct HashTraits> : SimpleClassHashTraits> { STATIC_ONLY(HashTraits); // FIXME: Implement proper const'ness for iterator types. Requires support // in the marking Visitor. using PeekInType = T*; using IteratorGetType = blink::TraceWrapperMember*; using IteratorConstGetType = const blink::TraceWrapperMember*; using IteratorReferenceType = blink::TraceWrapperMember&; using IteratorConstReferenceType = const blink::TraceWrapperMember&; static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { return *x; } static IteratorConstReferenceType GetToReferenceConstConversion( IteratorConstGetType x) { return *x; } using PeekOutType = T*; template static void Store(const U& value, blink::TraceWrapperMember& storage) { storage = value; } static PeekOutType Peek(const blink::TraceWrapperMember& value) { return value; } static blink::TraceWrapperMember EmptyValue() { return nullptr; } }; template struct HashTraits> : SimpleClassHashTraits> { STATIC_ONLY(HashTraits); static const bool kNeedsDestruction = false; // FIXME: Implement proper const'ness for iterator types. Requires support // in the marking Visitor. using PeekInType = T*; using IteratorGetType = blink::WeakMember*; using IteratorConstGetType = const blink::WeakMember*; using IteratorReferenceType = blink::WeakMember&; using IteratorConstReferenceType = const blink::WeakMember&; static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { return *x; } static IteratorConstReferenceType GetToReferenceConstConversion( IteratorConstGetType x) { return *x; } using PeekOutType = T*; template static void Store(const U& value, blink::WeakMember& storage) { storage = value; } static PeekOutType Peek(const blink::WeakMember& value) { return value; } static bool IsAlive(blink::WeakMember& weak_member) { return blink::ThreadHeap::IsHeapObjectAlive(weak_member); } template static bool TraceInCollection(VisitorDispatcher visitor, blink::WeakMember& weak_member, WeakHandlingFlag weakness) { if (weakness == kNoWeakHandling) { visitor->Trace(weak_member.Get()); // Strongified visit. return false; } return !blink::ThreadHeap::IsHeapObjectAlive(weak_member); } }; template struct HashTraits> : SimpleClassHashTraits> { STATIC_ONLY(HashTraits); static const bool kNeedsDestruction = false; // FIXME: Implement proper const'ness for iterator types. using PeekInType = T*; using IteratorGetType = blink::UntracedMember*; using IteratorConstGetType = const blink::UntracedMember*; using IteratorReferenceType = blink::UntracedMember&; using IteratorConstReferenceType = const blink::UntracedMember&; static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { return *x; } static IteratorConstReferenceType GetToReferenceConstConversion( IteratorConstGetType x) { return *x; } using PeekOutType = T*; template static void Store(const U& value, blink::UntracedMember& storage) { storage = value; } static PeekOutType Peek(const blink::UntracedMember& value) { return value; } }; template struct IsTraceable< ListHashSetNode>*> { STATIC_ONLY(IsTraceable); 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; }; template struct IsGarbageCollectedType< ListHashSetNode>> { static const bool value = true; }; template struct IsGarbageCollectedType> { static const bool value = IsGarbageCollectedType::value; }; template struct IsGarbageCollectedType> { static const bool value = IsGarbageCollectedType::value; }; template struct IsGarbageCollectedType> { static const bool value = IsGarbageCollectedType::value; }; template struct IsGarbageCollectedType> { static const bool value = IsGarbageCollectedType::value; }; template struct HandleHashTraits : SimpleClassHashTraits { STATIC_ONLY(HandleHashTraits); // TODO: Implement proper const'ness for iterator types. Requires support // in the marking Visitor. using PeekInType = T*; using IteratorGetType = H*; using IteratorConstGetType = const H*; using IteratorReferenceType = H&; using IteratorConstReferenceType = const H&; static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { return *x; } static IteratorConstReferenceType GetToReferenceConstConversion( IteratorConstGetType x) { return *x; } using PeekOutType = T*; template static void Store(const U& value, H& storage) { storage = value; } static PeekOutType Peek(const H& value) { return value; } }; template inline void CopyToVector( const blink::HeapHashCountedSet& set, VectorType& vector) { CopyToVector(static_cast&>(set), vector); } } // namespace WTF #endif