Skip to content

Commit 4feccb9

Browse files
committed
cppgc: Fix marking of ephemerons with keys in construction
Consider in-construction keys as live during the final GC pause. Bug: chromium:1259587 Change-Id: Ia8c05923db6e5827b68b17a51561fbc8b2c4b467 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3221153 Commit-Queue: Michael Lippautz <[email protected]> Reviewed-by: Anton Bikineev <[email protected]> Cr-Commit-Position: refs/heads/main@{#77386} (cherry picked from commit 32a09a6) Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3226785 Bot-Commit: Rubber Stamper <[email protected]>
1 parent 0b7bda0 commit 4feccb9

File tree

3 files changed

+63
-6
lines changed

3 files changed

+63
-6
lines changed

src/heap/cppgc/marker.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ void MarkerBase::EnterAtomicPause(MarkingConfig::StackState stack_state) {
243243
}
244244
config_.stack_state = stack_state;
245245
config_.marking_type = MarkingConfig::MarkingType::kAtomic;
246+
mutator_marking_state_.set_in_atomic_pause();
246247

247248
{
248249
// VisitRoots also resets the LABs.

src/heap/cppgc/marking-state.h

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

1010
#include "include/cppgc/trace-trait.h"
1111
#include "include/cppgc/visitor.h"
12+
#include "src/base/logging.h"
1213
#include "src/heap/cppgc/compaction-worklists.h"
1314
#include "src/heap/cppgc/globals.h"
1415
#include "src/heap/cppgc/heap-object-header.h"
@@ -123,6 +124,8 @@ class MarkingStateBase {
123124
discovered_new_ephemeron_pairs_ = false;
124125
}
125126

127+
void set_in_atomic_pause() { in_atomic_pause_ = true; }
128+
126129
protected:
127130
inline void MarkAndPush(HeapObjectHeader&, TraceDescriptor);
128131

@@ -160,6 +163,7 @@ class MarkingStateBase {
160163
size_t marked_bytes_ = 0;
161164
bool in_ephemeron_processing_ = false;
162165
bool discovered_new_ephemeron_pairs_ = false;
166+
bool in_atomic_pause_ = false;
163167
};
164168

165169
MarkingStateBase::MarkingStateBase(HeapBase& heap,
@@ -300,12 +304,19 @@ void MarkingStateBase::ProcessEphemeron(const void* key, const void* value,
300304
// would break the main marking loop.
301305
DCHECK(!in_ephemeron_processing_);
302306
in_ephemeron_processing_ = true;
303-
// Filter out already marked keys. The write barrier for WeakMember
304-
// ensures that any newly set value after this point is kept alive and does
305-
// not require the callback.
306-
if (!HeapObjectHeader::FromObject(key)
307-
.IsInConstruction<AccessMode::kAtomic>() &&
308-
HeapObjectHeader::FromObject(key).IsMarked<AccessMode::kAtomic>()) {
307+
// Keys are considered live even in incremental/concurrent marking settings
308+
// because the write barrier for WeakMember ensures that any newly set value
309+
// after this point is kept alive and does not require the callback.
310+
const bool key_in_construction =
311+
HeapObjectHeader::FromObject(key).IsInConstruction<AccessMode::kAtomic>();
312+
const bool key_considered_as_live =
313+
key_in_construction
314+
? in_atomic_pause_
315+
: HeapObjectHeader::FromObject(key).IsMarked<AccessMode::kAtomic>();
316+
DCHECK_IMPLIES(
317+
key_in_construction && in_atomic_pause_,
318+
HeapObjectHeader::FromObject(key).IsMarked<AccessMode::kAtomic>());
319+
if (key_considered_as_live) {
309320
if (value_desc.base_object_payload) {
310321
MarkAndPush(value_desc.base_object_payload, value_desc);
311322
} else {

test/unittests/heap/cppgc/ephemeron-pair-unittest.cc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,5 +242,50 @@ TEST_F(EphemeronPairTest, EphemeronPairWithEmptyMixinValue) {
242242
FinishMarking();
243243
}
244244

245+
namespace {
246+
247+
class KeyWithCallback final : public GarbageCollected<KeyWithCallback> {
248+
public:
249+
template <typename Callback>
250+
explicit KeyWithCallback(Callback callback) {
251+
callback(this);
252+
}
253+
void Trace(Visitor*) const {}
254+
};
255+
256+
class EphemeronHolderForKeyWithCallback final
257+
: public GarbageCollected<EphemeronHolderForKeyWithCallback> {
258+
public:
259+
EphemeronHolderForKeyWithCallback(KeyWithCallback* key, GCed* value)
260+
: ephemeron_pair_(key, value) {}
261+
void Trace(cppgc::Visitor* visitor) const { visitor->Trace(ephemeron_pair_); }
262+
263+
private:
264+
const EphemeronPair<KeyWithCallback, GCed> ephemeron_pair_;
265+
};
266+
267+
} // namespace
268+
269+
TEST_F(EphemeronPairTest, EphemeronPairWithKeyInConstruction) {
270+
GCed* value = MakeGarbageCollected<GCed>(GetAllocationHandle());
271+
Persistent<EphemeronHolderForKeyWithCallback> holder;
272+
InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get());
273+
FinishSteps();
274+
MakeGarbageCollected<KeyWithCallback>(
275+
GetAllocationHandle(), [this, &holder, value](KeyWithCallback* thiz) {
276+
// The test doesn't use conservative stack scanning to retain key to
277+
// avoid retaining value as a side effect.
278+
EXPECT_TRUE(HeapObjectHeader::FromObject(thiz).TryMarkAtomic());
279+
holder = MakeGarbageCollected<EphemeronHolderForKeyWithCallback>(
280+
GetAllocationHandle(), thiz, value);
281+
// Finishing marking at this point will leave an ephemeron pair
282+
// reachable where the key is still in construction. The GC needs to
283+
// mark the value for such pairs as live in the atomic pause as they key
284+
// is considered live.
285+
FinishMarking();
286+
});
287+
EXPECT_TRUE(HeapObjectHeader::FromObject(value).IsMarked());
288+
}
289+
245290
} // namespace internal
246291
} // namespace cppgc

0 commit comments

Comments
 (0)