Bug 1315756 - Do not allocate throwawayCapability in AsyncFunctionAwait. r=till
authorTooru Fujisawa <arai_a@mac.com>
Wed, 09 Nov 2016 03:27:51 +0900
changeset 351760 38f5ec02b1d669c4e2894075da59d3e0d354aeb3
parent 351759 1f38bd73f5bd95cfd150e9552bd499c220f07816
child 351761 5189ddac9614b043e29eee5e60981ac07ce2303c
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1315756
milestone52.0a1
Bug 1315756 - Do not allocate throwawayCapability in AsyncFunctionAwait. r=till
js/src/builtin/Promise.cpp
js/src/builtin/Promise.h
js/src/vm/AsyncFunction.cpp
js/src/vm/AsyncFunction.h
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -168,16 +168,17 @@ enum ReactionRecordSlots {
     ReactionRecordSlot_Flags,
     ReactionRecordSlot_HandlerArg,
     ReactionRecordSlots,
 };
 
 #define REACTION_FLAG_RESOLVED                  0x1
 #define REACTION_FLAG_FULFILLED                 0x2
 #define REACTION_FLAG_IGNORE_DEFAULT_RESOLUTION 0x4
+#define REACTION_FLAG_AWAIT                     0x8
 
 // ES2016, 25.4.1.2.
 class PromiseReactionRecord : public NativeObject
 {
   public:
     static const Class class_;
 
     JSObject* promise() { return getFixedSlot(ReactionRecordSlot_Promise).toObjectOrNull(); }
@@ -194,16 +195,25 @@ class PromiseReactionRecord : public Nat
         int32_t flags = this->flags();
         MOZ_ASSERT(!(flags & REACTION_FLAG_RESOLVED));
         MOZ_ASSERT(state != JS::PromiseState::Pending, "Can't revert a reaction to pending.");
         flags |= REACTION_FLAG_RESOLVED;
         if (state == JS::PromiseState::Fulfilled)
             flags |= REACTION_FLAG_FULFILLED;
         setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
     }
+    void setIsAwait() {
+        int32_t flags = this->flags();
+        flags |= REACTION_FLAG_AWAIT;
+        setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
+    }
+    bool isAwait() {
+        int32_t flags = this->flags();
+        return flags & REACTION_FLAG_AWAIT;
+    }
     Value handler() {
         MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
         uint32_t slot = targetState() == JS::PromiseState::Fulfilled
                         ? ReactionRecordSlot_OnFulfilled
                         : ReactionRecordSlot_OnRejected;
         return getFixedSlot(slot);
     }
     Value handlerArg() {
@@ -803,16 +813,45 @@ TriggerPromiseReactions(JSContext* cx, H
         reaction = &reactionsList->getDenseElement(i).toObject();
         if (!EnqueuePromiseReactionJob(cx, reaction, valueOrReason, state))
             return false;
     }
 
     return true;
 }
 
