1 // Copyright 2021 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 #ifndef INCLUDE_V8_PROMISE_H_
6 #define INCLUDE_V8_PROMISE_H_
7 
8 #include "v8-local-handle.h"  // NOLINT(build/include_directory)
9 #include "v8-object.h"        // NOLINT(build/include_directory)
10 #include "v8config.h"         // NOLINT(build/include_directory)
11 
12 namespace v8 {
13 
14 class Context;
15 
16 #ifndef V8_PROMISE_INTERNAL_FIELD_COUNT
17 // The number of required internal fields can be defined by embedder.
18 #define V8_PROMISE_INTERNAL_FIELD_COUNT 0
19 #endif
20 
21 /**
22  * An instance of the built-in Promise constructor (ES6 draft).
23  */
24 class V8_EXPORT Promise : public Object {
25  public:
26   /**
27    * State of the promise. Each value corresponds to one of the possible values
28    * of the [[PromiseState]] field.
29    */
30   enum PromiseState { kPending, kFulfilled, kRejected };
31 
32   class V8_EXPORT Resolver : public Object {
33    public:
34     /**
35      * Create a new resolver, along with an associated promise in pending state.
36      */
37     static V8_WARN_UNUSED_RESULT MaybeLocal<Resolver> New(
38         Local<Context> context);
39 
40     /**
41      * Extract the associated promise.
42      */
43     Local<Promise> GetPromise();
44 
45     /**
46      * Resolve/reject the associated promise with a given value.
47      * Ignored if the promise is no longer pending.
48      */
49     V8_WARN_UNUSED_RESULT Maybe<bool> Resolve(Local<Context> context,
50                                               Local<Value> value);
51 
52     V8_WARN_UNUSED_RESULT Maybe<bool> Reject(Local<Context> context,
53                                              Local<Value> value);
54 
Cast(Value * value)55     V8_INLINE static Resolver* Cast(Value* value) {
56 #ifdef V8_ENABLE_CHECKS
57       CheckCast(value);
58 #endif
59       return static_cast<Promise::Resolver*>(value);
60     }
61 
62    private:
63     Resolver();
64     static void CheckCast(Value* obj);
65   };
66 
67   /**
68    * Register a resolution/rejection handler with a promise.
69    * The handler is given the respective resolution/rejection value as
70    * an argument. If the promise is already resolved/rejected, the handler is
71    * invoked at the end of turn.
72    */
73   V8_WARN_UNUSED_RESULT MaybeLocal<Promise> Catch(Local<Context> context,
74                                                   Local<Function> handler);
75 
76   V8_WARN_UNUSED_RESULT MaybeLocal<Promise> Then(Local<Context> context,
77                                                  Local<Function> handler);
78 
79   V8_WARN_UNUSED_RESULT MaybeLocal<Promise> Then(Local<Context> context,
80                                                  Local<Function> on_fulfilled,
81                                                  Local<Function> on_rejected);
82 
83   /**
84    * Returns true if the promise has at least one derived promise, and
85    * therefore resolve/reject handlers (including default handler).
86    */
87   bool HasHandler() const;
88 
89   /**
90    * Returns the content of the [[PromiseResult]] field. The Promise must not
91    * be pending.
92    */
93   Local<Value> Result();
94 
95   /**
96    * Returns the value of the [[PromiseState]] field.
97    */
98   PromiseState State();
99 
100   /**
101    * Marks this promise as handled to avoid reporting unhandled rejections.
102    */
103   void MarkAsHandled();
104 
105   /**
106    * Marks this promise as silent to prevent pausing the debugger when the
107    * promise is rejected.
108    */
109   void MarkAsSilent();
110 
Cast(Value * value)111   V8_INLINE static Promise* Cast(Value* value) {
112 #ifdef V8_ENABLE_CHECKS
113     CheckCast(value);
114 #endif
115     return static_cast<Promise*>(value);
116   }
117 
118   static const int kEmbedderFieldCount = V8_PROMISE_INTERNAL_FIELD_COUNT;
119 
120  private:
121   Promise();
122   static void CheckCast(Value* obj);
123 };
124 
125 /**
126  * PromiseHook with type kInit is called when a new promise is
127  * created. When a new promise is created as part of the chain in the
128  * case of Promise.then or in the intermediate promises created by
129  * Promise.{race, all}/AsyncFunctionAwait, we pass the parent promise
130  * otherwise we pass undefined.
131  *
132  * PromiseHook with type kResolve is called at the beginning of
133  * resolve or reject function defined by CreateResolvingFunctions.
134  *
135  * PromiseHook with type kBefore is called at the beginning of the
136  * PromiseReactionJob.
137  *
138  * PromiseHook with type kAfter is called right at the end of the
139  * PromiseReactionJob.
140  */
141 enum class PromiseHookType { kInit, kResolve, kBefore, kAfter };
142 
143 using PromiseHook = void (*)(PromiseHookType type, Local<Promise> promise,
144                              Local<Value> parent);
145 
146 // --- Promise Reject Callback ---
147 enum PromiseRejectEvent {
148   kPromiseRejectWithNoHandler = 0,
149   kPromiseHandlerAddedAfterReject = 1,
150   kPromiseRejectAfterResolved = 2,
151   kPromiseResolveAfterResolved = 3,
152 };
153 
154 class PromiseRejectMessage {
155  public:
PromiseRejectMessage(Local<Promise> promise,PromiseRejectEvent event,Local<Value> value)156   PromiseRejectMessage(Local<Promise> promise, PromiseRejectEvent event,
157                        Local<Value> value)
158       : promise_(promise), event_(event), value_(value) {}
159 
GetPromise()160   V8_INLINE Local<Promise> GetPromise() const { return promise_; }
GetEvent()161   V8_INLINE PromiseRejectEvent GetEvent() const { return event_; }
GetValue()162   V8_INLINE Local<Value> GetValue() const { return value_; }
163 
164  private:
165   Local<Promise> promise_;
166   PromiseRejectEvent event_;
167   Local<Value> value_;
168 };
169 
170 using PromiseRejectCallback = void (*)(PromiseRejectMessage message);
171 
172 }  // namespace v8
173 
174 #endif  // INCLUDE_V8_PROMISE_H_
175