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)
This commit is contained in:
Alexandru Marc 2024-11-08 11:44:23 +02:00
parent 5ea2ca1ea1
commit 450aacd753
15 changed files with 115 additions and 182 deletions

View File

@ -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<JSObject*> 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

View File

@ -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<JSObject*> 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()

View File

@ -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;

View File

@ -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<JSObject*> 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<GlobalObject*> 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<JSObject*> hostDefinedData(cx);
if (!cx->runtime()->getHostDefinedData(cx, &hostDefinedData)) {
return false;
}
Rooted<GlobalObject*> 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<JSObject*> hostDefinedData(cx);
if (!cx->runtime()->getHostDefinedData(cx, &hostDefinedData)) {
return false;
}
Rooted<GlobalObject*> 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<PromiseCapability> 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<PromiseObject>()) {
// 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<PromiseReactionRecord*> reaction(
cx, NewReactionRecord(cx, resultCapability, onFulfilled, onRejected,
HostDefinedDataObject::Yes));
IncumbentGlobalObject::Yes));
if (!reaction) {
return false;
}
@ -5600,7 +5606,7 @@ template <typename T>
resultCapability.promise().set(resultPromise);
Rooted<PromiseReactionRecord*> 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<PromiseReactionRecord*> 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<PromiseReactionRecord*> 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<PromiseReactionRecord*> 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();
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);

View File

@ -814,17 +814,18 @@ JS_PUBLIC_API void js::RunJobs(JSContext* cx) {
JS::ClearKeptObjects(cx);
}
bool InternalJobQueue::getHostDefinedData(
JSContext* cx, JS::MutableHandle<JSObject*> 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);

View File

@ -88,12 +88,10 @@ class InternalJobQueue : public JS::JobQueue {
~InternalJobQueue() = default;
// JS::JobQueue methods.
bool getHostDefinedData(JSContext* cx,
JS::MutableHandle<JSObject*> 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_; }

View File

@ -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<GlobalObject*> 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;

View File

@ -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

View File

@ -571,16 +571,22 @@ SharedScriptDataTableHolder& JSRuntime::scriptDataTableHolder() {
return scriptDataTableHolder_;
}
bool JSRuntime::getHostDefinedData(JSContext* cx,
JS::MutableHandle<JSObject*> 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<GlobalObject>(),
"getIncumbentGlobalCallback must return a global!");
return &obj->as<GlobalObject>();
}
bool JSRuntime::enqueuePromiseJob(JSContext* cx, HandleFunction job,
HandleObject promise,
HandleObject hostDefinedData) {
Handle<GlobalObject*> 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,

View File

@ -438,12 +438,10 @@ struct JSRuntime {
js::UnprotectedData<JS::ConsumeStreamCallback> consumeStreamCallback;
js::UnprotectedData<JS::ReportStreamErrorCallback> reportStreamErrorCallback;
bool getHostDefinedData(JSContext* cx,
JS::MutableHandle<JSObject*> data) const;
js::GlobalObject* getIncumbentGlobal(JSContext* cx);
bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job,
js::HandleObject promise,
js::HandleObject hostDefinedData);
js::Handle<js::GlobalObject*> incumbentGlobal);
void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);

View File

@ -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<JSObject*> 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<JSObject*> incumbentGlobal(aCx, global->GetGlobalJSObject());
if (!incumbentGlobal) {
aData.set(nullptr);
return true;
}
JSAutoRealm ar(aCx, incumbentGlobal);
JS::Rooted<JSObject*> 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<PromiseJobRunnable> 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<FinalizationRegistryCleanup*>(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<CleanupRunnable> cleanup = new CleanupRunnable(this);

View File

@ -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<JSObject*> aData) const override;
JSObject* getIncumbentGlobal(JSContext* cx) override;
bool enqueuePromiseJob(JSContext* cx, JS::Handle<JSObject*> promise,
JS::Handle<JSObject*> job,
JS::Handle<JSObject*> allocationSite,
JS::Handle<JSObject*> hostDefinedData) override;
JS::Handle<JSObject*> 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.