diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index b322995dbc4a..0d31d4dccc5b 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -2126,9 +2126,12 @@ InlineTypedObject::obj_trace(JSTracer* trc, JSObject* object) typedObj.typeDescr().traceInstances(trc, typedObj.inlineTypedMem(), 1); } -/* static */ void -InlineTypedObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src) +/* static */ size_t +InlineTypedObject::obj_moved(JSObject* dst, JSObject* src) { + if (!IsInsideNursery(src)) + return 0; + // Inline typed object element arrays can be preserved on the stack by Ion // and need forwarding pointers created during a minor GC. We can't do this // in the trace hook because we don't have any stale data to determine @@ -2140,9 +2143,12 @@ InlineTypedObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObje // but they will not set any direct forwarding pointers. uint8_t* oldData = reinterpret_cast(src) + offsetOfDataStart(); uint8_t* newData = dst->as().inlineTypedMem(); - dst->zone()->group()->nursery().maybeSetForwardingPointer(trc, oldData, newData, - descr.size() >= sizeof(uintptr_t)); + auto& nursery = dst->zone()->group()->nursery(); + bool direct = descr.size() >= sizeof(uintptr_t); + nursery.setForwardingPointerWhileTenuring(oldData, newData, direct); } + + return 0; } ArrayBufferObject* @@ -2219,7 +2225,7 @@ const ObjectOps TypedObject::objectOps_ = { nullptr, /* thisValue */ }; -#define DEFINE_TYPEDOBJ_CLASS(Name, Trace, flag) \ +#define DEFINE_TYPEDOBJ_CLASS(Name, Trace, Moved, flag) \ static const ClassOps Name##ClassOps = { \ nullptr, /* addProperty */ \ nullptr, /* delProperty */ \ @@ -2233,20 +2239,34 @@ const ObjectOps TypedObject::objectOps_ = { nullptr, /* construct */ \ Trace, \ }; \ + static const ClassExtension Name##ClassExt = { \ + nullptr, /* weakmapKeyDelegateOp */ \ + Moved /* objectMovedOp */ \ + }; \ const Class Name::class_ = { \ # Name, \ Class::NON_NATIVE | flag, \ &Name##ClassOps, \ JS_NULL_CLASS_SPEC, \ - JS_NULL_CLASS_EXT, \ + &Name##ClassExt, \ &TypedObject::objectOps_ \ } -DEFINE_TYPEDOBJ_CLASS(OutlineTransparentTypedObject, OutlineTypedObject::obj_trace, 0); -DEFINE_TYPEDOBJ_CLASS(OutlineOpaqueTypedObject, OutlineTypedObject::obj_trace, 0); -DEFINE_TYPEDOBJ_CLASS(InlineTransparentTypedObject, InlineTypedObject::obj_trace, +DEFINE_TYPEDOBJ_CLASS(OutlineTransparentTypedObject, + OutlineTypedObject::obj_trace, + nullptr, + 0); +DEFINE_TYPEDOBJ_CLASS(OutlineOpaqueTypedObject, + OutlineTypedObject::obj_trace, + nullptr, + 0); +DEFINE_TYPEDOBJ_CLASS(InlineTransparentTypedObject, + InlineTypedObject::obj_trace, + InlineTypedObject::obj_moved, JSCLASS_DELAY_METADATA_BUILDER); -DEFINE_TYPEDOBJ_CLASS(InlineOpaqueTypedObject, InlineTypedObject::obj_trace, +DEFINE_TYPEDOBJ_CLASS(InlineOpaqueTypedObject, + InlineTypedObject::obj_trace, + InlineTypedObject::obj_moved, JSCLASS_DELAY_METADATA_BUILDER); static int32_t diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index f9d899eba729..d994e131752b 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -723,7 +723,7 @@ class InlineTypedObject : public TypedObject } static void obj_trace(JSTracer* trace, JSObject* object); - static void objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src); + static size_t obj_moved(JSObject* dst, JSObject* src); static size_t offsetOfDataStart() { return offsetof(InlineTypedObject, data_); diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index c2390df844a8..39bc5811c090 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2976,15 +2976,10 @@ js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind // shape list. This is updated in Nursery::sweepDictionaryModeObjects(). } - if (src->is()) { - InlineTypedObject::objectMovedDuringMinorGC(this, dst, src); - } else if (src->is()) { - tenuredSize += TypedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind); - } else if (src->is()) { - tenuredSize += UnboxedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind); - } else if (src->is()) { - tenuredSize += ArgumentsObject::objectMovedDuringMinorGC(this, dst, src); - } else if (src->is()) { + if (src->is()) { + // TODO: Push this logic into proxy_ObjectMoved and make all proxies use + // this. + // Objects in the nursery are never swapped so the proxy must have an // inline ProxyValueArray. MOZ_ASSERT(src->as().usingInlineValueArray()); diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 1f80406dc9df..e6523a5f9b54 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -217,7 +217,12 @@ class Nursery void forwardBufferPointer(HeapSlot** pSlotsElems); void maybeSetForwardingPointer(JSTracer* trc, void* oldData, void* newData, bool direct) { - if (trc->isTenuringTracer() && isInside(oldData)) + if (trc->isTenuringTracer()) + setForwardingPointerWhileTenuring(oldData, newData, direct); + } + + void setForwardingPointerWhileTenuring(void* oldData, void* newData, bool direct) { + if (isInside(oldData)) setForwardingPointer(oldData, newData, direct); } diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index 7349624d316a..6565a21518fe 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -855,12 +855,15 @@ ArgumentsObject::trace(JSTracer* trc, JSObject* obj) } /* static */ size_t -ArgumentsObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src) +ArgumentsObject::objectMoved(JSObject* dst, JSObject* src) { ArgumentsObject* ndst = &dst->as(); - ArgumentsObject* nsrc = &src->as(); + const ArgumentsObject* nsrc = &src->as(); MOZ_ASSERT(ndst->data() == nsrc->data()); + if (!IsInsideNursery(src)) + return 0; + Nursery& nursery = dst->zone()->group()->nursery(); size_t nbytesTotal = 0; @@ -917,6 +920,11 @@ const ClassOps MappedArgumentsObject::classOps_ = { ArgumentsObject::trace }; +const js::ClassExtension MappedArgumentsObject::classExt_ = { + nullptr, /* weakmapKeyDelegateOp */ + ArgumentsObject::objectMoved /* objectMovedOp */ +}; + const ObjectOps MappedArgumentsObject::objectOps_ = { nullptr, /* lookupProperty */ MappedArgumentsObject::obj_defineProperty @@ -931,7 +939,7 @@ const Class MappedArgumentsObject::class_ = { JSCLASS_BACKGROUND_FINALIZE, &MappedArgumentsObject::classOps_, nullptr, - nullptr, + &MappedArgumentsObject::classExt_, &MappedArgumentsObject::objectOps_ }; @@ -953,6 +961,11 @@ const ClassOps UnmappedArgumentsObject::classOps_ = { ArgumentsObject::trace }; +const js::ClassExtension UnmappedArgumentsObject::classExt_ = { + nullptr, /* weakmapKeyDelegateOp */ + ArgumentsObject::objectMoved /* objectMovedOp */ +}; + const Class UnmappedArgumentsObject::class_ = { "Arguments", JSCLASS_DELAY_METADATA_BUILDER | @@ -960,5 +973,7 @@ const Class UnmappedArgumentsObject::class_ = { JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | JSCLASS_SKIP_NURSERY_FINALIZE | JSCLASS_BACKGROUND_FINALIZE, - &UnmappedArgumentsObject::classOps_ + &UnmappedArgumentsObject::classOps_, + nullptr, + &UnmappedArgumentsObject::classExt_ }; diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index d0e645b3a70d..fb8389478cf5 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -361,7 +361,7 @@ class ArgumentsObject : public NativeObject static void finalize(FreeOp* fop, JSObject* obj); static void trace(JSTracer* trc, JSObject* obj); - static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src); + static size_t objectMoved(JSObject* dst, JSObject* src); /* For jit use: */ static size_t getDataSlotOffset() { @@ -399,6 +399,7 @@ class ArgumentsObject : public NativeObject class MappedArgumentsObject : public ArgumentsObject { static const ClassOps classOps_; + static const ClassExtension classExt_; static const ObjectOps objectOps_; public: @@ -428,6 +429,7 @@ class MappedArgumentsObject : public ArgumentsObject class UnmappedArgumentsObject : public ArgumentsObject { static const ClassOps classOps_; + static const ClassExtension classExt_; public: static const Class class_; diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 186722e13d54..6a8aec630f52 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -184,25 +184,7 @@ TypedArrayObject::finalize(FreeOp* fop, JSObject* obj) TypedArrayObject::objectMoved(JSObject* obj, JSObject* old) { TypedArrayObject* newObj = &obj->as(); - const TypedArrayObject* oldObj = &old->as(); - - // Typed arrays with a buffer object do not need an update. - if (oldObj->hasBuffer()) - return 0; - - // Update the data slot pointer if it points to the old JSObject. - if (oldObj->hasInlineElements()) - newObj->setInlineElements(); - - return 0; -} - -/* static */ size_t -TypedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* obj, const JSObject* old, - gc::AllocKind newAllocKind) -{ - TypedArrayObject* newObj = &obj->as(); - const TypedArrayObject* oldObj = &old->as(); + TypedArrayObject* oldObj = &old->as(); MOZ_ASSERT(newObj->elementsRaw() == oldObj->elementsRaw()); MOZ_ASSERT(obj->isTenured()); @@ -210,6 +192,14 @@ TypedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* obj, const J if (oldObj->hasBuffer()) return 0; + if (!IsInsideNursery(old)) { + // Update the data slot pointer if it points to the old JSObject. + if (oldObj->hasInlineElements()) + newObj->setInlineElements(); + + return 0; + } + Nursery& nursery = obj->zone()->group()->nursery(); void* buf = oldObj->elements(); @@ -236,6 +226,7 @@ JS_FOR_EACH_TYPED_ARRAY(OBJECT_MOVED_TYPED_ARRAY) size_t headerSize = dataOffset() + sizeof(HeapSlot); // See AllocKindForLazyBuffer. + AllocKind newAllocKind = obj->asTenured().getAllocKind(); MOZ_ASSERT_IF(nbytes == 0, headerSize + sizeof(uint8_t) <= GetGCKindBytes(newAllocKind)); if (headerSize + nbytes <= GetGCKindBytes(newAllocKind)) { @@ -262,8 +253,8 @@ JS_FOR_EACH_TYPED_ARRAY(OBJECT_MOVED_TYPED_ARRAY) // Set a forwarding pointer for the element buffers in case they were // preserved on the stack by Ion. - nursery.maybeSetForwardingPointer(trc, oldObj->elements(), newObj->elements(), - /* direct = */nbytes >= sizeof(uintptr_t)); + nursery.setForwardingPointerWhileTenuring(oldObj->elements(), newObj->elements(), + /* direct = */nbytes >= sizeof(uintptr_t)); return newObj->hasInlineElements() ? 0 : nbytes; } diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index fdb342a96125..a9f563481328 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -274,8 +274,6 @@ class TypedArrayObject : public NativeObject static void trace(JSTracer* trc, JSObject* obj); static void finalize(FreeOp* fop, JSObject* obj); static size_t objectMoved(JSObject* obj, JSObject* old); - static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* obj, const JSObject* old, - gc::AllocKind allocKind); /* Initialization bits */ diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index e21e7bd73154..0a9cdc621ae7 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -1203,19 +1203,6 @@ UnboxedArrayObject::trace(JSTracer* trc, JSObject* obj) } } -/* static */ size_t -UnboxedArrayObject::objectMoved(JSObject* obj, JSObject* old) -{ - UnboxedArrayObject& dst = obj->as(); - const UnboxedArrayObject& src = old->as(); - - // Fix up possible inline data pointer. - if (src.hasInlineElements()) - dst.setInlineElements(); - - return 0; -} - /* static */ void UnboxedArrayObject::finalize(FreeOp* fop, JSObject* obj) { @@ -1225,15 +1212,21 @@ UnboxedArrayObject::finalize(FreeOp* fop, JSObject* obj) } /* static */ size_t -UnboxedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src, - gc::AllocKind allocKind) +UnboxedArrayObject::objectMoved(JSObject* dst, JSObject* src) { UnboxedArrayObject* ndst = &dst->as(); UnboxedArrayObject* nsrc = &src->as(); MOZ_ASSERT(ndst->elements() == nsrc->elements()); - Nursery& nursery = dst->zone()->group()->nursery(); + if (!IsInsideNursery(src)) { + // Fix up possible inline data pointer. + if (nsrc->hasInlineElements()) + ndst->setInlineElements(); + return 0; + } + + Nursery& nursery = dst->zone()->group()->nursery(); if (!nursery.isInside(nsrc->elements())) { nursery.removeMallocedBuffer(nsrc->elements()); return 0; @@ -1243,7 +1236,8 @@ UnboxedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObj // possible, the nursery will have picked an allocation size that is large // enough. size_t nbytes = nsrc->capacity() * nsrc->elementSize(); - if (offsetOfInlineElements() + nbytes <= GetGCKindBytes(allocKind)) { + gc::AllocKind allocKind = dst->asTenured().getAllocKind(); + if (offsetOfInlineElements() + nbytes <= gc::GetGCKindBytes(allocKind)) { ndst->setInlineElements(); } else { MOZ_ASSERT(allocKind == gc::AllocKind::OBJECT0); @@ -1260,7 +1254,7 @@ UnboxedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObj // Set a forwarding pointer for the element buffers in case they were // preserved on the stack by Ion. bool direct = nsrc->capacity() * nsrc->elementSize() >= sizeof(uintptr_t); - nursery.maybeSetForwardingPointer(trc, nsrc->elements(), ndst->elements(), direct); + nursery.setForwardingPointerWhileTenuring(nsrc->elements(), ndst->elements(), direct); return ndst->hasInlineElements() ? 0 : nbytes; } diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 231e8d502280..335334aba889 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -446,9 +446,6 @@ class UnboxedArrayObject : public UnboxedObject static size_t objectMoved(JSObject* obj, JSObject* old); static void finalize(FreeOp* fop, JSObject* obj); - static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src, - gc::AllocKind allocKind); - uint8_t* elements() { return elements_; }