Back out 13 changesets (bug 1170760) for Gu bustage in homescreen/test/unit/apps_test.js

CLOSED TREE

Backed out changeset 5d84599a8846 (bug 1170760)
Backed out changeset 6104fe33d5f5 (bug 1170760)
Backed out changeset 1dfb229da01d (bug 1170760)
Backed out changeset f380faddfdd8 (bug 1170760)
Backed out changeset 541831dc6b57 (bug 1170760)
Backed out changeset 6a5b7dfab882 (bug 1170760)
Backed out changeset ee514a256922 (bug 1170760)
Backed out changeset 3c2c1acc34ee (bug 1170760)
Backed out changeset dc2a7f5dc5d6 (bug 1170760)
Backed out changeset b312a08fbab5 (bug 1170760)
Backed out changeset cb6aba9b8497 (bug 1170760)
Backed out changeset 39e4f5b1ba40 (bug 1170760)
Backed out changeset 7d79cce3630a (bug 1170760)
This commit is contained in:
Phil Ringnalda 2015-11-25 21:02:55 -08:00
parent 04870269d3
commit 53745073f0
30 changed files with 323 additions and 2388 deletions

View File

@ -273,7 +273,7 @@ var RemoteTabViewer = {
}.bind(this);
return CloudSync().tabs.getRemoteTabs()
.then(updateTabList, Promise.reject.bind(Promise));
.then(updateTabList, Promise.reject);
},
adjustContextMenu: function (event) {

View File

@ -13,7 +13,6 @@
#include "mozilla/dom/Event.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h"
#include "jsfriendapi.h"
using mozilla::dom::AnyCallback;
using mozilla::dom::DOMError;
@ -207,16 +206,14 @@ DOMRequest::RootResultVal()
mozilla::HoldJSObjects(this);
}
void
already_AddRefed<Promise>
DOMRequest::Then(JSContext* aCx, AnyCallback* aResolveCallback,
AnyCallback* aRejectCallback,
JS::MutableHandle<JS::Value> aRetval,
mozilla::ErrorResult& aRv)
AnyCallback* aRejectCallback, mozilla::ErrorResult& aRv)
{
if (!mPromise) {
mPromise = Promise::Create(DOMEventTargetHelper::GetParentObject(), aRv);
if (aRv.Failed()) {
return;
return nullptr;
}
if (mDone) {
// Since we create mPromise lazily, it's possible that the DOMRequest object
@ -231,10 +228,7 @@ DOMRequest::Then(JSContext* aCx, AnyCallback* aResolveCallback,
}
}
// Just use the global of the Promise itself as the callee global.
JS::Rooted<JSObject*> global(aCx, mPromise->GetWrapper());
global = js::GetGlobalForObjectCrossCompartment(global);
mPromise->Then(aCx, global, aResolveCallback, aRejectCallback, aRetval, aRv);
return mPromise->Then(aCx, aResolveCallback, aRejectCallback, aRv);
}
NS_IMPL_ISUPPORTS(DOMRequestService, nsIDOMRequestService)

View File

@ -74,11 +74,9 @@ public:
IMPL_EVENT_HANDLER(success)
IMPL_EVENT_HANDLER(error)
void
already_AddRefed<mozilla::dom::Promise>
Then(JSContext* aCx, AnyCallback* aResolveCallback,
AnyCallback* aRejectCallback,
JS::MutableHandle<JS::Value> aRetval,
mozilla::ErrorResult& aRv);
AnyCallback* aRejectCallback, mozilla::ErrorResult& aRv);
void FireSuccess(JS::Handle<JS::Value> aResult);
void FireError(const nsAString& aError);

View File

@ -2761,17 +2761,8 @@ ConvertExceptionToPromise(JSContext* cx,
}
JS_ClearPendingException(cx);
nsCOMPtr<nsIGlobalObject> globalObj =
do_QueryInterface(global.GetAsSupports());
if (!globalObj) {
ErrorResult rv;
rv.Throw(NS_ERROR_UNEXPECTED);
return !rv.MaybeSetPendingException(cx);
}
ErrorResult rv;
RefPtr<Promise> promise = Promise::Reject(globalObj, cx, exn, rv);
RefPtr<Promise> promise = Promise::Reject(global, exn, rv);
if (rv.MaybeSetPendingException(cx)) {
// We just give up. We put the exception from the ErrorResult on
// the JSContext just to make sure to not leak memory on the

View File

@ -1949,13 +1949,7 @@ DOMInterfaces = {
# Keep this in sync with TestExampleInterface
'headerFile': 'TestBindingHeader.h',
'register': False
},
'TestInterfaceWithPromiseConstructorArg' : {
'headerFile': 'TestBindingHeader.h',
'register': False,
},
}
}
# These are temporary, until they've been converted to use new DOM bindings

View File

