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.h'
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci// https://tc39.es/ecma262/#sec-promise-jobs
81cb0ef41Sopenharmony_cinamespace promise {
91cb0ef41Sopenharmony_ciextern macro IsJSPromiseMap(Map): bool;
101cb0ef41Sopenharmony_ciextern macro NeedsAnyPromiseHooks(): bool;
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci// https://tc39.es/ecma262/#sec-promiseresolvethenablejob
131cb0ef41Sopenharmony_citransitioning builtin
141cb0ef41Sopenharmony_ciPromiseResolveThenableJob(implicit context: Context)(
151cb0ef41Sopenharmony_ci    promiseToResolve: JSPromise, thenable: JSReceiver, then: JSAny): JSAny {
161cb0ef41Sopenharmony_ci  // We can use a simple optimization here if we know that {then} is the
171cb0ef41Sopenharmony_ci  // initial Promise.prototype.then method, and {thenable} is a JSPromise
181cb0ef41Sopenharmony_ci  // whose
191cb0ef41Sopenharmony_ci  // @@species lookup chain is intact: We can connect {thenable} and
201cb0ef41Sopenharmony_ci  // {promise_to_resolve} directly in that case and avoid the allocation of a
211cb0ef41Sopenharmony_ci  // temporary JSPromise and the closures plus context.
221cb0ef41Sopenharmony_ci  //
231cb0ef41Sopenharmony_ci  // We take the generic (slow-)path if a PromiseHook is enabled or the
241cb0ef41Sopenharmony_ci  // debugger is active, to make sure we expose spec compliant behavior.
251cb0ef41Sopenharmony_ci  const nativeContext = LoadNativeContext(context);
261cb0ef41Sopenharmony_ci  const promiseThen = *NativeContextSlot(ContextSlot::PROMISE_THEN_INDEX);
271cb0ef41Sopenharmony_ci  const thenableMap = thenable.map;
281cb0ef41Sopenharmony_ci  if (TaggedEqual(then, promiseThen) && IsJSPromiseMap(thenableMap) &&
291cb0ef41Sopenharmony_ci      !NeedsAnyPromiseHooks() &&
301cb0ef41Sopenharmony_ci      IsPromiseSpeciesLookupChainIntact(nativeContext, thenableMap)) {
311cb0ef41Sopenharmony_ci    // We know that the {thenable} is a JSPromise, which doesn't require
321cb0ef41Sopenharmony_ci    // any special treatment and that {then} corresponds to the initial
331cb0ef41Sopenharmony_ci    // Promise.prototype.then method. So instead of allocating a temporary
341cb0ef41Sopenharmony_ci    // JSPromise to connect the {thenable} with the {promise_to_resolve},
351cb0ef41Sopenharmony_ci    // we can directly schedule the {promise_to_resolve} with default
361cb0ef41Sopenharmony_ci    // handlers onto the {thenable} promise. This does not only save the
371cb0ef41Sopenharmony_ci    // JSPromise allocation, but also avoids the allocation of the two
381cb0ef41Sopenharmony_ci    // resolving closures and the shared context.
391cb0ef41Sopenharmony_ci    //
401cb0ef41Sopenharmony_ci    // What happens normally in this case is
411cb0ef41Sopenharmony_ci    //
421cb0ef41Sopenharmony_ci    //   resolve, reject = CreateResolvingFunctions(promise_to_resolve)
431cb0ef41Sopenharmony_ci    //   result_capability = NewPromiseCapability(%Promise%)
441cb0ef41Sopenharmony_ci    //   PerformPromiseThen(thenable, resolve, reject, result_capability)
451cb0ef41Sopenharmony_ci    //
461cb0ef41Sopenharmony_ci    // which means that PerformPromiseThen will either schedule a new
471cb0ef41Sopenharmony_ci    // PromiseReaction with resolve and reject or a PromiseReactionJob
481cb0ef41Sopenharmony_ci    // with resolve or reject based on the state of {thenable}. And
491cb0ef41Sopenharmony_ci    // resolve or reject will just invoke the default [[Resolve]] or
501cb0ef41Sopenharmony_ci    // [[Reject]] functions on the {promise_to_resolve}.
511cb0ef41Sopenharmony_ci    //
521cb0ef41Sopenharmony_ci    // This is the same as just doing
531cb0ef41Sopenharmony_ci    //
541cb0ef41Sopenharmony_ci    //   PerformPromiseThen(thenable, undefined, undefined,
551cb0ef41Sopenharmony_ci    //   promise_to_resolve)
561cb0ef41Sopenharmony_ci    //
571cb0ef41Sopenharmony_ci    // which performs exactly the same (observable) steps.
581cb0ef41Sopenharmony_ci    return PerformPromiseThen(
591cb0ef41Sopenharmony_ci        UnsafeCast<JSPromise>(thenable), UndefinedConstant(),
601cb0ef41Sopenharmony_ci        UndefinedConstant(), promiseToResolve);
611cb0ef41Sopenharmony_ci  } else {
621cb0ef41Sopenharmony_ci    const funcs =
631cb0ef41Sopenharmony_ci        CreatePromiseResolvingFunctions(promiseToResolve, False, nativeContext);
641cb0ef41Sopenharmony_ci    const resolve = funcs.resolve;
651cb0ef41Sopenharmony_ci    const reject = funcs.reject;
661cb0ef41Sopenharmony_ci    try {
671cb0ef41Sopenharmony_ci      return Call(
681cb0ef41Sopenharmony_ci          context, UnsafeCast<Callable>(then), thenable, resolve, reject);
691cb0ef41Sopenharmony_ci    } catch (e, _message) {
701cb0ef41Sopenharmony_ci      return Call(context, UnsafeCast<Callable>(reject), Undefined, e);
711cb0ef41Sopenharmony_ci    }
721cb0ef41Sopenharmony_ci  }
731cb0ef41Sopenharmony_ci}
741cb0ef41Sopenharmony_ci}
75