From 50cc1c6a4677716eb290f18a621d401479642029 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 19 Sep 2023 14:59:13 +0000 Subject: [PATCH] Bug 1852063 - Use WeakHeapPtr to store weak cache IR stub fields r=jandem The problem here is that we currently use GCPtr to store weak fields, and this has assertions that don't make sense in this case. Selecting the write wrapper class is slightly fiddly but can be accomplished by using a template class to map from the field type to the types required. Differential Revision: https://phabricator.services.mozilla.com/D188473 --- js/src/gc/Marking.cpp | 9 +- js/src/gc/Tracer.h | 2 +- js/src/jit-test/tests/gc/bug-1852063.js | 32 +++++ js/src/jit/BaselineCacheIRCompiler.cpp | 10 +- js/src/jit/CacheIR.cpp | 2 +- js/src/jit/CacheIRCompiler.cpp | 200 ++++++++++++++++---------------- js/src/jit/CacheIRCompiler.h | 71 +++++++++++- js/src/jit/WarpOracle.cpp | 71 +++++++----- 8 files changed, 256 insertions(+), 141 deletions(-) create mode 100644 js/src/jit-test/tests/gc/bug-1852063.js diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 7b5d7fb1d4ad..3672fcbfcb06 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -499,16 +499,17 @@ template void js::TraceManuallyBarrieredCrossCompartmentEdge( template void js::TraceSameZoneCrossCompartmentEdge(JSTracer* trc, - const WriteBarriered* dst, + const BarrieredBase* dst, const char* name) { #ifdef DEBUG if (trc->isMarkingTracer()) { - MOZ_ASSERT((*dst)->maybeCompartment(), + T thing = *dst->unbarrieredAddress(); + MOZ_ASSERT(thing->maybeCompartment(), "Use TraceEdge for GC things without a compartment"); GCMarker* gcMarker = GCMarker::fromTracer(trc); MOZ_ASSERT_IF(gcMarker->tracingZone, - (*dst)->zone() == gcMarker->tracingZone); + thing->zone() == gcMarker->tracingZone); } // Skip compartment checks for this edge. @@ -522,7 +523,7 @@ void js::TraceSameZoneCrossCompartmentEdge(JSTracer* trc, TraceEdgeInternal(trc, ConvertToBase(dst->unbarrieredAddress()), name); } template void js::TraceSameZoneCrossCompartmentEdge( - JSTracer*, const WriteBarriered*, const char*); + JSTracer*, const BarrieredBase*, const char*); template void js::TraceWeakMapKeyEdgeInternal(JSTracer* trc, Zone* weakMapZone, diff --git a/js/src/gc/Tracer.h b/js/src/gc/Tracer.h index ca2ea9c25ddb..22d24aaa9c3e 100644 --- a/js/src/gc/Tracer.h +++ b/js/src/gc/Tracer.h @@ -340,7 +340,7 @@ void TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, // GC peer first. template void TraceSameZoneCrossCompartmentEdge(JSTracer* trc, - const WriteBarriered* dst, + const BarrieredBase* dst, const char* name); // Trace a weak map key. For debugger weak maps these may be cross compartment, diff --git a/js/src/jit-test/tests/gc/bug-1852063.js b/js/src/jit-test/tests/gc/bug-1852063.js new file mode 100644 index 000000000000..7c464f6ed690 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1852063.js @@ -0,0 +1,32 @@ +// |jit-test| --fast-warmup + +gczeal(0); + +// Create a gray function. +grayRoot()[0] = (obj) => obj.x; + +function foo(obj, skip) { + if (!skip) + return grayRoot()[0](obj); +} + +with ({}) {} + +// Set up `foo` to inline the gray function when we hit the threshold. +for (var i = 0; i < 6; i++) { + foo({x:1}, false); + foo({y:1, x:2}, false); +} + +// Start a gc, yielding after marking gray roots. +gczeal(25); +startgc(1); + +// Trigger inlining, being careful not to call and mark the gray function. +// This adds the gray function to cellsToAssertNotGray. +for (var i = 0; i < 10; i++) { + foo({x:1}, true); +} + +// Finish the gc and process the delayed gray checks list. +finishgc(); diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp index 920e0c899213..887356abd813 100644 --- a/js/src/jit/BaselineCacheIRCompiler.cpp +++ b/js/src/jit/BaselineCacheIRCompiler.cpp @@ -2331,8 +2331,10 @@ bool js::jit::TryFoldingStubs(JSContext* cx, ICFallbackStub* fallback, writer.guardMultipleShapes(objId, shapeObj); success = true; } else { - Shape* shape = stubInfo->getStubField(firstStub, shapeOffset); - writer.guardShape(objId, shape); + WeakHeapPtr& ptr = + stubInfo->getStubField(firstStub, + shapeOffset); + writer.guardShape(objId, ptr.unbarrieredGet()); } break; } @@ -2416,8 +2418,8 @@ static bool AddToFoldedStub(JSContext* cx, const CacheIRWriter& writer, newShape = PrivateValue(shape); // Get the shape array from the old stub. - JSObject* shapeList = - stubInfo->getStubField(stub, stubShapesOffset); + JSObject* shapeList = stubInfo->getStubField( + stub, stubShapesOffset); foldedShapes = &shapeList->as(); MOZ_ASSERT(foldedShapes->compartment() == shape->compartment()); diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 0191bd41fdc4..bb6957798462 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -134,7 +134,7 @@ size_t js::jit::NumInputsForCacheKind(CacheKind kind) { #ifdef DEBUG void CacheIRWriter::assertSameCompartment(JSObject* obj) { - cx_->debugOnlyCheck(obj); + MOZ_ASSERT(cx_->compartment() == obj->compartment()); } void CacheIRWriter::assertSameZone(Shape* shape) { MOZ_ASSERT(cx_->zone() == shape->zone()); diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp index f0131c183abe..085c8f3bc058 100644 --- a/js/src/jit/CacheIRCompiler.cpp +++ b/js/src/jit/CacheIRCompiler.cpp @@ -1077,36 +1077,31 @@ void CacheIRStubInfo::replaceStubRawWord(uint8_t* stubData, uint32_t offset, *addr = newWord; } -template -GCPtr& CacheIRStubInfo::getStubField(Stub* stub, uint32_t offset) const { +template +typename MapStubFieldToType::WrappedType& CacheIRStubInfo::getStubField( + Stub* stub, uint32_t offset) const { uint8_t* stubData = (uint8_t*)stub + stubDataOffset_; MOZ_ASSERT(uintptr_t(stubData + offset) % sizeof(uintptr_t) == 0); - return *AsGCPtr((uintptr_t*)(stubData + offset)); -} - -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; -template GCPtr& CacheIRStubInfo::getStubField( - ICCacheIRStub* stub, uint32_t offset) const; + using WrappedType = typename MapStubFieldToType::WrappedType; + return *reinterpret_cast(stubData + offset); +} + +#define INSTANTIATE_GET_STUB_FIELD(Type) \ + template typename MapStubFieldToType::WrappedType& \ + CacheIRStubInfo::getStubField(ICCacheIRStub * stub, \ + uint32_t offset) const; +INSTANTIATE_GET_STUB_FIELD(StubField::Type::Shape) +INSTANTIATE_GET_STUB_FIELD(StubField::Type::WeakShape) +INSTANTIATE_GET_STUB_FIELD(StubField::Type::WeakGetterSetter) +INSTANTIATE_GET_STUB_FIELD(StubField::Type::JSObject) +INSTANTIATE_GET_STUB_FIELD(StubField::Type::WeakObject) +INSTANTIATE_GET_STUB_FIELD(StubField::Type::Symbol) +INSTANTIATE_GET_STUB_FIELD(StubField::Type::String) +INSTANTIATE_GET_STUB_FIELD(StubField::Type::WeakBaseScript) +INSTANTIATE_GET_STUB_FIELD(StubField::Type::Value) +INSTANTIATE_GET_STUB_FIELD(StubField::Type::Id) +#undef INSTANTIATE_GET_STUB_FIELD template T* CacheIRStubInfo::getPtrStubField(Stub* stub, uint32_t offset) const { @@ -1119,9 +1114,12 @@ T* CacheIRStubInfo::getPtrStubField(Stub* stub, uint32_t offset) const { template gc::AllocSite* CacheIRStubInfo::getPtrStubField(ICCacheIRStub* stub, uint32_t offset) const; -template -static void InitGCPtr(uintptr_t* ptr, V val) { - AsGCPtr(ptr)->init(mozilla::BitwiseCast(val)); +template +static void InitWrappedPtr(uintptr_t* ptr, V val) { + using RawType = typename MapStubFieldToType::RawType; + using WrappedType = typename MapStubFieldToType::WrappedType; + auto* wrapped = reinterpret_cast(ptr); + new (wrapped) WrappedType(mozilla::BitwiseCast(val)); } void CacheIRWriter::copyStubData(uint8_t* dest) const { @@ -1140,35 +1138,37 @@ void CacheIRWriter::copyStubData(uint8_t* dest) const { *destWords = field.asWord(); break; case StubField::Type::Shape: - InitGCPtr(destWords, field.asWord()); + InitWrappedPtr(destWords, field.asWord()); break; case StubField::Type::WeakShape: // No read barrier required to copy weak pointer. - InitGCPtr(destWords, field.asWord()); + InitWrappedPtr(destWords, field.asWord()); break; case StubField::Type::WeakGetterSetter: // No read barrier required to copy weak pointer. - InitGCPtr(destWords, field.asWord()); + InitWrappedPtr(destWords, + field.asWord()); break; case StubField::Type::JSObject: - InitGCPtr(destWords, field.asWord()); + InitWrappedPtr(destWords, field.asWord()); break; case StubField::Type::WeakObject: // No read barrier required to copy weak pointer. - InitGCPtr(destWords, field.asWord()); + InitWrappedPtr(destWords, field.asWord()); break; case StubField::Type::Symbol: - InitGCPtr(destWords, field.asWord()); + InitWrappedPtr(destWords, field.asWord()); break; case StubField::Type::String: - InitGCPtr(destWords, field.asWord()); + InitWrappedPtr(destWords, field.asWord()); break; case StubField::Type::WeakBaseScript: // No read barrier required to copy weak pointer. - InitGCPtr(destWords, field.asWord()); + InitWrappedPtr(destWords, + field.asWord()); break; case StubField::Type::JitCode: - InitGCPtr(destWords, field.asWord()); + InitWrappedPtr(destWords, field.asWord()); break; case StubField::Type::Id: AsGCPtr(destWords)->init(jsid::fromRawBits(field.asWord())); @@ -1202,89 +1202,93 @@ static inline bool ShouldTraceWeakEdgeInStub(JSTracer* trc) { template void jit::TraceCacheIRStub(JSTracer* trc, T* stub, const CacheIRStubInfo* stubInfo) { + using Type = StubField::Type; + uint32_t field = 0; size_t offset = 0; while (true) { - StubField::Type fieldType = stubInfo->fieldType(field); + Type fieldType = stubInfo->fieldType(field); switch (fieldType) { - case StubField::Type::RawInt32: - case StubField::Type::RawPointer: - case StubField::Type::RawInt64: - case StubField::Type::Double: + case Type::RawInt32: + case Type::RawPointer: + case Type::RawInt64: + case Type::Double: break; - case StubField::Type::Shape: { + case Type::Shape: { // For CCW IC stubs, we can store same-zone but cross-compartment // shapes. Use TraceSameZoneCrossCompartmentEdge to not assert in the // GC. Note: CacheIRWriter::writeShapeField asserts we never store // cross-zone shapes. GCPtr& shapeField = - stubInfo->getStubField(stub, offset); + stubInfo->getStubField(stub, offset); TraceSameZoneCrossCompartmentEdge(trc, &shapeField, "cacheir-shape"); break; } - case StubField::Type::WeakShape: + case Type::WeakShape: if (ShouldTraceWeakEdgeInStub(trc)) { - GCPtr& shapeField = - stubInfo->getStubField(stub, offset); + WeakHeapPtr& shapeField = + stubInfo->getStubField(stub, offset); if (shapeField) { TraceSameZoneCrossCompartmentEdge(trc, &shapeField, "cacheir-weak-shape"); } } break; - case StubField::Type::WeakGetterSetter: + case Type::WeakGetterSetter: if (ShouldTraceWeakEdgeInStub(trc)) { TraceNullableEdge( - trc, &stubInfo->getStubField(stub, offset), + trc, + &stubInfo->getStubField(stub, offset), "cacheir-weak-getter-setter"); } break; - case StubField::Type::JSObject: { - TraceEdge(trc, &stubInfo->getStubField(stub, offset), + case Type::JSObject: { + TraceEdge(trc, &stubInfo->getStubField(stub, offset), "cacheir-object"); break; } - case StubField::Type::WeakObject: + case Type::WeakObject: if (ShouldTraceWeakEdgeInStub(trc)) { - TraceNullableEdge(trc, - &stubInfo->getStubField(stub, offset), - "cacheir-weak-object"); + TraceNullableEdge( + trc, &stubInfo->getStubField(stub, offset), + "cacheir-weak-object"); } break; - case StubField::Type::Symbol: - TraceEdge(trc, &stubInfo->getStubField(stub, offset), + case Type::Symbol: + TraceEdge(trc, &stubInfo->getStubField(stub, offset), "cacheir-symbol"); break; - case StubField::Type::String: - TraceEdge(trc, &stubInfo->getStubField(stub, offset), + case Type::String: + TraceEdge(trc, &stubInfo->getStubField(stub, offset), "cacheir-string"); break; - case StubField::Type::WeakBaseScript: + case Type::WeakBaseScript: if (ShouldTraceWeakEdgeInStub(trc)) { TraceNullableEdge( - trc, &stubInfo->getStubField(stub, offset), + trc, + &stubInfo->getStubField(stub, offset), "cacheir-weak-script"); } break; - case StubField::Type::JitCode: - TraceEdge(trc, &stubInfo->getStubField(stub, offset), + case Type::JitCode: + TraceEdge(trc, &stubInfo->getStubField(stub, offset), "cacheir-jitcode"); break; - case StubField::Type::Id: - TraceEdge(trc, &stubInfo->getStubField(stub, offset), + case Type::Id: + TraceEdge(trc, &stubInfo->getStubField(stub, offset), "cacheir-id"); break; - case StubField::Type::Value: - TraceEdge(trc, &stubInfo->getStubField(stub, offset), + case Type::Value: + TraceEdge(trc, &stubInfo->getStubField(stub, offset), "cacheir-value"); break; - case StubField::Type::AllocSite: { + case Type::AllocSite: { gc::AllocSite* site = stubInfo->getPtrStubField(stub, offset); site->trace(trc); break; } - case StubField::Type::Limit: + case Type::Limit: return; // Done. } field++; @@ -1301,41 +1305,43 @@ template void jit::TraceCacheIRStub(JSTracer* trc, IonICStub* stub, template bool jit::TraceWeakCacheIRStub(JSTracer* trc, T* stub, const CacheIRStubInfo* stubInfo) { + using Type = StubField::Type; + uint32_t field = 0; size_t offset = 0; while (true) { - StubField::Type fieldType = stubInfo->fieldType(field); + Type fieldType = stubInfo->fieldType(field); switch (fieldType) { - case StubField::Type::WeakShape: { - GCPtr& shapeField = - stubInfo->getStubField(stub, offset); + case Type::WeakShape: { + WeakHeapPtr& shapeField = + stubInfo->getStubField(stub, offset); auto r = TraceWeakEdge(trc, &shapeField, "cacheir-weak-shape"); if (r.isDead()) { return false; } break; } - case StubField::Type::WeakObject: { - GCPtr& objectField = - stubInfo->getStubField(stub, offset); + case Type::WeakObject: { + WeakHeapPtr& objectField = + stubInfo->getStubField(stub, offset); auto r = TraceWeakEdge(trc, &objectField, "cacheir-weak-object"); if (r.isDead()) { return false; } break; } - case StubField::Type::WeakBaseScript: { - GCPtr& scriptField = - stubInfo->getStubField(stub, offset); + case Type::WeakBaseScript: { + WeakHeapPtr& scriptField = + stubInfo->getStubField(stub, offset); auto r = TraceWeakEdge(trc, &scriptField, "cacheir-weak-script"); if (r.isDead()) { return false; } break; } - case StubField::Type::WeakGetterSetter: { - GCPtr& getterSetterField = - stubInfo->getStubField(stub, offset); + case Type::WeakGetterSetter: { + WeakHeapPtr& getterSetterField = + stubInfo->getStubField(stub, offset); auto r = TraceWeakEdge(trc, &getterSetterField, "cacheir-weak-getter-setter"); if (r.isDead()) { @@ -1343,20 +1349,20 @@ bool jit::TraceWeakCacheIRStub(JSTracer* trc, T* stub, } break; } - case StubField::Type::Limit: + case Type::Limit: return true; // Done. - case StubField::Type::RawInt32: - case StubField::Type::RawPointer: - case StubField::Type::Shape: - case StubField::Type::JSObject: - case StubField::Type::Symbol: - case StubField::Type::String: - case StubField::Type::JitCode: - case StubField::Type::Id: - case StubField::Type::AllocSite: - case StubField::Type::RawInt64: - case StubField::Type::Value: - case StubField::Type::Double: + case Type::RawInt32: + case Type::RawPointer: + case Type::Shape: + case Type::JSObject: + case Type::Symbol: + case Type::String: + case Type::JitCode: + case Type::Id: + case Type::AllocSite: + case Type::RawInt64: + case Type::Value: + case Type::Double: break; // Skip non-weak fields. } field++; diff --git a/js/src/jit/CacheIRCompiler.h b/js/src/jit/CacheIRCompiler.h index 0c784aade266..a2388d22b9e3 100644 --- a/js/src/jit/CacheIRCompiler.h +++ b/js/src/jit/CacheIRCompiler.h @@ -1241,6 +1241,65 @@ class MOZ_RAII AutoAvailableFloatRegister { operator FloatRegister() const { return reg_; } }; +// For GC thing fields, map from StubField::Type to the C++ types used. +template +struct MapStubFieldToType {}; +template <> +struct MapStubFieldToType { + using RawType = Shape*; + using WrappedType = GCPtr; +}; +template <> +struct MapStubFieldToType { + using RawType = Shape*; + using WrappedType = WeakHeapPtr; +}; +template <> +struct MapStubFieldToType { + using RawType = GetterSetter*; + using WrappedType = WeakHeapPtr; +}; +template <> +struct MapStubFieldToType { + using RawType = JSObject*; + using WrappedType = GCPtr; +}; +template <> +struct MapStubFieldToType { + using RawType = JSObject*; + using WrappedType = WeakHeapPtr; +}; +template <> +struct MapStubFieldToType { + using RawType = JS::Symbol*; + using WrappedType = GCPtr; +}; +template <> +struct MapStubFieldToType { + using RawType = JSString*; + using WrappedType = GCPtr; +}; +template <> +struct MapStubFieldToType { + using RawType = BaseScript*; + using WrappedType = WeakHeapPtr; +}; +template <> +struct MapStubFieldToType { + using RawType = JitCode*; + using WrappedType = GCPtr; +}; +template <> +struct MapStubFieldToType { + using RawType = jsid; + using WrappedType = GCPtr; +}; +template <> +struct MapStubFieldToType { + using RawType = Value; + using WrappedType = GCPtr; +}; + // See the 'Sharing Baseline stub code' comment in CacheIR.h for a description // of this class. // @@ -1300,15 +1359,17 @@ class CacheIRStubInfo { bool canMakeCalls, uint32_t stubDataOffset, const CacheIRWriter& writer); - template - js::GCPtr& getStubField(Stub* stub, uint32_t offset) const; + template + typename MapStubFieldToType::WrappedType& getStubField( + Stub* stub, uint32_t offset) const; template T* getPtrStubField(Stub* stub, uint32_t offset) const; - template - js::GCPtr& getStubField(ICCacheIRStub* stub, uint32_t offset) const { - return getStubField(stub, offset); + template + typename MapStubFieldToType::WrappedType& getStubField( + ICCacheIRStub* stub, uint32_t offset) const { + return getStubField(stub, offset); } uintptr_t getStubRawWord(const uint8_t* stubData, uint32_t offset) const; diff --git a/js/src/jit/WarpOracle.cpp b/js/src/jit/WarpOracle.cpp index 1e8ee1a37144..b5ce578acbae 100644 --- a/js/src/jit/WarpOracle.cpp +++ b/js/src/jit/WarpOracle.cpp @@ -74,6 +74,9 @@ class MOZ_STACK_CLASS WarpScriptOracle { [[nodiscard]] bool replaceNurseryAndAllocSitePointers( ICCacheIRStub* stub, const CacheIRStubInfo* stubInfo, uint8_t* stubDataCopy); + bool maybeReplaceNurseryPointer(const CacheIRStubInfo* stubInfo, + uint8_t* stubDataCopy, JSObject* obj, + size_t offset); public: WarpScriptOracle(JSContext* cx, WarpOracle* oracle, HandleScript script, @@ -1147,8 +1150,8 @@ bool WarpScriptOracle::replaceNurseryAndAllocSitePointers( // initial heap to use, because the site's state may be mutated by the main // thread while we are compiling. // - // If the stub data contains weak pointers expose them to active JS. This is - // necessary as these will now be strong references in the snapshot. + // If the stub data contains weak pointers then trigger a read barrier. This + // is necessary as these will now be strong references in the snapshot. // // Also asserts non-object fields don't contain nursery pointers. @@ -1169,17 +1172,14 @@ bool WarpScriptOracle::replaceNurseryAndAllocSitePointers( case StubField::Type::WeakShape: { static_assert(std::is_convertible_v, "Code assumes shapes are tenured"); - Shape* shape = - stubInfo->getStubField(stub, offset); - gc::ExposeGCThingToActiveJS(JS::GCCellPtr(shape)); + stubInfo->getStubField(stub, offset).get(); break; } case StubField::Type::WeakGetterSetter: { static_assert(std::is_convertible_v, "Code assumes GetterSetters are tenured"); - GetterSetter* gs = - stubInfo->getStubField(stub, offset); - gc::ExposeGCThingToActiveJS(JS::GCCellPtr(gs)); + stubInfo->getStubField(stub, offset) + .get(); break; } case StubField::Type::Symbol: @@ -1189,38 +1189,34 @@ bool WarpScriptOracle::replaceNurseryAndAllocSitePointers( case StubField::Type::WeakBaseScript: { static_assert(std::is_convertible_v, "Code assumes scripts are tenured"); - BaseScript* script = - stubInfo->getStubField(stub, offset); - gc::ExposeGCThingToActiveJS(JS::GCCellPtr(script)); + stubInfo->getStubField(stub, offset) + .get(); break; } case StubField::Type::JitCode: static_assert(std::is_convertible_v, "Code assumes JitCodes are tenured"); break; - case StubField::Type::JSObject: - case StubField::Type::WeakObject: { + case StubField::Type::JSObject: { JSObject* obj = - stubInfo->getStubField(stub, offset); - if (fieldType == StubField::Type::WeakObject) { - gc::ExposeGCThingToActiveJS(JS::GCCellPtr(obj)); + stubInfo->getStubField(stub, offset); + if (!maybeReplaceNurseryPointer(stubInfo, stubDataCopy, obj, offset)) { + return false; } - if (IsInsideNursery(obj)) { - uint32_t nurseryIndex; - if (!oracle_->registerNurseryObject(obj, &nurseryIndex)) { - return false; - } - uintptr_t oldWord = WarpObjectField::fromObject(obj).rawData(); - uintptr_t newWord = - WarpObjectField::fromNurseryIndex(nurseryIndex).rawData(); - stubInfo->replaceStubRawWord(stubDataCopy, offset, oldWord, newWord); + break; + } + case StubField::Type::WeakObject: { + JSObject* obj = + stubInfo->getStubField(stub, offset); + if (!maybeReplaceNurseryPointer(stubInfo, stubDataCopy, obj, offset)) { + return false; } break; } case StubField::Type::String: { #ifdef DEBUG JSString* str = - stubInfo->getStubField(stub, offset); + stubInfo->getStubField(stub, offset); MOZ_ASSERT(!IsInsideNursery(str)); #endif break; @@ -1228,7 +1224,7 @@ bool WarpScriptOracle::replaceNurseryAndAllocSitePointers( case StubField::Type::Id: { #ifdef DEBUG // jsid never contains nursery-allocated things. - jsid id = stubInfo->getStubField(stub, offset); + jsid id = stubInfo->getStubField(stub, offset); MOZ_ASSERT_IF(id.isGCThing(), !IsInsideNursery(id.toGCCellPtr().asCell())); #endif @@ -1236,8 +1232,7 @@ bool WarpScriptOracle::replaceNurseryAndAllocSitePointers( } case StubField::Type::Value: { #ifdef DEBUG - Value v = - stubInfo->getStubField(stub, offset); + Value v = stubInfo->getStubField(stub, offset); MOZ_ASSERT_IF(v.isGCThing(), !IsInsideNursery(v.toGCThing())); #endif break; @@ -1258,6 +1253,24 @@ bool WarpScriptOracle::replaceNurseryAndAllocSitePointers( } } +bool WarpScriptOracle::maybeReplaceNurseryPointer( + const CacheIRStubInfo* stubInfo, uint8_t* stubDataCopy, JSObject* obj, + size_t offset) { + if (!IsInsideNursery(obj)) { + return true; + } + + uint32_t nurseryIndex; + if (!oracle_->registerNurseryObject(obj, &nurseryIndex)) { + return false; + } + + uintptr_t oldWord = WarpObjectField::fromObject(obj).rawData(); + uintptr_t newWord = WarpObjectField::fromNurseryIndex(nurseryIndex).rawData(); + stubInfo->replaceStubRawWord(stubDataCopy, offset, oldWord, newWord); + return true; +} + bool WarpOracle::registerNurseryObject(JSObject* obj, uint32_t* nurseryIndex) { MOZ_ASSERT(IsInsideNursery(obj)); -- 2.11.4.GIT