Commit f35a483b authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

heap: Fix collections initializations

- Fix various operator new invocations.
- Disallow nesting of HeapLinkedHashSet which depends on the fact that
  the collection itself does not move.

Change-Id: I37978a0ea226ab40227caaff0246e3c70f47b022
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1660556
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#669582}
parent e3314ef9
...@@ -22,7 +22,7 @@ namespace { ...@@ -22,7 +22,7 @@ namespace {
using ActiveScrollTimelineSet = HeapHashCountedSet<WeakMember<Node>>; using ActiveScrollTimelineSet = HeapHashCountedSet<WeakMember<Node>>;
ActiveScrollTimelineSet& GetActiveScrollTimelineSet() { ActiveScrollTimelineSet& GetActiveScrollTimelineSet() {
DEFINE_STATIC_LOCAL(Persistent<ActiveScrollTimelineSet>, set, DEFINE_STATIC_LOCAL(Persistent<ActiveScrollTimelineSet>, set,
(new ActiveScrollTimelineSet)); (MakeGarbageCollected<ActiveScrollTimelineSet>()));
return *set; return *set;
} }
......
...@@ -131,14 +131,15 @@ using DOMWindowSet = HeapHashCountedSet<WeakMember<LocalDOMWindow>>; ...@@ -131,14 +131,15 @@ using DOMWindowSet = HeapHashCountedSet<WeakMember<LocalDOMWindow>>;
static DOMWindowSet& WindowsWithUnloadEventListeners() { static DOMWindowSet& WindowsWithUnloadEventListeners() {
DEFINE_STATIC_LOCAL(Persistent<DOMWindowSet>, DEFINE_STATIC_LOCAL(Persistent<DOMWindowSet>,
windows_with_unload_event_listeners, (new DOMWindowSet)); windows_with_unload_event_listeners,
(MakeGarbageCollected<DOMWindowSet>()));
return *windows_with_unload_event_listeners; return *windows_with_unload_event_listeners;
} }
static DOMWindowSet& WindowsWithBeforeUnloadEventListeners() { static DOMWindowSet& WindowsWithBeforeUnloadEventListeners() {
DEFINE_STATIC_LOCAL(Persistent<DOMWindowSet>, DEFINE_STATIC_LOCAL(Persistent<DOMWindowSet>,
windows_with_before_unload_event_listeners, windows_with_before_unload_event_listeners,
(new DOMWindowSet)); (MakeGarbageCollected<DOMWindowSet>()));
return *windows_with_before_unload_event_listeners; return *windows_with_before_unload_event_listeners;
} }
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
#include <type_traits>
#include "build/build_config.h" #include "build/build_config.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_buildflags.h" #include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
...@@ -27,6 +29,22 @@ ...@@ -27,6 +29,22 @@
namespace blink { namespace blink {
#define DISALLOW_IN_CONTAINER() \
public: \
using IsDisallowedInContainerMarker = int; \
\
private: \
friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
// IsAllowedInContainer returns true if some type T supports being nested
// arbitrarily in other containers. This is relevant for collections where some
// collections assume that they are placed on a non-moving arena.
template <typename T, typename = int>
struct IsAllowedInContainer : std::true_type {};
template <typename T>
struct IsAllowedInContainer<T, typename T::IsDisallowedInContainerMarker>
: std::false_type {};
template <typename T, typename Traits = WTF::VectorTraits<T>> template <typename T, typename Traits = WTF::VectorTraits<T>>
class HeapVectorBacking { class HeapVectorBacking {
DISALLOW_NEW(); DISALLOW_NEW();
...@@ -457,12 +475,20 @@ class HeapHashMap : public HashMap<KeyArg, ...@@ -457,12 +475,20 @@ class HeapHashMap : public HashMap<KeyArg,
MappedTraitsArg, MappedTraitsArg,
HeapAllocator> { HeapAllocator> {
IS_GARBAGE_COLLECTED_TYPE(); IS_GARBAGE_COLLECTED_TYPE();
using Base = DISALLOW_NEW();
HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>;
static_assert(WTF::IsTraceable<KeyArg>::value || static void CheckType() {
WTF::IsTraceable<MappedArg>::value, static_assert(
"For hash maps without traceable elements, use HashMap<> " IsAllowedInContainer<KeyArg>::value,
"instead of HeapHashMap<>"); "Not allowed to directly nest type. Use Member<> indirection instead.");
static_assert(
IsAllowedInContainer<MappedArg>::value,
"Not allowed to directly nest type. Use Member<> indirection instead.");
static_assert(
WTF::IsTraceable<KeyArg>::value || WTF::IsTraceable<MappedArg>::value,
"For hash maps without traceable elements, use HashMap<> "
"instead of HeapHashMap<>");
}
public: public:
static void* AllocateObject(size_t size, bool eagerly_sweep) { static void* AllocateObject(size_t size, bool eagerly_sweep) {
...@@ -471,16 +497,7 @@ class HeapHashMap : public HashMap<KeyArg, ...@@ -471,16 +497,7 @@ class HeapHashMap : public HashMap<KeyArg,
size, eagerly_sweep); size, eagerly_sweep);
} }
void* operator new(size_t size) = delete; HeapHashMap() { CheckType(); }
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 <typename ValueArg, template <typename ValueArg,
...@@ -489,10 +506,16 @@ template <typename ValueArg, ...@@ -489,10 +506,16 @@ template <typename ValueArg,
class HeapHashSet class HeapHashSet
: public HashSet<ValueArg, HashArg, TraitsArg, HeapAllocator> { : public HashSet<ValueArg, HashArg, TraitsArg, HeapAllocator> {
IS_GARBAGE_COLLECTED_TYPE(); IS_GARBAGE_COLLECTED_TYPE();
using Base = HashSet<ValueArg, HashArg, TraitsArg>; DISALLOW_NEW();
static_assert(WTF::IsTraceable<ValueArg>::value,
"For hash sets without traceable elements, use HashSet<> " static void CheckType() {
"instead of HeapHashSet<>"); static_assert(
IsAllowedInContainer<ValueArg>::value,
"Not allowed to directly nest type. Use Member<> indirection instead.");
static_assert(WTF::IsTraceable<ValueArg>::value,
"For hash sets without traceable elements, use HashSet<> "
"instead of HeapHashSet<>");
}
public: public:
static void* AllocateObject(size_t size, bool eagerly_sweep) { static void* AllocateObject(size_t size, bool eagerly_sweep) {
...@@ -500,16 +523,7 @@ class HeapHashSet ...@@ -500,16 +523,7 @@ class HeapHashSet
size, eagerly_sweep); size, eagerly_sweep);
} }
void* operator new(size_t size) = delete; HeapHashSet() { CheckType(); }
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 <typename ValueArg, template <typename ValueArg,
...@@ -518,10 +532,19 @@ template <typename ValueArg, ...@@ -518,10 +532,19 @@ template <typename ValueArg,
class HeapLinkedHashSet class HeapLinkedHashSet
: public LinkedHashSet<ValueArg, HashArg, TraitsArg, HeapAllocator> { : public LinkedHashSet<ValueArg, HashArg, TraitsArg, HeapAllocator> {
IS_GARBAGE_COLLECTED_TYPE(); IS_GARBAGE_COLLECTED_TYPE();
using Base = LinkedHashSet<ValueArg, HashArg, TraitsArg>; DISALLOW_NEW();
static_assert(WTF::IsTraceable<ValueArg>::value, // HeapLinkedHashSet is using custom callbacks for compaction that rely on the
"For sets without traceable elements, use LinkedHashSet<> " // fact that the container itself does not move.
"instead of HeapLinkedHashSet<>"); DISALLOW_IN_CONTAINER();
static void CheckType() {
static_assert(
IsAllowedInContainer<ValueArg>::value,
"Not allowed to directly nest type. Use Member<> indirection instead.");
static_assert(WTF::IsTraceable<ValueArg>::value,
"For sets without traceable elements, use LinkedHashSet<> "
"instead of HeapLinkedHashSet<>");
}
public: public:
static void* AllocateObject(size_t size, bool eagerly_sweep) { static void* AllocateObject(size_t size, bool eagerly_sweep) {
...@@ -529,16 +552,7 @@ class HeapLinkedHashSet ...@@ -529,16 +552,7 @@ class HeapLinkedHashSet
HeapLinkedHashSet<ValueArg, HashArg, TraitsArg>>(size, eagerly_sweep); HeapLinkedHashSet<ValueArg, HashArg, TraitsArg>>(size, eagerly_sweep);
} }
void* operator new(size_t size) = delete; HeapLinkedHashSet() { CheckType(); }
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 <typename ValueArg, template <typename ValueArg,
...@@ -552,10 +566,16 @@ class HeapListHashSet ...@@ -552,10 +566,16 @@ class HeapListHashSet
HashArg, HashArg,
HeapListHashSetAllocator<ValueArg, inlineCapacity>> { HeapListHashSetAllocator<ValueArg, inlineCapacity>> {
IS_GARBAGE_COLLECTED_TYPE(); IS_GARBAGE_COLLECTED_TYPE();
using Base = ListHashSet<ValueArg, inlineCapacity, HashArg>; DISALLOW_NEW();
static_assert(WTF::IsTraceable<ValueArg>::value,
"For sets without traceable elements, use ListHashSet<> " static void CheckType() {
"instead of HeapListHashSet<>"); static_assert(
IsAllowedInContainer<ValueArg>::value,
"Not allowed to directly nest type. Use Member<> indirection instead.");
static_assert(WTF::IsTraceable<ValueArg>::value,
"For sets without traceable elements, use ListHashSet<> "
"instead of HeapListHashSet<>");
}
public: public:
static void* AllocateObject(size_t size, bool eagerly_sweep) { static void* AllocateObject(size_t size, bool eagerly_sweep) {
...@@ -564,16 +584,7 @@ class HeapListHashSet ...@@ -564,16 +584,7 @@ class HeapListHashSet
eagerly_sweep); eagerly_sweep);
} }
void* operator new(size_t size) = delete; HeapListHashSet() { CheckType(); }
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 <typename Value, template <typename Value,
...@@ -582,23 +593,41 @@ template <typename Value, ...@@ -582,23 +593,41 @@ template <typename Value,
class HeapHashCountedSet class HeapHashCountedSet
: public HashCountedSet<Value, HashFunctions, Traits, HeapAllocator> { : public HashCountedSet<Value, HashFunctions, Traits, HeapAllocator> {
IS_GARBAGE_COLLECTED_TYPE(); IS_GARBAGE_COLLECTED_TYPE();
static_assert(WTF::IsTraceable<Value>::value, DISALLOW_NEW();
"For counted sets without traceable elements, use "
"HashCountedSet<> instead of HeapHashCountedSet<>"); static void CheckType() {
static_assert(
IsAllowedInContainer<Value>::value,
"Not allowed to directly nest type. Use Member<> indirection instead.");
static_assert(WTF::IsTraceable<Value>::value,
"For counted sets without traceable elements, use "
"HashCountedSet<> instead of HeapHashCountedSet<>");
}
public:
static void* AllocateObject(size_t size, bool eagerly_sweep) {
return ThreadHeap::Allocate<
HeapHashCountedSet<Value, HashFunctions, Traits>>(size, eagerly_sweep);
}
HeapHashCountedSet() { CheckType(); }
}; };
template <typename T, wtf_size_t inlineCapacity = 0> template <typename T, wtf_size_t inlineCapacity = 0>
class HeapVector : public Vector<T, inlineCapacity, HeapAllocator> { class HeapVector : public Vector<T, inlineCapacity, HeapAllocator> {
IS_GARBAGE_COLLECTED_TYPE(); IS_GARBAGE_COLLECTED_TYPE();
using Base = Vector<T, inlineCapacity, HeapAllocator>; DISALLOW_NEW();
public: static void CheckType() {
HeapVector() { static_assert(
IsAllowedInContainer<T>::value,
"Not allowed to directly nest type. Use Member<> indirection instead.");
static_assert(WTF::IsTraceable<T>::value, static_assert(WTF::IsTraceable<T>::value,
"For vectors without traceable elements, use Vector<> " "For vectors without traceable elements, use Vector<> "
"instead of HeapVector<>"); "instead of HeapVector<>");
} }
public:
static void* AllocateObject(size_t size, bool eagerly_sweep) { static void* AllocateObject(size_t size, bool eagerly_sweep) {
// On-heap HeapVectors generally should not have inline capacity, but it is // 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 // hard to avoid when using a type alias. Hence we only disallow the
...@@ -609,43 +638,45 @@ class HeapVector : public Vector<T, inlineCapacity, HeapAllocator> { ...@@ -609,43 +638,45 @@ class HeapVector : public Vector<T, inlineCapacity, HeapAllocator> {
eagerly_sweep); eagerly_sweep);
} }
void* operator new(size_t size) = delete; HeapVector() { CheckType(); }
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) explicit HeapVector(wtf_size_t size)
: Vector<T, inlineCapacity, HeapAllocator>(size) {} : Vector<T, inlineCapacity, HeapAllocator>(size) {
CheckType();
}
HeapVector(wtf_size_t size, const T& val) HeapVector(wtf_size_t size, const T& val)
: Vector<T, inlineCapacity, HeapAllocator>(size, val) {} : Vector<T, inlineCapacity, HeapAllocator>(size, val) {
CheckType();
}
template <wtf_size_t otherCapacity> template <wtf_size_t otherCapacity>
HeapVector(const HeapVector<T, otherCapacity>& other) HeapVector(const HeapVector<T, otherCapacity>& other)
: Vector<T, inlineCapacity, HeapAllocator>(other) {} : Vector<T, inlineCapacity, HeapAllocator>(other) {
CheckType();
}
HeapVector(std::initializer_list<T> elements) HeapVector(std::initializer_list<T> elements)
: Vector<T, inlineCapacity, HeapAllocator>(elements) {} : Vector<T, inlineCapacity, HeapAllocator>(elements) {
CheckType();
}
}; };
template <typename T, wtf_size_t inlineCapacity = 0> template <typename T, wtf_size_t inlineCapacity = 0>
class HeapDeque : public Deque<T, inlineCapacity, HeapAllocator> { class HeapDeque : public Deque<T, inlineCapacity, HeapAllocator> {
IS_GARBAGE_COLLECTED_TYPE(); IS_GARBAGE_COLLECTED_TYPE();
using Base = Deque<T, inlineCapacity, HeapAllocator>; DISALLOW_NEW();
public: static void CheckType() {
HeapDeque() { static_assert(
IsAllowedInContainer<T>::value,
"Not allowed to directly nest type. Use Member<> indirection instead.");
static_assert(WTF::IsTraceable<T>::value, static_assert(WTF::IsTraceable<T>::value,
"For vectors without traceable elements, use Deque<> instead " "For vectors without traceable elements, use Deque<> instead "
"of HeapDeque<>"); "of HeapDeque<>");
} }
public:
static void* AllocateObject(size_t size, bool eagerly_sweep) { static void* AllocateObject(size_t size, bool eagerly_sweep) {
// On-heap HeapDeques generally should not have inline capacity, but it is // 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 // hard to avoid when using a type alias. Hence we only disallow the
...@@ -656,22 +687,17 @@ class HeapDeque : public Deque<T, inlineCapacity, HeapAllocator> { ...@@ -656,22 +687,17 @@ class HeapDeque : public Deque<T, inlineCapacity, HeapAllocator> {
eagerly_sweep); eagerly_sweep);
} }
void* operator new(size_t size) = delete; HeapDeque() { CheckType(); }
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) explicit HeapDeque(wtf_size_t size)
: Deque<T, inlineCapacity, HeapAllocator>(size) {} : Deque<T, inlineCapacity, HeapAllocator>(size) {
CheckType();
}
HeapDeque(wtf_size_t size, const T& val) HeapDeque(wtf_size_t size, const T& val)
: Deque<T, inlineCapacity, HeapAllocator>(size, val) {} : Deque<T, inlineCapacity, HeapAllocator>(size, val) {
CheckType();
}
HeapDeque& operator=(const HeapDeque& other) { HeapDeque& operator=(const HeapDeque& other) {
HeapDeque<T> copy(other); HeapDeque<T> copy(other);
...@@ -684,23 +710,6 @@ class HeapDeque : public Deque<T, inlineCapacity, HeapAllocator> { ...@@ -684,23 +710,6 @@ class HeapDeque : public Deque<T, inlineCapacity, HeapAllocator> {
: Deque<T, inlineCapacity, HeapAllocator>(other) {} : Deque<T, inlineCapacity, HeapAllocator>(other) {}
}; };
template <typename T>
class HeapDoublyLinkedList : public DoublyLinkedList<T, Member<T>> {
IS_GARBAGE_COLLECTED_TYPE();
DISALLOW_NEW();
public:
HeapDoublyLinkedList() {
static_assert(WTF::IsGarbageCollectedType<T>::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 blink
namespace WTF { namespace WTF {
......
...@@ -2304,9 +2304,9 @@ TEST(HeapTest, LargeVector) { ...@@ -2304,9 +2304,9 @@ TEST(HeapTest, LargeVector) {
// Try to allocate a HeapVectors larger than kMaxHeapObjectSize // Try to allocate a HeapVectors larger than kMaxHeapObjectSize
// (crbug.com/597953). // (crbug.com/597953).
wtf_size_t size = kMaxHeapObjectSize / sizeof(int); const wtf_size_t size = kMaxHeapObjectSize / sizeof(Member<IntWrapper>);
Persistent<HeapVector<int>> vector = Persistent<HeapVector<Member<IntWrapper>>> vector =
MakeGarbageCollected<HeapVector<int>>(size); MakeGarbageCollected<HeapVector<Member<IntWrapper>>>(size);
EXPECT_LE(size, vector->capacity()); EXPECT_LE(size, vector->capacity());
} }
...@@ -2529,7 +2529,7 @@ TEST(HeapTest, HeapCollectionTypes) { ...@@ -2529,7 +2529,7 @@ TEST(HeapTest, HeapCollectionTypes) {
MakeGarbageCollected<PrimitiveMember>(); MakeGarbageCollected<PrimitiveMember>();
Persistent<MemberSet> set = MakeGarbageCollected<MemberSet>(); Persistent<MemberSet> set = MakeGarbageCollected<MemberSet>();
Persistent<MemberSet> set2 = MakeGarbageCollected<MemberSet>(); Persistent<MemberSet> set2 = MakeGarbageCollected<MemberSet>();
Persistent<MemberCountedSet> set3 = new MemberCountedSet(); Persistent<MemberCountedSet> set3 = MakeGarbageCollected<MemberCountedSet>();
Persistent<MemberVector> vector = MakeGarbageCollected<MemberVector>(); Persistent<MemberVector> vector = MakeGarbageCollected<MemberVector>();
Persistent<MemberVector> vector2 = MakeGarbageCollected<MemberVector>(); Persistent<MemberVector> vector2 = MakeGarbageCollected<MemberVector>();
Persistent<VectorWU> vector_wu = MakeGarbageCollected<VectorWU>(); Persistent<VectorWU> vector_wu = MakeGarbageCollected<VectorWU>();
...@@ -3107,7 +3107,8 @@ TEST(HeapTest, HeapWeakCollectionSimple) { ...@@ -3107,7 +3107,8 @@ TEST(HeapTest, HeapWeakCollectionSimple) {
Persistent<StrongWeak> strong_weak = MakeGarbageCollected<StrongWeak>(); Persistent<StrongWeak> strong_weak = MakeGarbageCollected<StrongWeak>();
Persistent<WeakWeak> weak_weak = MakeGarbageCollected<WeakWeak>(); Persistent<WeakWeak> weak_weak = MakeGarbageCollected<WeakWeak>();
Persistent<WeakSet> weak_set = MakeGarbageCollected<WeakSet>(); Persistent<WeakSet> weak_set = MakeGarbageCollected<WeakSet>();
Persistent<WeakCountedSet> weak_counted_set = new WeakCountedSet(); Persistent<WeakCountedSet> weak_counted_set =
MakeGarbageCollected<WeakCountedSet>();
Persistent<IntWrapper> two = MakeGarbageCollected<IntWrapper>(2); Persistent<IntWrapper> two = MakeGarbageCollected<IntWrapper>(2);
...@@ -5982,58 +5983,6 @@ TEST(HeapTest, HeapHashMapCallsDestructor) { ...@@ -5982,58 +5983,6 @@ TEST(HeapTest, HeapHashMapCallsDestructor) {
EXPECT_TRUE(string.Impl()->HasOneRef()); EXPECT_TRUE(string.Impl()->HasOneRef());
} }
class DoublyLinkedListNodeImpl
: public GarbageCollectedFinalized<DoublyLinkedListNodeImpl>,
public DoublyLinkedListNode<DoublyLinkedListNodeImpl> {
public:
DoublyLinkedListNodeImpl() = default;
static int destructor_calls_;
~DoublyLinkedListNodeImpl() { ++destructor_calls_; }
void Trace(Visitor* visitor) {
visitor->Trace(prev_);
visitor->Trace(next_);
}
private:
friend class WTF::DoublyLinkedListNode<DoublyLinkedListNodeImpl>;
Member<DoublyLinkedListNodeImpl> prev_;
Member<DoublyLinkedListNodeImpl> next_;
};
int DoublyLinkedListNodeImpl::destructor_calls_ = 0;
template <typename T>
class HeapDoublyLinkedListContainer
: public GarbageCollected<HeapDoublyLinkedListContainer<T>> {
public:
HeapDoublyLinkedListContainer<T>() = default;
HeapDoublyLinkedList<T> list_;
void Trace(Visitor* visitor) { visitor->Trace(list_); }
};
TEST(HeapTest, HeapDoublyLinkedList) {
Persistent<HeapDoublyLinkedListContainer<DoublyLinkedListNodeImpl>>
container = MakeGarbageCollected<
HeapDoublyLinkedListContainer<DoublyLinkedListNodeImpl>>();
DoublyLinkedListNodeImpl::destructor_calls_ = 0;
container->list_.Append(MakeGarbageCollected<DoublyLinkedListNodeImpl>());
container->list_.Append(MakeGarbageCollected<DoublyLinkedListNodeImpl>());
PreciselyCollectGarbage();
EXPECT_EQ(DoublyLinkedListNodeImpl::destructor_calls_, 0);
container->list_.RemoveHead();
PreciselyCollectGarbage();
EXPECT_EQ(DoublyLinkedListNodeImpl::destructor_calls_, 1);
container->list_.RemoveHead();
PreciselyCollectGarbage();
EXPECT_EQ(DoublyLinkedListNodeImpl::destructor_calls_, 2);
}
TEST(HeapTest, PromptlyFreeStackAllocatedHeapVector) { TEST(HeapTest, PromptlyFreeStackAllocatedHeapVector) {
NormalPageArena* normal_arena; NormalPageArena* normal_arena;
Address before; Address before;
...@@ -6151,6 +6100,9 @@ TEST(HeapTest, GarbageCollectedMixinIsAliveDuringConstruction) { ...@@ -6151,6 +6100,9 @@ TEST(HeapTest, GarbageCollectedMixinIsAliveDuringConstruction) {
using O = ObjectWithMixinWithCallbackBeforeInitializer<IntWrapper>; using O = ObjectWithMixinWithCallbackBeforeInitializer<IntWrapper>;
MakeGarbageCollected<O>(base::BindOnce( MakeGarbageCollected<O>(base::BindOnce(
[](O::Mixin* thiz) { CHECK(ThreadHeap::IsHeapObjectAlive(thiz)); })); [](O::Mixin* thiz) { CHECK(ThreadHeap::IsHeapObjectAlive(thiz)); }));
using P = HeapVector<Member<HeapLinkedHashSet<Member<IntWrapper>>>>;
MakeGarbageCollected<P>();
} }
} // namespace blink } // namespace blink
...@@ -658,57 +658,6 @@ TEST(IncrementalMarkingTest, HeapVectorEagerTracingStopsAtMember) { ...@@ -658,57 +658,6 @@ TEST(IncrementalMarkingTest, HeapVectorEagerTracingStopsAtMember) {
} }
} }
// =============================================================================
// HeapDoublyLinkedList support. ===============================================
// =============================================================================
namespace {
class ObjectNode : public GarbageCollected<ObjectNode>,
public DoublyLinkedListNode<ObjectNode> {
public:
explicit ObjectNode(Object* obj) : obj_(obj) {}
void Trace(Visitor* visitor) {
visitor->Trace(obj_);
visitor->Trace(prev_);
visitor->Trace(next_);
}
private:
friend class WTF::DoublyLinkedListNode<ObjectNode>;
Member<Object> obj_;
Member<ObjectNode> prev_;
Member<ObjectNode> next_;
};
} // namespace
TEST(IncrementalMarkingTest, HeapDoublyLinkedListPush) {
auto* obj = MakeGarbageCollected<Object>();
ObjectNode* obj_node = MakeGarbageCollected<ObjectNode>(obj);
HeapDoublyLinkedList<ObjectNode> list;
{
ExpectWriteBarrierFires scope(ThreadState::Current(), {obj_node});
list.Push(obj_node);
// |obj| will be marked once |obj_node| gets processed.
EXPECT_FALSE(obj->IsMarked());
}
}
TEST(IncrementalMarkingTest, HeapDoublyLinkedListAppend) {
auto* obj = MakeGarbageCollected<Object>();
ObjectNode* obj_node = MakeGarbageCollected<ObjectNode>(obj);
HeapDoublyLinkedList<ObjectNode> list;
{
ExpectWriteBarrierFires scope(ThreadState::Current(), {obj_node});
list.Append(obj_node);
// |obj| will be marked once |obj_node| gets processed.
EXPECT_FALSE(obj->IsMarked());
}
}
// ============================================================================= // =============================================================================
// HeapDeque support. ========================================================== // HeapDeque support. ==========================================================
// ============================================================================= // =============================================================================
...@@ -1602,7 +1551,7 @@ TEST(IncrementalMarkingTest, DropBackingStore) { ...@@ -1602,7 +1551,7 @@ TEST(IncrementalMarkingTest, DropBackingStore) {
// Regression test: https://crbug.com/828537 // Regression test: https://crbug.com/828537
using WeakStore = HeapHashCountedSet<WeakMember<Object>>; using WeakStore = HeapHashCountedSet<WeakMember<Object>>;
Persistent<WeakStore> persistent(new WeakStore); Persistent<WeakStore> persistent(MakeGarbageCollected<WeakStore>());
persistent->insert(MakeGarbageCollected<Object>()); persistent->insert(MakeGarbageCollected<Object>());
IncrementalMarkingTestDriver driver(ThreadState::Current()); IncrementalMarkingTestDriver driver(ThreadState::Current());
driver.Start(); driver.Start();
...@@ -1619,7 +1568,7 @@ TEST(IncrementalMarkingTest, WeakCallbackDoesNotReviveDeletedValue) { ...@@ -1619,7 +1568,7 @@ TEST(IncrementalMarkingTest, WeakCallbackDoesNotReviveDeletedValue) {
// std::pair avoids treating the hashset backing as weak backing. // std::pair avoids treating the hashset backing as weak backing.
using WeakStore = HeapHashCountedSet<std::pair<WeakMember<Object>, size_t>>; using WeakStore = HeapHashCountedSet<std::pair<WeakMember<Object>, size_t>>;
Persistent<WeakStore> persistent(new WeakStore); Persistent<WeakStore> persistent(MakeGarbageCollected<WeakStore>());
// Create at least two entries to avoid completely emptying out the data // Create at least two entries to avoid completely emptying out the data
// structure. The values for .second are chosen to be non-null as they // structure. The values for .second are chosen to be non-null as they
// would otherwise count as empty and be skipped during iteration after the // would otherwise count as empty and be skipped during iteration after the
...@@ -1654,7 +1603,7 @@ TEST(IncrementalMarkingTest, NoBackingFreeDuringIncrementalMarking) { ...@@ -1654,7 +1603,7 @@ TEST(IncrementalMarkingTest, NoBackingFreeDuringIncrementalMarking) {
// Only reproduces in ASAN configurations. // Only reproduces in ASAN configurations.
using WeakStore = HeapHashCountedSet<std::pair<WeakMember<Object>, size_t>>; using WeakStore = HeapHashCountedSet<std::pair<WeakMember<Object>, size_t>>;
Persistent<WeakStore> persistent(new WeakStore); Persistent<WeakStore> persistent(MakeGarbageCollected<WeakStore>());
// Prefill the collection to grow backing store. A new backing store allocaton // Prefill the collection to grow backing store. A new backing store allocaton
// would trigger the write barrier, mitigating the bug where a backing store // would trigger the write barrier, mitigating the bug where a backing store
// is promptly freed. // is promptly freed.
...@@ -1674,7 +1623,7 @@ TEST(IncrementalMarkingTest, NoBackingFreeDuringIncrementalMarking) { ...@@ -1674,7 +1623,7 @@ TEST(IncrementalMarkingTest, NoBackingFreeDuringIncrementalMarking) {
TEST(IncrementalMarkingTest, DropReferenceWithHeapCompaction) { TEST(IncrementalMarkingTest, DropReferenceWithHeapCompaction) {
using Store = HeapHashCountedSet<Member<Object>>; using Store = HeapHashCountedSet<Member<Object>>;
Persistent<Store> persistent(new Store()); Persistent<Store> persistent(MakeGarbageCollected<Store>());
persistent->insert(MakeGarbageCollected<Object>()); persistent->insert(MakeGarbageCollected<Object>());
IncrementalMarkingTestDriver driver(ThreadState::Current()); IncrementalMarkingTestDriver driver(ThreadState::Current());
ThreadState::Current()->EnableCompactionForNextGCForTesting(); ThreadState::Current()->EnableCompactionForNextGCForTesting();
...@@ -1711,7 +1660,7 @@ TEST(IncrementalMarkingTest, HasInlineCapacityCollectionWithHeapCompaction) { ...@@ -1711,7 +1660,7 @@ TEST(IncrementalMarkingTest, HasInlineCapacityCollectionWithHeapCompaction) {
TEST(IncrementalMarkingTest, WeakHashMapHeapCompaction) { TEST(IncrementalMarkingTest, WeakHashMapHeapCompaction) {
using Store = HeapHashCountedSet<WeakMember<Object>>; using Store = HeapHashCountedSet<WeakMember<Object>>;
Persistent<Store> persistent(new Store()); Persistent<Store> persistent(MakeGarbageCollected<Store>());
IncrementalMarkingTestDriver driver(ThreadState::Current()); IncrementalMarkingTestDriver driver(ThreadState::Current());
ThreadState::Current()->EnableCompactionForNextGCForTesting(); ThreadState::Current()->EnableCompactionForNextGCForTesting();
......
...@@ -128,11 +128,9 @@ class DoublyLinkedList { ...@@ -128,11 +128,9 @@ class DoublyLinkedList {
template <typename T, typename PointerType> template <typename T, typename PointerType>
inline DoublyLinkedList<T, PointerType>::DoublyLinkedList() inline DoublyLinkedList<T, PointerType>::DoublyLinkedList()
: head_(nullptr), tail_(nullptr) { : head_(nullptr), tail_(nullptr) {
static_assert( static_assert(!IsGarbageCollectedType<T>::value ||
!IsGarbageCollectedType<T>::value || !std::is_same<PointerType, T*>::value,
!std::is_same<PointerType, T*>::value, "Cannot use DoublyLinkedList<> with garbage collected types.");
"Cannot use DoublyLinkedList<> with garbage collected types, use "
"HeapDoublyLinkedList<> instead.");
} }
template <typename T, typename PointerType> template <typename T, typename PointerType>
......
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