@ -2979,21 +2979,6 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
else:
unforgeableHolderSetup = None
if self.descriptor.name == "Promise":
speciesSetup = CGGeneric(fill(
"""
JS::Rooted<JSObject*> promiseConstructor(aCx, *interfaceCache);
JS::Rooted<jsid> species(aCx,
SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::species)));
if (!JS_DefinePropertyById(aCx, promiseConstructor, species, JS::UndefinedHandleValue,
JSPROP_SHARED, Promise::PromiseSpecies, nullptr)) {
$*{failureCode}
}
""",
failureCode=failureCode))
else:
speciesSetup = None
if (self.descriptor.interface.isOnGlobalProtoChain() and
needInterfacePrototypeObject):
makeProtoPrototypeImmutable = CGGeneric(fill(
@ -3019,7 +3004,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
return CGList(
[getParentProto, CGGeneric(getConstructorProto), initIds,
prefCache, CGGeneric(call), defineAliases, unforgeableHolderSetup,
speciesSetup, makeProtoPrototypeImmutable],
makeProtoPrototypeImmutable],
"\n").define()
@ -5093,124 +5078,24 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
templateBody += 'static_assert(IsRefcounted<%s>::value, "We can only store refcounted classes.");' % typeName
if isPromise:
# Per spec, what we're supposed to do is take the original
# Promise.resolve and call it with the original Promise as this
# value to make a Promise out of whatever value we actually have
# here. The question is which global we should use. There are
# several cases to consider:
#
# 1) Normal call to API with a Promise argument. This is a case the
# spec covers, and we should be using the current Realm's
# Promise. That means the current compartment.
# 2) Call to API with a Promise argument over Xrays. In practice,
# this sort of thing seems to be used for giving an API
# implementation a way to wait for conclusion of an asyc
# operation, _not_ to expose the Promise to content code. So we
# probably want to allow callers to use such an API in a
# "natural" way, by passing chrome-side promises; indeed, that
# may be all that the caller has to represent their async
# operation. That means we really need to do the
# Promise.resolve() in the caller (chrome) compartment: if we do
# it in the content compartment, we will try to call .then() on
# the chrome promise while in the content compartment, which will
# throw and we'll just get a rejected Promise. Note that this is
# also the reason why a caller who has a chrome Promise
# representing an async operation can't itself convert it to a
# content-side Promise (at least not without some serious
# gyrations).
# 3) Promise return value from a callback or callback interface.
# This is in theory a case the spec covers but in practice it
# really doesn't define behavior here because it doesn't define
# what Realm we're in after the callback returns, which is when
# the argument conversion happens. We will use the current
# compartment, which is the compartment of the callable (which
# may itself be a cross-compartment wrapper itself), which makes
# as much sense as anything else. In practice, such an API would
# once again be providing a Promise to signal completion of an
# operation, which would then not be exposed to anyone other than
# our own implementation code.
# 4) Return value from a JS-implemented interface. In this case we
# have a problem. Our current compartment is the compartment of
# the JS implementation. But if the JS implementation returned
# a page-side Promise (which is a totally sane thing to do, and
# in fact the right thing to do given that this return value is
# going right to content script) then we don't want to
# Promise.resolve with our current compartment Promise, because
# that will wrap it up in a chrome-side Promise, which is
# decidedly _not_ what's desired here. So in that case we
# should really unwrap the return value and use the global of
# the result. CheckedUnwrap should be good enough for that; if
# it fails, then we're failing unwrap while in a
# system-privileged compartment, so presumably we have a dead
# object wrapper. Just error out. Do NOT fall back to using
# the current compartment instead: that will return a
# system-privileged rejected (because getting .then inside
# resolve() failed) Promise to the caller, which they won't be
# able to touch. That's not helpful. If we error out, on the
# other hand, they will get a content-side rejected promise.
# Same thing if the value returned is not even an object.
if isCallbackReturnValue == "JSImpl":
# Case 4 above. Note that globalObj defaults to the current
# compartment global. Note that we don't use $*{exceptionCode}
# here because that will try to aRv.Throw(NS_ERROR_UNEXPECTED)
# which we don't really want here.
assert exceptionCode == "aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n"
getPromiseGlobal = fill(
"""
if (!$${val}.isObject()) {
aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
return nullptr;
}
JSObject* unwrappedVal = js::CheckedUnwrap(&$${val}.toObject());
if (!unwrappedVal) {
// A slight lie, but not much of one, for a dead object wrapper.
aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
return nullptr;
}
globalObj = js::GetGlobalForObjectCrossCompartment(unwrappedVal);
""",
sourceDescription=sourceDescription)
else:
getPromiseGlobal = ""
templateBody = fill(
"""
{ // Scope for our GlobalObject, ErrorResult, JSAutoCompartment,
// etc.
{ // Scope for our GlobalObject and ErrorResult
JS::Rooted<JSObject*> globalObj(cx, JS::CurrentGlobalOrNull(cx));
$*{getPromiseGlobal}
JSAutoCompartment ac(cx, globalObj);
GlobalObject promiseGlobal(cx, globalObj);
// Might as well use CurrentGlobalOrNull here; that will at
// least give us the same behavior as if the caller just called
// Promise.resolve() themselves.
GlobalObject promiseGlobal(cx, JS::CurrentGlobalOrNull(cx));
if (promiseGlobal.Failed()) {
$*{exceptionCode}
}
ErrorResult promiseRv;
JS::Handle<JSObject*> promiseCtor =
PromiseBinding::GetConstructorObjectHandle(cx, globalObj);
if (!promiseCtor) {
$*{exceptionCode}
}
JS::Rooted<JS::Value> resolveThisv(cx, JS::ObjectValue(*promiseCtor));
JS::Rooted<JS::Value> resolveResult(cx);
JS::Rooted<JS::Value> valueToResolve(cx, $${val});
if (!JS_WrapValue(cx, &valueToResolve)) {
$*{exceptionCode}
}
Promise::Resolve(promiseGlobal, resolveThisv, valueToResolve,
&resolveResult, promiseRv);
$${declName} = Promise::Resolve(promiseGlobal, $${val}, promiseRv);
if (promiseRv.MaybeSetPendingException(cx)) {
$*{exceptionCode}
}
nsresult unwrapRv = UNWRAP_OBJECT(Promise, &resolveResult.toObject(), $${declName});
if (NS_FAILED(unwrapRv)) { // Quite odd
promiseRv.Throw(unwrapRv);
promiseRv.MaybeSetPendingException(cx);
$*{exceptionCode}
}
}
""",
getPromiseGlobal=getPromiseGlobal,
exceptionCode=exceptionCode)
elif not descriptor.skipGen and not descriptor.interface.isConsequential() and not descriptor.interface.isExternal():
if failureCode is not None:
@ -7147,59 +7032,16 @@ class CGPerSignatureCall(CGThing):
if needsCx:
argsPre.append("cx")
# Hack for making Promise.prototype.then work well over Xrays.
if (not static and
(descriptor.name == "Promise" or
descriptor.name == "MozAbortablePromise") and
idlNode.isMethod() and
idlNode.identifier.name == "then"):
cgThings.append(CGGeneric(dedent(
"""
JS::Rooted<JSObject*> calleeGlobal(cx, xpc::XrayAwareCalleeGlobal(&args.callee()));
""")))
argsPre.append("calleeGlobal")
needsUnwrap = False
argsPost = []
if isConstructor:
needsUnwrap = True
needsUnwrappedVar = False
unwrappedVar = "obj"
if descriptor.name == "Promise" or descriptor.name == "MozAbortablePromise":
# Hack for Promise for now: pass in our desired proto so the
# implementation can create the reflector with the right proto.
argsPost.append("desiredProto")
# Also, we do not want to enter the content compartment when the
# Promise constructor is called via Xrays, because we want to
# create our callback functions that we will hand to our caller
# in the Xray compartment. The reason we want to do that is the
# following situation, over Xrays:
#
# contentWindow.Promise.race([Promise.resolve(5)])
#
# Ideally this would work. Internally, race() does a
# contentWindow.Promise.resolve() on everything in the array.
# Per spec, to support subclassing,
# contentWindow.Promise.resolve has to do:
#
# var resolve, reject;
# var p = new contentWindow.Promise(function(a, b) {
# resolve = a;
# reject = b;
# });
# resolve(arg);
# return p;
#
# where "arg" is, in this case, the chrome-side return value of
# Promise.resolve(5). But if the "resolve" function in that
# case were created in the content compartment, then calling it
# would wrap "arg" in an opaque wrapper, and that function tries
# to get .then off the argument, which would throw. So we need
# to create the "resolve" function in the chrome compartment,
# and hence want to be running the entire Promise constructor
# (which creates that function) in the chrome compartment in
# this case. So don't set needsUnwrap here.
else:
needsUnwrap = True
needsUnwrappedVar = False
unwrappedVar = "obj"
elif descriptor.interface.isJSImplemented():
if not idlNode.isStatic():
needsUnwrap = True
@ -7212,11 +7054,6 @@ class CGPerSignatureCall(CGThing):
needsUnwrappedVar = True
argsPre.append("unwrappedObj ? *unwrappedObj : obj")
if static and not isConstructor and descriptor.name == "Promise":
# Hack for Promise for now: pass in the "this" value to
# Promise static methods.
argsPre.append("args.thisv()")
if needsUnwrap and needsUnwrappedVar:
# We cannot assign into obj because it's a Handle, not a
# MutableHandle, so we need a separate Rooted.
@ -9161,6 +8998,26 @@ class CGStaticMethodJitinfo(CGGeneric):
IDLToCIdentifier(method.identifier.name))))
class CGMethodIdentityTest(CGAbstractMethod):
"""
A class to generate a method-identity test for a given IDL operation.
"""
def __init__(self, descriptor, method):
self.method = method
name = "Is%sMethod" % MakeNativeName(method.identifier.name)
CGAbstractMethod.__init__(self, descriptor, name, 'bool',
[Argument('JS::Handle<JSObject*>', 'aObj')])
def definition_body(self):
return dedent(
"""
MOZ_ASSERT(aObj);
return js::IsFunctionObject(aObj) &&
js::FunctionObjectIsNative(aObj) &&
FUNCTION_VALUE_TO_JITINFO(JS::ObjectValue(*aObj)) == &%s_methodinfo;
""" % IDLToCIdentifier(self.method.identifier.name))
def getEnumValueName(value):
# Some enum values can be empty strings. Others might have weird
# characters in them. Deal with the former by returning "_empty",
@ -11792,6 +11649,8 @@ class CGDescriptor(CGThing):
cgThings.append(CGMemberJITInfo(descriptor, m))
if props.isCrossOriginMethod:
crossOriginMethods.add(m.identifier.name)
if m.getExtendedAttribute("MethodIdentityTestable"):
cgThings.append(CGMethodIdentityTest(descriptor, m))
# If we've hit the maplike/setlike member itself, go ahead and
# generate its convenience functions.
elif m.isMaplikeOrSetlike():

