[heap] Verify usages of SKIP_WRITE_BARRIER

Verify usages of SKIP_WRITE_BARRIER in builds with SLOW_DCHECKs enabled.
We can only remove the write barrier in specific circumstances that
can also be DCHECK'ed.

I also switched some write barriers to UPDATE_WRITE_BARRIER where those
simple rules didn't hold but relied on more elaborate explanations.

Bug: v8:12544
Change-Id: I4caa43627f8a3209d853e3352caabc161568e6eb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3386803
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Dominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78649}
This commit is contained in:
Dominik Inführ 2022-01-17 14:46:27 +01:00 committed by V8 LUCI CQ
parent cbcedb0439
commit 1ccf7663ce
6 changed files with 47 additions and 4 deletions

View File

@ -283,6 +283,19 @@ void WriteBarrier::MarkingFromInternalFields(JSObject host) {
MarkingSlowFromInternalFields(*heap, host);
}
#ifdef ENABLE_SLOW_DCHECKS
// static
template <typename T>
bool WriteBarrier::IsRequired(HeapObject host, T value) {
if (BasicMemoryChunk::FromHeapObject(host)->InYoungGeneration()) return false;
if (value.IsSmi()) return false;
if (value.IsCleared()) return false;
HeapObject target = value.GetHeapObject();
if (ReadOnlyHeap::Contains(target)) return false;
return !IsImmortalImmovableHeapObject(target);
}
#endif
} // namespace internal
} // namespace v8

View File

@ -7,6 +7,7 @@
#include "src/heap/embedder-tracing.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/heap/marking-barrier.h"
#include "src/objects/code-inl.h"
#include "src/objects/descriptor-array.h"
#include "src/objects/js-objects.h"
#include "src/objects/maybe-object.h"
@ -96,5 +97,21 @@ int WriteBarrier::MarkingFromCode(Address raw_host, Address raw_slot) {
return 0;
}
#ifdef ENABLE_SLOW_DCHECKS
bool WriteBarrier::IsImmortalImmovableHeapObject(HeapObject object) {
BasicMemoryChunk* basic_chunk = BasicMemoryChunk::FromHeapObject(object);
// All objects in readonly space are immortal and immovable.
if (basic_chunk->InReadOnlySpace()) return true;
MemoryChunk* chunk = MemoryChunk::FromHeapObject(object);
// There are also objects in "regular" spaces which are immortal and
// immovable. Objects on a page that can get compacted are movable and can be
// filtered out.
if (!chunk->IsFlagSet(MemoryChunk::NEVER_EVACUATE)) return false;
// Now we know the object is immovable, check whether it is also immortal.
// Builtins are roots and therefore always kept alive by the GC.
return object.IsCode() && Code::cast(object).is_builtin();
}
#endif
} // namespace internal
} // namespace v8

View File

@ -65,6 +65,12 @@ class V8_EXPORT_PRIVATE WriteBarrier {
static MarkingBarrier* CurrentMarkingBarrier(Heap* heap);
#ifdef ENABLE_SLOW_DCHECKS
template <typename T>
static inline bool IsRequired(HeapObject host, T value);
static bool IsImmortalImmovableHeapObject(HeapObject object);
#endif
private:
static inline base::Optional<Heap*> GetHeapIfMarking(HeapObject object);

View File

@ -5671,9 +5671,9 @@ void Genesis::InitializeMapCaches() {
DisallowGarbageCollection no_gc;
native_context()->set_map_cache(*cache);
Map initial = native_context()->object_function().initial_map();
cache->Set(0, HeapObjectReference::Weak(initial), SKIP_WRITE_BARRIER);
cache->Set(0, HeapObjectReference::Weak(initial));
cache->Set(initial.GetInObjectProperties(),
HeapObjectReference::Weak(initial), SKIP_WRITE_BARRIER);
HeapObjectReference::Weak(initial));
}
}

View File

@ -1009,8 +1009,9 @@ void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count));
count = SpeculationModeField::update(count, mode);
MaybeObject feedback = GetFeedback();
// We can skip the write barrier for {feedback} because it's not changing.
SetFeedback(feedback, SKIP_WRITE_BARRIER, Smi::FromInt(count),
// We could've skipped WB here (since we set the slot to the same value again)
// but we don't to make WB verification happy.
SetFeedback(feedback, UPDATE_WRITE_BARRIER, Smi::FromInt(count),
SKIP_WRITE_BARRIER);
}

View File

@ -484,6 +484,8 @@
WriteBarrier::Marking(object, (object).RawField(offset), value); \
} \
GenerationalBarrier(object, (object).RawField(offset), value); \
} else { \
SLOW_DCHECK(!WriteBarrier::IsRequired(object, value)); \
} \
} while (false)
#endif
@ -504,6 +506,8 @@
value); \
} \
GenerationalBarrier(object, (object).RawMaybeWeakField(offset), value); \
} else { \
SLOW_DCHECK(!WriteBarrier::IsRequired(object, value)); \
} \
} while (false)
#endif
@ -522,6 +526,8 @@
} \
GenerationalEphemeronKeyBarrier(table, (object).RawField(offset), \
value); \
} else { \
SLOW_DCHECK(!WriteBarrier::IsRequired(object, value)); \
} \
} while (false)
#endif