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

master
Fedor 2019-09-05 20:05:31 +03:00
parent 9e9223be14
commit a75c03ed8a
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.
static MOZ_MUST_USE bool
CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, ResolutionMode mode)
static MOZ_MUST_USE JSObject*
CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue argVal,
ResolutionMode mode)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue x(cx, args.get(0));
// Steps 1-2.
if (!args.thisv().isObject()) {
if (!thisVal.isObject()) {
const char* msg = mode == ResolveMode
? "Receiver of Promise.resolve call"
: "Receiver of Promise.reject call";
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, msg);
return false;
return nullptr;
}
RootedValue cVal(cx, args.thisv());
RootedObject C(cx, &cVal.toObject());
RootedObject C(cx, &thisVal.toObject());
// Step 3 of Resolve.
if (mode == ResolveMode && x.isObject()) {
RootedObject xObj(cx, &x.toObject());
if (mode == ResolveMode && argVal.isObject()) {
RootedObject xObj(cx, &argVal.toObject());
bool isPromise = false;
if (xObj->is<PromiseObject>()) {
isPromise = true;
@ -1985,11 +1982,9 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio
if (isPromise) {
RootedValue ctorVal(cx);
if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal))
return false;
if (ctorVal == cVal) {
args.rval().set(x);
return true;
}
return nullptr;
if (ctorVal == thisVal)
return xObj;
}
}
@ -1998,15 +1993,17 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio
RootedObject resolveFun(cx);
RootedObject rejectFun(cx);
if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true))
return false;
return nullptr;
// Step 5 of Resolve, 4 of Reject.
if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, x, mode, promise))
return false;
if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, argVal, mode,
promise))
{
return nullptr;
}
// Step 6 of Resolve, 4 of Reject.
args.rval().setObject(*promise);
return true;
return promise;
}
/**
@ -2015,7 +2012,14 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio
bool
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*
PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
{
// Steps 1-2 (omitted).
// Roughly step 3.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
if (!promise)
RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
if (!promiseCtor)
return nullptr;
// Roughly step 4.
if (!ResolvePromise(cx, promise, value, JS::PromiseState::Rejected))
return nullptr;
// Step 5.
return promise;
RootedValue cVal(cx, ObjectValue(*promiseCtor));
return CommonStaticResolveRejectImpl(cx, cVal, value, RejectMode);
}
/**
@ -2045,7 +2041,14 @@ PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
bool
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*
PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value)
{
// Steps 1-2 (omitted).
// 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)
RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
if (!promiseCtor)
return nullptr;
// Steps 5.
if (!ResolvePromiseInternal(cx, promise, value))
return nullptr;
// Step 6.
return promise;
RootedValue cVal(cx, ObjectValue(*promiseCtor));
return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode);
}
// 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);
RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, resolutionValue));
MOZ_ASSERT_IF(promise, promise->is<PromiseObject>());
MOZ_ASSERT_IF(promise, CheckedUnwrap(promise)->is<PromiseObject>());
return promise;
}
@ -4896,7 +4896,7 @@ JS::CallOriginalPromiseReject(JSContext* cx, JS::HandleValue rejectionValue)
assertSameCompartment(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;
}