+static MOZ_MUST_USE bool
+AwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
+                        MutableHandleValue rval)
+{
+    MOZ_ASSERT(reaction->isAwait());
+
+    RootedValue handlerVal(cx, reaction->handler());
+    RootedValue argument(cx, reaction->handlerArg());
+    Rooted<PromiseObject*> resultPromise(cx, &reaction->promise()->as<PromiseObject>());
+    RootedValue generatorVal(cx, resultPromise->getFixedSlot(PromiseSlot_AwaitGenerator));
+
+    int32_t handlerNum = int32_t(handlerVal.toNumber());
+    MOZ_ASSERT(handlerNum == PROMISE_HANDLER_AWAIT_FULFILLED
+               || handlerNum == PROMISE_HANDLER_AWAIT_REJECTED);
+
+    // Await's handlers don't return a value, nor throw exception.
+    // They fail only on OOM.
+    if (handlerNum == PROMISE_HANDLER_AWAIT_FULFILLED) {
+        if (!AsyncFunctionAwaitedFulfilled(cx, resultPromise, generatorVal, argument))
+            return false;
+    } else {
+        if (!AsyncFunctionAwaitedRejected(cx, resultPromise, generatorVal, argument))
+            return false;
+    }
+
+    rval.setUndefined();
+    return true;
+}
+
 // ES2016, 25.4.2.1.
 /**
  * Callback triggering the fulfill/reject reaction for a resolved Promise,
  * to be invoked by the embedding during its processing of the Promise job
  * queue.
  *
  * See http://www.ecma-international.org/ecma-262/7.0/index.html#sec-jobs-and-job-queues
  *
@@ -839,58 +878,39 @@ PromiseReactionJob(JSContext* cx, unsign
     mozilla::Maybe<AutoCompartment> ac;
     if (IsWrapper(reactionObj)) {
         reactionObj = UncheckedUnwrap(reactionObj);
         ac.emplace(cx, reactionObj);
     }
 
     // Steps 1-2.
     Rooted<PromiseReactionRecord*> reaction(cx, &reactionObj->as<PromiseReactionRecord>());
+    if (reaction->isAwait())
+        return AwaitPromiseReactionJob(cx, reaction, args.rval());
 
     // Step 3.
     RootedValue handlerVal(cx, reaction->handler());
 
     RootedValue argument(cx, reaction->handlerArg());
 
     RootedValue handlerResult(cx);
     ResolutionMode resolutionMode = ResolveMode;
 
     // Steps 4-6.
     if (handlerVal.isNumber()) {
         int32_t handlerNum = int32_t(handlerVal.toNumber());
 
         // Step 4.
         if (handlerNum == PROMISE_HANDLER_IDENTITY) {
             handlerResult = argument;
-        } else if (handlerNum == PROMISE_HANDLER_THROWER) {
+        } else {
             // Step 5.
+            MOZ_ASSERT(handlerNum == PROMISE_HANDLER_THROWER);
             resolutionMode = RejectMode;
             handlerResult = argument;
-        } else {
-            MOZ_ASSERT(handlerNum == PROMISE_HANDLER_AWAIT_FULFILLED
-                       || handlerNum == PROMISE_HANDLER_AWAIT_REJECTED);
-
-            Rooted<PromiseObject*> promiseObj(cx, &reaction->promise()->as<PromiseObject>());
-            MOZ_ASSERT(PromiseHasAnyFlag(*promiseObj, PROMISE_FLAG_AWAIT));
-
-            RootedValue generatorVal(cx, promiseObj->getFixedSlot(PromiseSlot_AwaitGenerator));
-
-            // Step 6.
-            // Optimized for await.
-            bool result;
-            if (handlerNum == PROMISE_HANDLER_AWAIT_FULFILLED)
-                result = AsyncFunctionAwaitedFulfilled(cx, argument, generatorVal, &handlerResult);
-            else
-                result = AsyncFunctionAwaitedRejected(cx, argument, generatorVal, &handlerResult);
-
-            if (!result) {
-                resolutionMode = RejectMode;
-                if (!cx->isExceptionPending() || !GetAndClearException(cx, &handlerResult))
-                    return false;
-            }
         }
     } else {
         // Step 6.
         FixedInvokeArgs<1> args2(cx);
         args2[0].set(argument);
         if (!Call(cx, handlerVal, UndefinedHandleValue, args2, &handlerResult)) {
             resolutionMode = RejectMode;
             // Not much we can do about uncatchable exceptions, so just bail
@@ -2083,61 +2103,98 @@ js::OriginalPromiseThen(JSContext* cx, H
 
     // Step 5.
     if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultPromise, resolve, reject))
         return nullptr;
 
     return resultPromise;
 }
 
-static MOZ_MUST_USE bool PerformPromiseThenImpl(JSContext* cx, Handle<PromiseObject*> promise,
-                                                HandleValue onFulfilled,
-                                                HandleValue onRejected,
-                                                HandleObject resultPromise,
-                                                HandleObject resolve,
-                                                HandleObject reject);
+static MOZ_MUST_USE bool PerformPromiseThenWithReaction(JSContext* cx,
+                                                        Handle<PromiseObject*> promise,
+                                                        Handle<PromiseReactionRecord*> reaction);
+
+// Some async/await functions are implemented here instead of
+// js/src/builtin/AsyncFunction.cpp, to call Promise internal functions.
+
+// Async Functions proposal 1.1.8 and 1.2.14 step 1.
+MOZ_MUST_USE PromiseObject*
+js::CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal)
+{
+    // Step 1.
+    Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithDefaultResolution(cx));
+    if (!promise)
+        return nullptr;
+
+    AddPromiseFlags(*promise, PROMISE_FLAG_ASYNC);
+    promise->setFixedSlot(PromiseSlot_AwaitGenerator, generatorVal);
+    return promise;
+}
+
+// Async Functions proposal 2.2 steps 3.f, 3.g.
+MOZ_MUST_USE bool
+js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise)
+{
+    // Step 3.f.
+    RootedValue exc(cx);
+    if (!GetAndClearException(cx, &exc))
+        return false;
+
+    if (!RejectMaybeWrappedPromise(cx, resultPromise, exc))
+        return false;
+
+    // Step 3.g.
+    return true;
+}
+
+// Async Functions proposal 2.2 steps 3.d-e, 3.g.
+MOZ_MUST_USE bool
+js::AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
+{
+    // Steps 3.d-e.
+    if (!ResolvePromiseInternal(cx, resultPromise, value))
+        return false;
+
+    // Step 3.g.
+    return true;
+}
 
 // Async Functions proposal 2.3 steps 2-8.
-// Implemented here instead of js/src/builtin/AsyncFunction.cpp
-// to call Promise internal functions
-bool
-js::AsyncFunctionAwait(JSContext* cx, HandleValue generatorVal, HandleValue value,
-                       MutableHandleValue rval)
+MOZ_MUST_USE bool
+js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
 {
     // Step 2.
     Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithDefaultResolution(cx));
     if (!promise)
         return false;
 
     // Steps 3.
     if (!ResolvePromiseInternal(cx, promise, value))
         return false;
 
     // Steps 4-5.
     RootedValue onFulfilled(cx, Int32Value(PROMISE_HANDLER_AWAIT_FULFILLED));
     RootedValue onRejected(cx, Int32Value(PROMISE_HANDLER_AWAIT_REJECTED));
 
-    // Step 7.
-    Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectWithDefaultResolution(cx));
-    if (!resultPromise)
+    RootedObject incumbentGlobal(cx);
+    if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
         return false;
 
-    // Step 6 (reordered).
-    AddPromiseFlags(*resultPromise, PROMISE_FLAG_AWAIT);
-    resultPromise->setFixedSlot(PromiseSlot_AwaitGenerator, generatorVal);
+    // Steps 6-7.
+    Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
+                                                                  onFulfilled, onRejected,
+                                                                  nullptr, nullptr,
+                                                                  incumbentGlobal));
+    if (!reaction)
+        return false;
+
+    reaction->setIsAwait();
 
     // Step 8.
-    if (!PerformPromiseThenImpl(cx, promise, onFulfilled, onRejected, resultPromise,
-                                nullptr, nullptr))
-    {
-        return false;
-    }
-
-    rval.setObject(*resultPromise);
-    return true;
+    return PerformPromiseThenWithReaction(cx, promise, reaction);
 }
 
 // ES2016, 25.4.5.3.
 bool
 js::Promise_then(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -2196,37 +2253,35 @@ PerformPromiseThen(JSContext* cx, Handle
     if (!IsCallable(onFulfilled))
         onFulfilled = Int32Value(PROMISE_HANDLER_IDENTITY);
 
     // Step 4.
     RootedValue onRejected(cx, onRejected_);
     if (!IsCallable(onRejected))
         onRejected = Int32Value(PROMISE_HANDLER_THROWER);
 
-    return PerformPromiseThenImpl(cx, promise, onFulfilled, onRejected, resultPromise,
-                                  resolve, reject);
-}
-
-static MOZ_MUST_USE bool
-PerformPromiseThenImpl(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled,
-                       HandleValue onRejected, HandleObject resultPromise,
-                       HandleObject resolve, HandleObject reject)
-{
     RootedObject incumbentGlobal(cx);
     if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
         return false;
 
     // Step 7.
     Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
                                                                   onFulfilled, onRejected,
                                                                   resolve, reject,
                                                                   incumbentGlobal));
     if (!reaction)
         return false;
 
+    return PerformPromiseThenWithReaction(cx, promise, reaction);
+}
+
+static MOZ_MUST_USE bool
+PerformPromiseThenWithReaction(JSContext* cx, Handle<PromiseObject*> promise,
+                               Handle<PromiseReactionRecord*> reaction)
+{
     JS::PromiseState state = promise->state();
     int32_t flags = promise->getFixedSlot(PromiseSlot_Flags).toInt32();
     if (state == JS::PromiseState::Pending) {
         // Steps 5,6 (reordered).
         // Instead of creating separate reaction records for fulfillment and
         // rejection, we create a combined record. All places we use the record
         // can handle that.
         if (!AddPromiseReaction(cx, promise, reaction))
@@ -2529,17 +2584,17 @@ PromiseObject::dependentPromises(JSConte
     }
 
     return true;
 }
 
 bool
 PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue)
 {
-    MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_AWAIT));
+    MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_ASYNC));
     if (state() != JS::PromiseState::Pending)
         return true;
 
     RootedObject resolveFun(cx, GetResolveFunctionFromPromise(this));
     RootedValue funVal(cx, ObjectValue(*resolveFun));
 
     // For xray'd Promises, the resolve fun may have been created in another
     // compartment. For the call below to work in that case, wrap the
@@ -2552,17 +2607,17 @@ PromiseObject::resolve(JSContext* cx, Ha
 
     RootedValue dummy(cx);
     return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
 }
 
 bool
 PromiseObject::reject(JSContext* cx, HandleValue rejectionValue)
 {
-    MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_AWAIT));
+    MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_ASYNC));
     if (state() != JS::PromiseState::Pending)
         return true;
 
     RootedValue funVal(cx, this->getFixedSlot(PromiseSlot_RejectFunction));
     MOZ_ASSERT(IsCallable(funVal));
 
     FixedInvokeArgs<1> args(cx);
     args[0].set(rejectionValue);
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -26,17 +26,17 @@ enum PromiseSlots {
 };
 
 #define PROMISE_FLAG_RESOLVED  0x1
 #define PROMISE_FLAG_FULFILLED 0x2
 #define PROMISE_FLAG_HANDLED   0x4
 #define PROMISE_FLAG_REPORTED  0x8
 #define PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION 0x10
 #define PROMISE_FLAG_DEFAULT_REJECT_FUNCTION  0x20
-#define PROMISE_FLAG_AWAIT     0x40
+#define PROMISE_FLAG_ASYNC    0x40
 
 class AutoSetNewObjectMetadata;
 
 class PromiseObject : public NativeObject
 {
   public:
     static const unsigned RESERVED_SLOTS = PromiseSlots;
     static const Class class_;
@@ -114,19 +114,27 @@ EnqueuePromiseReactions(JSContext* cx, H
 
 MOZ_MUST_USE JSObject*
 GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises);
 
 MOZ_MUST_USE JSObject*
 OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled,
                     HandleValue onRejected);
 
-bool
-AsyncFunctionAwait(JSContext* cx, HandleValue generatorVal, HandleValue value,
-                   MutableHandleValue rval);
+MOZ_MUST_USE PromiseObject*
+CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal);
+
+MOZ_MUST_USE bool
+AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value);
+
+MOZ_MUST_USE bool
+AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise);
+
+MOZ_MUST_USE bool
+AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value);
 
 /**
  * A PromiseTask represents a task that can be dispatched to a helper thread
  * (via StartPromiseTask), executed (by implementing PromiseTask::execute()),
  * and then resolved back on the original JSContext owner thread.
  * Because it contains a PersistentRooted, a PromiseTask will only be destroyed
  * on the JSContext's owner thread.
  */
