• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 V8_BUILTINS_BUILTINS_PROMISE_GEN_H_
6 #define V8_BUILTINS_BUILTINS_PROMISE_GEN_H_
7 
8 #include "src/code-stub-assembler.h"
9 #include "src/contexts.h"
10 #include "src/objects/promise.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 typedef compiler::CodeAssemblerState CodeAssemblerState;
16 
17 class PromiseBuiltinsAssembler : public CodeStubAssembler {
18  public:
19   enum PromiseResolvingFunctionContextSlot {
20     // The promise which resolve/reject callbacks fulfill.
21     kPromiseSlot = Context::MIN_CONTEXT_SLOTS,
22 
23     // Whether the callback was already invoked.
24     kAlreadyResolvedSlot,
25 
26     // Whether to trigger a debug event or not. Used in catch
27     // prediction.
28     kDebugEventSlot,
29     kPromiseContextLength,
30   };
31 
32  protected:
33   enum PromiseAllResolveElementContextSlots {
34     // Remaining elements count
35     kPromiseAllResolveElementRemainingSlot = Context::MIN_CONTEXT_SLOTS,
36 
37     // Promise capability from Promise.all
38     kPromiseAllResolveElementCapabilitySlot,
39 
40     // Values array from Promise.all
41     kPromiseAllResolveElementValuesArraySlot,
42 
43     kPromiseAllResolveElementLength
44   };
45 
46  public:
47   enum FunctionContextSlot {
48     kCapabilitySlot = Context::MIN_CONTEXT_SLOTS,
49 
50     kCapabilitiesContextLength,
51   };
52 
53   // This is used by the Promise.prototype.finally builtin to store
54   // onFinally callback and the Promise constructor.
55   // TODO(gsathya): For native promises we can create a variant of
56   // this without extra space for the constructor to save memory.
57   enum PromiseFinallyContextSlot {
58     kOnFinallySlot = Context::MIN_CONTEXT_SLOTS,
59     kConstructorSlot,
60 
61     kPromiseFinallyContextLength,
62   };
63 
64   // This is used by the ThenFinally and CatchFinally builtins to
65   // store the value to return or reason to throw.
66   enum PromiseValueThunkOrReasonContextSlot {
67     kValueSlot = Context::MIN_CONTEXT_SLOTS,
68 
69     kPromiseValueThunkOrReasonContextLength,
70   };
71 
PromiseBuiltinsAssembler(compiler::CodeAssemblerState * state)72   explicit PromiseBuiltinsAssembler(compiler::CodeAssemblerState* state)
73       : CodeStubAssembler(state) {}
74   // These allocate and initialize a promise with pending state and
75   // undefined fields.
76   //
77   // This uses undefined as the parent promise for the promise init
78   // hook.
79   Node* AllocateAndInitJSPromise(Node* context);
80   // This uses the given parent as the parent promise for the promise
81   // init hook.
82   Node* AllocateAndInitJSPromise(Node* context, Node* parent);
83 
84   // This allocates and initializes a promise with the given state and
85   // fields.
86   Node* AllocateAndSetJSPromise(Node* context, v8::Promise::PromiseState status,
87                                 Node* result);
88 
89   Node* AllocatePromiseReaction(Node* next, Node* promise_or_capability,
90                                 Node* fulfill_handler, Node* reject_handler);
91 
92   Node* AllocatePromiseReactionJobTask(Heap::RootListIndex map_root_index,
93                                        Node* context, Node* argument,
94                                        Node* handler,
95                                        Node* promise_or_capability);
96   Node* AllocatePromiseReactionJobTask(Node* map, Node* context, Node* argument,
97                                        Node* handler,
98                                        Node* promise_or_capability);
99   Node* AllocatePromiseResolveThenableJobTask(Node* promise_to_resolve,
100                                               Node* then, Node* thenable,
101                                               Node* context);
102 
103   std::pair<Node*, Node*> CreatePromiseResolvingFunctions(
104       Node* promise, Node* native_context, Node* promise_context);
105 
106   Node* PromiseHasHandler(Node* promise);
107 
108   // Creates the context used by all Promise.all resolve element closures,
109   // together with the values array. Since all closures for a single Promise.all
110   // call use the same context, we need to store the indices for the individual
111   // closures somewhere else (we put them into the identity hash field of the
112   // closures), and we also need to have a separate marker for when the closure
113   // was called already (we slap the native context onto the closure in that
114   // case to mark it's done).
115   Node* CreatePromiseAllResolveElementContext(Node* promise_capability,
116                                               Node* native_context);
117   Node* CreatePromiseAllResolveElementFunction(Node* context, TNode<Smi> index,
118                                                Node* native_context);
119 
120   Node* CreatePromiseResolvingFunctionsContext(Node* promise, Node* debug_event,
121                                                Node* native_context);
122 
123   Node* CreatePromiseGetCapabilitiesExecutorContext(Node* native_context,
124                                                     Node* promise_capability);
125 
126  protected:
127   void PromiseInit(Node* promise);
128 
129   void PromiseSetHasHandler(Node* promise);
130   void PromiseSetHandledHint(Node* promise);
131 
132   void PerformPromiseThen(Node* context, Node* promise, Node* on_fulfilled,
133                           Node* on_rejected,
134                           Node* result_promise_or_capability);
135 
136   Node* CreatePromiseContext(Node* native_context, int slots);
137 
138   Node* TriggerPromiseReactions(Node* context, Node* promise, Node* result,
139                                 PromiseReaction::Type type);
140 
141   // We can skip the "resolve" lookup on {constructor} if it's the (initial)
142   // Promise constructor and the Promise.resolve() protector is intact, as
143   // that guards the lookup path for the "resolve" property on the %Promise%
144   // intrinsic object.
145   void BranchIfPromiseResolveLookupChainIntact(Node* native_context,
146                                                Node* constructor,
147                                                Label* if_fast, Label* if_slow);
148 
149   // We can shortcut the SpeciesConstructor on {promise_map} if it's
150   // [[Prototype]] is the (initial)  Promise.prototype and the @@species
151   // protector is intact, as that guards the lookup path for the "constructor"
152   // property on JSPromise instances which have the %PromisePrototype%.
153   void BranchIfPromiseSpeciesLookupChainIntact(Node* native_context,
154                                                Node* promise_map,
155                                                Label* if_fast, Label* if_slow);
156 
157   // We can skip the "then" lookup on {receiver_map} if it's [[Prototype]]
158   // is the (initial) Promise.prototype and the Promise#then() protector
159   // is intact, as that guards the lookup path for the "then" property
160   // on JSPromise instances which have the (initial) %PromisePrototype%.
161   void BranchIfPromiseThenLookupChainIntact(Node* native_context,
162                                             Node* receiver_map, Label* if_fast,
163                                             Label* if_slow);
164 
165   Node* InvokeResolve(Node* native_context, Node* constructor, Node* value,
166                       Label* if_exception, Variable* var_exception);
167   template <typename... TArgs>
168   Node* InvokeThen(Node* native_context, Node* receiver, TArgs... args);
169 
170   void BranchIfAccessCheckFailed(Node* context, Node* native_context,
171                                  Node* promise_constructor, Node* executor,
172                                  Label* if_noaccess);
173 
174   std::pair<Node*, Node*> CreatePromiseFinallyFunctions(Node* on_finally,
175                                                         Node* constructor,
176                                                         Node* native_context);
177   Node* CreateValueThunkFunction(Node* value, Node* native_context);
178 
179   Node* CreateThrowerFunction(Node* reason, Node* native_context);
180 
181   Node* PerformPromiseAll(Node* context, Node* constructor, Node* capability,
182                           const IteratorRecord& record, Label* if_exception,
183                           Variable* var_exception);
184 
185   void SetForwardingHandlerIfTrue(Node* context, Node* condition,
186                                   const NodeGenerator& object);
SetForwardingHandlerIfTrue(Node * context,Node * condition,Node * object)187   inline void SetForwardingHandlerIfTrue(Node* context, Node* condition,
188                                          Node* object) {
189     return SetForwardingHandlerIfTrue(context, condition,
190                                       [object]() -> Node* { return object; });
191   }
192   void SetPromiseHandledByIfTrue(Node* context, Node* condition, Node* promise,
193                                  const NodeGenerator& handled_by);
194 
195   Node* PromiseStatus(Node* promise);
196 
197   void PromiseReactionJob(Node* context, Node* argument, Node* handler,
198                           Node* promise_or_capability,
199                           PromiseReaction::Type type);
200 
201   Node* IsPromiseStatus(Node* actual, v8::Promise::PromiseState expected);
202   void PromiseSetStatus(Node* promise, v8::Promise::PromiseState status);
203 
204   Node* AllocateJSPromise(Node* context);
205 };
206 
207 }  // namespace internal
208 }  // namespace v8
209 
210 #endif  // V8_BUILTINS_BUILTINS_PROMISE_GEN_H_
211