diff --git a/include/hermes/VM/HermesValue-inline.h b/include/hermes/VM/HermesValue-inline.h index e60dfb6219e..45f42842c8d 100644 --- a/include/hermes/VM/HermesValue-inline.h +++ b/include/hermes/VM/HermesValue-inline.h @@ -37,6 +37,18 @@ GCHermesValueBase::GCHermesValueBase(HVType hv, GC &gc) : HVType{hv} { gc.constructorWriteBarrier(this, hv); } +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); +} + template template GCHermesValueBase::GCHermesValueBase(HVType hv, GC &gc, std::nullptr_t) @@ -61,6 +73,22 @@ inline void GCHermesValueBase::set(HVType hv, GC &gc) { HVType::setNoBarrier(hv); } +template +template +inline void +GCHermesValueBase::set(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"); + } + assert(NeedsBarriers::value || !gc.needsWriteBarrier(this, hv)); + if constexpr (NeedsBarriers::value) { + gc.writeBarrierForLargeObj(owningObj, this, hv); + } + 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..3a9981753a5 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 set(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.