Home | History | Annotate | Download | only in builtins
      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 
     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);
    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