From 450aacd753c98b3200f120ed4340e1ed53b7ff47 Mon Sep 17 00:00:00 2001 From: Alexandru Marc Date: Fri, 8 Nov 2024 11:44:23 +0200 Subject: [PATCH] Backed out 2 changesets (bug 1928412) for causing js::IsProxy crashes. a=backout Backed out changeset b376de7b4345 (bug 1928412) Backed out changeset b91e4d87f3c1 (bug 1928412) --- js/public/Promise.h | 27 ++---- js/src/builtin/FinalizationRegistryObject.cpp | 13 ++- js/src/builtin/FinalizationRegistryObject.h | 4 +- js/src/builtin/Promise.cpp | 89 ++++++++++--------- js/src/gc/FinalizationObservers.cpp | 12 +-- js/src/gc/GC.cpp | 4 +- js/src/gc/GCRuntime.h | 4 +- js/src/vm/JSContext.cpp | 11 +-- js/src/vm/JSContext.h | 6 +- js/src/vm/JSObject.cpp | 10 ++- js/src/vm/JSObject.h | 2 +- js/src/vm/Runtime.cpp | 16 ++-- js/src/vm/Runtime.h | 6 +- xpcom/base/CycleCollectedJSContext.cpp | 83 +++-------------- xpcom/base/CycleCollectedJSContext.h | 10 +-- 15 files changed, 115 insertions(+), 182 deletions(-) diff --git a/js/public/Promise.h b/js/public/Promise.h index d652f5790713..75bc7fd8370d 100644 --- a/js/public/Promise.h +++ b/js/public/Promise.h @@ -36,36 +36,19 @@ class JS_PUBLIC_API JobQueue { virtual ~JobQueue() = default; /** - * Ask the embedding for the host defined data. + * Ask the embedding for the incumbent global. * - * This is the step 5 in - * https://html.spec.whatwg.org/multipage/webappapis.html#hostmakejobcallback - * - * SpiderMonkey doesn't itself have a notion of host defined data as defined + * SpiderMonkey doesn't itself have a notion of incumbent globals as defined * by the HTML spec, so we need the embedding to provide this. See * dom/script/ScriptSettings.h for details. - * - * If the embedding has the host defined data, this method should return the - * host defined data via the `data` out parameter and return `true`. - * The object in the `data` out parameter can belong to any compartment. - * If the embedding doesn't need the host defined data, this method should - * set the `data` out parameter to `nullptr` and return `true`. - * If any error happens while generating the host defined data, this method - * should set a pending exception to `cx` and return `false`. */ - virtual bool getHostDefinedData(JSContext* cx, - JS::MutableHandle data) const = 0; + virtual JSObject* getIncumbentGlobal(JSContext* cx) = 0; /** * Enqueue a reaction job `job` for `promise`, which was allocated at - * `allocationSite`. Provide `hostDefineData` as the host defined data for + * `allocationSite`. Provide `incumbentGlobal` as the incumbent global for * the reaction job's execution. * - * The `hostDefinedData` value comes from `getHostDefinedData` method. - * The object is unwrapped, and it can belong to a different compartment - * than the current compartment. It can be `nullptr` if `getHostDefinedData` - * returns `nullptr`. - * * `promise` can be null if the promise is optimized out. * `promise` is guaranteed not to be optimized out if the promise has * non-default user-interaction flag. @@ -73,7 +56,7 @@ class JS_PUBLIC_API JobQueue { virtual bool enqueuePromiseJob(JSContext* cx, JS::HandleObject promise, JS::HandleObject job, JS::HandleObject allocationSite, - JS::HandleObject hostDefinedData) = 0; + JS::HandleObject incumbentGlobal) = 0; /** * Run all jobs in the queue. Running one job may enqueue others; continue to diff --git a/js/src/builtin/FinalizationRegistryObject.cpp b/js/src/builtin/FinalizationRegistryObject.cpp index cdb6e7c229b0..070becc0a744 100644 --- a/js/src/builtin/FinalizationRegistryObject.cpp +++ b/js/src/builtin/FinalizationRegistryObject.cpp @@ -688,8 +688,8 @@ FinalizationQueueObject* FinalizationQueueObject::create( // you don't know how far to unwrap it to get the original object // back. Instead store a CCW to a plain object in the same compartment as the // global (this uses Object.prototype). - Rooted hostDefinedData(cx); - if (!GetObjectFromHostDefinedData(cx, &hostDefinedData)) { + RootedObject incumbentObject(cx); + if (!GetObjectFromIncumbentGlobal(cx, &incumbentObject) || !incumbentObject) { return nullptr; } @@ -700,8 +700,7 @@ FinalizationQueueObject* FinalizationQueueObject::create( } queue->initReservedSlot(CleanupCallbackSlot, ObjectValue(*cleanupCallback)); - queue->initReservedSlot(HostDefinedDataSlot, - JS::ObjectOrNullValue(hostDefinedData)); + queue->initReservedSlot(IncumbentObjectSlot, ObjectValue(*incumbentObject)); InitReservedSlot(queue, RecordsToBeCleanedUpSlot, recordsToBeCleanedUp.release(), MemoryUse::FinalizationRegistryRecordVector); @@ -755,12 +754,12 @@ inline JSObject* FinalizationQueueObject::cleanupCallback() const { return &value.toObject(); } -JSObject* FinalizationQueueObject::getHostDefinedData() const { - Value value = getReservedSlot(HostDefinedDataSlot); +JSObject* FinalizationQueueObject::incumbentObject() const { + Value value = getReservedSlot(IncumbentObjectSlot); if (value.isUndefined()) { return nullptr; } - return value.toObjectOrNull(); + return &value.toObject(); } FinalizationRecordVector* FinalizationQueueObject::recordsToBeCleanedUp() diff --git a/js/src/builtin/FinalizationRegistryObject.h b/js/src/builtin/FinalizationRegistryObject.h index e442c2d1ae3c..288ebea424cf 100644 --- a/js/src/builtin/FinalizationRegistryObject.h +++ b/js/src/builtin/FinalizationRegistryObject.h @@ -226,7 +226,7 @@ class FinalizationRegistryObject : public NativeObject { class FinalizationQueueObject : public NativeObject { enum { CleanupCallbackSlot = 0, - HostDefinedDataSlot, + IncumbentObjectSlot, RecordsToBeCleanedUpSlot, IsQueuedForCleanupSlot, DoCleanupFunctionSlot, @@ -242,7 +242,7 @@ class FinalizationQueueObject : public NativeObject { static const JSClass class_; JSObject* cleanupCallback() const; - JSObject* getHostDefinedData() const; + JSObject* incumbentObject() const; FinalizationRecordVector* recordsToBeCleanedUp() const; bool isQueuedForCleanup() const; JSFunction* doCleanupFunction() const; diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 2c0ad573b9b8..4e9a435a0019 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -700,9 +700,8 @@ enum ReactionRecordSlots { ReactionRecordSlot_Resolve, ReactionRecordSlot_Reject, - // The host defined data for this reaction record. Can be null. - // See step 5 in https://html.spec.whatwg.org/#hostmakejobcallback - ReactionRecordSlot_HostDefinedData, + // The incumbent global for this reaction record. Can be null. + ReactionRecordSlot_IncumbentGlobalObject, // Bitmask of the REACTION_FLAG values. ReactionRecordSlot_Flags, @@ -902,10 +901,10 @@ class PromiseReactionRecord : public NativeObject { return getFixedSlot(handlerArgSlot()); } - JSObject* getAndClearHostDefinedData() { + JSObject* getAndClearIncumbentGlobalObject() { JSObject* obj = - getFixedSlot(ReactionRecordSlot_HostDefinedData).toObjectOrNull(); - setFixedSlot(ReactionRecordSlot_HostDefinedData, UndefinedValue()); + getFixedSlot(ReactionRecordSlot_IncumbentGlobalObject).toObjectOrNull(); + setFixedSlot(ReactionRecordSlot_IncumbentGlobalObject, UndefinedValue()); return obj; } @@ -1546,15 +1545,26 @@ static bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp); } } - JS::Rooted hostDefinedData(cx); - if (JSObject* hostDefined = reaction->getAndClearHostDefinedData()) { - hostDefined = CheckedUnwrapStatic(hostDefined); - MOZ_ASSERT(hostDefined); - hostDefinedData = hostDefined; + // Using objectFromIncumbentGlobal, we can derive the incumbent global by + // unwrapping and then getting the global. This is very convoluted, but + // much better than having to store the original global as a private value + // because we couldn't wrap it to store it as a normal JS value. + Rooted global(cx); + if (JSObject* objectFromIncumbentGlobal = + reaction->getAndClearIncumbentGlobalObject()) { + objectFromIncumbentGlobal = CheckedUnwrapStatic(objectFromIncumbentGlobal); + MOZ_ASSERT(objectFromIncumbentGlobal); + global = &objectFromIncumbentGlobal->nonCCWGlobal(); } // HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]). - return cx->runtime()->enqueuePromiseJob(cx, job, promise, hostDefinedData); + // + // Note: the global we pass here might be from a different compartment + // than job and promise. While it's somewhat unusual to pass objects + // from multiple compartments, in this case we specifically need the + // global to be unwrapped because wrapping and unwrapping aren't + // necessarily symmetric for globals. + return cx->runtime()->enqueuePromiseJob(cx, job, promise, global); } [[nodiscard]] static bool TriggerPromiseReactions(JSContext* cx, @@ -2490,13 +2500,11 @@ static bool PromiseResolveBuiltinThenableJob(JSContext* cx, unsigned argc, // compartment. RootedObject promise(cx, &promiseToResolve.toObject()); - Rooted hostDefinedData(cx); - if (!cx->runtime()->getHostDefinedData(cx, &hostDefinedData)) { - return false; - } + Rooted incumbentGlobal(cx, + cx->runtime()->getIncumbentGlobal(cx)); // Step X. HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]). - return cx->runtime()->enqueuePromiseJob(cx, job, promise, hostDefinedData); + return cx->runtime()->enqueuePromiseJob(cx, job, promise, incumbentGlobal); } /** @@ -2538,14 +2546,12 @@ static bool PromiseResolveBuiltinThenableJob(JSContext* cx, unsigned argc, job->setExtendedSlot(ThenableJobSlot_Promise, ObjectValue(*promiseToResolve)); job->setExtendedSlot(ThenableJobSlot_Thenable, ObjectValue(*thenable)); - Rooted hostDefinedData(cx); - if (!cx->runtime()->getHostDefinedData(cx, &hostDefinedData)) { - return false; - } + Rooted incumbentGlobal(cx, + cx->runtime()->getIncumbentGlobal(cx)); // HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]). return cx->runtime()->enqueuePromiseJob(cx, job, promiseToResolve, - hostDefinedData); + incumbentGlobal); } [[nodiscard]] static bool AddDummyPromiseReactionForDebugger( @@ -5053,12 +5059,12 @@ bool js::Promise_static_species(JSContext* cx, unsigned argc, Value* vp) { return true; } -enum class HostDefinedDataObject { - // Do not use the host defined data object, this is a special case used by the +enum class IncumbentGlobalObject { + // Do not use the incumbent global, this is a special case used by the // debugger. No, - // Use host defined data object, this is the normal operation. + // Use incumbent global, this is the normal operation. Yes }; @@ -5075,10 +5081,10 @@ enum class HostDefinedDataObject { static PromiseReactionRecord* NewReactionRecord( JSContext* cx, Handle resultCapability, HandleValue onFulfilled, HandleValue onRejected, - HostDefinedDataObject hostDefinedDataObjectOption) { + IncumbentGlobalObject incumbentGlobalObjectOption) { #ifdef DEBUG if (resultCapability.promise()) { - if (hostDefinedDataObjectOption == HostDefinedDataObject::Yes) { + if (incumbentGlobalObjectOption == IncumbentGlobalObject::Yes) { if (resultCapability.promise()->is()) { // If `resultCapability.promise` is a Promise object, // `resultCapability.{resolve,reject}` may be optimized out, @@ -5116,7 +5122,7 @@ static PromiseReactionRecord* NewReactionRecord( // In any case, other fields are also not used. MOZ_ASSERT(!resultCapability.resolve()); MOZ_ASSERT(!resultCapability.reject()); - MOZ_ASSERT(hostDefinedDataObjectOption == HostDefinedDataObject::Yes); + MOZ_ASSERT(incumbentGlobalObjectOption == IncumbentGlobalObject::Yes); } #endif @@ -5137,9 +5143,9 @@ static PromiseReactionRecord* NewReactionRecord( // Handlers must either both be present or both be absent. MOZ_ASSERT(onFulfilled.isNull() == onRejected.isNull()); - RootedObject hostDefinedData(cx); - if (hostDefinedDataObjectOption == HostDefinedDataObject::Yes) { - if (!GetObjectFromHostDefinedData(cx, &hostDefinedData)) { + RootedObject incumbentGlobalObject(cx); + if (incumbentGlobalObjectOption == IncumbentGlobalObject::Yes) { + if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobalObject)) { return nullptr; } } @@ -5155,7 +5161,7 @@ static PromiseReactionRecord* NewReactionRecord( cx->check(onRejected); cx->check(resultCapability.resolve()); cx->check(resultCapability.reject()); - cx->check(hostDefinedData); + cx->check(incumbentGlobalObject); // Step 7. Let fulfillReaction be the PromiseReaction // { [[Capability]]: resultCapability, [[Type]]: Fulfill, @@ -5177,8 +5183,8 @@ static PromiseReactionRecord* NewReactionRecord( ObjectOrNullValue(resultCapability.resolve())); reaction->setFixedSlot(ReactionRecordSlot_Reject, ObjectOrNullValue(resultCapability.reject())); - reaction->setFixedSlot(ReactionRecordSlot_HostDefinedData, - ObjectOrNullValue(hostDefinedData)); + reaction->setFixedSlot(ReactionRecordSlot_IncumbentGlobalObject, + ObjectOrNullValue(incumbentGlobalObject)); return reaction; } @@ -5347,7 +5353,7 @@ static bool PromiseThenNewPromiseCapability( Rooted reaction( cx, NewReactionRecord(cx, resultCapability, onFulfilled, onRejected, - HostDefinedDataObject::Yes)); + IncumbentGlobalObject::Yes)); if (!reaction) { return false; } @@ -5600,7 +5606,7 @@ template resultCapability.promise().set(resultPromise); Rooted reaction( cx, NewReactionRecord(cx, resultCapability, onFulfilledValue, - onRejectedValue, HostDefinedDataObject::Yes)); + onRejectedValue, IncumbentGlobalObject::Yes)); if (!reaction) { return false; } @@ -6090,7 +6096,7 @@ bool js::Promise_then(JSContext* cx, unsigned argc, Value* vp) { // NOTE: We use single object for both reactions. Rooted reaction( cx, NewReactionRecord(cx, resultCapability, onFulfilled, onRejected, - HostDefinedDataObject::Yes)); + IncumbentGlobalObject::Yes)); if (!reaction) { return false; } @@ -6130,7 +6136,7 @@ bool js::Promise_then(JSContext* cx, unsigned argc, Value* vp) { // [[Handler]]: onRejectedJobCallback }. Rooted reaction( cx, NewReactionRecord(cx, resultCapability, onFulfilled, onRejected, - HostDefinedDataObject::Yes)); + IncumbentGlobalObject::Yes)); if (!reaction) { return false; } @@ -6319,7 +6325,7 @@ bool js::Promise_then(JSContext* cx, unsigned argc, Value* vp) { Rooted reaction( cx, NewReactionRecord(cx, capability, NullHandleValue, NullHandleValue, - HostDefinedDataObject::No)); + IncumbentGlobalObject::No)); if (!reaction) { return false; } @@ -6711,8 +6717,9 @@ void PromiseReactionRecord::dumpOwnFields(js::JSONPrinter& json) const { } { - js::GenericPrinter& out = json.beginStringProperty("hostDefinedData"); - getFixedSlot(ReactionRecordSlot_HostDefinedData).dumpStringContent(out); + js::GenericPrinter& out = json.beginStringProperty("incumbentGlobal"); + getFixedSlot(ReactionRecordSlot_IncumbentGlobalObject) + .dumpStringContent(out); json.endStringProperty(); } diff --git a/js/src/gc/FinalizationObservers.cpp b/js/src/gc/FinalizationObservers.cpp index 0b06b9575307..3a7a11464523 100644 --- a/js/src/gc/FinalizationObservers.cpp +++ b/js/src/gc/FinalizationObservers.cpp @@ -300,14 +300,14 @@ void GCRuntime::queueFinalizationRegistryForCleanup( return; } - JSObject* unwrappedHostDefineData = nullptr; - - if (JSObject* wrapped = queue->getHostDefinedData()) { - unwrappedHostDefineData = UncheckedUnwrapWithoutExpose(wrapped); - } + // Derive the incumbent global by unwrapping the incumbent global object and + // then getting its global. + JSObject* object = UncheckedUnwrapWithoutExpose(queue->incumbentObject()); + MOZ_ASSERT(object); + GlobalObject* incumbentGlobal = &object->nonCCWGlobal(); callHostCleanupFinalizationRegistryCallback(queue->doCleanupFunction(), - unwrappedHostDefineData); + incumbentGlobal); // The queue object may be gray, and that's OK. AutoTouchingGrayThings atgt; diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index 601d6b547aac..7d020614dbc5 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -1646,11 +1646,11 @@ void GCRuntime::setHostCleanupFinalizationRegistryCallback( } void GCRuntime::callHostCleanupFinalizationRegistryCallback( - JSFunction* doCleanup, JSObject* hostDefinedData) { + JSFunction* doCleanup, GlobalObject* incumbentGlobal) { JS::AutoSuppressGCAnalysis nogc; const auto& callback = hostCleanupFinalizationRegistryCallback.ref(); if (callback.op) { - callback.op(doCleanup, hostDefinedData, callback.data); + callback.op(doCleanup, incumbentGlobal, callback.data); } } diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index dfeca45505c2..4a2ba828e2c1 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -473,8 +473,8 @@ class GCRuntime { void removeFinalizeCallback(JSFinalizeCallback callback); void setHostCleanupFinalizationRegistryCallback( JSHostCleanupFinalizationRegistryCallback callback, void* data); - void callHostCleanupFinalizationRegistryCallback(JSFunction* doCleanup, - JSObject* hostDefinedData); + void callHostCleanupFinalizationRegistryCallback( + JSFunction* doCleanup, GlobalObject* incumbentGlobal); [[nodiscard]] bool addWeakPointerZonesCallback( JSWeakPointerZonesCallback callback, void* data); void removeWeakPointerZonesCallback(JSWeakPointerZonesCallback callback); diff --git a/js/src/vm/JSContext.cpp b/js/src/vm/JSContext.cpp index d23062e1b474..117eac7b17a3 100644 --- a/js/src/vm/JSContext.cpp +++ b/js/src/vm/JSContext.cpp @@ -814,17 +814,18 @@ JS_PUBLIC_API void js::RunJobs(JSContext* cx) { JS::ClearKeptObjects(cx); } -bool InternalJobQueue::getHostDefinedData( - JSContext* cx, JS::MutableHandle data) const { - data.set(nullptr); - return true; +JSObject* InternalJobQueue::getIncumbentGlobal(JSContext* cx) { + if (!cx->compartment()) { + return nullptr; + } + return cx->global(); } bool InternalJobQueue::enqueuePromiseJob(JSContext* cx, JS::HandleObject promise, JS::HandleObject job, JS::HandleObject allocationSite, - JS::HandleObject hostDefinedData) { + JS::HandleObject incumbentGlobal) { MOZ_ASSERT(job); if (!queue.pushBack(job)) { ReportOutOfMemory(cx); diff --git a/js/src/vm/JSContext.h b/js/src/vm/JSContext.h index 8aa5ade0f2c8..3a1bee10a2ef 100644 --- a/js/src/vm/JSContext.h +++ b/js/src/vm/JSContext.h @@ -88,12 +88,10 @@ class InternalJobQueue : public JS::JobQueue { ~InternalJobQueue() = default; // JS::JobQueue methods. - bool getHostDefinedData(JSContext* cx, - JS::MutableHandle data) const override; - + JSObject* getIncumbentGlobal(JSContext* cx) override; bool enqueuePromiseJob(JSContext* cx, JS::HandleObject promise, JS::HandleObject job, JS::HandleObject allocationSite, - JS::HandleObject hostDefinedData) override; + JS::HandleObject incumbentGlobal) override; void runJobs(JSContext* cx) override; bool empty() const override; bool isDrainingStopped() const override { return interrupted_; } diff --git a/js/src/vm/JSObject.cpp b/js/src/vm/JSObject.cpp index 2d6a318dc69a..fb632cd9c925 100644 --- a/js/src/vm/JSObject.cpp +++ b/js/src/vm/JSObject.cpp @@ -1504,11 +1504,15 @@ NativeObject* js::InitClass(JSContext* cx, HandleObject obj, * it - e.g. EnqueuePromiseReactionJob - can then unwrap the object and get * its global without fear of unwrapping too far. */ -bool js::GetObjectFromHostDefinedData(JSContext* cx, MutableHandleObject obj) { - if (!cx->runtime()->getHostDefinedData(cx, obj)) { - return false; +bool js::GetObjectFromIncumbentGlobal(JSContext* cx, MutableHandleObject obj) { + Rooted globalObj(cx, cx->runtime()->getIncumbentGlobal(cx)); + if (!globalObj) { + obj.set(nullptr); + return true; } + obj.set(&globalObj->getObjectPrototype()); + // The object might be from a different compartment, so wrap it. if (obj && !cx->compartment()->wrap(cx, obj)) { return false; diff --git a/js/src/vm/JSObject.h b/js/src/vm/JSObject.h index fb6bb9867cb5..5d2047e3b50e 100644 --- a/js/src/vm/JSObject.h +++ b/js/src/vm/JSObject.h @@ -1075,7 +1075,7 @@ extern bool TestIntegrityLevel(JSContext* cx, HandleObject obj, JSContext* cx, HandleObject obj, JSProtoKey ctorKey, bool (*isDefaultSpecies)(JSContext*, JSFunction*)); -extern bool GetObjectFromHostDefinedData(JSContext* cx, +extern bool GetObjectFromIncumbentGlobal(JSContext* cx, MutableHandleObject obj); #ifdef DEBUG diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index e34173885e69..847a01846bb1 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -571,16 +571,22 @@ SharedScriptDataTableHolder& JSRuntime::scriptDataTableHolder() { return scriptDataTableHolder_; } -bool JSRuntime::getHostDefinedData(JSContext* cx, - JS::MutableHandle data) const { +GlobalObject* JSRuntime::getIncumbentGlobal(JSContext* cx) { MOZ_ASSERT(cx->jobQueue); - return cx->jobQueue->getHostDefinedData(cx, data); + JSObject* obj = cx->jobQueue->getIncumbentGlobal(cx); + if (!obj) { + return nullptr; + } + + MOZ_ASSERT(obj->is(), + "getIncumbentGlobalCallback must return a global!"); + return &obj->as(); } bool JSRuntime::enqueuePromiseJob(JSContext* cx, HandleFunction job, HandleObject promise, - HandleObject hostDefinedData) { + Handle incumbentGlobal) { MOZ_ASSERT(cx->jobQueue, "Must select a JobQueue implementation using JS::JobQueue " "or js::UseInternalJobQueues before using Promises"); @@ -603,7 +609,7 @@ bool JSRuntime::enqueuePromiseJob(JSContext* cx, HandleFunction job, } } return cx->jobQueue->enqueuePromiseJob(cx, promise, job, allocationSite, - hostDefinedData); + incumbentGlobal); } void JSRuntime::addUnhandledRejectedPromise(JSContext* cx, diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index c43fa7303553..40753df85ab4 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -438,12 +438,10 @@ struct JSRuntime { js::UnprotectedData consumeStreamCallback; js::UnprotectedData reportStreamErrorCallback; - bool getHostDefinedData(JSContext* cx, - JS::MutableHandle data) const; - + js::GlobalObject* getIncumbentGlobal(JSContext* cx); bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, js::HandleObject promise, - js::HandleObject hostDefinedData); + js::Handle incumbentGlobal); void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise); void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise); diff --git a/xpcom/base/CycleCollectedJSContext.cpp b/xpcom/base/CycleCollectedJSContext.cpp index 2b71fcf40298..5def01d88c47 100644 --- a/xpcom/base/CycleCollectedJSContext.cpp +++ b/xpcom/base/CycleCollectedJSContext.cpp @@ -228,76 +228,24 @@ class PromiseJobRunnable final : public MicroTaskRunnable { bool mPropagateUserInputEventHandling; }; -// Finalizer for instances of FinalizeHostDefinedData. -// -// HostDefinedData only contains incumbent global, no need to -// clean that up. -// TODO(sefeng): Bug 1929356 will add [[SchedulingState]] to HostDefinedData. -void FinalizeHostDefinedData(JS::GCContext* gcx, JSObject* objSelf) {} - -static const JSClassOps sHostDefinedData = { - nullptr /* addProperty */, nullptr /* delProperty */, - nullptr /* enumerate */, nullptr /* newEnumerate */, - nullptr /* resolve */, nullptr /* mayResolve */, - FinalizeHostDefinedData /* finalize */ -}; - -enum { INCUMBENT_SETTING_SLOT, HOSTDEFINED_DATA_SLOTS }; - -// Implements `HostDefined` in https://html.spec.whatwg.org/#hostmakejobcallback -static const JSClass sHostDefinedDataClass = { - "HostDefinedData", - JSCLASS_HAS_RESERVED_SLOTS(HOSTDEFINED_DATA_SLOTS) | - JSCLASS_BACKGROUND_FINALIZE, - &sHostDefinedData}; - -bool CycleCollectedJSContext::getHostDefinedData( - JSContext* aCx, JS::MutableHandle aData) const { +JSObject* CycleCollectedJSContext::getIncumbentGlobal(JSContext* aCx) { nsIGlobalObject* global = mozilla::dom::GetIncumbentGlobal(); - if (!global) { - aData.set(nullptr); - return true; + if (global) { + return global->GetGlobalJSObject(); } - - JS::Rooted incumbentGlobal(aCx, global->GetGlobalJSObject()); - - if (!incumbentGlobal) { - aData.set(nullptr); - return true; - } - - JSAutoRealm ar(aCx, incumbentGlobal); - - JS::Rooted objResult(aCx, - JS_NewObject(aCx, &sHostDefinedDataClass)); - if (!objResult) { - aData.set(nullptr); - return false; - } - - JS_SetReservedSlot(objResult, INCUMBENT_SETTING_SLOT, - JS::ObjectValue(*incumbentGlobal)); - aData.set(objResult); - - return true; + return nullptr; } bool CycleCollectedJSContext::enqueuePromiseJob( JSContext* aCx, JS::HandleObject aPromise, JS::HandleObject aJob, - JS::HandleObject aAllocationSite, JS::HandleObject hostDefinedData) { + JS::HandleObject aAllocationSite, JS::HandleObject aIncumbentGlobal) { MOZ_ASSERT(aCx == Context()); MOZ_ASSERT(Get() == this); nsIGlobalObject* global = nullptr; - - if (hostDefinedData) { - JS::Value incumbentGlobal = - JS::GetReservedSlot(hostDefinedData.get(), INCUMBENT_SETTING_SLOT); - // hostDefinedData is only created when incumbent global exists. - MOZ_ASSERT(incumbentGlobal.isObject()); - global = xpc::NativeGlobal(&incumbentGlobal.toObject()); + if (aIncumbentGlobal) { + global = xpc::NativeGlobal(aIncumbentGlobal); } - JS::RootedObject jobGlobal(aCx, JS::CurrentGlobalOrNull(aCx)); RefPtr runnable = new PromiseJobRunnable( aPromise, aJob, jobGlobal, aAllocationSite, global); @@ -944,27 +892,18 @@ void FinalizationRegistryCleanup::Init() { /* static */ void FinalizationRegistryCleanup::QueueCallback(JSFunction* aDoCleanup, - JSObject* aHostDefinedData, + JSObject* aIncumbentGlobal, void* aData) { FinalizationRegistryCleanup* cleanup = static_cast(aData); - cleanup->QueueCallback(aDoCleanup, aHostDefinedData); + cleanup->QueueCallback(aDoCleanup, aIncumbentGlobal); } void FinalizationRegistryCleanup::QueueCallback(JSFunction* aDoCleanup, - JSObject* aHostDefinedData) { + JSObject* aIncumbentGlobal) { bool firstCallback = mCallbacks.empty(); - JSObject* incumbentGlobal = nullptr; - - // Extract incumbentGlobal from aHostDefinedData. - if (aHostDefinedData) { - JS::Value global = - JS::GetReservedSlot(aHostDefinedData, INCUMBENT_SETTING_SLOT); - incumbentGlobal = &global.toObject(); - } - - MOZ_ALWAYS_TRUE(mCallbacks.append(Callback{aDoCleanup, incumbentGlobal})); + MOZ_ALWAYS_TRUE(mCallbacks.append(Callback{aDoCleanup, aIncumbentGlobal})); if (firstCallback) { RefPtr cleanup = new CleanupRunnable(this); diff --git a/xpcom/base/CycleCollectedJSContext.h b/xpcom/base/CycleCollectedJSContext.h index 038f3c0d4e98..43ecbd85cb60 100644 --- a/xpcom/base/CycleCollectedJSContext.h +++ b/xpcom/base/CycleCollectedJSContext.h @@ -108,11 +108,11 @@ class FinalizationRegistryCleanup { explicit FinalizationRegistryCleanup(CycleCollectedJSContext* aContext); void Init(); void Destroy(); - void QueueCallback(JSFunction* aDoCleanup, JSObject* aHostDefinedData); + void QueueCallback(JSFunction* aDoCleanup, JSObject* aIncumbentGlobal); MOZ_CAN_RUN_SCRIPT void DoCleanup(); private: - static void QueueCallback(JSFunction* aDoCleanup, JSObject* aHostDefinedData, + static void QueueCallback(JSFunction* aDoCleanup, JSObject* aIncumbentGlobal, void* aData); class CleanupRunnable; @@ -298,13 +298,11 @@ class CycleCollectedJSContext : dom::PerThreadAtomCache, private JS::JobQueue { // Others protect the debuggee microtask queue from the debugger's // interruptions; see the comments on JS::AutoDebuggerJobQueueInterruption for // details. - bool getHostDefinedData(JSContext* cx, - JS::MutableHandle aData) const override; - + JSObject* getIncumbentGlobal(JSContext* cx) override; bool enqueuePromiseJob(JSContext* cx, JS::Handle promise, JS::Handle job, JS::Handle allocationSite, - JS::Handle hostDefinedData) override; + JS::Handle incumbentGlobal) override; // MOZ_CAN_RUN_SCRIPT_BOUNDARY for now so we don't have to change SpiderMonkey // headers. The caller presumably knows this can run script (like everything // in SpiderMonkey!) and will deal.