11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include 'src/builtins/builtins-promise-gen.h'
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_cinamespace runtime {
81cb0ef41Sopenharmony_ciextern transitioning runtime
91cb0ef41Sopenharmony_ciDebugPromiseThen(implicit context: Context)(JSAny): JSAny;
101cb0ef41Sopenharmony_ci}
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cinamespace promise {
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciextern macro
151cb0ef41Sopenharmony_ciCodeStubAssembler::HasAsyncEventDelegate(): bool;
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cimacro
181cb0ef41Sopenharmony_ciIsPromiseSpeciesLookupChainIntact(
191cb0ef41Sopenharmony_ci    nativeContext: NativeContext, promiseMap: Map): bool {
201cb0ef41Sopenharmony_ci  const promisePrototype =
211cb0ef41Sopenharmony_ci      *NativeContextSlot(nativeContext, ContextSlot::PROMISE_PROTOTYPE_INDEX);
221cb0ef41Sopenharmony_ci  if (IsForceSlowPath()) return false;
231cb0ef41Sopenharmony_ci  if (promiseMap.prototype != promisePrototype) return false;
241cb0ef41Sopenharmony_ci  return !IsPromiseSpeciesProtectorCellInvalid();
251cb0ef41Sopenharmony_ci}
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci// https://tc39.es/ecma262/#sec-promise.prototype.then
281cb0ef41Sopenharmony_citransitioning javascript builtin
291cb0ef41Sopenharmony_ciPromisePrototypeThen(js-implicit context: NativeContext, receiver: JSAny)(
301cb0ef41Sopenharmony_ci    onFulfilled: JSAny, onRejected: JSAny): JSAny {
311cb0ef41Sopenharmony_ci  // 1. Let promise be the this value.
321cb0ef41Sopenharmony_ci  // 2. If IsPromise(promise) is false, throw a TypeError exception.
331cb0ef41Sopenharmony_ci  const promise = Cast<JSPromise>(receiver) otherwise ThrowTypeError(
341cb0ef41Sopenharmony_ci      MessageTemplate::kIncompatibleMethodReceiver, 'Promise.prototype.then',
351cb0ef41Sopenharmony_ci      receiver);
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
381cb0ef41Sopenharmony_ci  const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX);
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci  // 4. Let resultCapability be ? NewPromiseCapability(C).
411cb0ef41Sopenharmony_ci  let resultPromiseOrCapability: JSPromise|PromiseCapability;
421cb0ef41Sopenharmony_ci  let resultPromise: JSAny;
431cb0ef41Sopenharmony_ci  try {
441cb0ef41Sopenharmony_ci    if (IsPromiseSpeciesLookupChainIntact(context, promise.map)) {
451cb0ef41Sopenharmony_ci      goto AllocateAndInit;
461cb0ef41Sopenharmony_ci    }
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci    const constructor = SpeciesConstructor(promise, promiseFun);
491cb0ef41Sopenharmony_ci    if (TaggedEqual(constructor, promiseFun)) {
501cb0ef41Sopenharmony_ci      goto AllocateAndInit;
511cb0ef41Sopenharmony_ci    } else {
521cb0ef41Sopenharmony_ci      const promiseCapability = NewPromiseCapability(constructor, True);
531cb0ef41Sopenharmony_ci      resultPromiseOrCapability = promiseCapability;
541cb0ef41Sopenharmony_ci      resultPromise = promiseCapability.promise;
551cb0ef41Sopenharmony_ci    }
561cb0ef41Sopenharmony_ci  } label AllocateAndInit {
571cb0ef41Sopenharmony_ci    const resultJSPromise = NewJSPromise(promise);
581cb0ef41Sopenharmony_ci    resultPromiseOrCapability = resultJSPromise;
591cb0ef41Sopenharmony_ci    resultPromise = resultJSPromise;
601cb0ef41Sopenharmony_ci  }
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  // We do some work of the PerformPromiseThen operation here, in that
631cb0ef41Sopenharmony_ci  // we check the handlers and turn non-callable handlers into undefined.
641cb0ef41Sopenharmony_ci  // This is because this is the one and only callsite of PerformPromiseThen
651cb0ef41Sopenharmony_ci  // that has to do this.
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  // 3. If IsCallable(onFulfilled) is false, then
681cb0ef41Sopenharmony_ci  //    a. Set onFulfilled to undefined.
691cb0ef41Sopenharmony_ci  const onFulfilled = CastOrDefault<Callable>(onFulfilled, Undefined);
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  // 4. If IsCallable(onRejected) is false, then
721cb0ef41Sopenharmony_ci  //    a. Set onRejected to undefined.
731cb0ef41Sopenharmony_ci  const onRejected = CastOrDefault<Callable>(onRejected, Undefined);
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
761cb0ef41Sopenharmony_ci  //    resultCapability).
771cb0ef41Sopenharmony_ci  PerformPromiseThenImpl(
781cb0ef41Sopenharmony_ci      promise, onFulfilled, onRejected, resultPromiseOrCapability);
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci  // Async instrumentation for Promise#then(), Promise#catch() and
811cb0ef41Sopenharmony_ci  // Promise#finally(), where the latter two both call eventually
821cb0ef41Sopenharmony_ci  // call into Promise#then().
831cb0ef41Sopenharmony_ci  if (HasAsyncEventDelegate()) {
841cb0ef41Sopenharmony_ci    return runtime::DebugPromiseThen(resultPromise);
851cb0ef41Sopenharmony_ci  }
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  return resultPromise;
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci}
90