Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass the pointer of owning object in ctor of GCPointer #1503

Open
wants to merge 17 commits into
base: static_h
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
556 changes: 314 additions & 242 deletions include/hermes/VM/AlignedHeapSegment.h

Large diffs are not rendered by default.

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
215 changes: 167 additions & 48 deletions include/hermes/VM/CardTableNC.h

Large diffs are not rendered by default.

34 changes: 33 additions & 1 deletion include/hermes/VM/GCBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,12 @@ enum XorPtrKeyID {
/// const GCSmallHermesValue *start,
/// uint32_t numHVs);
///
/// The above barriers may have a variant with "ForLargeObj" suffix, which is
/// used when the heap location may be from a GCCell that supports large
/// allocation. This variant is less efficient since it has to load the cards
/// array through pointer in SHSegmentInfo, instead of the inline array field
/// in CardTable structure.
///
/// In debug builds: is a write barrier necessary for a write of the given
/// GC pointer \p value to the given \p loc?
/// bool needsWriteBarrier(void *loc, void *value);
Expand All @@ -226,7 +232,7 @@ enum XorPtrKeyID {
/// Return the maximum amount of bytes holdable by this heap.
/// gcheapsize_t max() const;
/// Return the total amount of bytes of storage this GC will require.
/// This will be a multiple of AlignedHeapSegment::storageSize().
/// This will be a multiple of FixedSizeHeapSegment::storageSize().
/// gcheapsize_t storageFootprint() const;
///
class GCBase {
Expand Down Expand Up @@ -1154,18 +1160,44 @@ class GCBase {
/// Default implementations for read and write barriers: do nothing.
void writeBarrier(const GCHermesValue *loc, HermesValue value);
void writeBarrier(const GCSmallHermesValue *loc, SmallHermesValue value);
void writeBarrierForLargeObj(
const GCCell *owningObj,
const GCHermesValue *loc,
HermesValue value);
void writeBarrierForLargeObj(
const GCCell *owningObj,
const GCSmallHermesValue *loc,
SmallHermesValue value);
void writeBarrier(const GCPointerBase *loc, const GCCell *value);
void writeBarrierForLargeObj(
const GCCell *owningObj,
const GCPointerBase *loc,
const GCCell *value);
void constructorWriteBarrier(const GCHermesValue *loc, HermesValue value);
void constructorWriteBarrier(
const GCSmallHermesValue *loc,
SmallHermesValue value);
void constructorWriteBarrierForLargeObj(
const GCCell *owningObj,
const GCHermesValue *loc,
HermesValue value);
void constructorWriteBarrierForLargeObj(
const GCCell *owningObj,
const GCSmallHermesValue *loc,
SmallHermesValue value);
void constructorWriteBarrier(const GCPointerBase *loc, const GCCell *value);
void constructorWriteBarrierForLargeObj(
const GCCell *owningObj,
const GCPointerBase *loc,
const GCCell *value);
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);
Expand Down
56 changes: 56 additions & 0 deletions include/hermes/VM/GCPointer-inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@ GCPointerBase::GCPointerBase(
}
}

template <typename NeedsBarriers>
GCPointerBase::GCPointerBase(
PointerBase &base,
GCCell *ptr,
GC &gc,
const GCCell *owningObj,
NeedsBarriers)
: CompressedPointer(CompressedPointer::encode(ptr, base)) {
assert(
(!ptr || gc.validPointer(ptr)) &&
"Cannot construct a GCPointer from an invalid pointer");
if constexpr (NeedsBarriers::value) {
gc.constructorWriteBarrierForLargeObj(owningObj, this, ptr);
} else {
assert(!gc.needsWriteBarrier(this, ptr));
}
}

inline void GCPointerBase::set(PointerBase &base, GCCell *ptr, GC &gc) {
assert(
(!ptr || gc.validPointer(ptr)) &&
Expand Down Expand Up @@ -59,6 +77,44 @@ GCPointerBase::set(PointerBase &base, CompressedPointer ptr, GC &gc) {
setNoBarrier(ptr);
}

inline void GCPointerBase::set(
PointerBase &base,
GCCell *ptr,
GC &gc,
const GCCell *owningObj) {
assert(
(!ptr || gc.validPointer(ptr)) &&
"Cannot set a GCPointer to an invalid pointer");
// Write barrier must happen before the write.
gc.writeBarrierForLargeObj(owningObj, this, ptr);
setNoBarrier(CompressedPointer::encode(ptr, base));
}

inline void GCPointerBase::setNonNull(
PointerBase &base,
GCCell *ptr,
GC &gc,
const GCCell *owningObj) {
assert(
gc.validPointer(ptr) && "Cannot set a GCPointer to an invalid pointer");
// Write barrier must happen before the write.
gc.writeBarrierForLargeObj(owningObj, this, ptr);
setNoBarrier(CompressedPointer::encodeNonNull(ptr, base));
}

inline void GCPointerBase::set(
PointerBase &base,
CompressedPointer ptr,
GC &gc,
const GCCell *owningObj) {
assert(
(!ptr || gc.validPointer(ptr.get(base))) &&
"Cannot set a GCPointer to an invalid pointer");
// Write barrier must happen before the write.
gc.writeBarrierForLargeObj(owningObj, this, ptr.get(base));
setNoBarrier(ptr);
}

inline void GCPointerBase::setNull(GC &gc) {
gc.snapshotWriteBarrier(this);
setNoBarrier(CompressedPointer(nullptr));
Expand Down
71 changes: 67 additions & 4 deletions include/hermes/VM/GCPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,46 @@ class GCPointerBase : public CompressedPointer {
template <typename NeedsBarriers>
inline GCPointerBase(PointerBase &base, GCCell *ptr, GC &gc, NeedsBarriers);

template <typename NeedsBarriers>
inline GCPointerBase(
PointerBase &base,
GCCell *ptr,
GC &gc,
const GCCell *owningObj,
NeedsBarriers);

public:
// These classes are used as arguments to GCPointer constructors, to
// indicate whether write barriers are necessary in initializing the
// GCPointer.
class NoBarriers : public std::false_type {};
class YesBarriers : public std::true_type {};

/// This must be used to assign a new value to this GCPointer.
/// This must be used to assign a new value to this GCPointer. This must not
/// be used if it lives in an object that supports large allocation.
/// \param ptr The memory being pointed to.
/// \param base The base of ptr.
/// \param gc Used for write barriers.
inline void set(PointerBase &base, GCCell *ptr, GC &gc);
inline void set(PointerBase &base, CompressedPointer ptr, GC &gc);
inline void setNonNull(PointerBase &base, GCCell *ptr, GC &gc);

/// This must be used to assign a new value to this GCPointer.
/// \param ptr The memory being pointed to.
/// \param base The base of ptr.
/// \param gc Used for write barriers.
/// \param owningObj The object that contains this GCPointer, used by the
/// writer barriers.
inline void
set(PointerBase &base, GCCell *ptr, GC &gc, const GCCell *owningObj);
inline void set(
PointerBase &base,
CompressedPointer ptr,
GC &gc,
const GCCell *owningObj);
inline void
setNonNull(PointerBase &base, GCCell *ptr, GC &gc, const GCCell *owningObj);

/// Set this pointer to null. This needs a write barrier in some types of
/// garbage collectors.
inline void setNull(GC &gc);
Expand All @@ -64,12 +89,26 @@ class GCPointer : public GCPointerBase {
template <typename NeedsBarriers>
GCPointer(PointerBase &base, T *ptr, GC &gc, NeedsBarriers needsBarriers)
: GCPointerBase(base, ptr, gc, needsBarriers) {}
/// Pass the owning object pointer to perform barriers when the object
/// supports large allocation.
template <typename NeedsBarriers>
GCPointer(
PointerBase &base,
T *ptr,
GC &gc,
const GCCell *owningObj,
NeedsBarriers needsBarriers)
: GCPointerBase(base, ptr, gc, owningObj, needsBarriers) {}

/// Same as the constructor above, with the default for
/// NeedsBarriers as "YesBarriers". (We can't use default template
/// arguments with the idiom used above.)
inline GCPointer(PointerBase &base, T *ptr, GC &gc)
GCPointer(PointerBase &base, T *ptr, GC &gc)
: GCPointer<T>(base, ptr, gc, YesBarriers()) {}
/// Pass the owning object pointer to perform barriers when the object
/// supports large allocation.
GCPointer(PointerBase &base, T *ptr, GC &gc, const GCCell *owningObj)
: GCPointer<T>(base, ptr, gc, owningObj, YesBarriers()) {}

/// We are not allowed to copy-construct or assign GCPointers.
GCPointer(const GCPointerBase &) = delete;
Expand All @@ -86,7 +125,8 @@ class GCPointer : public GCPointerBase {
return vmcast<T>(GCPointerBase::getNonNull(base));
}

/// Assign a new value to this GCPointer.
/// Assign a new value to this GCPointer. This must not be used if it lives in
/// an object that supports large allocation.
/// \param base The base of ptr.
/// \param ptr The memory being pointed to.
/// \param gc Used for write barriers.
Expand All @@ -97,10 +137,33 @@ class GCPointer : public GCPointerBase {
GCPointerBase::setNonNull(base, ptr, gc);
}

/// Convenience overload of GCPointer::set for other GCPointers.
/// Assign a new value to this GCPointer.
/// \param ptr The memory being pointed to.
/// \param gc Used for write barriers.
/// \param owningObj The object that contains this GCPointer, used by the
/// writer barriers.
void set(PointerBase &base, T *ptr, GC &gc, const GCCell *owningObj) {
GCPointerBase::set(base, ptr, gc, owningObj);
}
void setNonNull(PointerBase &base, T *ptr, GC &gc, const GCCell *owningObj) {
GCPointerBase::setNonNull(base, ptr, gc, owningObj);
}

/// Convenience overload of GCPointer::set for other GCPointers. This must not
/// be used if it lives in an object that supports large allocation.
void set(PointerBase &base, const GCPointer<T> &ptr, GC &gc) {
GCPointerBase::set(base, ptr, gc);
}

/// Convenience overload of GCPointer::set for other GCPointers. \p owningObj
/// is used by the writer barriers.
void set(
PointerBase &base,
const GCPointer<T> &ptr,
GC &gc,
const GCCell *owningObj) {
GCPointerBase::set(base, ptr, gc, owningObj);
}
};

} // namespace vm
Expand Down
Loading
Loading