• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include 'src/builtins/builtins-promise-gen.h'
6
7namespace promise {
8
9transitioning
10macro RejectPromiseReactionJob(
11    context: Context,
12    promiseOrCapability: JSPromise|PromiseCapability|Undefined, reason: JSAny,
13    reactionType: constexpr PromiseReactionType): JSAny {
14  if constexpr (reactionType == kPromiseReactionReject) {
15    typeswitch (promiseOrCapability) {
16      case (promise: JSPromise): {
17        // For fast native promises we can skip the indirection via the
18        // promiseCapability.[[Reject]] function and run the resolve logic
19        // directly from here.
20        return RejectPromise(promise, reason, False);
21      }
22      case (Undefined): {
23        return Undefined;
24      }
25      case (capability: PromiseCapability): {
26        // In the general case we need to call the (user provided)
27        // promiseCapability.[[Reject]] function.
28        const reject = UnsafeCast<Callable>(capability.reject);
29        return Call(context, reject, Undefined, reason);
30      }
31    }
32  } else {
33    static_assert(reactionType == kPromiseReactionFulfill);
34    // We have to call out to the dedicated PromiseRejectReactionJob
35    // builtin here, instead of just doing the work inline, as otherwise
36    // the catch predictions in the debugger will be wrong, which just
37    // walks the stack and checks for certain builtins.
38    return PromiseRejectReactionJob(reason, Undefined, promiseOrCapability);
39  }
40}
41
42transitioning
43macro FuflfillPromiseReactionJob(
44    context: Context,
45    promiseOrCapability: JSPromise|PromiseCapability|Undefined, result: JSAny,
46    reactionType: constexpr PromiseReactionType): JSAny {
47  typeswitch (promiseOrCapability) {
48    case (promise: JSPromise): {
49      // For fast native promises we can skip the indirection via the
50      // promiseCapability.[[Resolve]] function and run the resolve logic
51      // directly from here.
52      return ResolvePromise(context, promise, result);
53    }
54    case (Undefined): {
55      return Undefined;
56    }
57    case (capability: PromiseCapability): {
58      // In the general case we need to call the (user provided)
59      // promiseCapability.[[Resolve]] function.
60      const resolve = UnsafeCast<Callable>(capability.resolve);
61      try {
62        return Call(context, resolve, Undefined, result);
63      } catch (e) {
64        return RejectPromiseReactionJob(
65            context, promiseOrCapability, e, reactionType);
66      }
67    }
68  }
69}
70
71// https://tc39.es/ecma262/#sec-promisereactionjob
72transitioning
73macro PromiseReactionJob(
74    context: Context, argument: JSAny, handler: Callable|Undefined,
75    promiseOrCapability: JSPromise|PromiseCapability|Undefined,
76    reactionType: constexpr PromiseReactionType): JSAny {
77  if (handler == Undefined) {
78    if constexpr (reactionType == kPromiseReactionFulfill) {
79      return FuflfillPromiseReactionJob(
80          context, promiseOrCapability, argument, reactionType);
81    } else {
82      static_assert(reactionType == kPromiseReactionReject);
83      return RejectPromiseReactionJob(
84          context, promiseOrCapability, argument, reactionType);
85    }
86  } else {
87    try {
88      const result =
89          Call(context, UnsafeCast<Callable>(handler), Undefined, argument);
90      if (promiseOrCapability == Undefined) {
91        // There's no [[Capability]] for this promise reaction job, which
92        // means that this is a specification-internal operation (aka
93        // await) where the result does not matter (see the specification
94        // change in https://github.com/tc39/ecma262/pull/1146 for
95        // details).
96        return Undefined;
97      } else {
98        return FuflfillPromiseReactionJob(
99            context, promiseOrCapability, result, reactionType);
100      }
101    } catch (e) {
102      return RejectPromiseReactionJob(
103          context, promiseOrCapability, e, reactionType);
104    }
105  }
106}
107
108transitioning builtin
109PromiseFulfillReactionJob(implicit context: Context)(
110    value: JSAny, handler: Callable|Undefined,
111    promiseOrCapability: JSPromise|PromiseCapability|Undefined): JSAny {
112  return PromiseReactionJob(
113      context, value, handler, promiseOrCapability, kPromiseReactionFulfill);
114}
115
116transitioning builtin
117PromiseRejectReactionJob(implicit context: Context)(
118    reason: JSAny, handler: Callable|Undefined,
119    promiseOrCapability: JSPromise|PromiseCapability|Undefined): JSAny {
120  return PromiseReactionJob(
121      context, reason, handler, promiseOrCapability, kPromiseReactionReject);
122}
123}
124