View File

@ -83,11 +83,5 @@ MSG_DEF(MSG_NOTIFICATION_PERMISSION_DENIED, 0, JSEXN_TYPEERR, "Permission to sho
MSG_DEF(MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER, 0, JSEXN_TYPEERR, "Notification constructor cannot be used in ServiceWorkerGlobalScope. Use registration.showNotification() instead.")
MSG_DEF(MSG_INVALID_SCOPE, 2, JSEXN_TYPEERR, "Invalid scope trying to resolve {0} with base URL {1}.")
MSG_DEF(MSG_INVALID_KEYFRAME_OFFSETS, 0, JSEXN_TYPEERR, "Keyframes with specified offsets must be in order and all be in the range [0, 1].")
MSG_DEF(MSG_ILLEGAL_PROMISE_CONSTRUCTOR, 0, JSEXN_TYPEERR, "Non-constructor value passed to NewPromiseCapability.")
MSG_DEF(MSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY, 0, JSEXN_TYPEERR, "GetCapabilitiesExecutor function already invoked with non-undefined values.")
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

@ -4805,6 +4805,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
identifier == "CheckAnyPermissions" or
identifier == "CheckAllPermissions" or
identifier == "BinaryName" or
identifier == "MethodIdentityTestable" or
identifier == "StaticClassOverride"):
# Known attributes that we don't need to do anything with here
pass

View File

@ -1371,18 +1371,6 @@ public:
virtual nsISupports* GetParentObject();
};
class TestInterfaceWithPromiseConstructorArg : public nsISupports, public nsWrapperCache
{
public:
NS_DECL_ISUPPORTS
static
already_AddRefed<TestInterfaceWithPromiseConstructorArg>
Constructor(const GlobalObject&, Promise&, ErrorResult&);
virtual nsISupports* GetParentObject();
};
} // namespace dom
} // namespace mozilla

View File

