Bug 1622184 - Add a public method to mark a settled Promise as handled; r=arai

Differential Revision: https://phabricator.services.mozilla.com/D67103

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Brian Birtles 2020-03-18 02:22:00 +00:00
Родитель 527311ae4e
Коммит e14c3f5ed1
10 изменённых файлов: 95 добавлений и 29 удалений

Просмотреть файл

@ -9,6 +9,7 @@
#include <utility>
#include "js/Promise.h"
#include "js/TypeDecls.h"
#include "jspubtd.h"
#include "mozilla/Attributes.h"
@ -180,6 +181,15 @@ class Promise : public nsISupports, public SupportsWeakPtr<Promise> {
// specializations in the .cpp for
// the T values we support.
// Mark a settled promise as already handled so that rejections will not
// be reported as unhandled.
void SetSettledPromiseIsHandled() {
AutoEntryScript aes(mGlobal, "Set settled promise handled");
JSContext* cx = aes.cx();
JS::RootedObject promiseObj(cx, mPromiseObj);
JS::SetSettledPromiseIsHandled(cx, promiseObj);
}
// WebIDL
nsIGlobalObject* GetParentObject() const { return GetGlobalObject(); }

Просмотреть файл

@ -355,6 +355,14 @@ extern JS_PUBLIC_API JS::Value GetPromiseResult(JS::HandleObject promise);
*/
extern JS_PUBLIC_API bool GetPromiseIsHandled(JS::HandleObject promise);
/*
* Given a settled (i.e. fulfilled or rejected, not pending) promise, sets
* |promise.[[PromiseIsHandled]]| to true and removes it from the list of
* unhandled rejected promises.
*/
extern JS_PUBLIC_API void SetSettledPromiseIsHandled(JSContext* cx,
JS::HandleObject promise);
/**
* Returns a js::SavedFrame linked list of the stack that lead to the given
* Promise's allocation.

Просмотреть файл

@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef builtin_Promise_inl_h
#define builtin_Promise_inl_h
#include "js/Promise.h" // JS::PromiseState
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "js/RootingAPI.h" // JS::Handle
#include "vm/JSContext.h" // JSContext
#include "vm/PromiseObject.h" // js::PromiseObject
namespace js {
/**
* Given a settled (i.e. fulfilled or rejected, not pending) promise, sets
* |promise.[[PromiseIsHandled]]| to true and removes it from the list of
* unhandled rejected promises.
*
* NOTE: If you need to set |promise.[[PromiseIsHandled]]| on a pending promise,
* use |PromiseObject::setHandled()| directly.
*/
inline void SetSettledPromiseIsHandled(
JSContext* cx, JS::Handle<PromiseObject*> unwrappedPromise) {
MOZ_ASSERT(unwrappedPromise->state() != JS::PromiseState::Pending);
unwrappedPromise->setHandled();
cx->runtime()->removeUnhandledRejectedPromise(cx, unwrappedPromise);
}
} // namespace js
#endif // builtin_Promise_inl_h

Просмотреть файл

@ -14,7 +14,7 @@
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "js/Promise.h" // JS::{Resolve,Reject}Promise, JS::PromiseState
#include "js/Promise.h" // JS::{Resolve,Reject}Promise
#include "js/RootingAPI.h" // JS::Rooted, JS::{,Mutable}Handle
#include "js/Value.h" // JS::UndefinedHandleValue, JS::Value
#include "vm/Compartment.h" // JS::Compartment
@ -110,21 +110,6 @@ inline MOZ_MUST_USE bool RejectUnwrappedPromiseWithError(
return RejectUnwrappedPromiseWithError(cx, &promise, error);
}
/**
* Given a settled (i.e. fulfilled or rejected, not pending) promise, sets
* |promise.[[PromiseIsHandled]]| to true and removes it from the list of
* unhandled rejected promises.
*
* NOTE: If you need to set |promise.[[PromiseIsHandled]]| on a pending promise,
* use |PromiseObject::setHandled()| directly.
*/
inline void SetSettledPromiseIsHandled(
JSContext* cx, JS::Handle<PromiseObject*> unwrappedPromise) {
MOZ_ASSERT(unwrappedPromise->state() != JS::PromiseState::Pending);
unwrappedPromise->setHandled();
cx->runtime()->removeUnhandledRejectedPromise(cx, unwrappedPromise);
}
} // namespace js
#endif // builtin_streams_MiscellaneousOperations_inl_h

