Skip to content

Commit 0166be9

Browse files
mlippautzCommit Bot
authored andcommitted
Revert "heap: Avoid eager destruction of heap collections allocated on stack"
This reverts commit de61609. Reason for revert: Speculative revert for crashers, see bugs. Original change's description: > heap: Avoid eager destruction of heap collections allocated on stack > > Before this CL the rules for GarbageCollectedFinalized were diverging > from standard C++ std::is_trivially_destructible because heap > collections had a destructor that would be ignored because the classes > were not required to be GarbageCollectedFinalized. > > After the CL, std::is_trivially_destructible can be used as replacement > for GarbageCollectedFinalized. > > Benchmarks (blink_perf.dom, blink_perf.bindings, speedometer) show no > regressions. > > Bug: 990913 > Change-Id: Ie1722b5c7f97bc7197c34c7d26120e7147893fd5 > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1742147 > Commit-Queue: Anton Bikineev <bikineev@chromium.org> > Reviewed-by: Michael Lippautz <mlippautz@chromium.org> > Reviewed-by: Kentaro Hara <haraken@chromium.org> > Cr-Commit-Position: refs/heads/master@{#685557} TBR=haraken@chromium.org,mlippautz@chromium.org,bikineev@chromium.org # Not skipping CQ checks because original CL landed > 1 day ago. Bug: 990913,992794,992657 Change-Id: I95e350eb65a053a9846cab5b261194963f69da46 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1746261 Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Kentaro Hara <haraken@chromium.org> Commit-Queue: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#685941}
1 parent 7b47b5b commit 0166be9

File tree

6 files changed

+129
-66
lines changed

6 files changed

+129
-66
lines changed

third_party/blink/renderer/platform/heap/heap_allocator.h

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -473,8 +473,6 @@ class HeapHashMap : public HashMap<KeyArg,
473473
DISALLOW_NEW();
474474

475475
static void CheckType() {
476-
static_assert(std::is_trivially_destructible<HeapHashMap>::value,
477-
"HeapHashMap must be trivially destructible.");
478476
static_assert(
479477
IsAllowedInContainer<KeyArg>::value,
480478
"Not allowed to directly nest type. Use Member<> indirection instead.");
@@ -484,7 +482,7 @@ class HeapHashMap : public HashMap<KeyArg,
484482
static_assert(
485483
WTF::IsTraceable<KeyArg>::value || WTF::IsTraceable<MappedArg>::value,
486484
"For hash maps without traceable elements, use HashMap<> "
487-
"instead of HeapHashMap<>.");
485+
"instead of HeapHashMap<>");
488486
}
489487

490488
public:
@@ -506,14 +504,12 @@ class HeapHashSet
506504
DISALLOW_NEW();
507505

508506
static void CheckType() {
509-
static_assert(std::is_trivially_destructible<HeapHashSet>::value,
510-
"HeapHashSet must be trivially destructible.");
511507
static_assert(
512508
IsAllowedInContainer<ValueArg>::value,
513509
"Not allowed to directly nest type. Use Member<> indirection instead.");
514510
static_assert(WTF::IsTraceable<ValueArg>::value,
515511
"For hash sets without traceable elements, use HashSet<> "
516-
"instead of HeapHashSet<>.");
512+
"instead of HeapHashSet<>");
517513
}
518514

519515
public:
@@ -542,7 +538,7 @@ class HeapLinkedHashSet
542538
"Not allowed to directly nest type. Use Member<> indirection instead.");
543539
static_assert(WTF::IsTraceable<ValueArg>::value,
544540
"For sets without traceable elements, use LinkedHashSet<> "
545-
"instead of HeapLinkedHashSet<>.");
541+
"instead of HeapLinkedHashSet<>");
546542
}
547543

548544
public:
@@ -568,14 +564,12 @@ class HeapListHashSet
568564
DISALLOW_NEW();
569565

570566
static void CheckType() {
571-
static_assert(std::is_trivially_destructible<HeapListHashSet>::value,
572-
"HeapListHashSet must be trivially destructible.");
573567
static_assert(
574568
IsAllowedInContainer<ValueArg>::value,
575569
"Not allowed to directly nest type. Use Member<> indirection instead.");
576570
static_assert(WTF::IsTraceable<ValueArg>::value,
577571
"For sets without traceable elements, use ListHashSet<> "
578-
"instead of HeapListHashSet<>.");
572+
"instead of HeapListHashSet<>");
579573
}
580574

