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