Skip to content

Commit

Permalink
Pass the pointer of owning object in constructorWriteBarrierRange
Browse files Browse the repository at this point in the history
Summary:
Add a `GCCell` pointer parameter to `constructorWriteBarrierRange`,
which represents the owning object address. It's used to get the
correct card table for pointers live in large segment.

Differential Revision: D62171114
  • Loading branch information
lavenzg authored and facebook-github-bot committed Sep 6, 2024
1 parent 5094431 commit 68766c9
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 15 deletions.
17 changes: 17 additions & 0 deletions include/hermes/VM/AlignedHeapSegment.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ class AlignedHeapSegmentBase {
return contents()->cardTable_;
}

/// Given a \p cell into the memory region of some valid segment \c s, returns
/// a pointer to the CardTable covering the segment containing the cell.
///
/// \pre There exists a currently alive heap in which \p cell is allocated.
static CardTable *cardTableCovering(const GCCell *cell) {
return &contents(alignedStorageStart(cell))->cardTable_;
}

/// Return a reference to the mark bit array covering the memory region
/// managed by this segment.
Contents::MarkBitArray &markBitArray() const {
Expand All @@ -215,6 +223,15 @@ class AlignedHeapSegmentBase {
return markBits->at(ind);
}

#ifndef NDEBUG
/// Get the storage end of segment that \p cell resides in.
static char *storageEnd(const GCCell *cell) {
auto *start = alignedStorageStart(cell);
auto *segmentInfo = reinterpret_cast<const SHSegmentInfo *>(start);
return start + segmentInfo->segmentSize;
}
#endif

protected:
AlignedHeapSegmentBase() = default;

Expand Down
2 changes: 1 addition & 1 deletion include/hermes/VM/ArrayStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, runtime.getHeap(), this);
size_.store(sz + otherSz, std::memory_order_release);
}

Expand Down
1 change: 1 addition & 0 deletions include/hermes/VM/GCBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,7 @@ class GCBase {
void constructorWriteBarrier(const GCPointerBase *loc, const GCCell *value);
template <typename HVType>
void constructorWriteBarrierRange(
const GCCell *cell,
const GCHermesValueBase<HVType> *start,
uint32_t numHVs);
template <typename HVType>
Expand Down
19 changes: 11 additions & 8 deletions include/hermes/VM/HadesGC.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,27 +216,30 @@ class HadesGC final : public GCBase {

template <typename HVType>
void constructorWriteBarrierRange(
const GCCell *cell,
const GCHermesValueBase<HVType> *start,
uint32_t numHVs) {
// A pointer that lives in YG never needs any write barriers.
if (LLVM_UNLIKELY(!inYoungGen(start)))
constructorWriteBarrierRangeSlow(start, numHVs);
constructorWriteBarrierRangeSlow(cell, start, numHVs);
}
template <typename HVType>
void constructorWriteBarrierRangeSlow(
const GCCell *cell,
const GCHermesValueBase<HVType> *start,
uint32_t numHVs) {
assert(
AlignedHeapSegment::containedInSame(start, start + numHVs) &&
reinterpret_cast<const char *>(start + numHVs) <
AlignedHeapSegmentBase::storageEnd(cell) &&
"Range must start and end within a heap segment.");

// 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.
// 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.

AlignedHeapSegment::cardTableCovering(start)->dirtyCardsForAddressRange(
AlignedHeapSegmentBase::cardTableCovering(cell)->dirtyCardsForAddressRange(
start, start + numHVs);
}

Expand Down
5 changes: 3 additions & 2 deletions include/hermes/VM/HermesValue-inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ inline GCHermesValueBase<HVType> *GCHermesValueBase<HVType>::uninitialized_copy(
GCHermesValueBase<HVType> *first,
GCHermesValueBase<HVType> *last,
GCHermesValueBase<HVType> *result,
GC &gc) {
GC &gc,
const GCCell *cell) {
#ifndef NDEBUG
uintptr_t fromFirst = reinterpret_cast<uintptr_t>(first),
fromLast = reinterpret_cast<uintptr_t>(last);
Expand All @@ -194,7 +195,7 @@ inline GCHermesValueBase<HVType> *GCHermesValueBase<HVType>::uninitialized_copy(
"Uninitialized range cannot overlap with an initialized one.");
#endif

gc.constructorWriteBarrierRange(result, last - first);
gc.constructorWriteBarrierRange(cell, result, last - first);
// memcpy is fine for an uninitialized copy.
std::memcpy(
reinterpret_cast<void *>(result), first, (last - first) * sizeof(HVType));
Expand Down
3 changes: 2 additions & 1 deletion include/hermes/VM/HermesValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,8 @@ class GCHermesValueBase final : public HVType {
GCHermesValueBase<HVType> *first,
GCHermesValueBase<HVType> *last,
GCHermesValueBase<HVType> *result,
GC &gc);
GC &gc,
const GCCell *cell);

/// Copies a range of values and performs a write barrier on each.
template <typename InputIt, typename OutputIt>
Expand Down
1 change: 1 addition & 0 deletions include/hermes/VM/MallocGC.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ class MallocGC final : public GCBase {
void writeBarrierRange(const GCHermesValueBase<HVType> *, uint32_t) {}
template <typename HVType>
void constructorWriteBarrierRange(
const GCCell *cell,
const GCHermesValueBase<HVType> *,
uint32_t) {}
template <typename HVType>
Expand Down
3 changes: 2 additions & 1 deletion lib/VM/ArrayStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ ExecutionStatus ArrayStorageBase<HVType>::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, runtime.getHeap(), self);
}

// Initialize the elements before the first copied element.
Expand Down
7 changes: 6 additions & 1 deletion lib/VM/GCBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -979,9 +979,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(
constructorWriteBarrierRange,
const GCCell *,
const GCHermesValue *,
uint32_t);
GCBASE_BARRIER_2(
constructorWriteBarrierRange,
const GCCell *,
const GCSmallHermesValue *,
uint32_t);
GCBASE_BARRIER_1(snapshotWriteBarrier, const GCHermesValue *);
Expand Down
3 changes: 2 additions & 1 deletion lib/VM/SegmentedArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,8 @@ ExecutionStatus SegmentedArrayBase<HVType>::growRight(
self->inlineStorage(),
self->inlineStorage() + numSlotsUsed,
newSegmentedArray->inlineStorage(),
runtime.getHeap());
runtime.getHeap(),
*self);
// Set the size of the new array to be the same as the old array's size.
newSegmentedArray->numSlotsUsed_.store(
numSlotsUsed, std::memory_order_release);
Expand Down

0 comments on commit 68766c9

Please sign in to comment.