581575
public:
@@ -596,14 +590,12 @@ class HeapHashCountedSet
596590
DISALLOW_NEW();
597591

598592
static void CheckType() {
599-
static_assert(std::is_trivially_destructible<HeapHashCountedSet>::value,
600-
"HeapHashCountedSet must be trivially destructible.");
601593
static_assert(
602594
IsAllowedInContainer<Value>::value,
603595
"Not allowed to directly nest type. Use Member<> indirection instead.");
604596
static_assert(WTF::IsTraceable<Value>::value,
605597
"For counted sets without traceable elements, use "
606-
"HashCountedSet<> instead of HeapHashCountedSet<>.");
598+
"HashCountedSet<> instead of HeapHashCountedSet<>");
607599
}
608600

609601
public:
@@ -621,15 +613,12 @@ class HeapVector : public Vector<T, inlineCapacity, HeapAllocator> {
621613
DISALLOW_NEW();
622614

623615
static void CheckType() {
624-
static_assert(
625-
std::is_trivially_destructible<HeapVector>::value || inlineCapacity,
626-
"HeapVector must be trivially destructible.");
627616
static_assert(
628617
IsAllowedInContainer<T>::value,
629618
"Not allowed to directly nest type. Use Member<> indirection instead.");
630619
static_assert(WTF::IsTraceable<T>::value,
631620
"For vectors without traceable elements, use Vector<> "
632-
"instead of HeapVector<>.");
621+
"instead of HeapVector<>");
633622
}
634623