--- a/js/src/vm/AsyncFunction.cpp
+++ b/js/src/vm/AsyncFunction.cpp
@@ -42,17 +42,18 @@ GlobalObject::initAsyncFunction(JSContex
     if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto))
         return false;
 
     global->setReservedSlot(ASYNC_FUNCTION, ObjectValue(*asyncFunction));
     global->setReservedSlot(ASYNC_FUNCTION_PROTO, ObjectValue(*asyncFunctionProto));
     return true;
 }
 
-static bool AsyncFunctionStart(JSContext* cx, HandleValue generatorVal, MutableHandleValue rval);
+static MOZ_MUST_USE bool AsyncFunctionStart(JSContext* cx, Handle<PromiseObject*> resultPromise,
+                                            HandleValue generatorVal);
 
 #define UNWRAPPED_ASYNC_WRAPPED_SLOT 1
 #define WRAPPED_ASYNC_UNWRAPPED_SLOT 0
 
 // Async Functions proposal 1.1.8 and 1.2.14.
 static bool
 WrappedAsyncFunction(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -67,21 +68,31 @@ WrappedAsyncFunction(JSContext* cx, unsi
     // Also does a part of 2.2 steps 1-2.
     RootedValue generatorVal(cx);
     InvokeArgs args2(cx);
     if (!args2.init(cx, argc))
         return false;
     for (size_t i = 0, len = argc; i < len; i++)
         args2[i].set(args[i]);
     if (Call(cx, unwrappedVal, thisValue, args2, &generatorVal)) {
-        // Steps 3, 5.
-        return AsyncFunctionStart(cx, generatorVal, args.rval());
+        // Step 1.
+        Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectForAsync(cx, generatorVal));
+        if (!resultPromise)
+            return false;
+
+        // Step 3.
+        if (!AsyncFunctionStart(cx, resultPromise, generatorVal))
+            return false;
+
+        // Step 5.
+        args.rval().setObject(*resultPromise);
+        return true;
     }
 
-    // Step 4.
+    // Steps 1, 4.
     RootedValue exc(cx);
     if (!GetAndClearException(cx, &exc))
         return false;
     RootedObject rejectPromise(cx, PromiseObject::unforgeableReject(cx, exc));
     if (!rejectPromise)
         return false;
 
     // Step 5.
@@ -124,112 +135,84 @@ js::WrapAsyncFunction(JSContext* cx, Han
     // Link them to each other to make GetWrappedAsyncFunction and
     // GetUnwrappedAsyncFunction work.
     unwrapped->setExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT, ObjectValue(*wrapped));
     wrapped->setExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT, ObjectValue(*unwrapped));
 
     return wrapped;
 }
 
-// Async Functions proposal 2.2 steps 3.f, 3.g.
-static bool
-AsyncFunctionThrown(JSContext* cx, MutableHandleValue rval)
-{
-    // Step 3.f.
-    RootedValue exc(cx);
-    if (!GetAndClearException(cx, &exc))
-        return false;
-
-    RootedObject rejectPromise(cx, PromiseObject::unforgeableReject(cx, exc));
-    if (!rejectPromise)
-        return false;
-
-    // Step 3.g.
-    rval.setObject(*rejectPromise);
-    return true;
-}
-
-// Async Functions proposal 2.2 steps 3.d-e, 3.g.
-static bool
-AsyncFunctionReturned(JSContext* cx, HandleValue value, MutableHandleValue rval)
-{
-    // Steps 3.d-e.
-    RootedObject resolveObj(cx, PromiseObject::unforgeableResolve(cx, value));
-    if (!resolveObj)
-        return false;
-
-    // Step 3.g.
-    rval.setObject(*resolveObj);
-    return true;
-}
-
 enum class ResumeKind {
     Normal,
     Throw
 };
 
+// Async Functions proposal 2.2 steps 3.f, 3.g.
+// Async Functions proposal 2.2 steps 3.d-e, 3.g.
+// Implemented in js/src/builtin/Promise.cpp
+
 // Async Functions proposal 2.2 steps 3-8, 2.4 steps 2-7, 2.5 steps 2-7.
 static bool
-AsyncFunctionResume(JSContext* cx, HandleValue generatorVal, ResumeKind kind,
-                    HandleValue valueOrReason, MutableHandleValue rval)
+AsyncFunctionResume(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue generatorVal,
+                    ResumeKind kind, HandleValue valueOrReason)
 {
     // Execution context switching is handled in generator.
     HandlePropertyName funName = kind == ResumeKind::Normal
                                  ? cx->names().StarGeneratorNext
                                  : cx->names().StarGeneratorThrow;
     FixedInvokeArgs<1> args(cx);
     args[0].set(valueOrReason);
     RootedValue result(cx);
     if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result))
-        return AsyncFunctionThrown(cx, rval);
+        return AsyncFunctionThrown(cx, resultPromise);
 
     RootedObject resultObj(cx, &result.toObject());
     RootedValue doneVal(cx);
     RootedValue value(cx);
     if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
         return false;
     if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
         return false;
 
     if (doneVal.toBoolean())
-        return AsyncFunctionReturned(cx, value, rval);
+        return AsyncFunctionReturned(cx, resultPromise, value);
 
-    return AsyncFunctionAwait(cx, generatorVal, value, rval);
+    return AsyncFunctionAwait(cx, resultPromise, value);
 }
 
 // Async Functions proposal 2.2 steps 3-8.
