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#include 'src/builtins/builtins-promise-gen.h'
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_cinamespace runtime {
91cb0ef41Sopenharmony_ciextern transitioning runtime
101cb0ef41Sopenharmony_ciAllowDynamicFunction(implicit context: Context)(JSAny): JSAny;
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciextern transitioning runtime ThrowNoAccess(implicit context: Context)(): never;
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciextern transitioning runtime
151cb0ef41Sopenharmony_ciReportMessageFromMicrotask(implicit context: Context)(JSAny): JSAny;
161cb0ef41Sopenharmony_ci}
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci// Unsafe functions that should be used very carefully.
191cb0ef41Sopenharmony_cinamespace promise_internal {
201cb0ef41Sopenharmony_ciextern macro PromiseBuiltinsAssembler::ZeroOutEmbedderOffsets(JSPromise): void;
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciextern macro PromiseBuiltinsAssembler::AllocateJSPromise(Context): HeapObject;
231cb0ef41Sopenharmony_ci}
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciextern macro
261cb0ef41Sopenharmony_ciPromiseBuiltinsAssembler::IsContextPromiseHookEnabled(uint32): bool;
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ciextern macro
291cb0ef41Sopenharmony_ciPromiseBuiltinsAssembler::IsIsolatePromiseHookEnabled(uint32): bool;
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ciextern macro
321cb0ef41Sopenharmony_ciPromiseBuiltinsAssembler::PromiseHookFlags(): uint32;
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_cinamespace promise {
351cb0ef41Sopenharmony_ciextern macro IsFunctionWithPrototypeSlotMap(Map): bool;
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci@export
381cb0ef41Sopenharmony_cimacro PromiseHasHandler(promise: JSPromise): bool {
391cb0ef41Sopenharmony_ci  return promise.HasHandler();
401cb0ef41Sopenharmony_ci}
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci@export
431cb0ef41Sopenharmony_cimacro PromiseInit(promise: JSPromise): void {
441cb0ef41Sopenharmony_ci  promise.reactions_or_result = kZero;
451cb0ef41Sopenharmony_ci  promise.flags = SmiTag(JSPromiseFlags{
461cb0ef41Sopenharmony_ci    status: PromiseState::kPending,
471cb0ef41Sopenharmony_ci    has_handler: false,
481cb0ef41Sopenharmony_ci    handled_hint: false,
491cb0ef41Sopenharmony_ci    is_silent: false,
501cb0ef41Sopenharmony_ci    async_task_id: 0
511cb0ef41Sopenharmony_ci  });
521cb0ef41Sopenharmony_ci  promise_internal::ZeroOutEmbedderOffsets(promise);
531cb0ef41Sopenharmony_ci}
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_cimacro InnerNewJSPromise(implicit context: Context)(): JSPromise {
561cb0ef41Sopenharmony_ci  const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX);
571cb0ef41Sopenharmony_ci  dcheck(IsFunctionWithPrototypeSlotMap(promiseFun.map));
581cb0ef41Sopenharmony_ci  const promiseMap = UnsafeCast<Map>(promiseFun.prototype_or_initial_map);
591cb0ef41Sopenharmony_ci  const promiseHeapObject = promise_internal::AllocateJSPromise(context);
601cb0ef41Sopenharmony_ci  *UnsafeConstCast(&promiseHeapObject.map) = promiseMap;
611cb0ef41Sopenharmony_ci  const promise = UnsafeCast<JSPromise>(promiseHeapObject);
621cb0ef41Sopenharmony_ci  promise.properties_or_hash = kEmptyFixedArray;
631cb0ef41Sopenharmony_ci  promise.elements = kEmptyFixedArray;
641cb0ef41Sopenharmony_ci  promise.reactions_or_result = kZero;
651cb0ef41Sopenharmony_ci  promise.flags = SmiTag(JSPromiseFlags{
661cb0ef41Sopenharmony_ci    status: PromiseState::kPending,
671cb0ef41Sopenharmony_ci    has_handler: false,
681cb0ef41Sopenharmony_ci    handled_hint: false,
691cb0ef41Sopenharmony_ci    is_silent: false,
701cb0ef41Sopenharmony_ci    async_task_id: 0
711cb0ef41Sopenharmony_ci  });
721cb0ef41Sopenharmony_ci  return promise;
731cb0ef41Sopenharmony_ci}
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_cimacro NewPromiseFulfillReactionJobTask(implicit context: Context)(
761cb0ef41Sopenharmony_ci    handlerContext: Context, argument: Object, handler: Callable|Undefined,
771cb0ef41Sopenharmony_ci    promiseOrCapability: JSPromise|PromiseCapability|
781cb0ef41Sopenharmony_ci    Undefined): PromiseFulfillReactionJobTask {
791cb0ef41Sopenharmony_ci  const nativeContext = LoadNativeContext(handlerContext);
801cb0ef41Sopenharmony_ci  return new PromiseFulfillReactionJobTask{
811cb0ef41Sopenharmony_ci    map: PromiseFulfillReactionJobTaskMapConstant(),
821cb0ef41Sopenharmony_ci    argument,
831cb0ef41Sopenharmony_ci    context: handlerContext,
841cb0ef41Sopenharmony_ci    handler,
851cb0ef41Sopenharmony_ci    promise_or_capability: promiseOrCapability,
861cb0ef41Sopenharmony_ci    continuation_preserved_embedder_data:
871cb0ef41Sopenharmony_ci        *ContextSlot(
881cb0ef41Sopenharmony_ci        nativeContext, ContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX)
891cb0ef41Sopenharmony_ci  };
901cb0ef41Sopenharmony_ci}
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_cimacro NewPromiseRejectReactionJobTask(implicit context: Context)(
931cb0ef41Sopenharmony_ci    handlerContext: Context, argument: Object, handler: Callable|Undefined,
941cb0ef41Sopenharmony_ci    promiseOrCapability: JSPromise|PromiseCapability|
951cb0ef41Sopenharmony_ci    Undefined): PromiseRejectReactionJobTask {
961cb0ef41Sopenharmony_ci  const nativeContext = LoadNativeContext(handlerContext);
971cb0ef41Sopenharmony_ci  return new PromiseRejectReactionJobTask{
981cb0ef41Sopenharmony_ci    map: PromiseRejectReactionJobTaskMapConstant(),
991cb0ef41Sopenharmony_ci    argument,
1001cb0ef41Sopenharmony_ci    context: handlerContext,
1011cb0ef41Sopenharmony_ci    handler,
1021cb0ef41Sopenharmony_ci    promise_or_capability: promiseOrCapability,
1031cb0ef41Sopenharmony_ci    continuation_preserved_embedder_data:
1041cb0ef41Sopenharmony_ci        *ContextSlot(
1051cb0ef41Sopenharmony_ci        nativeContext, ContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX)
1061cb0ef41Sopenharmony_ci  };
1071cb0ef41Sopenharmony_ci}
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci@export
1101cb0ef41Sopenharmony_citransitioning macro RunContextPromiseHookInit(implicit context: Context)(
1111cb0ef41Sopenharmony_ci    promise: JSPromise, parent: Object): void {
1121cb0ef41Sopenharmony_ci  const maybeHook = *NativeContextSlot(
1131cb0ef41Sopenharmony_ci      ContextSlot::PROMISE_HOOK_INIT_FUNCTION_INDEX);
1141cb0ef41Sopenharmony_ci  const hook = Cast<Callable>(maybeHook) otherwise return;
1151cb0ef41Sopenharmony_ci  const parentObject = Is<JSPromise>(parent) ? Cast<JSPromise>(parent)
1161cb0ef41Sopenharmony_ci      otherwise unreachable: Undefined;
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  try {
1191cb0ef41Sopenharmony_ci    Call(context, hook, Undefined, promise, parentObject);
1201cb0ef41Sopenharmony_ci  } catch (e, _message) {
1211cb0ef41Sopenharmony_ci    runtime::ReportMessageFromMicrotask(e);
1221cb0ef41Sopenharmony_ci  }
1231cb0ef41Sopenharmony_ci}
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci@export
1261cb0ef41Sopenharmony_citransitioning macro RunContextPromiseHookResolve(implicit context: Context)(
1271cb0ef41Sopenharmony_ci    promise: JSPromise): void {
1281cb0ef41Sopenharmony_ci  // Use potentially unused variables.
1291cb0ef41Sopenharmony_ci  const _unusedPromise = promise;
1301cb0ef41Sopenharmony_ci  @if(V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS) {
1311cb0ef41Sopenharmony_ci    RunContextPromiseHook(
1321cb0ef41Sopenharmony_ci        ContextSlot::PROMISE_HOOK_RESOLVE_FUNCTION_INDEX, promise,
1331cb0ef41Sopenharmony_ci        PromiseHookFlags());
1341cb0ef41Sopenharmony_ci  }
1351cb0ef41Sopenharmony_ci}
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci@export
1381cb0ef41Sopenharmony_citransitioning macro RunContextPromiseHookResolve(implicit context: Context)(
1391cb0ef41Sopenharmony_ci    promise: JSPromise, flags: uint32): void {
1401cb0ef41Sopenharmony_ci  RunContextPromiseHook(
1411cb0ef41Sopenharmony_ci      ContextSlot::PROMISE_HOOK_RESOLVE_FUNCTION_INDEX, promise, flags);
1421cb0ef41Sopenharmony_ci}
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci@export
1451cb0ef41Sopenharmony_citransitioning macro RunContextPromiseHookBefore(implicit context: Context)(
1461cb0ef41Sopenharmony_ci    promiseOrCapability: JSPromise|PromiseCapability|Undefined): void {
1471cb0ef41Sopenharmony_ci  // Use potentially unused variables.
1481cb0ef41Sopenharmony_ci  const _unusedPromiseOrCapability = promiseOrCapability;
1491cb0ef41Sopenharmony_ci  @if(V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS) {
1501cb0ef41Sopenharmony_ci    RunContextPromiseHook(
1511cb0ef41Sopenharmony_ci        ContextSlot::PROMISE_HOOK_BEFORE_FUNCTION_INDEX, promiseOrCapability,
1521cb0ef41Sopenharmony_ci        PromiseHookFlags());
1531cb0ef41Sopenharmony_ci  }
1541cb0ef41Sopenharmony_ci}
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci@export
1571cb0ef41Sopenharmony_citransitioning macro RunContextPromiseHookBefore(implicit context: Context)(
1581cb0ef41Sopenharmony_ci    promiseOrCapability: JSPromise|PromiseCapability|Undefined, flags: uint32):
1591cb0ef41Sopenharmony_ci    void {
1601cb0ef41Sopenharmony_ci  RunContextPromiseHook(
1611cb0ef41Sopenharmony_ci      ContextSlot::PROMISE_HOOK_BEFORE_FUNCTION_INDEX, promiseOrCapability,
1621cb0ef41Sopenharmony_ci      flags);
1631cb0ef41Sopenharmony_ci}
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci@export
1661cb0ef41Sopenharmony_citransitioning macro RunContextPromiseHookAfter(implicit context: Context)(
1671cb0ef41Sopenharmony_ci    promiseOrCapability: JSPromise|PromiseCapability|Undefined): void {
1681cb0ef41Sopenharmony_ci  // Use potentially unused variables.
1691cb0ef41Sopenharmony_ci  const _unusedPromiseOrCapability = promiseOrCapability;
1701cb0ef41Sopenharmony_ci  @if(V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS) {
1711cb0ef41Sopenharmony_ci    RunContextPromiseHook(
1721cb0ef41Sopenharmony_ci        ContextSlot::PROMISE_HOOK_AFTER_FUNCTION_INDEX, promiseOrCapability,
1731cb0ef41Sopenharmony_ci        PromiseHookFlags());
1741cb0ef41Sopenharmony_ci  }
1751cb0ef41Sopenharmony_ci}
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci@export
1781cb0ef41Sopenharmony_citransitioning macro RunContextPromiseHookAfter(implicit context: Context)(
1791cb0ef41Sopenharmony_ci    promiseOrCapability: JSPromise|PromiseCapability|Undefined, flags: uint32):
1801cb0ef41Sopenharmony_ci    void {
1811cb0ef41Sopenharmony_ci  RunContextPromiseHook(
1821cb0ef41Sopenharmony_ci      ContextSlot::PROMISE_HOOK_AFTER_FUNCTION_INDEX, promiseOrCapability,
1831cb0ef41Sopenharmony_ci      flags);
1841cb0ef41Sopenharmony_ci}
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_citransitioning macro RunContextPromiseHook(implicit context: Context)(
1871cb0ef41Sopenharmony_ci    slot: Slot<NativeContext, Undefined|Callable>,
1881cb0ef41Sopenharmony_ci    promiseOrCapability: JSPromise|PromiseCapability|Undefined,
1891cb0ef41Sopenharmony_ci    flags: uint32): void {
1901cb0ef41Sopenharmony_ci  // Use potentially unused variables.
1911cb0ef41Sopenharmony_ci  const _unusedSlot = slot;
1921cb0ef41Sopenharmony_ci  const _unusedPromiseOrCapability = promiseOrCapability;
1931cb0ef41Sopenharmony_ci  const _unusedFlags = flags;
1941cb0ef41Sopenharmony_ci  @if(V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS) {
1951cb0ef41Sopenharmony_ci    if (!IsContextPromiseHookEnabled(flags)) return;
1961cb0ef41Sopenharmony_ci    const maybeHook = *NativeContextSlot(slot);
1971cb0ef41Sopenharmony_ci    const hook = Cast<Callable>(maybeHook) otherwise return;
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci    let promise: JSPromise;
2001cb0ef41Sopenharmony_ci    typeswitch (promiseOrCapability) {
2011cb0ef41Sopenharmony_ci      case (jspromise: JSPromise): {
2021cb0ef41Sopenharmony_ci        promise = jspromise;
2031cb0ef41Sopenharmony_ci      }
2041cb0ef41Sopenharmony_ci      case (capability: PromiseCapability): {
2051cb0ef41Sopenharmony_ci        promise = Cast<JSPromise>(capability.promise) otherwise return;
2061cb0ef41Sopenharmony_ci      }
2071cb0ef41Sopenharmony_ci      case (Undefined): {
2081cb0ef41Sopenharmony_ci        return;
2091cb0ef41Sopenharmony_ci      }
2101cb0ef41Sopenharmony_ci    }
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci    try {
2131cb0ef41Sopenharmony_ci      Call(context, hook, Undefined, promise);
2141cb0ef41Sopenharmony_ci    } catch (e, _message) {
2151cb0ef41Sopenharmony_ci      runtime::ReportMessageFromMicrotask(e);
2161cb0ef41Sopenharmony_ci    }
2171cb0ef41Sopenharmony_ci  }
2181cb0ef41Sopenharmony_ci}
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_citransitioning macro RunAnyPromiseHookInit(implicit context: Context)(
2211cb0ef41Sopenharmony_ci    promise: JSPromise, parent: Object): void {
2221cb0ef41Sopenharmony_ci  const promiseHookFlags = PromiseHookFlags();
2231cb0ef41Sopenharmony_ci  // Fast return if no hooks are set.
2241cb0ef41Sopenharmony_ci  if (promiseHookFlags == 0) return;
2251cb0ef41Sopenharmony_ci  @if(V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS) {
2261cb0ef41Sopenharmony_ci    if (IsContextPromiseHookEnabled(promiseHookFlags)) {
2271cb0ef41Sopenharmony_ci      RunContextPromiseHookInit(promise, parent);
2281cb0ef41Sopenharmony_ci    }
2291cb0ef41Sopenharmony_ci  }
2301cb0ef41Sopenharmony_ci  if (IsIsolatePromiseHookEnabled(promiseHookFlags)) {
2311cb0ef41Sopenharmony_ci    runtime::PromiseHookInit(promise, parent);
2321cb0ef41Sopenharmony_ci  }
2331cb0ef41Sopenharmony_ci}
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci// These allocate and initialize a promise with pending state and
2361cb0ef41Sopenharmony_ci// undefined fields.
2371cb0ef41Sopenharmony_ci//
2381cb0ef41Sopenharmony_ci// This uses the given parent as the parent promise for the promise
2391cb0ef41Sopenharmony_ci// init hook.
2401cb0ef41Sopenharmony_ci@export
2411cb0ef41Sopenharmony_citransitioning macro NewJSPromise(implicit context: Context)(parent: Object):
2421cb0ef41Sopenharmony_ci    JSPromise {
2431cb0ef41Sopenharmony_ci  const instance = InnerNewJSPromise();
2441cb0ef41Sopenharmony_ci  PromiseInit(instance);
2451cb0ef41Sopenharmony_ci  RunAnyPromiseHookInit(instance, parent);
2461cb0ef41Sopenharmony_ci  return instance;
2471cb0ef41Sopenharmony_ci}
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ci// This uses undefined as the parent promise for the promise init
2501cb0ef41Sopenharmony_ci// hook.
2511cb0ef41Sopenharmony_ci@export
2521cb0ef41Sopenharmony_citransitioning macro NewJSPromise(implicit context: Context)(): JSPromise {
2531cb0ef41Sopenharmony_ci  return NewJSPromise(Undefined);
2541cb0ef41Sopenharmony_ci}
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci// This allocates and initializes a promise with the given state and
2571cb0ef41Sopenharmony_ci// fields.
2581cb0ef41Sopenharmony_ci@export
2591cb0ef41Sopenharmony_citransitioning macro NewJSPromise(implicit context: Context)(
2601cb0ef41Sopenharmony_ci    status: constexpr PromiseState, result: JSAny): JSPromise {
2611cb0ef41Sopenharmony_ci  dcheck(status != PromiseState::kPending);
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  const instance = InnerNewJSPromise();
2641cb0ef41Sopenharmony_ci  instance.reactions_or_result = result;
2651cb0ef41Sopenharmony_ci  instance.SetStatus(status);
2661cb0ef41Sopenharmony_ci  promise_internal::ZeroOutEmbedderOffsets(instance);
2671cb0ef41Sopenharmony_ci  RunAnyPromiseHookInit(instance, Undefined);
2681cb0ef41Sopenharmony_ci  return instance;
2691cb0ef41Sopenharmony_ci}
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_cimacro NewPromiseReaction(implicit context: Context)(
2721cb0ef41Sopenharmony_ci    handlerContext: Context, next: Zero|PromiseReaction,
2731cb0ef41Sopenharmony_ci    promiseOrCapability: JSPromise|PromiseCapability|Undefined,
2741cb0ef41Sopenharmony_ci    fulfillHandler: Callable|Undefined,
2751cb0ef41Sopenharmony_ci    rejectHandler: Callable|Undefined): PromiseReaction {
2761cb0ef41Sopenharmony_ci  const nativeContext = LoadNativeContext(handlerContext);
2771cb0ef41Sopenharmony_ci  return new PromiseReaction{
2781cb0ef41Sopenharmony_ci    map: PromiseReactionMapConstant(),
2791cb0ef41Sopenharmony_ci    next: next,
2801cb0ef41Sopenharmony_ci    reject_handler: rejectHandler,
2811cb0ef41Sopenharmony_ci    fulfill_handler: fulfillHandler,
2821cb0ef41Sopenharmony_ci    promise_or_capability: promiseOrCapability,
2831cb0ef41Sopenharmony_ci    continuation_preserved_embedder_data:
2841cb0ef41Sopenharmony_ci        *ContextSlot(
2851cb0ef41Sopenharmony_ci        nativeContext, ContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX)
2861cb0ef41Sopenharmony_ci  };
2871cb0ef41Sopenharmony_ci}
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ciextern macro PromiseResolveThenableJobTaskMapConstant(): Map;
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci// https://tc39.es/ecma262/#sec-newpromiseresolvethenablejob
2921cb0ef41Sopenharmony_cimacro NewPromiseResolveThenableJobTask(implicit context: Context)(
2931cb0ef41Sopenharmony_ci    promiseToResolve: JSPromise, thenable: JSReceiver,
2941cb0ef41Sopenharmony_ci    then: Callable): PromiseResolveThenableJobTask {
2951cb0ef41Sopenharmony_ci  // 2. Let getThenRealmResult be GetFunctionRealm(then).
2961cb0ef41Sopenharmony_ci  // 3. If getThenRealmResult is a normal completion, then let thenRealm be
2971cb0ef41Sopenharmony_ci  //    getThenRealmResult.[[Value]].
2981cb0ef41Sopenharmony_ci  // 4. Otherwise, let thenRealm be null.
2991cb0ef41Sopenharmony_ci  //
3001cb0ef41Sopenharmony_ci  // The only cases where |thenRealm| can be null is when |then| is a revoked
3011cb0ef41Sopenharmony_ci  // Proxy object, which would throw when it is called anyway. So instead of
3021cb0ef41Sopenharmony_ci  // setting the context to null as the spec does, we just use the current
3031cb0ef41Sopenharmony_ci  // realm.
3041cb0ef41Sopenharmony_ci  const thenContext: Context = ExtractHandlerContext(then);
3051cb0ef41Sopenharmony_ci  const nativeContext = LoadNativeContext(thenContext);
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci  // 1. Let job be a new Job abstract closure with no parameters that
3081cb0ef41Sopenharmony_ci  //    captures promiseToResolve, thenable, and then...
3091cb0ef41Sopenharmony_ci  // 5. Return { [[Job]]: job, [[Realm]]: thenRealm }.
3101cb0ef41Sopenharmony_ci  return new PromiseResolveThenableJobTask{
3111cb0ef41Sopenharmony_ci    map: PromiseResolveThenableJobTaskMapConstant(),
3121cb0ef41Sopenharmony_ci    context: nativeContext,
3131cb0ef41Sopenharmony_ci    promise_to_resolve: promiseToResolve,
3141cb0ef41Sopenharmony_ci    thenable,
3151cb0ef41Sopenharmony_ci    then
3161cb0ef41Sopenharmony_ci  };
3171cb0ef41Sopenharmony_ci}
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_cistruct InvokeThenOneArgFunctor {
3201cb0ef41Sopenharmony_ci  transitioning
3211cb0ef41Sopenharmony_ci  macro Call(
3221cb0ef41Sopenharmony_ci      nativeContext: NativeContext, then: JSAny, receiver: JSAny, arg1: JSAny,
3231cb0ef41Sopenharmony_ci      _arg2: JSAny): JSAny {
3241cb0ef41Sopenharmony_ci    return Call(nativeContext, then, receiver, arg1);
3251cb0ef41Sopenharmony_ci  }
3261cb0ef41Sopenharmony_ci}
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_cistruct InvokeThenTwoArgFunctor {
3291cb0ef41Sopenharmony_ci  transitioning
3301cb0ef41Sopenharmony_ci  macro Call(
3311cb0ef41Sopenharmony_ci      nativeContext: NativeContext, then: JSAny, receiver: JSAny, arg1: JSAny,
3321cb0ef41Sopenharmony_ci      arg2: JSAny): JSAny {
3331cb0ef41Sopenharmony_ci    return Call(nativeContext, then, receiver, arg1, arg2);
3341cb0ef41Sopenharmony_ci  }
3351cb0ef41Sopenharmony_ci}
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_citransitioning
3381cb0ef41Sopenharmony_cimacro InvokeThen<F: type>(implicit context: Context)(
3391cb0ef41Sopenharmony_ci    nativeContext: NativeContext, receiver: JSAny, arg1: JSAny, arg2: JSAny,
3401cb0ef41Sopenharmony_ci    callFunctor: F): JSAny {
3411cb0ef41Sopenharmony_ci  // We can skip the "then" lookup on {receiver} if it's [[Prototype]]
3421cb0ef41Sopenharmony_ci  // is the (initial) Promise.prototype and the Promise#then protector
3431cb0ef41Sopenharmony_ci  // is intact, as that guards the lookup path for the "then" property
3441cb0ef41Sopenharmony_ci  // on JSPromise instances which have the (initial) %PromisePrototype%.
3451cb0ef41Sopenharmony_ci  if (!Is<Smi>(receiver) &&
3461cb0ef41Sopenharmony_ci      IsPromiseThenLookupChainIntact(
3471cb0ef41Sopenharmony_ci          nativeContext, UnsafeCast<HeapObject>(receiver).map)) {
3481cb0ef41Sopenharmony_ci    const then =
3491cb0ef41Sopenharmony_ci        *NativeContextSlot(nativeContext, ContextSlot::PROMISE_THEN_INDEX);
3501cb0ef41Sopenharmony_ci    return callFunctor.Call(nativeContext, then, receiver, arg1, arg2);
3511cb0ef41Sopenharmony_ci  } else
3521cb0ef41Sopenharmony_ci    deferred {
3531cb0ef41Sopenharmony_ci      const then = UnsafeCast<JSAny>(GetProperty(receiver, kThenString));
3541cb0ef41Sopenharmony_ci      return callFunctor.Call(nativeContext, then, receiver, arg1, arg2);
3551cb0ef41Sopenharmony_ci    }
3561cb0ef41Sopenharmony_ci}
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_citransitioning
3591cb0ef41Sopenharmony_cimacro InvokeThen(implicit context: Context)(
3601cb0ef41Sopenharmony_ci    nativeContext: NativeContext, receiver: JSAny, arg: JSAny): JSAny {
3611cb0ef41Sopenharmony_ci  return InvokeThen(
3621cb0ef41Sopenharmony_ci      nativeContext, receiver, arg, Undefined, InvokeThenOneArgFunctor{});
3631cb0ef41Sopenharmony_ci}
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_citransitioning
3661cb0ef41Sopenharmony_cimacro InvokeThen(implicit context: Context)(
3671cb0ef41Sopenharmony_ci    nativeContext: NativeContext, receiver: JSAny, arg1: JSAny,
3681cb0ef41Sopenharmony_ci    arg2: JSAny): JSAny {
3691cb0ef41Sopenharmony_ci  return InvokeThen(
3701cb0ef41Sopenharmony_ci      nativeContext, receiver, arg1, arg2, InvokeThenTwoArgFunctor{});
3711cb0ef41Sopenharmony_ci}
3721cb0ef41Sopenharmony_ci
3731cb0ef41Sopenharmony_citransitioning
3741cb0ef41Sopenharmony_cimacro BranchIfAccessCheckFailed(implicit context: Context)(
3751cb0ef41Sopenharmony_ci    nativeContext: NativeContext, promiseConstructor: JSAny,
3761cb0ef41Sopenharmony_ci    executor: JSAny): void labels IfNoAccess {
3771cb0ef41Sopenharmony_ci  try {
3781cb0ef41Sopenharmony_ci    // If executor is a bound function, load the bound function until we've
3791cb0ef41Sopenharmony_ci    // reached an actual function.
3801cb0ef41Sopenharmony_ci    let foundExecutor = executor;
3811cb0ef41Sopenharmony_ci    while (true) {
3821cb0ef41Sopenharmony_ci      typeswitch (foundExecutor) {
3831cb0ef41Sopenharmony_ci        case (f: JSFunction): {
3841cb0ef41Sopenharmony_ci          // Load the context from the function and compare it to the Promise
3851cb0ef41Sopenharmony_ci          // constructor's context. If they match, everything is fine,
3861cb0ef41Sopenharmony_ci          // otherwise, bail out to the runtime.
3871cb0ef41Sopenharmony_ci          const functionContext = f.context;
3881cb0ef41Sopenharmony_ci          const nativeFunctionContext = LoadNativeContext(functionContext);
3891cb0ef41Sopenharmony_ci          if (TaggedEqual(nativeContext, nativeFunctionContext)) {
3901cb0ef41Sopenharmony_ci            goto HasAccess;
3911cb0ef41Sopenharmony_ci          } else {
3921cb0ef41Sopenharmony_ci            goto CallRuntime;
3931cb0ef41Sopenharmony_ci          }
3941cb0ef41Sopenharmony_ci        }
3951cb0ef41Sopenharmony_ci        case (b: JSBoundFunction): {
3961cb0ef41Sopenharmony_ci          foundExecutor = b.bound_target_function;
3971cb0ef41Sopenharmony_ci        }
3981cb0ef41Sopenharmony_ci        case (Object): {
3991cb0ef41Sopenharmony_ci          goto CallRuntime;
4001cb0ef41Sopenharmony_ci        }
4011cb0ef41Sopenharmony_ci      }
4021cb0ef41Sopenharmony_ci    }
4031cb0ef41Sopenharmony_ci  } label CallRuntime deferred {
4041cb0ef41Sopenharmony_ci    const result = runtime::AllowDynamicFunction(promiseConstructor);
4051cb0ef41Sopenharmony_ci    if (result != True) {
4061cb0ef41Sopenharmony_ci      goto IfNoAccess;
4071cb0ef41Sopenharmony_ci    }
4081cb0ef41Sopenharmony_ci  } label HasAccess {}
4091cb0ef41Sopenharmony_ci}
4101cb0ef41Sopenharmony_ci}
411