From 52e22e231b065cc7d5975d5f6f8a9231c4f18f6e Mon Sep 17 00:00:00 2001
From: Gaming4JC <g4jc@hyperbola.info>
Date: Sat, 29 Jun 2019 22:19:56 -0400
Subject: 1323324 - Part 1: Make Promise::unforgeable{Resolve,Reject}
 spec-compliant.

---
 js/src/builtin/Promise.cpp | 100 +++++++++++++++++++--------------------------
 js/src/jsapi.cpp           |   4 +-
 2 files changed, 44 insertions(+), 60 deletions(-)

(limited to 'js')

diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp
index c781a336d..9941c6f57 100644
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -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)
-        return nullptr;
-
-    // Roughly step 4.
-    if (!ResolvePromise(cx, promise, value, JS::PromiseState::Rejected))
+    RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
+    if (!promiseCtor)
         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.
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index 9ee29ffe4..ac7b78581 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -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;
 }
 
-- 
cgit v1.2.3