Просмотреть файл

@ -33,7 +33,8 @@
#include "vm/Realm.h" // JS::Realm
#include "vm/StringType.h" // js::PropertyName
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::{Reject,Resolve}UnwrappedPromiseWithUndefined, js::SetSettledPromiseIsHandled
#include "builtin/Promise-inl.h" // js::SetSettledPromiseIsHandled
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::{Reject,Resolve}UnwrappedPromiseWithUndefined
#include "builtin/streams/ReadableStreamReader-inl.h" // js::js::UnwrapReaderFromStream{,NoThrow}
#include "vm/Compartment-inl.h" // JS::Compartment::wrap
#include "vm/JSContext-inl.h" // JSContext::check
@ -354,7 +355,7 @@ MOZ_MUST_USE bool js::ReadableStreamErrorInternal(
// 3.8.5 ReadableStreamReaderGenericRelease step 6 sets
// stream.[[reader]] to undefined.
Rooted<JSObject*> closedPromise(cx, unwrappedReader->closedPromise());
SetSettledPromiseIsHandled(cx, closedPromise.as<PromiseObject>());
js::SetSettledPromiseIsHandled(cx, closedPromise.as<PromiseObject>());
if (unwrappedStream->mode() == JS::ReadableStreamMode::ExternalSource) {
// Make sure we're in the stream's compartment.

Просмотреть файл

@ -24,7 +24,7 @@
#include "vm/PromiseObject.h" // js::PromiseObject
#include "vm/Runtime.h" // JSRuntime
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::SetSettledPromiseIsHandled
#include "builtin/Promise-inl.h" // js::SetSettledPromiseIsHandled
#include "vm/Compartment-inl.h" // JS::Compartment::wrap, js::UnwrapInternalSlot
#include "vm/List-inl.h" // js::StoreNewListInFixedSlot
#include "vm/Realm-inl.h" // js::AutoRealm
@ -113,7 +113,7 @@ MOZ_MUST_USE bool js::ReadableStreamReaderGenericInitialize(
}
// Step c. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
SetSettledPromiseIsHandled(cx, promise);
js::SetSettledPromiseIsHandled(cx, promise);
}
if (!promise) {
@ -211,7 +211,7 @@ MOZ_MUST_USE bool js::ReadableStreamReaderGenericRelease(
}
// Step 5: Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
SetSettledPromiseIsHandled(cx, unwrappedClosedPromise);
js::SetSettledPromiseIsHandled(cx, unwrappedClosedPromise);
// Step 6: Set reader.[[ownerReadableStream]].[[reader]] to undefined.
unwrappedStream->clearReader();

Просмотреть файл

@ -28,7 +28,7 @@
#include "vm/JSContext.h" // JSContext
#include "vm/PromiseObject.h" // js::PromiseObject
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::SetSettledPromiseIsHandled
#include "builtin/Promise-inl.h" // js::SetSettledPromiseIsHandled
#include "vm/Compartment-inl.h" // JS::Compartment::wrap, js::UnwrapAndTypeCheck{Argument,This}
#include "vm/JSObject-inl.h" // js::NewObjectWithClassProto
#include "vm/NativeObject-inl.h" // js::ThrowIfNotConstructing
@ -147,7 +147,7 @@ MOZ_MUST_USE WritableStreamDefaultWriter* js::CreateWritableStreamDefaultWriter(
writer->setReadyPromise(promise);
// Step 7.b: Set this.[[readyPromise]].[[PromiseIsHandled]] to true.
SetSettledPromiseIsHandled(cx, promise.as<PromiseObject>());
js::SetSettledPromiseIsHandled(cx, promise.as<PromiseObject>());
// Step 7.c: Set this.[[closedPromise]] to a new promise.
JSObject* closedPromise = PromiseObject::createSkippingExecutor(cx);
@ -175,7 +175,7 @@ MOZ_MUST_USE WritableStreamDefaultWriter* js::CreateWritableStreamDefaultWriter(
writer->setReadyPromise(promise);
// Step 9.d: Set this.[[readyPromise]].[[PromiseIsHandled]] to true.
SetSettledPromiseIsHandled(cx, promise.as<PromiseObject>());
js::SetSettledPromiseIsHandled(cx, promise.as<PromiseObject>());
// Step 9.e: Set this.[[closedPromise]] to a promise rejected with
// storedError.
@ -187,7 +187,7 @@ MOZ_MUST_USE WritableStreamDefaultWriter* js::CreateWritableStreamDefaultWriter(
writer->setClosedPromise(promise);
// Step 9.f: Set this.[[closedPromise]].[[PromiseIsHandled]] to true.
SetSettledPromiseIsHandled(cx, promise.as<PromiseObject>());
js::SetSettledPromiseIsHandled(cx, promise.as<PromiseObject>());
}
}

Просмотреть файл

@ -30,8 +30,9 @@
#include "vm/List.h" // js::ListObject
#include "vm/PromiseObject.h" // js::PromiseObject
#include "builtin/Promise-inl.h" // js::SetSettledPromiseIsHandled
#include "builtin/streams/HandlerFunction-inl.h" // js::NewHandler, js::TargetFromHandler
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::ResolveUnwrappedPromiseWithUndefined, js::RejectUnwrappedPromiseWithError, js::SetSettledPromiseIsHandled
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::ResolveUnwrappedPromiseWithUndefined, js::RejectUnwrappedPromiseWithError
#include "builtin/streams/WritableStream-inl.h" // js::UnwrapWriterFromStream
#include "builtin/streams/WritableStreamDefaultWriter-inl.h" // js::WritableStreamDefaultWriter::closedPromise
#include "vm/Compartment-inl.h" // JS::Compartment::wrap, js::UnwrapAndDowncastObject
@ -862,7 +863,7 @@ MOZ_MUST_USE bool js::WritableStreamRejectCloseAndClosedPromiseIfNeeded(
return false;
}
SetSettledPromiseIsHandled(cx, unwrappedClosedPromise);
js::SetSettledPromiseIsHandled(cx, unwrappedClosedPromise);
}
return true;

Просмотреть файл

@ -27,7 +27,8 @@
#include "vm/JSContext.h" // JSContext
#include "vm/PromiseObject.h" // js::PromiseObject
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::ResolveUnwrappedPromiseWithUndefined, js::SetSettledPromiseIsHandled
#include "builtin/Promise-inl.h" // js::SetSettledPromiseIsHandled
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::ResolveUnwrappedPromiseWithUndefined
#include "builtin/streams/WritableStream-inl.h" // js::WritableStream::setCloseRequest
#include "builtin/streams/WritableStreamDefaultWriter-inl.h" // js::UnwrapStreamFromWriter
#include "vm/Compartment-inl.h" // js::UnwrapAnd{DowncastObject,TypeCheckThis}
@ -185,7 +186,7 @@ static bool EnsurePromiseRejected(
}
// 4.6.{5,6} step 3: Set writer.[[<field>]].[[PromiseIsHandled]] to true.
SetSettledPromiseIsHandled(cx, unwrappedPromise);
js::SetSettledPromiseIsHandled(cx, unwrappedPromise);
return true;
}

Просмотреть файл

@ -99,6 +99,7 @@
#include "wasm/WasmModule.h"
#include "wasm/WasmProcess.h"
#include "builtin/Promise-inl.h"
#include "debugger/DebugAPI-inl.h"
#include "vm/Compartment-inl.h"
#include "vm/Interpreter-inl.h"
@ -3828,6 +3829,28 @@ JS_PUBLIC_API bool JS::GetPromiseIsHandled(JS::HandleObject promiseObj) {
return !promise->isUnhandled();
}
JS_PUBLIC_API void JS::SetSettledPromiseIsHandled(JSContext* cx,
JS::HandleObject promise) {
AssertHeapIsIdle();
CHECK_THREAD(cx);
cx->check(promise);
mozilla::Maybe<AutoRealm> ar;
Rooted<PromiseObject*> promiseObj(cx);
if (IsWrapper(promise)) {
promiseObj = promise->maybeUnwrapAs<PromiseObject>();
if (!promiseObj) {
ReportAccessDenied(cx);
return;
}
ar.emplace(cx, promiseObj);
} else {
promiseObj = promise.as<PromiseObject>();
}
js::SetSettledPromiseIsHandled(cx, promiseObj);
}
JS_PUBLIC_API JSObject* JS::GetPromiseAllocationSite(JS::HandleObject promise) {
return promise->as<PromiseObject>().allocationSite();
}