Bug 1170760 part 9. Stop using Promise::Resolve in the bindings for PromiseDebugging. r=baku

This commit is contained in:
Boris Zbarsky 2015-11-25 15:48:09 -05:00
parent 7796192fb5
commit 9d3287ef48
4 changed files with 132 additions and 50 deletions

View File

@ -88,5 +88,6 @@ MSG_DEF(MSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY, 0, JSEXN_TYPEERR, "GetCapa
MSG_DEF(MSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the resolve function.")
MSG_DEF(MSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the reject function.")
MSG_DEF(MSG_PROMISE_ARG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable")
MSG_DEF(MSG_IS_NOT_PROMISE, 1, JSEXN_TYPEERR, "{0} is not a Promise")
MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} encountered an error during installation.")
MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.")

View File

@ -14,6 +14,7 @@
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseBinding.h"
#include "mozilla/dom/PromiseDebugging.h"
#include "mozilla/dom/PromiseDebuggingBinding.h"
@ -65,23 +66,39 @@ private:
/* static */ ThreadLocal<bool>
FlushRejections::sDispatched;
/* static */ void
PromiseDebugging::GetState(GlobalObject&, Promise& aPromise,
PromiseDebuggingStateHolder& aState)
static Promise*
UnwrapPromise(JS::Handle<JSObject*> aPromise, ErrorResult& aRv)
{
switch (aPromise.mState) {
Promise* promise;
if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Promise, aPromise, promise)))) {
aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING("Argument"));
return nullptr;
}
return promise;
}
/* static */ void
PromiseDebugging::GetState(GlobalObject&, JS::Handle<JSObject*> aPromise,
PromiseDebuggingStateHolder& aState,
ErrorResult& aRv)
{
Promise* promise = UnwrapPromise(aPromise, aRv);
if (aRv.Failed()) {
return;
}
switch (promise->mState) {
case Promise::Pending:
aState.mState = PromiseDebuggingState::Pending;
break;
case Promise::Resolved:
aState.mState = PromiseDebuggingState::Fulfilled;
JS::ExposeValueToActiveJS(aPromise.mResult);
aState.mValue = aPromise.mResult;
JS::ExposeValueToActiveJS(promise->mResult);
aState.mValue = promise->mResult;
break;
case Promise::Rejected:
aState.mState = PromiseDebuggingState::Rejected;
JS::ExposeValueToActiveJS(aPromise.mResult);
aState.mReason = aPromise.mResult;
JS::ExposeValueToActiveJS(promise->mResult);
aState.mReason = promise->mResult;
break;
}
}
@ -118,49 +135,79 @@ PromiseDebugging::FlushUncaughtRejections()
}
/* static */ void
PromiseDebugging::GetAllocationStack(GlobalObject&, Promise& aPromise,
JS::MutableHandle<JSObject*> aStack)
PromiseDebugging::GetAllocationStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv)
{
aStack.set(aPromise.mAllocationStack);
Promise* promise = UnwrapPromise(aPromise, aRv);
if (aRv.Failed()) {
return;
}
aStack.set(promise->mAllocationStack);
}
/* static */ void
PromiseDebugging::GetRejectionStack(GlobalObject&, Promise& aPromise,
JS::MutableHandle<JSObject*> aStack)
PromiseDebugging::GetRejectionStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv)
{
aStack.set(aPromise.mRejectionStack);
Promise* promise = UnwrapPromise(aPromise, aRv);
if (aRv.Failed()) {
return;
}
aStack.set(promise->mRejectionStack);
}
/* static */ void
PromiseDebugging::GetFullfillmentStack(GlobalObject&, Promise& aPromise,
JS::MutableHandle<JSObject*> aStack)
PromiseDebugging::GetFullfillmentStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv)
{
aStack.set(aPromise.mFullfillmentStack);
Promise* promise = UnwrapPromise(aPromise, aRv);
if (aRv.Failed()) {
return;
}
aStack.set(promise->mFullfillmentStack);
}
/* static */ void
PromiseDebugging::GetDependentPromises(GlobalObject&, Promise& aPromise,
nsTArray<RefPtr<Promise>>& aPromises)
PromiseDebugging::GetDependentPromises(GlobalObject&, JS::Handle<JSObject*> aPromise,
nsTArray<RefPtr<Promise>>& aPromises,
ErrorResult& aRv)
{
aPromise.GetDependentPromises(aPromises);
Promise* promise = UnwrapPromise(aPromise, aRv);
if (aRv.Failed()) {
return;
}
promise->GetDependentPromises(aPromises);
}
/* static */ double
PromiseDebugging::GetPromiseLifetime(GlobalObject&, Promise& aPromise)
PromiseDebugging::GetPromiseLifetime(GlobalObject&,
JS::Handle<JSObject*> aPromise,
ErrorResult& aRv)
{
return (TimeStamp::Now() - aPromise.mCreationTimestamp).ToMilliseconds();
Promise* promise = UnwrapPromise(aPromise, aRv);
if (aRv.Failed()) {
return 0;
}
return (TimeStamp::Now() - promise->mCreationTimestamp).ToMilliseconds();
}
/* static */ double
PromiseDebugging::GetTimeToSettle(GlobalObject&, Promise& aPromise,
PromiseDebugging::GetTimeToSettle(GlobalObject&, JS::Handle<JSObject*> aPromise,
ErrorResult& aRv)
{
if (aPromise.mState == Promise::Pending) {
Promise* promise = UnwrapPromise(aPromise, aRv);
if (aRv.Failed()) {
return 0;
}
if (promise->mState == Promise::Pending) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return 0;
}
return (aPromise.mSettlementTimestamp -
aPromise.mCreationTimestamp).ToMilliseconds();
return (promise->mSettlementTimestamp -
promise->mCreationTimestamp).ToMilliseconds();
}
/* static */ void
@ -204,10 +251,15 @@ PromiseDebugging::AddConsumedRejection(Promise& aPromise)
/* static */ void
PromiseDebugging::GetPromiseID(GlobalObject&,
Promise& aPromise,
nsString& aID)
JS::Handle<JSObject*> aPromise,
nsString& aID,
ErrorResult& aRv)
{
uint64_t promiseID = aPromise.GetID();
Promise* promise = UnwrapPromise(aPromise, aRv);
if (aRv.Failed()) {
return;
}
uint64_t promiseID = promise->GetID();
aID = sIDPrefix;
aID.AppendInt(promiseID);
}

