From e8d567f859e0e668b809ccbc3320ba416efad657 Mon Sep 17 00:00:00 2001 From: Gang Zhao Date: Sun, 1 Dec 2024 23:50:25 -0800 Subject: [PATCH] Update constructorWriteBarrierRange Differential Revision: D62171114 --- include/hermes/VM/ArrayStorage.h | 2 +- include/hermes/VM/GCBase.h | 2 ++ include/hermes/VM/HadesGC.h | 8 ++++++-- include/hermes/VM/HermesValue-inline.h | 3 ++- include/hermes/VM/HermesValue.h | 1 + include/hermes/VM/MallocGC.h | 10 ++++++++-- lib/VM/ArrayStorage.cpp | 3 ++- lib/VM/GCBase.cpp | 14 ++++++++++++-- lib/VM/SegmentedArray.cpp | 1 + lib/VM/gcs/HadesGC.cpp | 23 +++++++++++++++++------ 10 files changed, 52 insertions(+), 15 deletions(-) diff --git a/include/hermes/VM/ArrayStorage.h b/include/hermes/VM/ArrayStorage.h index 15d90f83e3b..a67ae09657d 100644 --- a/include/hermes/VM/ArrayStorage.h +++ b/include/hermes/VM/ArrayStorage.h @@ -237,7 +237,7 @@ class ArrayStorageBase final auto *fromStart = other->data(); auto *fromEnd = fromStart + otherSz; GCHVType::uninitialized_copy( - fromStart, fromEnd, data() + sz, runtime.getHeap()); + fromStart, fromEnd, data() + sz, this, runtime.getHeap()); size_.store(sz + otherSz, std::memory_order_release); } diff --git a/include/hermes/VM/GCBase.h b/include/hermes/VM/GCBase.h index a869d08c4a4..0692064e221 100644 --- a/include/hermes/VM/GCBase.h +++ b/include/hermes/VM/GCBase.h @@ -1163,9 +1163,11 @@ class GCBase { void writeBarrierRange(const GCHermesValue *start, uint32_t numHVs); void writeBarrierRange(const GCSmallHermesValue *start, uint32_t numHVs); void constructorWriteBarrierRange( + const GCCell *owningObj, const GCHermesValue *start, uint32_t numHVs); void constructorWriteBarrierRange( + const GCCell *owningObj, const GCSmallHermesValue *start, uint32_t numHVs); void snapshotWriteBarrier(const GCHermesValue *loc); diff --git a/include/hermes/VM/HadesGC.h b/include/hermes/VM/HadesGC.h index a904e875b77..e6686fd2e9d 100644 --- a/include/hermes/VM/HadesGC.h +++ b/include/hermes/VM/HadesGC.h @@ -213,24 +213,28 @@ class HadesGC final : public GCBase { } void constructorWriteBarrierRange( + const GCCell *owningObj, const GCHermesValue *start, uint32_t numHVs) { // A pointer that lives in YG never needs any write barriers. if (LLVM_UNLIKELY(!inYoungGen(start))) - constructorWriteBarrierRangeSlow(start, numHVs); + constructorWriteBarrierRangeSlow(owningObj, start, numHVs); } void constructorWriteBarrierRangeSlow( + const GCCell *owningObj, const GCHermesValue *start, uint32_t numHVs); void constructorWriteBarrierRange( + const GCCell *owningObj, const GCSmallHermesValue *start, uint32_t numHVs) { // A pointer that lives in YG never needs any write barriers. if (LLVM_UNLIKELY(!inYoungGen(start))) - constructorWriteBarrierRangeSlow(start, numHVs); + constructorWriteBarrierRangeSlow(owningObj, start, numHVs); } void constructorWriteBarrierRangeSlow( + const GCCell *owningObj, const GCSmallHermesValue *start, uint32_t numHVs); diff --git a/include/hermes/VM/HermesValue-inline.h b/include/hermes/VM/HermesValue-inline.h index d38a9219879..e60dfb6219e 100644 --- a/include/hermes/VM/HermesValue-inline.h +++ b/include/hermes/VM/HermesValue-inline.h @@ -182,6 +182,7 @@ inline GCHermesValueBase *GCHermesValueBase::uninitialized_copy( GCHermesValueBase *first, GCHermesValueBase *last, GCHermesValueBase *result, + const GCCell *owningObj, GC &gc) { #ifndef NDEBUG uintptr_t fromFirst = reinterpret_cast(first), @@ -194,7 +195,7 @@ inline GCHermesValueBase *GCHermesValueBase::uninitialized_copy( "Uninitialized range cannot overlap with an initialized one."); #endif - gc.constructorWriteBarrierRange(result, last - first); + gc.constructorWriteBarrierRange(owningObj, result, last - first); // memcpy is fine for an uninitialized copy. std::memcpy( reinterpret_cast(result), first, (last - first) * sizeof(HVType)); diff --git a/include/hermes/VM/HermesValue.h b/include/hermes/VM/HermesValue.h index 7e377d44754..1dbd01effe5 100644 --- a/include/hermes/VM/HermesValue.h +++ b/include/hermes/VM/HermesValue.h @@ -589,6 +589,7 @@ class GCHermesValueBase final : public HVType { GCHermesValueBase *first, GCHermesValueBase *last, GCHermesValueBase *result, + const GCCell *owningObj, GC &gc); /// Copies a range of values and performs a write barrier on each. diff --git a/include/hermes/VM/MallocGC.h b/include/hermes/VM/MallocGC.h index 98ed5c523a3..8e5e1b88277 100644 --- a/include/hermes/VM/MallocGC.h +++ b/include/hermes/VM/MallocGC.h @@ -241,8 +241,14 @@ class MallocGC final : public GCBase { void constructorWriteBarrier(const GCPointerBase *, const GCCell *) {} void writeBarrierRange(const GCHermesValue *, uint32_t) {} void writeBarrierRange(const GCSmallHermesValue *, uint32_t) {} - void constructorWriteBarrierRange(const GCHermesValue *, uint32_t) {} - void constructorWriteBarrierRange(const GCSmallHermesValue *, uint32_t) {} + void constructorWriteBarrierRange( + const GCCell *, + const GCHermesValue *, + uint32_t) {} + void constructorWriteBarrierRange( + const GCCell *, + const GCSmallHermesValue *, + uint32_t) {} void snapshotWriteBarrier(const GCHermesValue *) {} void snapshotWriteBarrier(const GCSmallHermesValue *) {} void snapshotWriteBarrier(const GCPointerBase *) {} diff --git a/lib/VM/ArrayStorage.cpp b/lib/VM/ArrayStorage.cpp index d73718ab7db..7d4807e97e7 100644 --- a/lib/VM/ArrayStorage.cpp +++ b/lib/VM/ArrayStorage.cpp @@ -104,7 +104,8 @@ ExecutionStatus ArrayStorageBase::reallocateToLarger( { GCHVType *from = self->data() + fromFirst; GCHVType *to = newSelf->data() + toFirst; - GCHVType::uninitialized_copy(from, from + copySize, to, runtime.getHeap()); + GCHVType::uninitialized_copy( + from, from + copySize, to, newSelf, runtime.getHeap()); } // Initialize the elements before the first copied element. diff --git a/lib/VM/GCBase.cpp b/lib/VM/GCBase.cpp index 1247b35828d..a7e2b37dcd3 100644 --- a/lib/VM/GCBase.cpp +++ b/lib/VM/GCBase.cpp @@ -965,6 +965,11 @@ bool GCBase::shouldSanitizeHandles() { runtimeGCDispatch([&](auto *gc) { gc->name(arg1, arg2); }); \ } +#define GCBASE_BARRIER_3(name, type1, type2, type3) \ + void GCBase::name(type1 arg1, type2 arg2, type3 arg3) { \ + runtimeGCDispatch([&](auto *gc) { gc->name(arg1, arg2, arg3); }); \ + } + GCBASE_BARRIER_2(writeBarrier, const GCHermesValue *, HermesValue); GCBASE_BARRIER_2(writeBarrier, const GCSmallHermesValue *, SmallHermesValue); GCBASE_BARRIER_2(writeBarrier, const GCPointerBase *, const GCCell *); @@ -979,9 +984,14 @@ GCBASE_BARRIER_2( const GCCell *); GCBASE_BARRIER_2(writeBarrierRange, const GCHermesValue *, uint32_t); GCBASE_BARRIER_2(writeBarrierRange, const GCSmallHermesValue *, uint32_t); -GCBASE_BARRIER_2(constructorWriteBarrierRange, const GCHermesValue *, uint32_t); -GCBASE_BARRIER_2( +GCBASE_BARRIER_3( + constructorWriteBarrierRange, + const GCCell *, + const GCHermesValue *, + uint32_t); +GCBASE_BARRIER_3( constructorWriteBarrierRange, + const GCCell *, const GCSmallHermesValue *, uint32_t); GCBASE_BARRIER_1(snapshotWriteBarrier, const GCHermesValue *); diff --git a/lib/VM/SegmentedArray.cpp b/lib/VM/SegmentedArray.cpp index d59d622f68d..0a04c7aa566 100644 --- a/lib/VM/SegmentedArray.cpp +++ b/lib/VM/SegmentedArray.cpp @@ -294,6 +294,7 @@ ExecutionStatus SegmentedArrayBase::growRight( self->inlineStorage(), self->inlineStorage() + numSlotsUsed, newSegmentedArray->inlineStorage(), + newSegmentedArray.get(), runtime.getHeap()); // Set the size of the new array to be the same as the old array's size. newSegmentedArray->numSlotsUsed_.store( diff --git a/lib/VM/gcs/HadesGC.cpp b/lib/VM/gcs/HadesGC.cpp index 8a6e49044dc..3a783fbb601 100644 --- a/lib/VM/gcs/HadesGC.cpp +++ b/lib/VM/gcs/HadesGC.cpp @@ -1992,28 +1992,39 @@ void HadesGC::constructorWriteBarrierSlow( } void HadesGC::constructorWriteBarrierRangeSlow( + const GCCell *owningObj, const GCHermesValue *start, uint32_t numHVs) { assert( - FixedSizeHeapSegment::containedInSame(start, start + numHVs) && - "Range must start and end within a heap segment."); + reinterpret_cast(owningObj) <= + reinterpret_cast(start) && + reinterpret_cast(start + numHVs) <= + (reinterpret_cast(owningObj) + + owningObj->getAllocatedSize()) && + "Range must start and end within the owning object."); // Most constructors should be running in the YG, so in the common case, we // can avoid doing anything for the whole range. If the range is in the OG, // then just dirty all the cards corresponding to it, and we can scan them for // pointers later. This is less precise but makes the write barrier faster. - FixedSizeHeapSegment::cardTableCovering(start)->dirtyCardsForAddressRange( + FixedSizeHeapSegment::cardTableCovering(owningObj)->dirtyCardsForAddressRange( start, start + numHVs); } void HadesGC::constructorWriteBarrierRangeSlow( + const GCCell *owningObj, const GCSmallHermesValue *start, uint32_t numHVs) { assert( - FixedSizeHeapSegment::containedInSame(start, start + numHVs) && - "Range must start and end within a heap segment."); - FixedSizeHeapSegment::cardTableCovering(start)->dirtyCardsForAddressRange( + reinterpret_cast(owningObj) <= + reinterpret_cast(start) && + reinterpret_cast(start + numHVs) <= + (reinterpret_cast(owningObj) + + owningObj->getAllocatedSize()) && + "Range must start and end within the owning object."); + + FixedSizeHeapSegment::cardTableCovering(owningObj)->dirtyCardsForAddressRange( start, start + numHVs); }