@ -55,7 +55,6 @@ callback interface TestCallbackInterface {
void passVariadicNullableTypedArray(Float32Array?... arg);
Uint8Array receiveUint8Array();
attribute Uint8Array uint8ArrayAttr;
Promise<void> receivePromise();
};
callback interface TestSingleOperationCallbackInterface {
@ -1035,9 +1034,6 @@ dictionary Dict : ParentDict {
CustomEventInit customEventInit;
TestDictionaryTypedef dictionaryTypedef;
Promise<void> promise;
sequence<Promise<void>> promiseSequence;
};
dictionary ParentDict : GrandparentDict {
@ -1165,7 +1161,3 @@ interface TestDeprecatedInterface {
static void alsoDeprecated();
};
[Constructor(Promise<void> promise)]
interface TestInterfaceWithPromiseConstructorArg {
};

View File

@ -124,11 +124,12 @@ TestInterfaceJS.prototype = {
},
testPromiseWithThrowingChromeThenable: function() {
var thenable = {
then: function() {
noSuchMethodExistsYo3()
}
};
// We need to produce a thing that has a "then" property in the page
// compartment, since we plan to call the page-provided resolve function.
var thenable = new this._win.Object();
Cu.waiveXrays(thenable).then = function() {
noSuchMethodExistsYo3()
}
return new this._win.Promise(function(resolve) {
resolve(thenable)
});
@ -143,12 +144,13 @@ TestInterfaceJS.prototype = {
},
testPromiseWithDOMExceptionThrowingThenable: function() {
var thenable = {
then: () => {
throw new this._win.DOMException("We are a fourth DOMException",
"TypeMismatchError");
}
};
// We need to produce a thing that has a "then" property in the page
// compartment, since we plan to call the page-provided resolve function.
var thenable = new this._win.Object();
Cu.waiveXrays(thenable).then = () => {
throw new this._win.DOMException("We are a fourth DOMException",
"TypeMismatchError");
}
return new this._win.Promise(function(resolve) {
resolve(thenable)
});

File diff suppressed because it is too large Load Diff

View File

@ -163,55 +163,40 @@ public:
Constructor(const GlobalObject& aGlobal, PromiseInit& aInit,
ErrorResult& aRv, JS::Handle<JSObject*> aDesiredProto);
static void
Resolve(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
JS::Handle<JS::Value> aValue,
JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv);
static already_AddRefed<Promise>
Resolve(const GlobalObject& aGlobal,
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
static already_AddRefed<Promise>
Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
static void
Reject(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
JS::Handle<JS::Value> aValue,
JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv);
static already_AddRefed<Promise>
Reject(const GlobalObject& aGlobal,
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
static already_AddRefed<Promise>
Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
void
Then(JSContext* aCx,
// aCalleeGlobal may not be in the compartment of aCx, when called over
// Xrays.
JS::Handle<JSObject*> aCalleeGlobal,
AnyCallback* aResolveCallback, AnyCallback* aRejectCallback,
JS::MutableHandle<JS::Value> aRetval,
ErrorResult& aRv);
already_AddRefed<Promise>
Then(JSContext* aCx, AnyCallback* aResolveCallback,
AnyCallback* aRejectCallback, ErrorResult& aRv);
void
Catch(JSContext* aCx,
AnyCallback* aRejectCallback,
JS::MutableHandle<JS::Value> aRetval,
ErrorResult& aRv);
already_AddRefed<Promise>
Catch(JSContext* aCx, AnyCallback* aRejectCallback, ErrorResult& aRv);
static void
All(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
JS::Handle<JS::Value> aIterable, JS::MutableHandle<JS::Value> aRetval,
ErrorResult& aRv);
static already_AddRefed<Promise>
All(const GlobalObject& aGlobal,
const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
static already_AddRefed<Promise>
All(const GlobalObject& aGlobal,
const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv);
static void
Race(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
JS::Handle<JS::Value> aIterable, JS::MutableHandle<JS::Value> aRetval,
ErrorResult& aRv);
static bool
PromiseSpecies(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
static already_AddRefed<Promise>
Race(const GlobalObject& aGlobal,
const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
void AppendNativeHandler(PromiseNativeHandler* aRunnable);
@ -226,14 +211,7 @@ public:
static void
DispatchToMicroTask(nsIRunnable* aRunnable);
enum JSCallbackSlots {
SLOT_PROMISE = 0,
SLOT_DATA
};
protected:
struct PromiseCapability;
// Do NOT call this unless you're Promise::Create. I wish we could enforce
// that from inside this class too, somehow.
explicit Promise(nsIGlobalObject* aGlobal);
@ -250,17 +228,6 @@ protected:
void CallInitFunction(const GlobalObject& aGlobal, PromiseInit& aInit,
ErrorResult& aRv);
// The NewPromiseCapability function from
// <http://www.ecma-international.org/ecma-262/6.0/#sec-newpromisecapability>.
// Errors are communicated via aRv. If aForceCallbackCreation is
// true, then this function will ensure that aCapability has a
// useful mResolve/mReject even if mNativePromise is non-null.
static void NewPromiseCapability(JSContext* aCx, nsIGlobalObject* aGlobal,
JS::Handle<JS::Value> aConstructor,
bool aForceCallbackCreation,
PromiseCapability& aCapability,
ErrorResult& aRv);
bool IsPending()
{
return mResolvePending;

View File

@ -9,8 +9,6 @@
#include "mozilla/dom/PromiseNativeHandler.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "jswrapper.h"
namespace mozilla {
namespace dom {
@ -156,113 +154,25 @@ RejectPromiseCallback::Call(JSContext* aCx,
return NS_OK;
}
// InvokePromiseFuncCallback
NS_IMPL_CYCLE_COLLECTION_CLASS(InvokePromiseFuncCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(InvokePromiseFuncCallback,
PromiseCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromiseFunc)
tmp->mGlobal = nullptr;
tmp->mNextPromiseObj = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(InvokePromiseFuncCallback,
PromiseCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromiseFunc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(InvokePromiseFuncCallback)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mGlobal)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mNextPromiseObj)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(InvokePromiseFuncCallback)
NS_INTERFACE_MAP_END_INHERITING(PromiseCallback)
NS_IMPL_ADDREF_INHERITED(InvokePromiseFuncCallback, PromiseCallback)
NS_IMPL_RELEASE_INHERITED(InvokePromiseFuncCallback, PromiseCallback)
InvokePromiseFuncCallback::InvokePromiseFuncCallback(JS::Handle<JSObject*> aGlobal,
JS::Handle<JSObject*> aNextPromiseObj,
AnyCallback* aPromiseFunc)
: mGlobal(aGlobal)
, mNextPromiseObj(aNextPromiseObj)
, mPromiseFunc(aPromiseFunc)
{
MOZ_ASSERT(aGlobal);
MOZ_ASSERT(aNextPromiseObj);
MOZ_ASSERT(aPromiseFunc);
HoldJSObjects(this);
}
InvokePromiseFuncCallback::~InvokePromiseFuncCallback()
{
DropJSObjects(this);
}
nsresult
InvokePromiseFuncCallback::Call(JSContext* aCx,
JS::Handle<JS::Value> aValue)
{
// Run resolver's algorithm with value and the synchronous flag set.
JS::ExposeObjectToActiveJS(mGlobal);
JS::ExposeValueToActiveJS(aValue);
JSAutoCompartment ac(aCx, mGlobal);
JS::Rooted<JS::Value> value(aCx, aValue);
if (!JS_WrapValue(aCx, &value)) {
NS_WARNING("Failed to wrap value into the right compartment.");
return NS_ERROR_FAILURE;
}
ErrorResult rv;
JS::Rooted<JS::Value> ignored(aCx);
mPromiseFunc->Call(value, &ignored, rv);
// Useful exceptions already got reported.
rv.SuppressException();
return NS_OK;
}
Promise*
InvokePromiseFuncCallback::GetDependentPromise()
{
Promise* promise;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Promise, mNextPromiseObj, promise))) {
return promise;
}
// Oh, well.
return nullptr;
}
// WrapperPromiseCallback
NS_IMPL_CYCLE_COLLECTION_CLASS(WrapperPromiseCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WrapperPromiseCallback,
PromiseCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNextPromise)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mResolveFunc)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRejectFunc)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
tmp->mGlobal = nullptr;
tmp->mNextPromiseObj = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WrapperPromiseCallback,
PromiseCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNextPromise)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResolveFunc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRejectFunc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WrapperPromiseCallback)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mGlobal)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mNextPromiseObj)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(WrapperPromiseCallback)
@ -283,24 +193,6 @@ WrapperPromiseCallback::WrapperPromiseCallback(Promise* aNextPromise,
HoldJSObjects(this);
}
WrapperPromiseCallback::WrapperPromiseCallback(JS::Handle<JSObject*> aGlobal,
AnyCallback* aCallback,
JS::Handle<JSObject*> aNextPromiseObj,
AnyCallback* aResolveFunc,
AnyCallback* aRejectFunc)
: mNextPromiseObj(aNextPromiseObj)
, mResolveFunc(aResolveFunc)
, mRejectFunc(aRejectFunc)
, mGlobal(aGlobal)
, mCallback(aCallback)
{
MOZ_ASSERT(mNextPromiseObj);
MOZ_ASSERT(aResolveFunc);
MOZ_ASSERT(aRejectFunc);
MOZ_ASSERT(aGlobal);
HoldJSObjects(this);
}
WrapperPromiseCallback::~WrapperPromiseCallback()
{
DropJSObjects(this);
@ -324,16 +216,9 @@ WrapperPromiseCallback::Call(JSContext* aCx,
// PromiseReactionTask step 6
JS::Rooted<JS::Value> retValue(aCx);
JSCompartment* compartment;
if (mNextPromise) {
compartment = mNextPromise->Compartment();
} else {
MOZ_ASSERT(mNextPromiseObj);
compartment = js::GetObjectCompartment(mNextPromiseObj);
}
mCallback->Call(value, &retValue, rv, "promise callback",
CallbackObject::eRethrowExceptions,
compartment);
mNextPromise->Compartment());
rv.WouldReportJSException();
@ -344,43 +229,23 @@ WrapperPromiseCallback::Call(JSContext* aCx,
// Convert the ErrorResult to a JS exception object that we can reject
// ourselves with. This will be exactly the exception that would get
// thrown from a binding method whose ErrorResult ended up with whatever
// is on "rv" right now. Do this in the promise reflector compartment.
Maybe<JSAutoCompartment> ac;
if (mNextPromise) {
ac.emplace(aCx, mNextPromise->GlobalJSObject());
} else {
ac.emplace(aCx, mNextPromiseObj);
}
// is on "rv" right now.
JSAutoCompartment ac(aCx, mNextPromise->GlobalJSObject());
DebugOnly<bool> conversionResult = ToJSValue(aCx, rv, &value);
MOZ_ASSERT(conversionResult);
}
if (mNextPromise) {
mNextPromise->RejectInternal(aCx, value);
} else {
JS::Rooted<JS::Value> ignored(aCx);
ErrorResult rejectRv;
mRejectFunc->Call(value, &ignored, rejectRv);
// This reported any JS exceptions; we just have a pointless exception on
// there now.
rejectRv.SuppressException();
}
mNextPromise->RejectInternal(aCx, value);
return NS_OK;
}
// If the return value is the same as the promise itself, throw TypeError.
if (retValue.isObject()) {
JS::Rooted<JSObject*> valueObj(aCx, &retValue.toObject());
valueObj = js::CheckedUnwrap(valueObj);
JS::Rooted<JSObject*> nextPromiseObj(aCx);
if (mNextPromise) {
nextPromiseObj = mNextPromise->GetWrapper();
} else {
MOZ_ASSERT(mNextPromiseObj);
nextPromiseObj = mNextPromiseObj;
}
// XXXbz shouldn't this check be over in ResolveInternal anyway?
if (valueObj == nextPromiseObj) {
Promise* returnedPromise;
nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise);
if (NS_SUCCEEDED(r) && returnedPromise == mNextPromise) {
const char* fileName = nullptr;
uint32_t lineNumber = 0;
@ -429,16 +294,7 @@ WrapperPromiseCallback::Call(JSContext* aCx,
return NS_ERROR_OUT_OF_MEMORY;
}
if (mNextPromise) {
mNextPromise->RejectInternal(aCx, typeError);
} else {
JS::Rooted<JS::Value> ignored(aCx);
ErrorResult rejectRv;
mRejectFunc->Call(typeError, &ignored, rejectRv);
// This reported any JS exceptions; we just have a pointless exception
// on there now.
rejectRv.SuppressException();
}
mNextPromise->RejectInternal(aCx, typeError);
return NS_OK;
}
}
@ -449,56 +305,10 @@ WrapperPromiseCallback::Call(JSContext* aCx,
return NS_ERROR_FAILURE;
}
if (mNextPromise) {
mNextPromise->ResolveInternal(aCx, retValue);
} else {
JS::Rooted<JS::Value> ignored(aCx);
ErrorResult resolveRv;
mResolveFunc->Call(retValue, &ignored, resolveRv);
// This reported any JS exceptions; we just have a pointless exception
// on there now.
resolveRv.SuppressException();
}
mNextPromise->ResolveInternal(aCx, retValue);
return NS_OK;
}
Promise*
WrapperPromiseCallback::GetDependentPromise()
{
// Per spec, various algorithms like all() and race() are actually implemented
// in terms of calling then() but passing it the resolve/reject functions that
// are passed as arguments to function passed to the Promise constructor.
// That will cause the promise in question to hold on to a
// WrapperPromiseCallback, but the dependent promise should really be the one
// whose constructor those functions came from, not the about-to-be-ignored
// return value of "then". So try to determine whether we're in that case and
// if so go ahead and dig the dependent promise out of the function we have.
JSObject* callable = mCallback->Callable();
// Unwrap it, in case it's a cross-compartment wrapper. Our caller here is
// system, so it's really ok to just go and unwrap.
callable = js::UncheckedUnwrap(callable);
if (JS_IsNativeFunction(callable, Promise::JSCallback)) {
JS::Value promiseVal =
js::GetFunctionNativeReserved(callable, Promise::SLOT_PROMISE);
Promise* promise;
UNWRAP_OBJECT(Promise, &promiseVal.toObject(), promise);
return promise;
}
if (mNextPromise) {
return mNextPromise;
}
Promise* promise;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Promise, mNextPromiseObj, promise))) {
return promise;
}
// Oh, well.
return nullptr;
}
// NativePromiseCallback
NS_IMPL_CYCLE_COLLECTION_INHERITED(NativePromiseCallback,

View File

@ -45,13 +45,8 @@ public:
};
// WrapperPromiseCallback execs a JS Callback with a value, and then the return
// value is sent to either:
// a) If aNextPromise is non-null, the aNextPromise->ResolveFunction() or to
// aNextPromise->RejectFunction() if the JS Callback throws.
// or
// b) If aNextPromise is null, in which case aResolveFunc and aRejectFunc must
// be non-null, then to aResolveFunc, unless aCallback threw, in which case
// aRejectFunc.
// value is sent to the aNextPromise->ResolveFunction() or to
// aNextPromise->RejectFunction() if the JS Callback throws.
class WrapperPromiseCallback final : public PromiseCallback
{
public:
@ -62,30 +57,18 @@ public:
nsresult Call(JSContext* aCx,
JS::Handle<JS::Value> aValue) override;
Promise* GetDependentPromise() override;
Promise* GetDependentPromise() override
{
return mNextPromise;
}
// Constructor for when we know we have a vanilla Promise.
WrapperPromiseCallback(Promise* aNextPromise, JS::Handle<JSObject*> aGlobal,
AnyCallback* aCallback);
// Constructor for when all we have to work with are resolve/reject functions.
WrapperPromiseCallback(JS::Handle<JSObject*> aGlobal,
AnyCallback* aCallback,
JS::Handle<JSObject*> mNextPromiseObj,
AnyCallback* aResolveFunc,
AnyCallback* aRejectFunc);
private:
~WrapperPromiseCallback();
// Either mNextPromise is non-null or all three of mNextPromiseObj,
// mResolveFund and mRejectFunc must are non-null.
RefPtr<Promise> mNextPromise;
// mNextPromiseObj is the reflector itself; it may not be in the
// same compartment as anything else we have.
JS::Heap<JSObject*> mNextPromiseObj;
RefPtr<AnyCallback> mResolveFunc;
RefPtr<AnyCallback> mRejectFunc;
JS::Heap<JSObject*> mGlobal;
RefPtr<AnyCallback> mCallback;
};
@ -142,32 +125,6 @@ private:
JS::Heap<JSObject*> mGlobal;
};
// InvokePromiseFuncCallback calls the given function with the value
// received by Call().
class InvokePromiseFuncCallback final : public PromiseCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(InvokePromiseFuncCallback,
PromiseCallback)
nsresult Call(JSContext* aCx,
JS::Handle<JS::Value> aValue) override;
Promise* GetDependentPromise() override;
InvokePromiseFuncCallback(JS::Handle<JSObject*> aGlobal,
JS::Handle<JSObject*> aNextPromiseObj,
AnyCallback* aPromiseFunc);
private:
~InvokePromiseFuncCallback();
JS::Heap<JSObject*> mGlobal;
JS::Heap<JSObject*> mNextPromiseObj;
RefPtr<AnyCallback> mPromiseFunc;
};
// NativePromiseCallback wraps a PromiseNativeHandler.
class NativePromiseCallback final : public PromiseCallback
{

View File

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

View File

@ -32,32 +32,22 @@ public:
static void Init();
static void Shutdown();
static void GetState(GlobalObject&, JS::Handle<JSObject*> aPromise,
PromiseDebuggingStateHolder& aState,
ErrorResult& aRv);
static void GetState(GlobalObject&, Promise& aPromise,
PromiseDebuggingStateHolder& aState);
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,
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,
ErrorResult& aRv);
static void GetPromiseID(GlobalObject&, JS::Handle<JSObject*>, nsString&,
ErrorResult&);
static void GetPromiseID(GlobalObject&, Promise&, nsString&);
// Mechanism for watching uncaught instances of Promise.
static void AddUncaughtRejectionObserver(GlobalObject&,

View File

@ -5,4 +5,3 @@ skip-if = buildapp == 'b2g'
[test_on_new_promise.html]
[test_on_promise_settled.html]
[test_on_promise_settled_duplicates.html]
[test_promise_xrays.html]

View File

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html>
<script>
function vendGetter(name) {
return function() { throw "Getting " + String(name) };
}
function vendSetter(name) {
return function() { throw "Setting " + String(name) };
}
var setupThrew = false;
try {
// Neuter everything we can think of on Promise.
for (var obj of [Promise, Promise.prototype]) {
propNames = Object.getOwnPropertyNames(obj);
propNames = propNames.concat(Object.getOwnPropertySymbols(obj));
for (var propName of propNames) {
if (propName == "prototype" && obj == Promise) {
// It's not configurable
continue;
}
Object.defineProperty(obj, propName,
{ get: vendGetter(propName), set: vendSetter(propName) });
}
}
} catch (e) {
// Something went wrong. Save that info so the test can check for it.
setupThrew = e;
}
</script>
</html>

View File

@ -1,7 +1,4 @@
[DEFAULT]
# Support files for chrome tests that we want to load over HTTP need
# to go in here, not chrome.ini, apparently.
support-files = file_promise_xrays.html
[test_abortable_promise.html]
[test_bug883683.html]
@ -14,4 +11,3 @@ support-files = file_promise_xrays.html
support-files = file_promise_and_timeout_ordering.js
[test_promise_and_timeout_ordering_workers.html]
support-files = file_promise_and_timeout_ordering.js
[test_species_getter.html]

View File

@ -17,10 +17,10 @@
<script type="application/javascript"><!--
function runTest() {
[{}, {}, {}, {}, {}].reduce(Promise.reject.bind(Promise));
[{}, {}, {}, {}, {}].reduce(Promise.reject);
ok(true, "No leaks with reject?");
[{}, {}, {}, {}, {}].reduce(Promise.resolve.bind(Promise));
[{}, {}, {}, {}, {}].reduce(Promise.resolve);
ok(true, "No leaks with resolve?");
[{}, {}, {}, {}, {}].reduce(function(a, b, c, d) { return new Promise(function(r1, r2) { throw a; }); });

View File

@ -1,301 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1170760
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1170760</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1170760">Mozilla Bug 1170760</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe id="t" src="http://example.org/tests/dom/promise/tests/file_promise_xrays.html"></iframe>
</div>
<pre id="test">
<script type="application/javascript">
var win = $("t").contentWindow;
/** Test for Bug 1170760 **/
SimpleTest.waitForExplicitFinish();
function testLoadComplete() {
is(win.location.href, $("t").src, "Should have loaded the right thing");
nextTest();
}
function testHaveXray() {
is(typeof win.Promise.race, "function", "Should see a race() function");
var exception;
try {
win.Promise.wrappedJSObject.race;
} catch (e) {
exception = e;
}
is(exception, "Getting race", "Should have thrown the right exception");
is(win.wrappedJSObject.setupThrew, false, "Setup should not have thrown");
nextTest();
}
function testRace1() {
var p = win.Promise.race(new win.Array(1, 2));
p.then(
function(arg) {
ok(arg == 1 || arg == 2,
"Should get the right value when racing content-side array");
},
function(e) {
ok(false, "testRace1 threw exception: " + e);
}
).then(nextTest);
}
function testRace2() {
var p = win.Promise.race(
new Array(win.Promise.resolve(1), win.Promise.resolve(2)));
p.then(
function(arg) {
ok(arg == 1 || arg == 2,
"Should get the right value when racing content-side array of explicit Promises");
},
function(e) {
ok(false, "testRace2 threw exception: " + e);
}
).then(nextTest);
}
function testRace3() {
// This works with a chrome-side array because we do the iteration
// while still in the Xray compartment.
var p = win.Promise.race([1, 2]);
p.then(
function(arg) {
ok(arg == 1 || arg == 2,
"Should get the right value when racing chrome-side array");
},
function(e) {
ok(false, "testRace3 threw exception: " + e);
}
).then(nextTest);
}
function testRace4() {
// This works with both content-side and chrome-side Promises because we want
// it to and go to some lengths to make it work.
var p = win.Promise.race([Promise.resolve(1), win.Promise.resolve(2)]);
p.then(
function(arg) {
ok(arg == 1 || arg == 2,
"Should get the right value when racing chrome-side promises");
},
function(e) {
ok(false, "testRace4 threw exception: " + e);
}
).then(nextTest);
}
function testAll1() {
var p = win.Promise.all(new win.Array(1, 2));
p.then(
function(arg) {
ok(arg instanceof win.Array, "Should get an Array from Promise.all (1)");
is(arg[0], 1, "First entry of Promise.all return value should be correct (1)");
is(arg[1], 2, "Second entry of Promise.all return value should be correct (1)");
},
function(e) {
ok(false, "testAll1 threw exception: " + e);
}
).then(nextTest);
}
function testAll2() {
var p = win.Promise.all(
new Array(win.Promise.resolve(1), win.Promise.resolve(2)));
p.then(
function(arg) {
ok(arg instanceof win.Array, "Should get an Array from Promise.all (2)");
is(arg[0], 1, "First entry of Promise.all return value should be correct (2)");
is(arg[1], 2, "Second entry of Promise.all return value should be correct (2)");
},
function(e) {
ok(false, "testAll2 threw exception: " + e);
}
).then(nextTest);
}
function testAll3() {
// This works with a chrome-side array because we do the iteration
// while still in the Xray compartment.
var p = win.Promise.all([1, 2]);
p.then(
function(arg) {
ok(arg instanceof win.Array, "Should get an Array from Promise.all (3)");
is(arg[0], 1, "First entry of Promise.all return value should be correct (3)");
is(arg[1], 2, "Second entry of Promise.all return value should be correct (3)");
},
function(e) {
ok(false, "testAll3 threw exception: " + e);
}
).then(nextTest);
}
function testAll4() {
// This works with both content-side and chrome-side Promises because we want
// it to and go to some lengths to make it work.
var p = win.Promise.all([Promise.resolve(1), win.Promise.resolve(2)]);
p.then(
function(arg) {
ok(arg instanceof win.Array, "Should get an Array from Promise.all (4)");
is(arg[0], 1, "First entry of Promise.all return value should be correct (4)");
is(arg[1], 2, "Second entry of Promise.all return value should be correct (4)");
},
function(e) {
ok(false, "testAll4 threw exception: " + e);
}
).then(nextTest);
}
function testAll5() {
var p = win.Promise.all(new win.Array());
p.then(
function(arg) {
ok(arg instanceof win.Array, "Should get an Array from Promise.all (5)");
},
function(e) {
ok(false, "testAll5 threw exception: " + e);
}
).then(nextTest);
}
function testResolve1() {
var p = win.Promise.resolve(5);
ok(p instanceof win.Promise, "Promise.resolve should return a promise");
p.then(
function(arg) {
is(arg, 5, "Should get correct Promise.resolve value");
},
function(e) {
ok(false, "testAll5 threw exception: " + e);
}
).then(nextTest);
}
function testResolve2() {
var p = win.Promise.resolve(5);
var q = win.Promise.resolve(p);
is(q, p, "Promise.resolve should just pass through Promise values");
nextTest();
}
function testResolve3() {
var p = win.Promise.resolve(Promise.resolve(5));
p.then(
function(arg) {
is(arg, 5, "Promise.resolve with chrome Promise should work");
},
function(e) {
ok(false, "Promise.resolve with chrome Promise should not fail");
}
).then(nextTest);
}
function testReject1() {
var p = win.Promise.reject(5);
ok(p instanceof win.Promise, "Promise.reject should return a promise");
p.then(
function(arg) {
ok(false, "Promise should be rejected");
},
function(e) {
is(e, 5, "Should get correct Promise.reject value");
}
).then(nextTest);
}
function testThen1() {
var p = win.Promise.resolve(5);
var q = p.then((x) => x*x);
ok(q instanceof win.Promise,
"Promise.then should return a promise from the right global");
q.then(
function(arg) {
is(arg, 25, "Promise.then should work");
},
function(e) {
ok(false, "Promise.then should not fail");
}
).then(nextTest);
}
function testThen2() {
var p = win.Promise.resolve(5);
var q = p.then((x) => Promise.resolve(x*x));
ok(q instanceof win.Promise,
"Promise.then should return a promise from the right global");
q.then(
function(arg) {
is(arg, 25, "Promise.then resolved with chrome promise should work");
},
function(e) {
ok(false, "Promise.then resolved with chrome promise should not fail");
}
).then(nextTest);
}
function testCatch1() {
var p = win.Promise.reject(5);
ok(p instanceof win.Promise, "Promise.resolve should return a promise");
var q = p.catch((x) => x*x);
ok(q instanceof win.Promise,
"Promise.catch should return a promise from the right global");
q.then(
function(arg) {
is(arg, 25, "Promise.catch should work");
},
function(e) {
ok(false, "Promise.catch should not fail");
}
).then(nextTest);
}
var tests = [
testLoadComplete,
testHaveXray,
testRace1,
testRace2,
testRace3,
testRace4,
testAll1,
testAll2,
testAll3,
testAll4,
testAll5,
testResolve1,
testResolve2,
testResolve3,
testReject1,
testThen1,
testThen2,
testCatch1,
];
function nextTest() {
if (tests.length == 0) {
SimpleTest.finish();
return;
}
tests.shift()();
}
addLoadEvent(nextTest);
</script>
</pre>
</body>
</html>

View File

@ -1,24 +0,0 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for ...</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
test(function() {
var desc = Object.getOwnPropertyDescriptor(Promise, Symbol.species);
assert_not_equals(desc, undefined, "Should have a property");
assert_equals(desc.configurable, true, "Property should be configurable");
assert_equals(desc.enumerable, false, "Property should not be enumerable");
assert_equals(desc.set, undefined, "Should not have a setter");
var getter = desc.get;
var things = [undefined, null, 5, "xyz", Promise, Object];
for (var thing of things) {
assert_equals(getter.call(thing), thing,
"Getter should return its this value");
}
}, "Promise should have an @@species getter that works per spec");
</script>

View File

@ -20,10 +20,9 @@ interface DOMRequestShared {
interface DOMRequest : EventTarget {
// The [TreatNonCallableAsNull] annotation is required since then() should do
// nothing instead of throwing errors when non-callable arguments are passed.
// See documentation for Promise.then to see why we return "any".
[NewObject, Throws]
any then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null,
[TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
[NewObject]
Promise<any> then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null,
[TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
};
DOMRequest implements DOMRequestShared;

View File

@ -20,39 +20,28 @@ callback AnyCallback = any (any value);
Exposed=(Window,Worker,System)]
// Need to escape "Promise" so it's treated as an identifier.
interface _Promise {
// Have to use "any" (or "object", but "any" is simpler) as the type to
// support the subclassing behavior, since nothing actually requires the
// return value of PromiseSubclass.resolve/reject to be a Promise object.
[NewObject, Throws]
static any resolve(optional any value);
[NewObject, Throws]
static any reject(optional any value);
// Disable the static methods when the interface object is supposed to be
// disabled, just in case some code decides to walk over to .constructor from
// the proto of a promise object or someone screws up and manages to create a
// Promise object in this scope without having resolved the interface object
// first.
[NewObject]
static Promise<any> resolve(optional any value);
[NewObject]
static Promise<void> reject(optional any value);
// The [TreatNonCallableAsNull] annotation is required since then() should do
// nothing instead of throwing errors when non-callable arguments are passed.
// Have to use "any" (or "object", but "any" is simpler) as the type to
// support the subclassing behavior, since nothing actually requires the
// return value of PromiseSubclass.then/catch to be a Promise object.
[NewObject, Throws]
any then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null,
[TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
[NewObject, MethodIdentityTestable]
Promise<any> then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null,
[TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
[NewObject, Throws]
any catch([TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
[NewObject]
Promise<any> catch([TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
// Have to use "any" (or "object", but "any" is simpler) as the type to
// support the subclassing behavior, since nothing actually requires the
// return value of PromiseSubclass.all to be a Promise object. As a result,
// we also have to do our argument conversion manually, because we want to
// convert its exceptions into rejections.
[NewObject, Throws]
static any all(optional any iterable);
[NewObject]
static Promise<any> all(sequence<any> iterable);
// Have to use "any" (or "object", but "any" is simpler) as the type to
// support the subclassing behavior, since nothing actually requires the
// return value of PromiseSubclass.race to be a Promise object. As a result,
// we also have to do our argument conversion manually, because we want to
// convert its exceptions into rejections.
[NewObject, Throws]
static any race(optional any iterable);
[NewObject]
static Promise<any> race(sequence<any> iterable);
};

View File

@ -52,50 +52,33 @@ callback interface UncaughtRejectionObserver {
[ChromeOnly, Exposed=(Window,System)]
interface PromiseDebugging {
/**
* 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);
static PromiseDebuggingStateHolder getState(Promise<any> p);
/**
* Return the stack to the promise's allocation point. This can
* return null if the promise was not created from script.
*/
[Throws]
static object? getAllocationStack(object p);
static object? getAllocationStack(Promise<any> 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.
*/
[Throws]
static object? getRejectionStack(object p);
static object? getRejectionStack(Promise<any> 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.
*/
[Throws]
static object? getFullfillmentStack(object p);
static object? getFullfillmentStack(Promise<any> p);
/**
* Return an identifier for a promise. This identifier is guaranteed
* to be unique to this instance of Firefox.
*/
[Throws]
static DOMString getPromiseID(object p);
static DOMString getPromiseID(Promise<any> p);
/**
* Get the promises directly depending on a given promise. These are:
@ -113,14 +96,12 @@ interface PromiseDebugging {
* p. It does not recursively return promises that depend on promises that
* depend on p.
*/
[Throws]
static sequence<Promise<any>> getDependentPromises(object p);
static sequence<Promise<any>> getDependentPromises(Promise<any> p);
/**
* Get the number of milliseconds elapsed since the given promise was created.
*/
[Throws]
static DOMHighResTimeStamp getPromiseLifetime(object p);
static DOMHighResTimeStamp getPromiseLifetime(Promise<any> p);
/*
* Get the number of milliseconds elapsed between the promise being created
@ -128,7 +109,7 @@ interface PromiseDebugging {
* settled.
*/
[Throws]
static DOMHighResTimeStamp getTimeToSettle(object p);
static DOMHighResTimeStamp getTimeToSettle(Promise<any> p);
/**
* Watching uncaught rejections on the current thread.

View File

@ -294,7 +294,7 @@ var RootFolder = function (rootId, rootName) {
result.parent = guidResult;
return Promise.resolve(result);
},
Promise.reject.bind(Promise)
Promise.reject
);
promises.push(promise);
});
@ -310,7 +310,7 @@ var RootFolder = function (rootId, rootName) {
result.annos = annos;
return Promise.resolve(result);
},
Promise.reject.bind(Promise)
Promise.reject
);
promises.push(promise);
});
@ -352,7 +352,7 @@ var RootFolder = function (rootId, rootName) {
result.parent = guidResult;
return Promise.resolve(result);
},
Promise.reject.bind(Promise)
Promise.reject
);
promises.push(promise);
});
@ -559,7 +559,7 @@ var RootFolder = function (rootId, rootName) {
continue;
}
let promise = exists(item).then(handleSortedItem, Promise.reject.bind(Promise));
let promise = exists(item).then(handleSortedItem, Promise.reject);
promises.push(promise);
}
@ -588,7 +588,7 @@ var RootFolder = function (rootId, rootName) {
function () {
return _createItem(root);
},
Promise.reject.bind(Promise)
Promise.reject
);
let items = [].concat(root._children);
@ -599,7 +599,7 @@ var RootFolder = function (rootId, rootName) {
function () {
return _createItem(item);
},
Promise.reject.bind(Promise)
Promise.reject
);
}
promises.push(promise);

View File

@ -29919,16 +29919,7 @@
},
"local_changes": {
"deleted": [],
"items": {
"testharness": {
"js/builtins/Promise-subclassing.html": [
{
"path": "js/builtins/Promise-subclassing.html",
"url": "/js/builtins/Promise-subclassing.html"
}
]
}
},
"items": {},
"reftest_nodes": {}
},
"reftest_nodes": {

View File

@ -1,265 +0,0 @@
<!doctype html>
<meta charset=utf-8>
<title></title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
var theLog = [];
var speciesGets = 0;
var speciesCalls = 0;
var constructorCalls = 0;
var constructorGets = 0;
var resolveCalls = 0;
var rejectCalls = 0;
var thenCalls = 0;
var catchCalls = 0;
var allCalls = 0;
var raceCalls = 0;
var nextCalls = 0;
function takeLog() {
var oldLog = theLog;
theLog = [];
speciesGets = speciesCalls = constructorCalls = resolveCalls =
rejectCalls = thenCalls = catchCalls = allCalls = raceCalls =
nextCalls = constructorGets = 0;
return oldLog;
}
function clearLog() {
takeLog();
}
function log(str) {
theLog.push(str);
}
class LoggingPromise extends Promise {
constructor(func) {
super(func);
Object.defineProperty(this, "constructor",
{
get: function() {
++constructorGets;
log(`Constructor get ${constructorGets}`);
return Object.getPrototypeOf(this).constructor;
}
});
++constructorCalls;
log(`Constructor ${constructorCalls}`);
}
static get [Symbol.species]() {
++speciesGets;
log(`Species get ${speciesGets}`);
return LoggingSpecies;
}
static resolve(val) {
++resolveCalls;
log(`Resolve ${resolveCalls}`);
return super.resolve(val);
}
static reject(val) {
++rejectCalls;
log(`Reject ${rejectCalls}`);
return super.reject(val);
}
then(resolve, reject) {
++thenCalls;
log(`Then ${thenCalls}`);
return super.then(resolve, reject);
}
catch(handler) {
++catchCalls;
log(`Catch ${catchCalls}`);
return super.catch(handler);
}
static all(val) {
++allCalls;
log(`All ${allCalls}`);
return super.all(val);
}
static race(val) {
++raceCalls;
log(`Race ${raceCalls}`);
return super.race(val);
}
}
class LoggingIterable {
constructor(array) {
this.iter = array[Symbol.iterator]();
}
get [Symbol.iterator]() { return () => this }
next() {
++nextCalls;
log(`Next ${nextCalls}`);
return this.iter.next();
}
}
class LoggingSpecies extends LoggingPromise {
constructor(func) {
++speciesCalls;
log(`Species call ${speciesCalls}`);
super(func)
}
}
class SpeciesLessPromise extends LoggingPromise {
static get [Symbol.species]() {
return undefined;
}
}
promise_test(function testBasicConstructor() {
var p = new LoggingPromise((resolve) => resolve(5));
var log = takeLog();
assert_array_equals(log, ["Constructor 1"]);
assert_true(p instanceof LoggingPromise);
return p.then(function(arg) {
assert_equals(arg, 5);
});
}, "Basic constructor behavior");
promise_test(function testPromiseRace() {
clearLog();
var p = LoggingPromise.race(new LoggingIterable([1, 2]));
var log = takeLog();
assert_array_equals(log, ["Race 1", "Constructor 1",
"Next 1", "Resolve 1", "Constructor 2",
"Then 1", "Constructor get 1", "Species get 1", "Species call 1", "Constructor 3",
"Next 2", "Resolve 2", "Constructor 4",
"Then 2", "Constructor get 2", "Species get 2", "Species call 2", "Constructor 5",
"Next 3"]);
assert_true(p instanceof LoggingPromise);
return p.then(function(arg) {
assert_true(arg == 1 || arg == 2);
});
}, "Promise.race behavior");
promise_test(function testPromiseRaceNoSpecies() {
clearLog();
var p = SpeciesLessPromise.race(new LoggingIterable([1, 2]));
var log = takeLog();
assert_array_equals(log, ["Race 1", "Constructor 1",
"Next 1", "Resolve 1", "Constructor 2",
"Then 1", "Constructor get 1",
"Next 2", "Resolve 2", "Constructor 3",
"Then 2", "Constructor get 2",
"Next 3"]);
assert_true(p instanceof SpeciesLessPromise);
return p.then(function(arg) {
assert_true(arg == 1 || arg == 2);
});
}, "Promise.race without species behavior");
promise_test(function testPromiseAll() {
clearLog();
var p = LoggingPromise.all(new LoggingIterable([1, 2]));
var log = takeLog();
assert_array_equals(log, ["All 1", "Constructor 1",
"Next 1", "Resolve 1", "Constructor 2",
"Then 1", "Constructor get 1", "Species get 1", "Species call 1", "Constructor 3",
"Next 2", "Resolve 2", "Constructor 4",
"Then 2", "Constructor get 2", "Species get 2", "Species call 2", "Constructor 5",
"Next 3"]);
assert_true(p instanceof LoggingPromise);
return p.then(function(arg) {
assert_array_equals(arg, [1, 2]);
});
}, "Promise.all behavior");
promise_test(function testPromiseResolve() {
clearLog();
var p = LoggingPromise.resolve(5);
var log = takeLog();
assert_array_equals(log, ["Resolve 1", "Constructor 1"]);
var q = LoggingPromise.resolve(p);
assert_equals(p, q,
"Promise.resolve with same constructor should preserve identity");
log = takeLog();
assert_array_equals(log, ["Resolve 1", "Constructor get 1"]);
var r = Promise.resolve(p);
log = takeLog();
assert_array_equals(log, ["Constructor get 1"]);
assert_not_equals(p, r,
"Promise.resolve with different constructor should " +
"create a new Promise instance (1)")
var s = Promise.resolve(6);
var u = LoggingPromise.resolve(s);
log = takeLog();
assert_array_equals(log, ["Resolve 1", "Constructor 1"]);
assert_not_equals(s, u,
"Promise.resolve with different constructor should " +
"create a new Promise instance (2)")
Object.defineProperty(s, "constructor", { value: LoggingPromise });
var v = LoggingPromise.resolve(s);
log = takeLog();
assert_array_equals(log, ["Resolve 1"]);
assert_equals(v, s, "Faking the .constructor should work");
assert_false(v instanceof LoggingPromise);
var results = Promise.all([p, q, r, s, u, v]);
return results.then(function(arg) {
assert_array_equals(arg, [5, 5, 5, 6, 6, 6]);
});
}, "Promise.resolve behavior");
promise_test(function testPromiseReject() {
clearLog();
var p = LoggingPromise.reject(5);
var log = takeLog();
assert_array_equals(log, ["Reject 1", "Constructor 1"]);
return p.catch(function(arg) {
assert_equals(arg, 5);
});
}, "Promise.reject behavior");
promise_test(function testPromiseThen() {
clearLog();
var p = LoggingPromise.resolve(5);
var log = takeLog();
assert_array_equals(log, ["Resolve 1", "Constructor 1"]);
var q = p.then((x) => x*x);
log = takeLog();
assert_array_equals(log, ["Then 1", "Constructor get 1", "Species get 1",
"Species call 1", "Constructor 1"]);
assert_true(q instanceof LoggingPromise);
return q.then(function(arg) {
assert_equals(arg, 25);
});
}, "Promise.then behavior");
promise_test(function testPromiseCatch() {
clearLog();
var p = LoggingPromise.reject(5);
var log = takeLog();
assert_array_equals(log, ["Reject 1", "Constructor 1"]);
var q = p.catch((x) => x*x);
log = takeLog();
assert_array_equals(log, ["Catch 1", "Then 1", "Constructor get 1",
"Species get 1", "Species call 1", "Constructor 1"]);
assert_true(q instanceof LoggingPromise);
return q.then(function(arg) {
assert_equals(arg, 25);
});
}, "Promise.catch behavior");
</script>

View File

@ -148,7 +148,7 @@ add_task(function* test_phase_removeBlocker() {
do_print("Attempt to remove a blocker after wait");
lock = makeLock(kind);
blocker = Promise.resolve.bind(Promise);
blocker = Promise.resolve;
yield lock.wait();
do_remove_blocker(lock, blocker, false);