mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
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:
parent
5ea2ca1ea1
commit
450aacd753
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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_; }
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user