1323324 - Part 1: Make Promise::unforgeable{Resolve,Reject} spec-compliant.

This commit is contained in:
Gaming4JC 2019-06-29 22:19:56 -04:00 • committed by Roy Tam
commit 146dbe7bee
2 changed files with 44 additions and 60 deletions

View file

@ -1947,26 +1947,23 @@ PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
} }
// ES2016, Sub-steps of 25.4.4.4 and 25.4.4.5. // ES2016, Sub-steps of 25.4.4.4 and 25.4.4.5.
static MOZ_MUST_USE bool static MOZ_MUST_USE JSObject*
CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, ResolutionMode mode) CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue argVal,
ResolutionMode mode)
{ {
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue x(cx, args.get(0));
// Steps 1-2. // Steps 1-2.
if (!args.thisv().isObject()) { if (!thisVal.isObject()) {
const char* msg = mode == ResolveMode const char* msg = mode == ResolveMode
? "Receiver of Promise.resolve call" ? "Receiver of Promise.resolve call"
: "Receiver of Promise.reject call"; : "Receiver of Promise.reject call";
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, msg); JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, msg);
return false; return nullptr;
} }
RootedValue cVal(cx, args.thisv()); RootedObject C(cx, &thisVal.toObject());
RootedObject C(cx, &cVal.toObject());
// Step 3 of Resolve. // Step 3 of Resolve.
if (mode == ResolveMode && x.isObject()) { if (mode == ResolveMode && argVal.isObject()) {
RootedObject xObj(cx, &x.toObject()); RootedObject xObj(cx, &argVal.toObject());
bool isPromise = false; bool isPromise = false;
if (xObj->is<PromiseObject>()) { if (xObj->is<PromiseObject>()) {
isPromise = true; isPromise = true;
@ -1985,11 +1982,9 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio
if (isPromise) { if (isPromise) {
RootedValue ctorVal(cx); RootedValue ctorVal(cx);
if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal)) if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal))
return false; return nullptr;
if (ctorVal == cVal) { if (ctorVal == thisVal)
args.rval().set(x); return xObj;
return true;
}
} }
} }
@ -1998,15 +1993,17 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio
RootedObject resolveFun(cx); RootedObject resolveFun(cx);
RootedObject rejectFun(cx); RootedObject rejectFun(cx);
if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true)) if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true))
return false; return nullptr;
// Step 5 of Resolve, 4 of Reject. // Step 5 of Resolve, 4 of Reject.
if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, x, mode, promise)) if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, argVal, mode,
return false; promise))
{
return nullptr;
}
// Step 6 of Resolve, 4 of Reject. // Step 6 of Resolve, 4 of Reject.
args.rval().setObject(*promise); return promise;
return true;
} }
/** /**
@ -2015,7 +2012,14 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio
bool bool
js::Promise_reject(JSContext* cx, unsigned argc, Value* vp) js::Promise_reject(JSContext* cx, unsigned argc, Value* vp)
{ {
return CommonStaticResolveRejectImpl(cx, argc, vp, RejectMode); CallArgs args = CallArgsFromVp(argc, vp);
RootedValue thisVal(cx, args.thisv());
RootedValue argVal(cx, args.get(0));
JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, RejectMode);
if (!result)
return false;
args.rval().setObject(*result);
return true;
} }
/** /**
@ -2024,19 +2028,11 @@ js::Promise_reject(JSContext* cx, unsigned argc, Value* vp)
/* static */ JSObject* /* static */ JSObject*
PromiseObject::unforgeableReject(JSContext* cx, HandleValue value) PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
{ {
// Steps 1-2 (omitted). RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
if (!promiseCtor)
// Roughly step 3.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
if (!promise)
return nullptr; return nullptr;
RootedValue cVal(cx, ObjectValue(*promiseCtor));
// Roughly step 4. return CommonStaticResolveRejectImpl(cx, cVal, value, RejectMode);
if (!ResolvePromise(cx, promise, value, JS::PromiseState::Rejected))
return nullptr;
// Step 5.
return promise;
} }
/** /**
@ -2045,7 +2041,14 @@ PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
bool bool
js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp) js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
{ {
return CommonStaticResolveRejectImpl(cx, argc, vp, ResolveMode); CallArgs args = CallArgsFromVp(argc, vp);
RootedValue thisVal(cx, args.thisv());
RootedValue argVal(cx, args.get(0));
JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, ResolveMode);
if (!result)
return false;
args.rval().setObject(*result);
return true;
} }
/** /**
@ -2054,30 +2057,11 @@ js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
/* static */ JSObject* /* static */ JSObject*
PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value) PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value)
{ {
// Steps 1-2 (omitted). RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
if (!promiseCtor)
// Step 3.
if (value.isObject()) {
JSObject* obj = &value.toObject();
if (IsWrapper(obj))
obj = CheckedUnwrap(obj);
// Instead of getting the `constructor` property, do an unforgeable
// check.
if (obj && obj->is<PromiseObject>())
return obj;
}
// Step 4.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
if (!promise)
return nullptr; return nullptr;
RootedValue cVal(cx, ObjectValue(*promiseCtor));
// Steps 5. return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode);
if (!ResolvePromiseInternal(cx, promise, value))
return nullptr;
// Step 6.
return promise;
} }
// ES2016, 25.4.4.6, implemented in Promise.js. // ES2016, 25.4.4.6, implemented in Promise.js.

View file

@ -4884,7 +4884,7 @@ JS::CallOriginalPromiseResolve(JSContext* cx, JS::HandleValue resolutionValue)
assertSameCompartment(cx, resolutionValue); assertSameCompartment(cx, resolutionValue);
RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, resolutionValue)); RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, resolutionValue));
MOZ_ASSERT_IF(promise, promise->is<PromiseObject>()); MOZ_ASSERT_IF(promise, CheckedUnwrap(promise)->is<PromiseObject>());
return promise; return promise;
} }
@ -4896,7 +4896,7 @@ JS::CallOriginalPromiseReject(JSContext* cx, JS::HandleValue rejectionValue)
assertSameCompartment(cx, rejectionValue); assertSameCompartment(cx, rejectionValue);
RootedObject promise(cx, PromiseObject::unforgeableReject(cx, rejectionValue)); RootedObject promise(cx, PromiseObject::unforgeableReject(cx, rejectionValue));
MOZ_ASSERT_IF(promise, promise->is<PromiseObject>()); MOZ_ASSERT_IF(promise, CheckedUnwrap(promise)->is<PromiseObject>());
return promise; return promise;
} }