635624
public:
@@ -672,9 +661,6 @@ class HeapDeque : public Deque<T, inlineCapacity, HeapAllocator> {
672661
DISALLOW_NEW();
673662

674663
static void CheckType() {
675-
static_assert(
676-
std::is_trivially_destructible<HeapDeque>::value || inlineCapacity,
677-
"HeapDeque must be trivially destructible.");
678664
static_assert(
679665
IsAllowedInContainer<T>::value,
680666
"Not allowed to directly nest type. Use Member<> indirection instead.");

third_party/blink/renderer/platform/heap/heap_test.cc

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6013,6 +6013,86 @@ TEST_F(HeapTest, HeapHashMapCallsDestructor) {
60136013
EXPECT_TRUE(string.Impl()->HasOneRef());
60146014
}
60156015

6016+
TEST_F(HeapTest, PromptlyFreeStackAllocatedHeapVector) {
6017+
NormalPageArena* normal_arena;
6018+
Address before;
6019+
{
6020+
HeapVector<Member<IntWrapper>> vector;
6021+
vector.push_back(MakeGarbageCollected<IntWrapper>(0));
6022+
NormalPage* normal_page =
6023+
static_cast<NormalPage*>(PageFromObject(vector.data()));
6024+
normal_arena = normal_page->ArenaForNormalPage();
6025+
CHECK(normal_arena);
6026+
before = normal_arena->CurrentAllocationPoint();
6027+
}
6028+
Address after = normal_arena->CurrentAllocationPoint();
6029+
// We check the allocation point to see if promptly freed
6030+
EXPECT_NE(after, before);
6031+
}
6032+
6033+
TEST_F(HeapTest, PromptlyFreeStackAllocatedHeapDeque) {
6034+
NormalPageArena* normal_arena;
6035+
Address before;
6036+
{
6037+
HeapDeque<Member<IntWrapper>> deque;
6038+
deque.push_back(MakeGarbageCollected<IntWrapper>(0));
6039+
NormalPage* normal_page =
6040+
static_cast<NormalPage*>(PageFromObject(&deque.front()));
6041+
normal_arena = normal_page->ArenaForNormalPage();
6042+
CHECK(normal_arena);
6043+
before = normal_arena->CurrentAllocationPoint();
6044+
}
6045+
Address after = normal_arena->CurrentAllocationPoint();
6046+
// We check the allocation point to see if promptly freed
6047+
EXPECT_NE(after, before);
6048+
}
6049+
6050+
TEST_F(HeapTest, PromptlyFreeStackAllocatedHeapHashSet) {
6051+
NormalPageArena* normal_arena = static_cast<NormalPageArena*>(
6052+
ThreadState::Current()->Heap().Arena(BlinkGC::kHashTableArenaIndex));
6053+
CHECK(normal_arena);
6054+
Address before;
6055+
{
6056+
HeapHashSet<Member<IntWrapper>> hash_set;
6057+
hash_set.insert(MakeGarbageCollected<IntWrapper>(0));
6058+
before = normal_arena->CurrentAllocationPoint();
6059+
}
6060+
Address after = normal_arena->CurrentAllocationPoint();
6061+
// We check the allocation point to see if promptly freed
6062+
EXPECT_NE(after, before);
6063+
}
6064+
6065+
TEST_F(HeapTest, PromptlyFreeStackAllocatedHeapListHashSet) {
6066+
ClearOutOldGarbage();
6067+
NormalPageArena* normal_arena = static_cast<NormalPageArena*>(
6068+
ThreadState::Current()->Heap().Arena(BlinkGC::kHashTableArenaIndex));
6069+
CHECK(normal_arena);
6070+
Address before;
6071+
{
6072+
HeapListHashSet<Member<IntWrapper>> list_hash_set;
6073+
list_hash_set.insert(MakeGarbageCollected<IntWrapper>(0));
6074+
before = normal_arena->CurrentAllocationPoint();
6075+
}
6076+
Address after = normal_arena->CurrentAllocationPoint();
6077+
// We check the allocation point to see if promptly freed
6078+
EXPECT_NE(after, before);
6079+
}
6080+
6081+
TEST_F(HeapTest, PromptlyFreeStackAllocatedHeapLinkedHashSet) {
6082+
NormalPageArena* normal_arena = static_cast<NormalPageArena*>(
6083+
ThreadState::Current()->Heap().Arena(BlinkGC::kHashTableArenaIndex));
6084+
CHECK(normal_arena);
6085+
Address before;
6086+
{
6087+
HeapLinkedHashSet<Member<IntWrapper>> linked_hash_set;
6088+
linked_hash_set.insert(MakeGarbageCollected<IntWrapper>(0));
6089+
before = normal_arena->CurrentAllocationPoint();
6090+
}
6091+
Address after = normal_arena->CurrentAllocationPoint();
6092+
// We check the allocation point to see if promptly freed
6093+
EXPECT_NE(after, before);
6094+
}
6095+
60166096
TEST_F(HeapTest, ShrinkVector) {
60176097
// Regression test: https://crbug.com/823289
60186098

third_party/blink/renderer/platform/wtf/deque.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,7 @@ class DequeConstIterator;
5252
template <typename T,
5353
wtf_size_t inlineCapacity = 0,
5454
typename Allocator = PartitionAllocator>
55-
class Deque : public ConditionalDestructor<Deque<T, INLINE_CAPACITY, Allocator>,
56-
(INLINE_CAPACITY == 0) &&
57-
Allocator::kIsGarbageCollected> {
55+
class Deque {
5856
USE_ALLOCATOR(Deque, Allocator);
5957

6058
public:
@@ -68,8 +66,9 @@ class Deque : public ConditionalDestructor<Deque<T, INLINE_CAPACITY, Allocator>,
6866
Deque& operator=(const Deque&);
6967
Deque(Deque&&);
7068
Deque& operator=(Deque&&);
69+
~Deque();
7170

72-
void Finalize();
71+
void FinalizeGarbageCollectedObject() { NOTREACHED(); }
7372

7473
void Swap(Deque&);
7574

@@ -375,18 +374,16 @@ inline void Deque<T, inlineCapacity, Allocator>::DestroyAll() {
375374
// For design of the destructor, please refer to
376375
// [here](https://docs.google.com/document/d/1AoGTvb3tNLx2tD1hNqAfLRLmyM59GM0O-7rCHTT_7_U/)
377376
template <typename T, wtf_size_t inlineCapacity, typename Allocator>
378-
inline void Deque<T, inlineCapacity, Allocator>::Finalize() {
379-
static_assert(!Allocator::kIsGarbageCollected || INLINE_CAPACITY,
380-
"GarbageCollected collections without inline capacity cannot "
381-
"be finalized.");
377+
inline Deque<T, inlineCapacity, Allocator>::~Deque() {
382378
if ((!INLINE_CAPACITY && !buffer_.Buffer()))
383379
return;
384380
if (!IsEmpty() &&
385381
!(Allocator::kIsGarbageCollected && buffer_.HasOutOfLineBuffer()))
386382
DestroyAll();
387383

388-
// For garbage collected deque HeapAllocator::BackingFree() will bail out
389-
// during sweeping.
384+
// If this is called during sweeping, it must not touch the OutOfLineBuffer.
385+
if (Allocator::IsSweepForbidden())
386+
return;
390387
buffer_.Destruct();
391388
}
392389

third_party/blink/renderer/platform/wtf/hash_table.h

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
3030
#include "third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h"
3131
#include "third_party/blink/renderer/platform/wtf/assertions.h"
32-
#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
3332
#include "third_party/blink/renderer/platform/wtf/construct_traits.h"
3433
#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
3534

@@ -695,15 +694,7 @@ template <typename Key,
695694
typename Traits,
696695
typename KeyTraits,
697696
typename Allocator>
698-
class HashTable final
699-
: public ConditionalDestructor<HashTable<Key,
700-
Value,
701-
Extractor,
702-
HashFunctions,
703-
Traits,
704-
KeyTraits,
705-
Allocator>,
706-
Allocator::kIsGarbageCollected> {
697+
class HashTable final {
707698
DISALLOW_NEW();
708699

709700
public:
@@ -735,11 +726,15 @@ class HashTable final
735726

736727
HashTable();
737728

738-
void Finalize() {
739-
static_assert(!Allocator::kIsGarbageCollected,
740-
"GCed collections can't be finalized.");
729+
// For design of the destructor, please refer to
730+
// [here](https://docs.google.com/document/d/1AoGTvb3tNLx2tD1hNqAfLRLmyM59GM0O-7rCHTT_7_U/)
731+
~HashTable() {
741732
if (LIKELY(!table_))
742733
return;
734+
// If this is called during sweeping, it must not touch other heap objects
735+
// such as the backing.
736+
if (Allocator::IsSweepForbidden())
737+
return;
743738
EnterAccessForbiddenScope();
744739
DeleteAllBucketsAndDeallocate(table_, table_size_);
745740
LeaveAccessForbiddenScope();

third_party/blink/renderer/platform/wtf/list_hash_set.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
#include <memory>
2727
#include "third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h"
28-
#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
2928
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
3029

3130
namespace WTF {
@@ -77,10 +76,7 @@ template <typename ValueArg,
7776
typename HashArg = typename DefaultHash<ValueArg>::Hash,
7877
typename AllocatorArg =
7978
ListHashSetAllocator<ValueArg, inlineCapacity>>
80-
class ListHashSet
81-
: public ConditionalDestructor<
82-
ListHashSet<ValueArg, inlineCapacity, HashArg, AllocatorArg>,
83-
AllocatorArg::kIsGarbageCollected> {
79+
class ListHashSet {
8480
typedef AllocatorArg Allocator;
8581
USE_ALLOCATOR(ListHashSet, Allocator);
8682

@@ -152,7 +148,7 @@ class ListHashSet
152148
ListHashSet(ListHashSet&&);
153149
ListHashSet& operator=(const ListHashSet&);
154150
ListHashSet& operator=(ListHashSet&&);
155-
void Finalize();
151+
~ListHashSet();
156152

157153
void Swap(ListHashSet&);
158154

@@ -808,10 +804,14 @@ inline void ListHashSet<T, inlineCapacity, U, V>::Swap(ListHashSet& other) {
808804
allocator_provider_.Swap(other.allocator_provider_);
809805
}
810806

807+
// For design of the destructor, please refer to
808+
// [here](https://docs.google.com/document/d/1AoGTvb3tNLx2tD1hNqAfLRLmyM59GM0O-7rCHTT_7_U/)
811809
template <typename T, size_t inlineCapacity, typename U, typename V>
812-
inline void ListHashSet<T, inlineCapacity, U, V>::Finalize() {
813-
static_assert(!Allocator::kIsGarbageCollected,
814-
"GCed collections can't be finalized");
810+
inline ListHashSet<T, inlineCapacity, U, V>::~ListHashSet() {
811+
// If this is called during GC sweeping, it must not touch other heap objects
812+
// such as the ListHashSetNodes that is touching in DeleteAllNodes().
813+
if (Allocator::IsSweepForbidden())
814+
return;
815815
DeleteAllNodes();
816816
allocator_provider_.ReleaseAllocator();
817817
}

third_party/blink/renderer/platform/wtf/vector.h

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#include "base/template_util.h"
3232
#include "build/build_config.h"
3333
#include "third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h"
34-
#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
3534
#include "third_party/blink/renderer/platform/wtf/construct_traits.h"
3635
#include "third_party/blink/renderer/platform/wtf/container_annotations.h"
3736
#include "third_party/blink/renderer/platform/wtf/forward.h" // For default Vector template parameters.
@@ -974,11 +973,7 @@ class VectorBuffer : protected VectorBufferBase<T, true, Allocator> {
974973
// store iterators in another heap object.
975974

976975
template <typename T, wtf_size_t inlineCapacity, typename Allocator>
977-
class Vector
978-
: private VectorBuffer<T, INLINE_CAPACITY, Allocator>,
979-
public ConditionalDestructor<Vector<T, INLINE_CAPACITY, Allocator>,
980-
(INLINE_CAPACITY == 0) &&
981-
Allocator::kIsGarbageCollected> {
976+
class Vector : private VectorBuffer<T, INLINE_CAPACITY, Allocator> {
982977
USE_ALLOCATOR(Vector, Allocator);
983978
using Base = VectorBuffer<T, INLINE_CAPACITY, Allocator>;
984979
using TypeOperations = VectorTypeOperations<T, Allocator>;
@@ -1262,12 +1257,12 @@ class Vector
12621257
return Allocator::template MaxElementCountInBackingStore<T>();
12631258
}
12641259

1265-
void Finalize() {
1266-
static_assert(!Allocator::kIsGarbageCollected || INLINE_CAPACITY,
1267-
"GarbageCollected collections without inline capacity cannot "
1268-
"be finalized.");
1269-
if (!INLINE_CAPACITY && LIKELY(!Base::Buffer())) {
1270-
return;
1260+
// For design of the destructor, please refer to
1261+
// [here](https://docs.google.com/document/d/1AoGTvb3tNLx2tD1hNqAfLRLmyM59GM0O-7rCHTT_7_U/)
1262+
~Vector() {
1263+
if (!INLINE_CAPACITY) {
1264+
if (LIKELY(!Base::Buffer()))
1265+
return;
12711266
}
12721267
ANNOTATE_DELETE_BUFFER(begin(), capacity(), size_);
12731268
if (LIKELY(size_) &&
@@ -1276,11 +1271,21 @@ class Vector
12761271
size_ = 0; // Partial protection against use-after-free.
12771272
}
12781273

1279-
// For garbage collected vector HeapAllocator::BackingFree() will bail out
1280-
// during sweeping.
1274+
// If this is called during sweeping, the backing should not be touched.
1275+
// Other collections have an early return here if IsSweepForbidden(), but
1276+
// adding that resulted in performance regression for shadow dom benchmarks
1277+
// (crbug.com/866084) because of the additional access to TLS. The check has
1278+
// been removed but the same check exists in HeapAllocator::BackingFree() so
1279+
// things should be fine as long as VectorBase does not touch the backing.
1280+
12811281
Base::Destruct();
12821282
}
12831283

1284+
// This method will be referenced when creating an on-heap HeapVector with
1285+
// inline capacity and elements requiring destruction. However usage of such a
1286+
// type is banned with a static assert.
1287+
void FinalizeGarbageCollectedObject() { NOTREACHED(); }
1288+
12841289
template <typename VisitorDispatcher, typename A = Allocator>
12851290
std::enable_if_t<A::kIsGarbageCollected> Trace(VisitorDispatcher);
12861291

0 commit comments

Comments
 (0)