diff --git a/include/hermes/VM/HermesValue-inline.h b/include/hermes/VM/HermesValue-inline.h index e60dfb6219e..cc18cd5ff72 100644 --- a/include/hermes/VM/HermesValue-inline.h +++ b/include/hermes/VM/HermesValue-inline.h @@ -33,8 +33,33 @@ template template GCHermesValueBase::GCHermesValueBase(HVType hv, GC &gc) : HVType{hv} { assert(!hv.isPointer() || hv.getPointer()); - if (NeedsBarriers::value) + if (NeedsBarriers::value) { gc.constructorWriteBarrier(this, hv); + } else { + assert( + !gc.needsWriteBarrierInCtor(this, hv) && + "Can't skip write barriers for this GCHermesValueBase and target value"); + } +} + +template +template +GCHermesValueBase::GCHermesValueBase( + HVType hv, + GC &gc, + const GCCell *owningObj) + : HVType{hv} { + assert(!hv.isPointer() || hv.getPointer()); + if (NeedsBarriers::value) { + gc.constructorWriteBarrierForLargeObj(owningObj, this, hv); + } else { + // We don't allow skipping write barriers for pointers live in objects that + // support large allocation. This may be revisited if we do have a case that + // needs optimization. + assert( + !hv.isPointer() && + "Initial value for GCHermesValueBase in a large object must not be pointer when NeedsBarriers is false"); + } } template @@ -61,6 +86,27 @@ inline void GCHermesValueBase::set(HVType hv, GC &gc) { HVType::setNoBarrier(hv); } +template +template +inline void GCHermesValueBase::setInLarge( + HVType hv, + GC &gc, + const GCCell *owningObj) { + if (hv.isPointer()) { + HERMES_SLOW_ASSERT( + gc.validPointer(hv.getPointer(gc.getPointerBase())) && + "Setting an invalid pointer into a GCHermesValue"); + } + if constexpr (NeedsBarriers::value) { + gc.writeBarrierForLargeObj(owningObj, this, hv); + } else { + assert( + !gc.needsWriteBarrierForLargeObj(this, hv) && + "Can't skip write barriers when assigning pointer to GCHermesValueBase in a large object"); + } + HVType::setNoBarrier(hv); +} + template void GCHermesValueBase::setNonPtr(HVType hv, GC &gc) { assert(!hv.isPointer()); diff --git a/include/hermes/VM/HermesValue.h b/include/hermes/VM/HermesValue.h index 1dbd01effe5..45c37f61bdf 100644 --- a/include/hermes/VM/HermesValue.h +++ b/include/hermes/VM/HermesValue.h @@ -520,9 +520,15 @@ template class GCHermesValueBase final : public HVType { public: GCHermesValueBase() : HVType(HVType::encodeUndefinedValue()) {} - /// Initialize a GCHermesValue from another HV. Performs a write barrier. + /// Initialize a GCHermesValue from another HV. Performs a write barrier. This + /// must not be used if it lives in an object that supports large allocation. template GCHermesValueBase(HVType hv, GC &gc); + /// Initialize a GCHermesValue from another HV. Performs a write barrier using + /// \p owningObj, which owns this GCHermesValue and may support large + /// allocation. + template + GCHermesValueBase(HVType hv, GC &gc, const GCCell *owningObj); /// Initialize a GCHermesValue from a non-pointer HV. Might perform a write /// barrier, depending on the GC. /// NOTE: The last parameter is unused, but acts as an overload selector. @@ -530,11 +536,19 @@ class GCHermesValueBase final : public HVType { GCHermesValueBase(HVType hv, GC &gc, std::nullptr_t); GCHermesValueBase(const HVType &) = delete; - /// The HermesValue \p hv may be an object pointer. Assign the - /// value, and perform any necessary write barriers. + /// The HermesValue \p hv may be an object pointer. Assign the value, and + /// perform any necessary write barriers. This must not be used if it lives in + /// an object that supports large allocation. template inline void set(HVType hv, GC &gc); + /// The HermesValue \p hv may be an object pointer. Assign the value, and + /// perform any necessary write barriers. \p owningObj is the object that + /// contains this GCHermesValueBase, and it may support large allocation. + /// for which the object pointer is needed by writer barriers. + template + inline void setInLarge(HVType hv, GC &gc, const GCCell *owningObj); + /// The HermesValue \p hv must not be an object pointer. Assign the /// value. /// Some GCs still need to do a write barrier though, so pass a GC parameter.