Commit 9af11a90 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

heap,wtf: Make FinalizerTrait a GC-internal concept

There's no particular reason FinalizerTrait needs to be overridable
for user code. The concepts that should be used are:
- T::FinalizeGarbageCollectedObject: Method that can dispatch
  finalization when virtual dtor is too expensive.
- WTF::ConditionalDestructor: Conditionally adding/removing dtor per
  type.

Bug: 1056170
Change-Id: I61ecef0392f4b1399b7311ff1b9acfeef18da2da
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2107593
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarOmer Katz <omerkatz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#761886}
parent 6d38faaf
...@@ -21,7 +21,6 @@ class Visitor; ...@@ -21,7 +21,6 @@ class Visitor;
using Address = uint8_t*; using Address = uint8_t*;
using ConstAddress = const uint8_t*; using ConstAddress = const uint8_t*;
using FinalizationCallback = void (*)(void*);
using VisitorCallback = void (*)(Visitor*, const void*); using VisitorCallback = void (*)(Visitor*, const void*);
using MarkingVisitorCallback = void (*)(MarkingVisitor*, const void*); using MarkingVisitorCallback = void (*)(MarkingVisitor*, const void*);
using TraceCallback = VisitorCallback; using TraceCallback = VisitorCallback;
......
...@@ -9,11 +9,15 @@ ...@@ -9,11 +9,15 @@
#include "third_party/blink/renderer/platform/heap/threading_traits.h" #include "third_party/blink/renderer/platform/heap/threading_traits.h"
#include "third_party/blink/renderer/platform/heap/trace_traits.h" #include "third_party/blink/renderer/platform/heap/trace_traits.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
namespace blink { namespace blink {
template <typename Table> template <typename Table>
class HeapHashTableBacking { class HeapHashTableBacking final
: public WTF::ConditionalDestructor<
HeapHashTableBacking<Table>,
std::is_trivially_destructible<typename Table::ValueType>::value> {
DISALLOW_NEW(); DISALLOW_NEW();
IS_GARBAGE_COLLECTED_TYPE(); IS_GARBAGE_COLLECTED_TYPE();
...@@ -21,8 +25,7 @@ class HeapHashTableBacking { ...@@ -21,8 +25,7 @@ class HeapHashTableBacking {
template <typename Backing> template <typename Backing>
static void* AllocateObject(size_t size); static void* AllocateObject(size_t size);
static void Finalize(void* pointer); void Finalize();
void FinalizeGarbageCollectedObject() { Finalize(this); }
}; };
template <typename Table> template <typename Table>
...@@ -51,16 +54,16 @@ void* HeapHashTableBacking<Table>::AllocateObject(size_t size) { ...@@ -51,16 +54,16 @@ void* HeapHashTableBacking<Table>::AllocateObject(size_t size) {
} }
template <typename Table> template <typename Table>
void HeapHashTableBacking<Table>::Finalize(void* pointer) { void HeapHashTableBacking<Table>::Finalize() {
using Value = typename Table::ValueType; using Value = typename Table::ValueType;
static_assert( static_assert(
!std::is_trivially_destructible<Value>::value, !std::is_trivially_destructible<Value>::value,
"Finalization of trivially destructible classes should not happen."); "Finalization of trivially destructible classes should not happen.");
HeapObjectHeader* header = HeapObjectHeader::FromPayload(pointer); HeapObjectHeader* header = HeapObjectHeader::FromPayload(this);
// Use the payload size as recorded by the heap to determine how many // Use the payload size as recorded by the heap to determine how many
// elements to finalize. // elements to finalize.
size_t length = header->PayloadSize() / sizeof(Value); size_t length = header->PayloadSize() / sizeof(Value);
Value* table = reinterpret_cast<Value*>(pointer); Value* table = reinterpret_cast<Value*>(this);
for (unsigned i = 0; i < length; ++i) { for (unsigned i = 0; i < length; ++i) {
if (!Table::IsEmptyOrDeletedBucket(table[i])) if (!Table::IsEmptyOrDeletedBucket(table[i]))
table[i].~Value(); table[i].~Value();
...@@ -83,17 +86,6 @@ struct MakeGarbageCollectedTrait<HeapHashTableBacking<Table>> { ...@@ -83,17 +86,6 @@ struct MakeGarbageCollectedTrait<HeapHashTableBacking<Table>> {
} }
}; };
template <typename Table>
struct FinalizerTrait<HeapHashTableBacking<Table>> {
STATIC_ONLY(FinalizerTrait);
static const bool kNonTrivialFinalizer =
!std::is_trivially_destructible<typename Table::ValueType>::value;
static void Finalize(void* obj) {
internal::FinalizerTraitImpl<HeapHashTableBacking<Table>,
kNonTrivialFinalizer>::Finalize(obj);
}
};
// The trace trait for the heap hashtable backing is used when we find a // The trace trait for the heap hashtable backing is used when we find a
// direct pointer to the backing from the conservative stack scanner. This // direct pointer to the backing from the conservative stack scanner. This
// normally indicates that there is an ongoing iteration over the table, and so // normally indicates that there is an ongoing iteration over the table, and so
......
...@@ -9,15 +9,19 @@ ...@@ -9,15 +9,19 @@
#include "third_party/blink/renderer/platform/heap/finalizer_traits.h" #include "third_party/blink/renderer/platform/heap/finalizer_traits.h"
#include "third_party/blink/renderer/platform/heap/gc_info.h" #include "third_party/blink/renderer/platform/heap/gc_info.h"
#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h" #include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/heap/threading_traits.h" #include "third_party/blink/renderer/platform/heap/threading_traits.h"
#include "third_party/blink/renderer/platform/heap/trace_traits.h" #include "third_party/blink/renderer/platform/heap/trace_traits.h"
#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
#include "third_party/blink/renderer/platform/wtf/vector.h" #include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink { namespace blink {
template <typename T, typename Traits = WTF::VectorTraits<T>> template <typename T, typename Traits = WTF::VectorTraits<T>>
class HeapVectorBacking final { class HeapVectorBacking final
: public WTF::ConditionalDestructor<HeapVectorBacking<T, Traits>,
!Traits::kNeedsDestruction> {
DISALLOW_NEW(); DISALLOW_NEW();
IS_GARBAGE_COLLECTED_TYPE(); IS_GARBAGE_COLLECTED_TYPE();
...@@ -33,12 +37,12 @@ class HeapVectorBacking final { ...@@ -33,12 +37,12 @@ class HeapVectorBacking final {
type_name); type_name);
} }
static void Finalize(void* pointer); // Conditionally invoked via destructor.
void FinalizeGarbageCollectedObject() { Finalize(this); } void Finalize();
}; };
template <typename T, typename Traits> template <typename T, typename Traits>
void HeapVectorBacking<T, Traits>::Finalize(void* pointer) { void HeapVectorBacking<T, Traits>::Finalize() {
static_assert(Traits::kNeedsDestruction, static_assert(Traits::kNeedsDestruction,
"Only vector buffers with items requiring destruction should " "Only vector buffers with items requiring destruction should "
"be finalized"); "be finalized");
...@@ -50,11 +54,11 @@ void HeapVectorBacking<T, Traits>::Finalize(void* pointer) { ...@@ -50,11 +54,11 @@ void HeapVectorBacking<T, Traits>::Finalize(void* pointer) {
static_assert( static_assert(
!std::is_trivially_destructible<T>::value, !std::is_trivially_destructible<T>::value,
"Finalization of trivially destructible classes should not happen."); "Finalization of trivially destructible classes should not happen.");
HeapObjectHeader* header = HeapObjectHeader::FromPayload(pointer); HeapObjectHeader* header = HeapObjectHeader::FromPayload(this);
// Use the payload size as recorded by the heap to determine how many // Use the payload size as recorded by the heap to determine how many
// elements to finalize. // elements to finalize.
size_t length = header->PayloadSize() / sizeof(T); size_t length = header->PayloadSize() / sizeof(T);
char* payload = static_cast<char*>(pointer); Address payload = header->Payload();
#ifdef ANNOTATE_CONTIGUOUS_CONTAINER #ifdef ANNOTATE_CONTIGUOUS_CONTAINER
ANNOTATE_CHANGE_SIZE(payload, length * sizeof(T), 0, length * sizeof(T)); ANNOTATE_CHANGE_SIZE(payload, length * sizeof(T), 0, length * sizeof(T));
#endif #endif
...@@ -62,7 +66,7 @@ void HeapVectorBacking<T, Traits>::Finalize(void* pointer) { ...@@ -62,7 +66,7 @@ void HeapVectorBacking<T, Traits>::Finalize(void* pointer) {
// (which are already zeroed out). // (which are already zeroed out).
if (std::is_polymorphic<T>::value) { if (std::is_polymorphic<T>::value) {
for (unsigned i = 0; i < length; ++i) { for (unsigned i = 0; i < length; ++i) {
char* element = payload + i * sizeof(T); Address element = payload + i * sizeof(T);
if (blink::VTableInitialized(element)) if (blink::VTableInitialized(element))
reinterpret_cast<T*>(element)->~T(); reinterpret_cast<T*>(element)->~T();
} }
...@@ -88,16 +92,6 @@ struct MakeGarbageCollectedTrait<HeapVectorBacking<T>> { ...@@ -88,16 +92,6 @@ struct MakeGarbageCollectedTrait<HeapVectorBacking<T>> {
} }
}; };
template <typename T, typename Traits>
struct FinalizerTrait<HeapVectorBacking<T, Traits>> {
STATIC_ONLY(FinalizerTrait);
static const bool kNonTrivialFinalizer = Traits::kNeedsDestruction;
static void Finalize(void* obj) {
internal::FinalizerTraitImpl<HeapVectorBacking<T, Traits>,
kNonTrivialFinalizer>::Finalize(obj);
}
};
template <typename T, typename Traits> template <typename T, typename Traits>
struct ThreadingTrait<HeapVectorBacking<T, Traits>> { struct ThreadingTrait<HeapVectorBacking<T, Traits>> {
STATIC_ONLY(ThreadingTrait); STATIC_ONLY(ThreadingTrait);
......
...@@ -8,19 +8,13 @@ ...@@ -8,19 +8,13 @@
#include <type_traits> #include <type_traits>
#include "base/template_util.h" #include "base/template_util.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace WTF {
template <typename ValueArg, typename Allocator>
class ListHashSetNode;
} // namespace WTF
namespace blink { namespace blink {
namespace internal { namespace internal {
using FinalizationCallback = void (*)(void*);
template <typename T, typename = void> template <typename T, typename = void>
struct HasFinalizeGarbageCollectedObject : std::false_type {}; struct HasFinalizeGarbageCollectedObject : std::false_type {};
...@@ -75,66 +69,27 @@ struct FinalizerTraitImpl<T, false> { ...@@ -75,66 +69,27 @@ struct FinalizerTraitImpl<T, false> {
} }
}; };
} // namespace internal
// The FinalizerTrait is used to determine if a type requires finalization and // The FinalizerTrait is used to determine if a type requires finalization and
// what finalization means. // what finalization means.
template <typename T> template <typename T>
struct FinalizerTrait { struct FinalizerTrait {
STATIC_ONLY(FinalizerTrait); STATIC_ONLY(FinalizerTrait);
private:
static constexpr bool kNonTrivialFinalizer = static constexpr bool kNonTrivialFinalizer =
internal::HasFinalizeGarbageCollectedObject<T>::value || internal::HasFinalizeGarbageCollectedObject<T>::value ||
!std::is_trivially_destructible<typename std::remove_cv<T>::type>::value; !std::is_trivially_destructible<typename std::remove_cv<T>::type>::value;
static void Finalize(void* obj) {
internal::FinalizerTraitImpl<T, kNonTrivialFinalizer>::Finalize(obj);
}
};
class HeapAllocator;
template <typename T, typename U, typename V>
struct FinalizerTrait<LinkedHashSet<T, U, V, HeapAllocator>> {
STATIC_ONLY(FinalizerTrait);
static constexpr bool kNonTrivialFinalizer = true;
static void Finalize(void* obj) {
internal::FinalizerTraitImpl<LinkedHashSet<T, U, V, HeapAllocator>,
kNonTrivialFinalizer>::Finalize(obj);
}
};
template <typename T, typename Allocator>
struct FinalizerTrait<WTF::ListHashSetNode<T, Allocator>> {
STATIC_ONLY(FinalizerTrait);
static constexpr bool kNonTrivialFinalizer =
!std::is_trivially_destructible<T>::value;
static void Finalize(void* obj) { static void Finalize(void* obj) {
internal::FinalizerTraitImpl<WTF::ListHashSetNode<T, Allocator>, internal::FinalizerTraitImpl<T, kNonTrivialFinalizer>::Finalize(obj);
kNonTrivialFinalizer>::Finalize(obj);
}
};
template <typename T, size_t inlineCapacity>
struct FinalizerTrait<Vector<T, inlineCapacity, HeapAllocator>> {
STATIC_ONLY(FinalizerTrait);
static constexpr bool kNonTrivialFinalizer =
inlineCapacity && VectorTraits<T>::kNeedsDestruction;
static void Finalize(void* obj) {
internal::FinalizerTraitImpl<Vector<T, inlineCapacity, HeapAllocator>,
kNonTrivialFinalizer>::Finalize(obj);
} }
};
template <typename T, size_t inlineCapacity> public:
struct FinalizerTrait<Deque<T, inlineCapacity, HeapAllocator>> { static constexpr FinalizationCallback kCallback =
STATIC_ONLY(FinalizerTrait); kNonTrivialFinalizer ? Finalize : nullptr;
static const bool kNonTrivialFinalizer =
inlineCapacity && VectorTraits<T>::kNeedsDestruction;
static void Finalize(void* obj) {
internal::FinalizerTraitImpl<Deque<T, inlineCapacity, HeapAllocator>,
kNonTrivialFinalizer>::Finalize(obj);
}
}; };
} // namespace internal
} // namespace blink } // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_FINALIZER_TRAITS_H_ #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_FINALIZER_TRAITS_H_
...@@ -7,8 +7,10 @@ ...@@ -7,8 +7,10 @@
#include <atomic> #include <atomic>
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "third_party/blink/renderer/platform/heap/blink_gc.h"
#include "third_party/blink/renderer/platform/heap/finalizer_traits.h" #include "third_party/blink/renderer/platform/heap/finalizer_traits.h"
#include "third_party/blink/renderer/platform/heap/name_traits.h" #include "third_party/blink/renderer/platform/heap/name_traits.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
namespace blink { namespace blink {
...@@ -23,7 +25,7 @@ struct PLATFORM_EXPORT GCInfo final { ...@@ -23,7 +25,7 @@ struct PLATFORM_EXPORT GCInfo final {
static inline const GCInfo& From(GCInfoIndex); static inline const GCInfo& From(GCInfoIndex);
const TraceCallback trace; const TraceCallback trace;
const FinalizationCallback finalize; const internal::FinalizationCallback finalize;
const NameCallback name; const NameCallback name;
const bool has_v_table; const bool has_v_table;
}; };
...@@ -102,9 +104,7 @@ struct GCInfoTrait { ...@@ -102,9 +104,7 @@ struct GCInfoTrait {
static GCInfoIndex Index() { static GCInfoIndex Index() {
static_assert(sizeof(T), "T must be fully defined"); static_assert(sizeof(T), "T must be fully defined");
static const GCInfo kGcInfo = { static const GCInfo kGcInfo = {
TraceTrait<T>::Trace, TraceTrait<T>::Trace, internal::FinalizerTrait<T>::kCallback,
FinalizerTrait<T>::kNonTrivialFinalizer ? FinalizerTrait<T>::Finalize
: nullptr,
NameTrait<T>::GetName, std::is_polymorphic<T>::value}; NameTrait<T>::GetName, std::is_polymorphic<T>::value};
// This is more complicated than using threadsafe initialization, but this // This is more complicated than using threadsafe initialization, but this
// is instantiated many times (once for every GC type). // is instantiated many times (once for every GC type).
......
...@@ -52,11 +52,15 @@ class DequeConstIterator; ...@@ -52,11 +52,15 @@ class DequeConstIterator;
template <typename T, template <typename T,
wtf_size_t inlineCapacity = 0, wtf_size_t inlineCapacity = 0,
typename Allocator = PartitionAllocator> typename Allocator = PartitionAllocator>
class Deque : public ConditionalDestructor<Deque<T, INLINE_CAPACITY, Allocator>, class Deque
(INLINE_CAPACITY == 0) && : public ConditionalDestructor<Deque<T, INLINE_CAPACITY, Allocator>,
Allocator::kIsGarbageCollected> { !VectorTraits<T>::kNeedsDestruction &&
Allocator::kIsGarbageCollected> {
USE_ALLOCATOR(Deque, Allocator); USE_ALLOCATOR(Deque, Allocator);
static_assert((inlineCapacity == 0) || !Allocator::kIsGarbageCollected,
"inlineCapacity not supported with garbage collection.");
public: public:
typedef DequeIterator<T, inlineCapacity, Allocator> iterator; typedef DequeIterator<T, inlineCapacity, Allocator> iterator;
typedef DequeConstIterator<T, inlineCapacity, Allocator> const_iterator; typedef DequeConstIterator<T, inlineCapacity, Allocator> const_iterator;
......
...@@ -262,11 +262,6 @@ class LinkedHashSet { ...@@ -262,11 +262,6 @@ class LinkedHashSet {
// Needs finalization. The anchor needs to unlink itself from the chain. // Needs finalization. The anchor needs to unlink itself from the chain.
~LinkedHashSet(); ~LinkedHashSet();
static void Finalize(void* pointer) {
reinterpret_cast<LinkedHashSet*>(pointer)->~LinkedHashSet();
}
void FinalizeGarbageCollectedObject() { Finalize(this); }
void Swap(LinkedHashSet&); void Swap(LinkedHashSet&);
unsigned size() const { return impl_.size(); } unsigned size() const { return impl_.size(); }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_LIST_HASH_SET_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_LIST_HASH_SET_H_
#include <memory> #include <memory>
#include <type_traits>
#include "third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h" #include "third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h"
#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h" #include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h"
...@@ -454,7 +455,19 @@ struct ListHashSetAllocator : public PartitionAllocator { ...@@ -454,7 +455,19 @@ struct ListHashSetAllocator : public PartitionAllocator {
}; };
template <typename ValueArg, typename AllocatorArg> template <typename ValueArg, typename AllocatorArg>
class ListHashSetNode : public ListHashSetNodeBase<ValueArg, AllocatorArg> { class ListHashSetNode
: public ListHashSetNodeBase<ValueArg, AllocatorArg>,
// Destruction handling:
// !AllocatorArg::kIsGarbageCollected (PartitionAlloc):
// - ListHashSet has destructor and manually destructs all nodes.
// - ListHashSetNode has no destructor.
// AllocatorArg::kIsGarbageCollected (Oilpan):
// - ListHashSet has no destructor.
// - ListHashSetNode has a destructor if it is not trivially destructible.
public ConditionalDestructor<
ListHashSetNode<ValueArg, AllocatorArg>,
!AllocatorArg::kIsGarbageCollected ||
std::is_trivially_destructible<ValueArg>::value> {
public: public:
typedef AllocatorArg NodeAllocator; typedef AllocatorArg NodeAllocator;
typedef ValueArg Value; typedef ValueArg Value;
...@@ -481,12 +494,12 @@ class ListHashSetNode : public ListHashSetNodeBase<ValueArg, AllocatorArg> { ...@@ -481,12 +494,12 @@ class ListHashSetNode : public ListHashSetNodeBase<ValueArg, AllocatorArg> {
return this->prev_ == UnlinkedNodePointer(); return this->prev_ == UnlinkedNodePointer();
} }
static void Finalize(void* pointer) { void Finalize() {
// No need to waste time calling finalize if it's not needed. // No need to waste time calling finalize if it's not needed.
static_assert( static_assert(
!std::is_trivially_destructible<ValueArg>::value, !std::is_trivially_destructible<ValueArg>::value,
"Finalization of trivially destructible classes should not happen."); "Finalization of trivially destructible classes should not happen.");
ListHashSetNode* self = reinterpret_cast_ptr<ListHashSetNode*>(pointer); ListHashSetNode* self = reinterpret_cast_ptr<ListHashSetNode*>(this);
// Check whether this node was already destructed before being unlinked // Check whether this node was already destructed before being unlinked
// from the collection. // from the collection.
...@@ -495,7 +508,6 @@ class ListHashSetNode : public ListHashSetNodeBase<ValueArg, AllocatorArg> { ...@@ -495,7 +508,6 @@ class ListHashSetNode : public ListHashSetNodeBase<ValueArg, AllocatorArg> {
self->value_.~ValueArg(); self->value_.~ValueArg();
} }
void FinalizeGarbageCollectedObject() { Finalize(this); }
void Destroy(NodeAllocator* allocator) { void Destroy(NodeAllocator* allocator) {
this->~ListHashSetNode(); this->~ListHashSetNode();
......
...@@ -1054,6 +1054,10 @@ class VectorBuffer : protected VectorBufferBase<T, Allocator> { ...@@ -1054,6 +1054,10 @@ class VectorBuffer : protected VectorBufferBase<T, Allocator> {
template <typename T, wtf_size_t inlineCapacity, typename Allocator> template <typename T, wtf_size_t inlineCapacity, typename Allocator>
class Vector class Vector
: private VectorBuffer<T, INLINE_CAPACITY, Allocator>, : private VectorBuffer<T, INLINE_CAPACITY, Allocator>,
// ConditionalDestructor could in addition check for
// VectorTraits<T>::kNeedsDestruction which requires that the complete
// type is available though. Unfortunately, there's some use cases that
// use Vector with foward-declared types.
public ConditionalDestructor<Vector<T, INLINE_CAPACITY, Allocator>, public ConditionalDestructor<Vector<T, INLINE_CAPACITY, Allocator>,
(INLINE_CAPACITY == 0) && (INLINE_CAPACITY == 0) &&
Allocator::kIsGarbageCollected> { Allocator::kIsGarbageCollected> {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment