| Index: src/builtins/builtins-promise.cc
|
| diff --git a/src/builtins/builtins-promise.cc b/src/builtins/builtins-promise.cc
|
| index 345625d6d098d09eeb7686658803da7bdbcfa046..0945303bad428b34ea494a0866156bef76c7f480 100644
|
| --- a/src/builtins/builtins-promise.cc
|
| +++ b/src/builtins/builtins-promise.cc
|
| @@ -605,6 +605,75 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
|
| return deferred_promise;
|
| }
|
|
|
| +void PromiseBuiltinsAssembler::FastPerformPromiseThen(Node* context,
|
| + Node* promise,
|
| + Node* on_resolve,
|
| + Node* on_reject,
|
| + Node* result_promise) {
|
| + CSA_SLOW_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE));
|
| + if (result_promise != nullptr) {
|
| + CSA_SLOW_ASSERT(this, HasInstanceType(result_promise, JS_PROMISE_TYPE));
|
| + }
|
| +
|
| + if (on_resolve == nullptr) {
|
| + on_resolve = LoadContextElement(LoadNativeContext(context),
|
| + Context::PROMISE_ID_RESOLVE_HANDLER_INDEX);
|
| + } else if (on_reject == nullptr) {
|
| + on_reject = LoadContextElement(LoadNativeContext(context),
|
| + Context::PROMISE_ID_REJECT_HANDLER_INDEX);
|
| + }
|
| + CSA_SLOW_ASSERT(this, IsJSFunction(on_resolve));
|
| + CSA_SLOW_ASSERT(this, IsJSFunction(on_reject));
|
| +
|
| + Label if_ispending(this), if_isfulfilled(this), merge(this);
|
| +
|
| + Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset);
|
| + Branch(SmiEqual(status, SmiConstant(v8::Promise::kPending)), &if_ispending,
|
| + &if_isfulfilled);
|
| +
|
| + Bind(&if_ispending);
|
| + {
|
| + // Assert: There are no callbacks attached.
|
| + CSA_SLOW_ASSERT(this, IsUndefined(LoadObjectField(
|
| + promise, JSPromise::kDeferredPromiseOffset)));
|
| +
|
| + // Store callbacks directly in the slots.
|
| + StoreObjectField(promise, JSPromise::kDeferredPromiseOffset,
|
| + result_promise ? result_promise : UndefinedConstant());
|
| + StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, on_resolve);
|
| + StoreObjectField(promise, JSPromise::kRejectReactionsOffset, on_reject);
|
| + Goto(&merge);
|
| + }
|
| +
|
| + Bind(&if_isfulfilled);
|
| + {
|
| + Node* const handler =
|
| + Select(SmiEqual(status, SmiConstant(v8::Promise::kFulfilled)),
|
| + [&]() -> Node* { return on_resolve; },
|
| + [&]() -> Node* {
|
| + Label done(this);
|
| + GotoIf(PromiseHasHandler(promise), &done);
|
| + // TODO(gsathya): Fold these runtime calls and move to TF.
|
| + CallRuntime(Runtime::kPromiseRevokeReject, context, promise);
|
| + Goto(&done);
|
| + Bind(&done);
|
| + return on_reject;
|
| + },
|
| + MachineRepresentation::kTagged);
|
| +
|
| + Node* const result = LoadObjectField(promise, JSPromise::kResultOffset);
|
| + Node* info = AllocatePromiseReactionJobInfo(
|
| + promise, result, handler,
|
| + result_promise ? result_promise : UndefinedConstant(),
|
| + UndefinedConstant(), UndefinedConstant(), context);
|
| + // TODO(gsathya): Move this to TF
|
| + CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info, status);
|
| + Goto(&merge);
|
| + }
|
| +
|
| + Bind(&merge);
|
| +}
|
| +
|
| // Promise fast path implementations rely on unmodified JSPromise instances.
|
| // We use a fairly coarse granularity for this and simply check whether both
|
| // the promise itself is unmodified (i.e. its map has not changed) and its
|
| @@ -1076,7 +1145,7 @@ TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) {
|
| Node* const context = Parameter(7);
|
|
|
| // No deferred_on_resolve/deferred_on_reject because this is just an
|
| - // internal promise created by async-await.
|
| + // internal promise created by async-await / async-iteration.
|
| Node* const result = InternalPerformPromiseThen(
|
| context, promise, on_resolve, on_reject, deferred_promise,
|
| UndefinedConstant(), UndefinedConstant());
|
|
|