diff --git a/include/hermes/VM/GCPointer-inline.h b/include/hermes/VM/GCPointer-inline.h index fa5f7633ed5..b5b94f3fc1f 100644 --- a/include/hermes/VM/GCPointer-inline.h +++ b/include/hermes/VM/GCPointer-inline.h @@ -32,21 +32,33 @@ GCPointerBase::GCPointerBase( } } -inline void GCPointerBase::set(PointerBase &base, GCCell *ptr, GC &gc) { +template < + GCPointerBase::MaybeLargeObj maybeLargeObj, + GCPointerBase::NonNull nonNull> +inline void GCPointerBase::setImpl( + 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.writeBarrier(this, ptr); - setNoBarrier(CompressedPointer::encode(ptr, base)); -} + (void)owningObj; + if constexpr (maybeLargeObj == MaybeLargeObj::Yes) { + assert( + owningObj && + "The cell pointer must be provided for cell kind that supports large allocation"); -inline void GCPointerBase::setNonNull(PointerBase &base, GCCell *ptr, GC &gc) { - assert( - gc.validPointer(ptr) && "Cannot set a GCPointer to an invalid pointer"); - // Write barrier must happen before the write. - gc.writeBarrier(this, ptr); - setNoBarrier(CompressedPointer::encodeNonNull(ptr, base)); + gc.writeBarrier(this, ptr); + } else { + gc.writeBarrier(this, ptr); + } + if constexpr (nonNull == NonNull::Yes) { + setNoBarrier(CompressedPointer::encodeNonNull(ptr, base)); + } else { + setNoBarrier(CompressedPointer::encode(ptr, base)); + } } inline void diff --git a/include/hermes/VM/GCPointer.h b/include/hermes/VM/GCPointer.h index 09db5f06d87..b288cc9112e 100644 --- a/include/hermes/VM/GCPointer.h +++ b/include/hermes/VM/GCPointer.h @@ -34,17 +34,47 @@ class GCPointerBase : public CompressedPointer { 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, GCCell *ptr, GC &gc) { + setImpl(base, ptr, gc, nullptr); + } inline void set(PointerBase &base, CompressedPointer ptr, GC &gc); - inline void setNonNull(PointerBase &base, GCCell *ptr, GC &gc); + inline void setNonNull(PointerBase &base, GCCell *ptr, GC &gc) { + setImpl(base, ptr, gc, nullptr); + } + + /// 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) { + setImpl(base, ptr, gc, owningObj); + } + inline void + setNonNull(PointerBase &base, GCCell *ptr, GC &gc, const GCCell *owningObj) { + setImpl(base, ptr, gc, owningObj); + } /// Set this pointer to null. This needs a write barrier in some types of /// garbage collectors. inline void setNull(GC &gc); + + private: + enum class MaybeLargeObj { No = 0, Yes }; + enum class NonNull { No = 0, Yes }; + /// Implementation details shared by all set* functions here. + /// \tparam maybeLargeObj Whether the owning object supports large allocation. + /// If it is false, \p owningObj is not used by the writer barriers. + /// \tparam nonNull Whether \p is non null. + template + void setImpl(PointerBase &base, GCCell *ptr, GC &gc, const GCCell *owningObj); }; /// A class to represent "raw" pointers to heap objects. Disallows assignment, @@ -86,7 +116,8 @@ class GCPointer : public GCPointerBase { return vmcast(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. @@ -97,6 +128,18 @@ class GCPointer : public GCPointerBase { GCPointerBase::setNonNull(base, ptr, gc); } + /// 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. void set(PointerBase &base, const GCPointer &ptr, GC &gc) { GCPointerBase::set(base, ptr, gc);