|
9 | 9 |
|
10 | 10 | #include "include/cppgc/trace-trait.h"
|
11 | 11 | #include "include/cppgc/visitor.h"
|
| 12 | +#include "src/base/logging.h" |
12 | 13 | #include "src/heap/cppgc/compaction-worklists.h"
|
13 | 14 | #include "src/heap/cppgc/globals.h"
|
14 | 15 | #include "src/heap/cppgc/heap-object-header.h"
|
@@ -115,6 +116,16 @@ class MarkingStateBase {
|
115 | 116 | movable_slots_worklist_.reset();
|
116 | 117 | }
|
117 | 118 |
|
| 119 | + bool DidDiscoverNewEphemeronPairs() const { |
| 120 | + return discovered_new_ephemeron_pairs_; |
| 121 | + } |
| 122 | + |
| 123 | + void ResetDidDiscoverNewEphemeronPairs() { |
| 124 | + discovered_new_ephemeron_pairs_ = false; |
| 125 | + } |
| 126 | + |
| 127 | + void set_in_atomic_pause() { in_atomic_pause_ = true; } |
| 128 | + |
118 | 129 | protected:
|
119 | 130 | inline void MarkAndPush(HeapObjectHeader&, TraceDescriptor);
|
120 | 131 |
|
@@ -150,6 +161,9 @@ class MarkingStateBase {
|
150 | 161 | movable_slots_worklist_;
|
151 | 162 |
|
152 | 163 | size_t marked_bytes_ = 0;
|
| 164 | + bool in_ephemeron_processing_ = false; |
| 165 | + bool discovered_new_ephemeron_pairs_ = false; |
| 166 | + bool in_atomic_pause_ = false; |
153 | 167 | };
|
154 | 168 |
|
155 | 169 | MarkingStateBase::MarkingStateBase(HeapBase& heap,
|
@@ -286,20 +300,35 @@ void MarkingStateBase::ProcessWeakContainer(const void* object,
|
286 | 300 | void MarkingStateBase::ProcessEphemeron(const void* key, const void* value,
|
287 | 301 | TraceDescriptor value_desc,
|
288 | 302 | Visitor& visitor) {
|
289 |
| - // Filter out already marked keys. The write barrier for WeakMember |
290 |
| - // ensures that any newly set value after this point is kept alive and does |
291 |
| - // not require the callback. |
292 |
| - if (HeapObjectHeader::FromObject(key).IsMarked<AccessMode::kAtomic>()) { |
| 303 | + // ProcessEphemeron is not expected to find new ephemerons recursively, which |
| 304 | + // would break the main marking loop. |
| 305 | + DCHECK(!in_ephemeron_processing_); |
| 306 | + in_ephemeron_processing_ = true; |
| 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) { |
293 | 320 | if (value_desc.base_object_payload) {
|
294 | 321 | MarkAndPush(value_desc.base_object_payload, value_desc);
|
295 | 322 | } else {
|
296 | 323 | // If value_desc.base_object_payload is nullptr, the value is not GCed and
|
297 | 324 | // should be immediately traced.
|
298 | 325 | value_desc.callback(&visitor, value);
|
299 | 326 | }
|
300 |
| - return; |
| 327 | + } else { |
| 328 | + discovered_ephemeron_pairs_worklist_.Push({key, value, value_desc}); |
| 329 | + discovered_new_ephemeron_pairs_ = true; |
301 | 330 | }
|
302 |
| - discovered_ephemeron_pairs_worklist_.Push({key, value, value_desc}); |
| 331 | + in_ephemeron_processing_ = false; |
303 | 332 | }
|
304 | 333 |
|
305 | 334 | void MarkingStateBase::AccountMarkedBytes(const HeapObjectHeader& header) {
|
|
0 commit comments