-static bool
-AsyncFunctionStart(JSContext* cx, HandleValue generatorVal, MutableHandleValue rval)
+static MOZ_MUST_USE bool
+AsyncFunctionStart(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue generatorVal)
 {
-    return AsyncFunctionResume(cx, generatorVal, ResumeKind::Normal, UndefinedHandleValue, rval);
+    return AsyncFunctionResume(cx, resultPromise, generatorVal, ResumeKind::Normal, UndefinedHandleValue);
 }
 
 // Async Functions proposal 2.3 steps 1-8.
 // Implemented in js/src/builtin/Promise.cpp
 
 // Async Functions proposal 2.4.
-bool
-js::AsyncFunctionAwaitedFulfilled(JSContext* cx, HandleValue value, HandleValue generatorVal,
-                                  MutableHandleValue rval)
+MOZ_MUST_USE bool
+js::AsyncFunctionAwaitedFulfilled(JSContext* cx, Handle<PromiseObject*> resultPromise,
+                                  HandleValue generatorVal, HandleValue value)
 {
     // Step 1 (implicit).
 
     // Steps 2-7.
-    return AsyncFunctionResume(cx, generatorVal, ResumeKind::Normal, value, rval);
+    return AsyncFunctionResume(cx, resultPromise, generatorVal, ResumeKind::Normal, value);
 }
 
 // Async Functions proposal 2.5.
-bool
-js::AsyncFunctionAwaitedRejected(JSContext* cx, HandleValue reason, HandleValue generatorVal,
-                                 MutableHandleValue rval)
+MOZ_MUST_USE bool
+js::AsyncFunctionAwaitedRejected(JSContext* cx, Handle<PromiseObject*> resultPromise,
+                                 HandleValue generatorVal, HandleValue reason)
 {
     // Step 1 (implicit).
 
     // Step 2-7.
-    return AsyncFunctionResume(cx, generatorVal, ResumeKind::Throw, reason, rval);
+    return AsyncFunctionResume(cx, resultPromise, generatorVal, ResumeKind::Throw, reason);
 }
 
 JSFunction*
 js::GetWrappedAsyncFunction(JSFunction* unwrapped)
 {
     MOZ_ASSERT(unwrapped->isAsync());
     return &unwrapped->getExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT).toObject().as<JSFunction>();
 }
--- a/js/src/vm/AsyncFunction.h
+++ b/js/src/vm/AsyncFunction.h
@@ -19,19 +19,19 @@ JSFunction*
 GetUnwrappedAsyncFunction(JSFunction* wrapped);
 
 bool
 IsWrappedAsyncFunction(JSFunction* fun);
 
 JSObject*
 WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped);
 
-bool
-AsyncFunctionAwaitedFulfilled(JSContext* cx, HandleValue value, HandleValue generatorVal,
-                              MutableHandleValue rval);
+MOZ_MUST_USE bool
+AsyncFunctionAwaitedFulfilled(JSContext* cx, Handle<PromiseObject*> resultPromise,
+                              HandleValue generatorVal, HandleValue value);
 
-bool
-AsyncFunctionAwaitedRejected(JSContext* cx, HandleValue reason, HandleValue generatorVal,
-                             MutableHandleValue rval);
+MOZ_MUST_USE bool
+AsyncFunctionAwaitedRejected(JSContext* cx, Handle<PromiseObject*> resultPromise,
+                             HandleValue generatorVal, HandleValue reason);
 
 } // namespace js
 
 #endif /* vm_AsyncFunction_h */