View File

@ -32,22 +32,32 @@ public:
static void Init();
static void Shutdown();
static void GetState(GlobalObject&, Promise& aPromise,
PromiseDebuggingStateHolder& aState);
static void GetState(GlobalObject&, JS::Handle<JSObject*> aPromise,
PromiseDebuggingStateHolder& aState,
ErrorResult& aRv);
static void GetAllocationStack(GlobalObject&, Promise& aPromise,
JS::MutableHandle<JSObject*> aStack);
static void GetRejectionStack(GlobalObject&, Promise& aPromise,
JS::MutableHandle<JSObject*> aStack);
static void GetFullfillmentStack(GlobalObject&, Promise& aPromise,
JS::MutableHandle<JSObject*> aStack);
static void GetDependentPromises(GlobalObject&, Promise& aPromise,
nsTArray<RefPtr<Promise>>& aPromises);
static double GetPromiseLifetime(GlobalObject&, Promise& aPromise);
static double GetTimeToSettle(GlobalObject&, Promise& aPromise,
static void GetAllocationStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv);
static void GetRejectionStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv);
static void GetFullfillmentStack(GlobalObject&,
JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv);
static void GetDependentPromises(GlobalObject&,
JS::Handle<JSObject*> aPromise,
nsTArray<RefPtr<Promise>>& aPromises,
ErrorResult& aRv);
static double GetPromiseLifetime(GlobalObject&,
JS::Handle<JSObject*> aPromise,
ErrorResult& aRv);
static double GetTimeToSettle(GlobalObject&, JS::Handle<JSObject*> aPromise,
ErrorResult& aRv);
static void GetPromiseID(GlobalObject&, Promise&, nsString&);
static void GetPromiseID(GlobalObject&, JS::Handle<JSObject*>, nsString&,
ErrorResult&);
// Mechanism for watching uncaught instances of Promise.
static void AddUncaughtRejectionObserver(GlobalObject&,

View File

@ -52,33 +52,50 @@ callback interface UncaughtRejectionObserver {
[ChromeOnly, Exposed=(Window,System)]
interface PromiseDebugging {
static PromiseDebuggingStateHolder getState(Promise<any> p);
/**
* The various functions on this interface all expect to take promises but
* don't want the WebIDL behavior of assimilating random passed-in objects
* into promises. They also want to treat Promise subclass instances as
* promises instead of wrapping them in a vanilla Promise, which is what the
* IDL spec says to do. So we list all our arguments as "object" instead of
* "Promise" and check for them being a Promise internally.
*/
/**
* Get the current state of the given promise.
*/
[Throws]
static PromiseDebuggingStateHolder getState(object p);
/**
* Return the stack to the promise's allocation point. This can
* return null if the promise was not created from script.
*/
static object? getAllocationStack(Promise<any> p);
[Throws]
static object? getAllocationStack(object p);
/**
* Return the stack to the promise's rejection point, if the
* rejection happened from script. This can return null if the
* promise has not been rejected or was not rejected from script.
*/
static object? getRejectionStack(Promise<any> p);
[Throws]
static object? getRejectionStack(object p);
/**
* Return the stack to the promise's fulfillment point, if the
* fulfillment happened from script. This can return null if the
* promise has not been fulfilled or was not fulfilled from script.
*/
static object? getFullfillmentStack(Promise<any> p);
[Throws]
static object? getFullfillmentStack(object p);
/**
* Return an identifier for a promise. This identifier is guaranteed
* to be unique to this instance of Firefox.
*/
static DOMString getPromiseID(Promise<any> p);
[Throws]
static DOMString getPromiseID(object p);
/**
* Get the promises directly depending on a given promise. These are:
@ -96,12 +113,14 @@ interface PromiseDebugging {
* p. It does not recursively return promises that depend on promises that
* depend on p.
*/
static sequence<Promise<any>> getDependentPromises(Promise<any> p);
[Throws]
static sequence<Promise<any>> getDependentPromises(object p);
/**
* Get the number of milliseconds elapsed since the given promise was created.
*/
static DOMHighResTimeStamp getPromiseLifetime(Promise<any> p);
[Throws]
static DOMHighResTimeStamp getPromiseLifetime(object p);
/*
* Get the number of milliseconds elapsed between the promise being created
@ -109,7 +128,7 @@ interface PromiseDebugging {
* settled.
*/
[Throws]
static DOMHighResTimeStamp getTimeToSettle(Promise<any> p);
static DOMHighResTimeStamp getTimeToSettle(object p);
/**
* Watching uncaught rejections on the current thread.