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 #include "src/builtins/builtins-promise.h"
      6 #include "src/builtins/builtins-constructor.h"
      7 #include "src/builtins/builtins-utils.h"
      8 #include "src/builtins/builtins.h"
      9 #include "src/code-factory.h"
     10 #include "src/code-stub-assembler.h"
     11 #include "src/objects-inl.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 typedef compiler::Node Node;
     17 typedef CodeStubAssembler::ParameterMode ParameterMode;
     18 typedef compiler::CodeAssemblerState CodeAssemblerState;
     19 
     20 Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) {
     21   Node* const native_context = LoadNativeContext(context);
     22   Node* const promise_fun =
     23       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
     24   Node* const initial_map =
     25       LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
     26   Node* const instance = AllocateJSObjectFromMap(initial_map);
     27   return instance;
     28 }
     29 
     30 void PromiseBuiltinsAssembler::PromiseInit(Node* promise) {
     31   StoreObjectField(promise, JSPromise::kStatusOffset,
     32                    SmiConstant(v8::Promise::kPending));
     33   StoreObjectField(promise, JSPromise::kFlagsOffset, SmiConstant(0));
     34 }
     35 
     36 Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context) {
     37   return AllocateAndInitJSPromise(context, UndefinedConstant());
     38 }
     39 
     40 Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context,
     41                                                          Node* parent) {
     42   Node* const instance = AllocateJSPromise(context);
     43   PromiseInit(instance);
     44 
     45   Label out(this);
     46   GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &out);
     47   CallRuntime(Runtime::kPromiseHookInit, context, instance, parent);
     48   Goto(&out);
     49 
     50   Bind(&out);
     51   return instance;
     52 }
     53 
     54 Node* PromiseBuiltinsAssembler::AllocateAndSetJSPromise(Node* context,
     55                                                         Node* status,
     56                                                         Node* result) {
     57   CSA_ASSERT(this, TaggedIsSmi(status));
     58 
     59   Node* const instance = AllocateJSPromise(context);
     60 
     61   StoreObjectFieldNoWriteBarrier(instance, JSPromise::kStatusOffset, status);
     62   StoreObjectFieldNoWriteBarrier(instance, JSPromise::kResultOffset, result);
     63   StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset,
     64                                  SmiConstant(0));
     65 
     66   Label out(this);
     67   GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &out);
     68   CallRuntime(Runtime::kPromiseHookInit, context, instance,
     69               UndefinedConstant());
     70   Goto(&out);
     71 
     72   Bind(&out);
     73   return instance;
     74 }
     75 
     76 std::pair<Node*, Node*>
     77 PromiseBuiltinsAssembler::CreatePromiseResolvingFunctions(
     78     Node* promise, Node* debug_event, Node* native_context) {
     79   Node* const promise_context = CreatePromiseResolvingFunctionsContext(
     80       promise, debug_event, native_context);
     81   Node* const map = LoadContextElement(
     82       native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
     83   Node* const resolve_info =
     84       LoadContextElement(native_context, Context::PROMISE_RESOLVE_SHARED_FUN);
     85   Node* const resolve =
     86       AllocateFunctionWithMapAndContext(map, resolve_info, promise_context);
     87   Node* const reject_info =
     88       LoadContextElement(native_context, Context::PROMISE_REJECT_SHARED_FUN);
     89   Node* const reject =
     90       AllocateFunctionWithMapAndContext(map, reject_info, promise_context);
     91   return std::make_pair(resolve, reject);
     92 }
     93 
     94 Node* PromiseBuiltinsAssembler::NewPromiseCapability(Node* context,
     95                                                      Node* constructor,
     96                                                      Node* debug_event) {
     97   if (debug_event == nullptr) {
     98     debug_event = TrueConstant();
     99   }
    100 
    101   Node* native_context = LoadNativeContext(context);
    102 
    103   Node* map = LoadRoot(Heap::kJSPromiseCapabilityMapRootIndex);
    104   Node* capability = AllocateJSObjectFromMap(map);
    105 
    106   StoreObjectFieldNoWriteBarrier(
    107       capability, JSPromiseCapability::kPromiseOffset, UndefinedConstant());
    108   StoreObjectFieldNoWriteBarrier(
    109       capability, JSPromiseCapability::kResolveOffset, UndefinedConstant());
    110   StoreObjectFieldNoWriteBarrier(capability, JSPromiseCapability::kRejectOffset,
    111                                  UndefinedConstant());
    112 
    113   Variable var_result(this, MachineRepresentation::kTagged);
    114   var_result.Bind(capability);
    115 
    116   Label if_builtin_promise(this), if_custom_promise(this, Label::kDeferred),
    117       out(this);
    118   Branch(WordEqual(constructor,
    119                    LoadContextElement(native_context,
    120                                       Context::PROMISE_FUNCTION_INDEX)),
    121          &if_builtin_promise, &if_custom_promise);
    122 
    123   Bind(&if_builtin_promise);
    124   {
    125     Node* promise = AllocateJSPromise(context);
    126     PromiseInit(promise);
    127     StoreObjectFieldNoWriteBarrier(
    128         capability, JSPromiseCapability::kPromiseOffset, promise);
    129 
    130     Node* resolve = nullptr;
    131     Node* reject = nullptr;
    132 
    133     std::tie(resolve, reject) =
    134         CreatePromiseResolvingFunctions(promise, debug_event, native_context);
    135     StoreObjectField(capability, JSPromiseCapability::kResolveOffset, resolve);
    136     StoreObjectField(capability, JSPromiseCapability::kRejectOffset, reject);
    137 
    138     GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &out);
    139     CallRuntime(Runtime::kPromiseHookInit, context, promise,
    140                 UndefinedConstant());
    141     Goto(&out);
    142   }
    143 
    144   Bind(&if_custom_promise);
    145   {
    146     Label if_notcallable(this, Label::kDeferred);
    147     Node* executor_context =
    148         CreatePromiseGetCapabilitiesExecutorContext(capability, native_context);
    149     Node* executor_info = LoadContextElement(
    150         native_context, Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN);
    151     Node* function_map = LoadContextElement(
    152         native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
    153     Node* executor = AllocateFunctionWithMapAndContext(
    154         function_map, executor_info, executor_context);
    155 
    156     Node* promise = ConstructJS(CodeFactory::Construct(isolate()), context,
    157                                 constructor, executor);
    158 
    159     Node* resolve =
    160         LoadObjectField(capability, JSPromiseCapability::kResolveOffset);
    161     GotoIf(TaggedIsSmi(resolve), &if_notcallable);
    162     GotoIfNot(IsCallableMap(LoadMap(resolve)), &if_notcallable);
    163 
    164     Node* reject =
    165         LoadObjectField(capability, JSPromiseCapability::kRejectOffset);
    166     GotoIf(TaggedIsSmi(reject), &if_notcallable);
    167     GotoIfNot(IsCallableMap(LoadMap(reject)), &if_notcallable);
    168 
    169     StoreObjectField(capability, JSPromiseCapability::kPromiseOffset, promise);
    170 
    171     Goto(&out);
    172 
    173     Bind(&if_notcallable);
    174     Node* message = SmiConstant(MessageTemplate::kPromiseNonCallable);
    175     StoreObjectField(capability, JSPromiseCapability::kPromiseOffset,
    176                      UndefinedConstant());
    177     StoreObjectField(capability, JSPromiseCapability::kResolveOffset,
    178                      UndefinedConstant());
    179     StoreObjectField(capability, JSPromiseCapability::kRejectOffset,
    180                      UndefinedConstant());
    181     CallRuntime(Runtime::kThrowTypeError, context, message);
    182     Unreachable();
    183   }
    184 
    185   Bind(&out);
    186   return var_result.value();
    187 }
    188 
    189 Node* PromiseBuiltinsAssembler::CreatePromiseContext(Node* native_context,
    190                                                      int slots) {
    191   DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
    192 
    193   Node* const context = Allocate(FixedArray::SizeFor(slots));
    194   StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex);
    195   StoreObjectFieldNoWriteBarrier(context, FixedArray::kLengthOffset,
    196                                  SmiConstant(slots));
    197 
    198   Node* const empty_fn =
    199       LoadContextElement(native_context, Context::CLOSURE_INDEX);
    200   StoreContextElementNoWriteBarrier(context, Context::CLOSURE_INDEX, empty_fn);
    201   StoreContextElementNoWriteBarrier(context, Context::PREVIOUS_INDEX,
    202                                     UndefinedConstant());
    203   StoreContextElementNoWriteBarrier(context, Context::EXTENSION_INDEX,
    204                                     TheHoleConstant());
    205   StoreContextElementNoWriteBarrier(context, Context::NATIVE_CONTEXT_INDEX,
    206                                     native_context);
    207   return context;
    208 }
    209 
    210 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
    211     Node* promise, Node* debug_event, Node* native_context) {
    212   Node* const context =
    213       CreatePromiseContext(native_context, kPromiseContextLength);
    214   StoreContextElementNoWriteBarrier(context, kAlreadyVisitedSlot,
    215                                     SmiConstant(0));
    216   StoreContextElementNoWriteBarrier(context, kPromiseSlot, promise);
    217   StoreContextElementNoWriteBarrier(context, kDebugEventSlot, debug_event);
    218   return context;
    219 }
    220 
    221 Node* PromiseBuiltinsAssembler::CreatePromiseGetCapabilitiesExecutorContext(
    222     Node* promise_capability, Node* native_context) {
    223   int kContextLength = kCapabilitiesContextLength;
    224   Node* context = CreatePromiseContext(native_context, kContextLength);
    225   StoreContextElementNoWriteBarrier(context, kCapabilitySlot,
    226                                     promise_capability);
    227   return context;
    228 }
    229 
    230 Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver(
    231     Node* context, Node* value, MessageTemplate::Template msg_template,
    232     const char* method_name) {
    233   Label out(this), throw_exception(this, Label::kDeferred);
    234   Variable var_value_map(this, MachineRepresentation::kTagged);
    235 
    236   GotoIf(TaggedIsSmi(value), &throw_exception);
    237 
    238   // Load the instance type of the {value}.
    239   var_value_map.Bind(LoadMap(value));
    240   Node* const value_instance_type = LoadMapInstanceType(var_value_map.value());
    241 
    242   Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception);
    243 
    244   // The {value} is not a compatible receiver for this method.
    245   Bind(&throw_exception);
    246   {
    247     Node* const method =
    248         method_name == nullptr
    249             ? UndefinedConstant()
    250             : HeapConstant(
    251                   isolate()->factory()->NewStringFromAsciiChecked(method_name));
    252     Node* const message_id = SmiConstant(msg_template);
    253     CallRuntime(Runtime::kThrowTypeError, context, message_id, method);
    254     Unreachable();
    255   }
    256 
    257   Bind(&out);
    258   return var_value_map.value();
    259 }
    260 
    261 Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) {
    262   Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
    263   return IsSetWord(SmiUntag(flags), 1 << JSPromise::kHasHandlerBit);
    264 }
    265 
    266 void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) {
    267   Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
    268   Node* const new_flags =
    269       SmiOr(flags, SmiConstant(1 << JSPromise::kHasHandlerBit));
    270   StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
    271 }
    272 
    273 void PromiseBuiltinsAssembler::PromiseSetHandledHint(Node* promise) {
    274   Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
    275   Node* const new_flags =
    276       SmiOr(flags, SmiConstant(1 << JSPromise::kHandledHintBit));
    277   StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
    278 }
    279 
    280 Node* PromiseBuiltinsAssembler::SpeciesConstructor(Node* context, Node* object,
    281                                                    Node* default_constructor) {
    282   Isolate* isolate = this->isolate();
    283   Variable var_result(this, MachineRepresentation::kTagged);
    284   var_result.Bind(default_constructor);
    285 
    286   // 2. Let C be ? Get(O, "constructor").
    287   Node* const constructor_str =
    288       HeapConstant(isolate->factory()->constructor_string());
    289   Callable getproperty_callable = CodeFactory::GetProperty(isolate);
    290   Node* const constructor =
    291       CallStub(getproperty_callable, context, object, constructor_str);
    292 
    293   // 3. If C is undefined, return defaultConstructor.
    294   Label out(this);
    295   GotoIf(IsUndefined(constructor), &out);
    296 
    297   // 4. If Type(C) is not Object, throw a TypeError exception.
    298   ThrowIfNotJSReceiver(context, constructor,
    299                        MessageTemplate::kConstructorNotReceiver);
    300 
    301   // 5. Let S be ? Get(C, @@species).
    302   Node* const species_symbol =
    303       HeapConstant(isolate->factory()->species_symbol());
    304   Node* const species =
    305       CallStub(getproperty_callable, context, constructor, species_symbol);
    306 
    307   // 6. If S is either undefined or null, return defaultConstructor.
    308   GotoIf(IsUndefined(species), &out);
    309   GotoIf(WordEqual(species, NullConstant()), &out);
    310 
    311   // 7. If IsConstructor(S) is true, return S.
    312   Label throw_error(this);
    313   Node* species_bitfield = LoadMapBitField(LoadMap(species));
    314   GotoIfNot(Word32Equal(Word32And(species_bitfield,
    315                                   Int32Constant((1 << Map::kIsConstructor))),
    316                         Int32Constant(1 << Map::kIsConstructor)),
    317             &throw_error);
    318   var_result.Bind(species);
    319   Goto(&out);
    320 
    321   // 8. Throw a TypeError exception.
    322   Bind(&throw_error);
    323   {
    324     Node* const message_id =
    325         SmiConstant(MessageTemplate::kSpeciesNotConstructor);
    326     CallRuntime(Runtime::kThrowTypeError, context, message_id);
    327     Unreachable();
    328   }
    329 
    330   Bind(&out);
    331   return var_result.value();
    332 }
    333 
    334 void PromiseBuiltinsAssembler::AppendPromiseCallback(int offset, Node* promise,
    335                                                      Node* value) {
    336   Node* elements = LoadObjectField(promise, offset);
    337   Node* length = LoadFixedArrayBaseLength(elements);
    338   CodeStubAssembler::ParameterMode mode = OptimalParameterMode();
    339   length = TaggedToParameter(length, mode);
    340 
    341   Node* delta = IntPtrOrSmiConstant(1, mode);
    342   Node* new_capacity = IntPtrOrSmiAdd(length, delta, mode);
    343 
    344   const ElementsKind kind = FAST_ELEMENTS;
    345   const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER;
    346   const CodeStubAssembler::AllocationFlags flags =
    347       CodeStubAssembler::kAllowLargeObjectAllocation;
    348   int additional_offset = 0;
    349 
    350   Node* new_elements = AllocateFixedArray(kind, new_capacity, mode, flags);
    351 
    352   CopyFixedArrayElements(kind, elements, new_elements, length, barrier_mode,
    353                          mode);
    354   StoreFixedArrayElement(new_elements, length, value, barrier_mode,
    355                          additional_offset, mode);
    356 
    357   StoreObjectField(promise, offset, new_elements);
    358 }
    359 
    360 Node* PromiseBuiltinsAssembler::InternalPromiseThen(Node* context,
    361                                                     Node* promise,
    362                                                     Node* on_resolve,
    363                                                     Node* on_reject) {
    364   Isolate* isolate = this->isolate();
    365 
    366   // 2. If IsPromise(promise) is false, throw a TypeError exception.
    367   ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
    368                          "Promise.prototype.then");
    369 
    370   Node* const native_context = LoadNativeContext(context);
    371   Node* const promise_fun =
    372       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
    373 
    374   // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
    375   Node* constructor = SpeciesConstructor(context, promise, promise_fun);
    376 
    377   // 4. Let resultCapability be ? NewPromiseCapability(C).
    378   Callable call_callable = CodeFactory::Call(isolate);
    379   Label fast_promise_capability(this), promise_capability(this),
    380       perform_promise_then(this);
    381   Variable var_deferred_promise(this, MachineRepresentation::kTagged),
    382       var_deferred_on_resolve(this, MachineRepresentation::kTagged),
    383       var_deferred_on_reject(this, MachineRepresentation::kTagged);
    384 
    385   Branch(WordEqual(promise_fun, constructor), &fast_promise_capability,
    386          &promise_capability);
    387 
    388   Bind(&fast_promise_capability);
    389   {
    390     Node* const deferred_promise = AllocateAndInitJSPromise(context, promise);
    391     var_deferred_promise.Bind(deferred_promise);
    392     var_deferred_on_resolve.Bind(UndefinedConstant());
    393     var_deferred_on_reject.Bind(UndefinedConstant());
    394     Goto(&perform_promise_then);
    395   }
    396 
    397   Bind(&promise_capability);
    398   {
    399     Node* const capability = NewPromiseCapability(context, constructor);
    400     var_deferred_promise.Bind(
    401         LoadObjectField(capability, JSPromiseCapability::kPromiseOffset));
    402     var_deferred_on_resolve.Bind(
    403         LoadObjectField(capability, JSPromiseCapability::kResolveOffset));
    404     var_deferred_on_reject.Bind(
    405         LoadObjectField(capability, JSPromiseCapability::kRejectOffset));
    406     Goto(&perform_promise_then);
    407   }
    408 
    409   // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
    410   //    resultCapability).
    411   Bind(&perform_promise_then);
    412   Node* const result = InternalPerformPromiseThen(
    413       context, promise, on_resolve, on_reject, var_deferred_promise.value(),
    414       var_deferred_on_resolve.value(), var_deferred_on_reject.value());
    415   return result;
    416 }
    417 
    418 Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
    419     Node* context, Node* promise, Node* on_resolve, Node* on_reject,
    420     Node* deferred_promise, Node* deferred_on_resolve,
    421     Node* deferred_on_reject) {
    422 
    423   Variable var_on_resolve(this, MachineRepresentation::kTagged),
    424       var_on_reject(this, MachineRepresentation::kTagged);
    425 
    426   var_on_resolve.Bind(on_resolve);
    427   var_on_reject.Bind(on_reject);
    428 
    429   Label out(this), if_onresolvenotcallable(this), onrejectcheck(this),
    430       append_callbacks(this);
    431   GotoIf(TaggedIsSmi(on_resolve), &if_onresolvenotcallable);
    432 
    433   Isolate* isolate = this->isolate();
    434   Node* const on_resolve_map = LoadMap(on_resolve);
    435   Branch(IsCallableMap(on_resolve_map), &onrejectcheck,
    436          &if_onresolvenotcallable);
    437 
    438   Bind(&if_onresolvenotcallable);
    439   {
    440     Node* const default_resolve_handler_symbol = HeapConstant(
    441         isolate->factory()->promise_default_resolve_handler_symbol());
    442     var_on_resolve.Bind(default_resolve_handler_symbol);
    443     Goto(&onrejectcheck);
    444   }
    445 
    446   Bind(&onrejectcheck);
    447   {
    448     Label if_onrejectnotcallable(this);
    449     GotoIf(TaggedIsSmi(on_reject), &if_onrejectnotcallable);
    450 
    451     Node* const on_reject_map = LoadMap(on_reject);
    452     Branch(IsCallableMap(on_reject_map), &append_callbacks,
    453            &if_onrejectnotcallable);
    454 
    455     Bind(&if_onrejectnotcallable);
    456     {
    457       Node* const default_reject_handler_symbol = HeapConstant(
    458           isolate->factory()->promise_default_reject_handler_symbol());
    459       var_on_reject.Bind(default_reject_handler_symbol);
    460       Goto(&append_callbacks);
    461     }
    462   }
    463 
    464   Bind(&append_callbacks);
    465   {
    466     Label fulfilled_check(this);
    467     Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset);
    468     GotoIfNot(SmiEqual(status, SmiConstant(v8::Promise::kPending)),
    469               &fulfilled_check);
    470 
    471     Node* const existing_deferred_promise =
    472         LoadObjectField(promise, JSPromise::kDeferredPromiseOffset);
    473 
    474     Label if_noexistingcallbacks(this), if_existingcallbacks(this);
    475     Branch(IsUndefined(existing_deferred_promise), &if_noexistingcallbacks,
    476            &if_existingcallbacks);
    477 
    478     Bind(&if_noexistingcallbacks);
    479     {
    480       // Store callbacks directly in the slots.
    481       StoreObjectField(promise, JSPromise::kDeferredPromiseOffset,
    482                        deferred_promise);
    483       StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset,
    484                        deferred_on_resolve);
    485       StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset,
    486                        deferred_on_reject);
    487       StoreObjectField(promise, JSPromise::kFulfillReactionsOffset,
    488                        var_on_resolve.value());
    489       StoreObjectField(promise, JSPromise::kRejectReactionsOffset,
    490                        var_on_reject.value());
    491       Goto(&out);
    492     }
    493 
    494     Bind(&if_existingcallbacks);
    495     {
    496       Label if_singlecallback(this), if_multiplecallbacks(this);
    497       BranchIfJSObject(existing_deferred_promise, &if_singlecallback,
    498                        &if_multiplecallbacks);
    499 
    500       Bind(&if_singlecallback);
    501       {
    502         // Create new FixedArrays to store callbacks, and migrate
    503         // existing callbacks.
    504         Node* const deferred_promise_arr =
    505             AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
    506         StoreFixedArrayElement(deferred_promise_arr, 0,
    507                                existing_deferred_promise);
    508         StoreFixedArrayElement(deferred_promise_arr, 1, deferred_promise);
    509 
    510         Node* const deferred_on_resolve_arr =
    511             AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
    512         StoreFixedArrayElement(
    513             deferred_on_resolve_arr, 0,
    514             LoadObjectField(promise, JSPromise::kDeferredOnResolveOffset));
    515         StoreFixedArrayElement(deferred_on_resolve_arr, 1, deferred_on_resolve);
    516 
    517         Node* const deferred_on_reject_arr =
    518             AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
    519         StoreFixedArrayElement(
    520             deferred_on_reject_arr, 0,
    521             LoadObjectField(promise, JSPromise::kDeferredOnRejectOffset));
    522         StoreFixedArrayElement(deferred_on_reject_arr, 1, deferred_on_reject);
    523 
    524         Node* const fulfill_reactions =
    525             AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
    526         StoreFixedArrayElement(
    527             fulfill_reactions, 0,
    528             LoadObjectField(promise, JSPromise::kFulfillReactionsOffset));
    529         StoreFixedArrayElement(fulfill_reactions, 1, var_on_resolve.value());
    530 
    531         Node* const reject_reactions =
    532             AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
    533         StoreFixedArrayElement(
    534             reject_reactions, 0,
    535             LoadObjectField(promise, JSPromise::kRejectReactionsOffset));
    536         StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value());
    537 
    538         // Store new FixedArrays in promise.
    539         StoreObjectField(promise, JSPromise::kDeferredPromiseOffset,
    540                          deferred_promise_arr);
    541         StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset,
    542                          deferred_on_resolve_arr);
    543         StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset,
    544                          deferred_on_reject_arr);
    545         StoreObjectField(promise, JSPromise::kFulfillReactionsOffset,
    546                          fulfill_reactions);
    547         StoreObjectField(promise, JSPromise::kRejectReactionsOffset,
    548                          reject_reactions);
    549         Goto(&out);
    550       }
    551 
    552       Bind(&if_multiplecallbacks);
    553       {
    554         AppendPromiseCallback(JSPromise::kDeferredPromiseOffset, promise,
    555                               deferred_promise);
    556         AppendPromiseCallback(JSPromise::kDeferredOnResolveOffset, promise,
    557                               deferred_on_resolve);
    558         AppendPromiseCallback(JSPromise::kDeferredOnRejectOffset, promise,
    559                               deferred_on_reject);
    560         AppendPromiseCallback(JSPromise::kFulfillReactionsOffset, promise,
    561                               var_on_resolve.value());
    562         AppendPromiseCallback(JSPromise::kRejectReactionsOffset, promise,
    563                               var_on_reject.value());
    564         Goto(&out);
    565       }
    566     }
    567 
    568     Bind(&fulfilled_check);
    569     {
    570       Label reject(this);
    571       Node* const result = LoadObjectField(promise, JSPromise::kResultOffset);
    572       GotoIfNot(WordEqual(status, SmiConstant(v8::Promise::kFulfilled)),
    573                 &reject);
    574 
    575       Node* info = AllocatePromiseReactionJobInfo(
    576           result, var_on_resolve.value(), deferred_promise, deferred_on_resolve,
    577           deferred_on_reject, context);
    578       // TODO(gsathya): Move this to TF
    579       CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info);
    580       Goto(&out);
    581 
    582       Bind(&reject);
    583       {
    584         Node* const has_handler = PromiseHasHandler(promise);
    585         Label enqueue(this);
    586 
    587         // TODO(gsathya): Fold these runtime calls and move to TF.
    588         GotoIf(has_handler, &enqueue);
    589         CallRuntime(Runtime::kPromiseRevokeReject, context, promise);
    590         Goto(&enqueue);
    591 
    592         Bind(&enqueue);
    593         {
    594           Node* info = AllocatePromiseReactionJobInfo(
    595               result, var_on_reject.value(), deferred_promise,
    596               deferred_on_resolve, deferred_on_reject, context);
    597           // TODO(gsathya): Move this to TF
    598           CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info);
    599           Goto(&out);
    600         }
    601       }
    602     }
    603   }
    604 
    605   Bind(&out);
    606   PromiseSetHasHandler(promise);
    607   return deferred_promise;
    608 }
    609 
    610 // Promise fast path implementations rely on unmodified JSPromise instances.
    611 // We use a fairly coarse granularity for this and simply check whether both
    612 // the promise itself is unmodified (i.e. its map has not changed) and its
    613 // prototype is unmodified.
    614 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp
    615 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise,
    616                                                 Label* if_isunmodified,
    617                                                 Label* if_ismodified) {
    618   Node* const native_context = LoadNativeContext(context);
    619   Node* const promise_fun =
    620       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
    621   BranchIfFastPath(native_context, promise_fun, promise, if_isunmodified,
    622                    if_ismodified);
    623 }
    624 
    625 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* native_context,
    626                                                 Node* promise_fun,
    627                                                 Node* promise,
    628                                                 Label* if_isunmodified,
    629                                                 Label* if_ismodified) {
    630   CSA_ASSERT(this, IsNativeContext(native_context));
    631   CSA_ASSERT(this,
    632              WordEqual(promise_fun,
    633                        LoadContextElement(native_context,
    634                                           Context::PROMISE_FUNCTION_INDEX)));
    635 
    636   Node* const map = LoadMap(promise);
    637   Node* const initial_map =
    638       LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
    639   Node* const has_initialmap = WordEqual(map, initial_map);
    640 
    641   GotoIfNot(has_initialmap, if_ismodified);
    642 
    643   Node* const initial_proto_initial_map =
    644       LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX);
    645   Node* const proto_map = LoadMap(LoadMapPrototype(map));
    646   Node* const proto_has_initialmap =
    647       WordEqual(proto_map, initial_proto_initial_map);
    648 
    649   Branch(proto_has_initialmap, if_isunmodified, if_ismodified);
    650 }
    651 
    652 Node* PromiseBuiltinsAssembler::AllocatePromiseResolveThenableJobInfo(
    653     Node* thenable, Node* then, Node* resolve, Node* reject, Node* context) {
    654   Node* const info = Allocate(PromiseResolveThenableJobInfo::kSize);
    655   StoreMapNoWriteBarrier(info,
    656                          Heap::kPromiseResolveThenableJobInfoMapRootIndex);
    657   StoreObjectFieldNoWriteBarrier(
    658       info, PromiseResolveThenableJobInfo::kThenableOffset, thenable);
    659   StoreObjectFieldNoWriteBarrier(
    660       info, PromiseResolveThenableJobInfo::kThenOffset, then);
    661   StoreObjectFieldNoWriteBarrier(
    662       info, PromiseResolveThenableJobInfo::kResolveOffset, resolve);
    663   StoreObjectFieldNoWriteBarrier(
    664       info, PromiseResolveThenableJobInfo::kRejectOffset, reject);
    665   StoreObjectFieldNoWriteBarrier(
    666       info, PromiseResolveThenableJobInfo::kContextOffset, context);
    667   return info;
    668 }
    669 
    670 void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
    671                                                       Node* promise,
    672                                                       Node* result) {
    673   Isolate* isolate = this->isolate();
    674 
    675   Variable var_reason(this, MachineRepresentation::kTagged),
    676       var_then(this, MachineRepresentation::kTagged);
    677 
    678   Label do_enqueue(this), fulfill(this), if_cycle(this, Label::kDeferred),
    679       if_rejectpromise(this, Label::kDeferred), out(this);
    680 
    681   Label cycle_check(this);
    682   GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &cycle_check);
    683   CallRuntime(Runtime::kPromiseHookResolve, context, promise);
    684   Goto(&cycle_check);
    685 
    686   Bind(&cycle_check);
    687   // 6. If SameValue(resolution, promise) is true, then
    688   GotoIf(SameValue(promise, result, context), &if_cycle);
    689 
    690   // 7. If Type(resolution) is not Object, then
    691   GotoIf(TaggedIsSmi(result), &fulfill);
    692   GotoIfNot(IsJSReceiver(result), &fulfill);
    693 
    694   Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred);
    695   Node* const native_context = LoadNativeContext(context);
    696   Node* const promise_fun =
    697       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
    698   BranchIfFastPath(native_context, promise_fun, result, &if_nativepromise,
    699                    &if_notnativepromise);
    700 
    701   // Resolution is a native promise and if it's already resolved or
    702   // rejected, shortcircuit the resolution procedure by directly
    703   // reusing the value from the promise.
    704   Bind(&if_nativepromise);
    705   {
    706     Node* const thenable_status =
    707         LoadObjectField(result, JSPromise::kStatusOffset);
    708     Node* const thenable_value =
    709         LoadObjectField(result, JSPromise::kResultOffset);
    710 
    711     Label if_isnotpending(this);
    712     GotoIfNot(SmiEqual(SmiConstant(v8::Promise::kPending), thenable_status),
    713               &if_isnotpending);
    714 
    715     // TODO(gsathya): Use a marker here instead of the actual then
    716     // callback, and check for the marker in PromiseResolveThenableJob
    717     // and perform PromiseThen.
    718     Node* const then =
    719         LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
    720     var_then.Bind(then);
    721     Goto(&do_enqueue);
    722 
    723     Bind(&if_isnotpending);
    724     {
    725       Label if_fulfilled(this), if_rejected(this);
    726       Branch(SmiEqual(SmiConstant(v8::Promise::kFulfilled), thenable_status),
    727              &if_fulfilled, &if_rejected);
    728 
    729       Bind(&if_fulfilled);
    730       {
    731         PromiseFulfill(context, promise, thenable_value,
    732                        v8::Promise::kFulfilled);
    733         PromiseSetHasHandler(promise);
    734         Goto(&out);
    735       }
    736 
    737       Bind(&if_rejected);
    738       {
    739         Label reject(this);
    740         Node* const has_handler = PromiseHasHandler(result);
    741 
    742         // Promise has already been rejected, but had no handler.
    743         // Revoke previously triggered reject event.
    744         GotoIf(has_handler, &reject);
    745         CallRuntime(Runtime::kPromiseRevokeReject, context, result);
    746         Goto(&reject);
    747 
    748         Bind(&reject);
    749         // Don't cause a debug event as this case is forwarding a rejection
    750         InternalPromiseReject(context, promise, thenable_value, false);
    751         PromiseSetHasHandler(result);
    752         Goto(&out);
    753       }
    754     }
    755   }
    756 
    757   Bind(&if_notnativepromise);
    758   {
    759     // 8. Let then be Get(resolution, "then").
    760     Node* const then_str = HeapConstant(isolate->factory()->then_string());
    761     Callable getproperty_callable = CodeFactory::GetProperty(isolate);
    762     Node* const then =
    763         CallStub(getproperty_callable, context, result, then_str);
    764 
    765     // 9. If then is an abrupt completion, then
    766     GotoIfException(then, &if_rejectpromise, &var_reason);
    767 
    768     // 11. If IsCallable(thenAction) is false, then
    769     GotoIf(TaggedIsSmi(then), &fulfill);
    770     Node* const then_map = LoadMap(then);
    771     GotoIfNot(IsCallableMap(then_map), &fulfill);
    772     var_then.Bind(then);
    773     Goto(&do_enqueue);
    774   }
    775 
    776   Bind(&do_enqueue);
    777   {
    778     // TODO(gsathya): Add fast path for native promises with unmodified
    779     // PromiseThen (which don't need these resolving functions, but
    780     // instead can just call resolve/reject directly).
    781     Node* resolve = nullptr;
    782     Node* reject = nullptr;
    783     std::tie(resolve, reject) = CreatePromiseResolvingFunctions(
    784         promise, FalseConstant(), native_context);
    785 
    786     Node* const info = AllocatePromiseResolveThenableJobInfo(
    787         result, var_then.value(), resolve, reject, context);
    788 
    789     Label enqueue(this);
    790     GotoIfNot(IsDebugActive(), &enqueue);
    791 
    792     GotoIf(TaggedIsSmi(result), &enqueue);
    793     GotoIfNot(HasInstanceType(result, JS_PROMISE_TYPE), &enqueue);
    794 
    795     // Mark the dependency of the new promise on the resolution
    796     Node* const key =
    797         HeapConstant(isolate->factory()->promise_handled_by_symbol());
    798     CallRuntime(Runtime::kSetProperty, context, result, key, promise,
    799                 SmiConstant(STRICT));
    800     Goto(&enqueue);
    801 
    802     // 12. Perform EnqueueJob("PromiseJobs",
    803     // PromiseResolveThenableJob,  promise, resolution, thenAction).
    804     Bind(&enqueue);
    805     // TODO(gsathya): Move this to TF
    806     CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, info);
    807     Goto(&out);
    808   }
    809 
    810   // 7.b Return FulfillPromise(promise, resolution).
    811   Bind(&fulfill);
    812   {
    813     PromiseFulfill(context, promise, result, v8::Promise::kFulfilled);
    814     Goto(&out);
    815   }
    816 
    817   Bind(&if_cycle);
    818   {
    819     // 6.a Let selfResolutionError be a newly created TypeError object.
    820     Node* const message_id = SmiConstant(MessageTemplate::kPromiseCyclic);
    821     Node* const error =
    822         CallRuntime(Runtime::kNewTypeError, context, message_id, result);
    823     var_reason.Bind(error);
    824 
    825     // 6.b Return RejectPromise(promise, selfResolutionError).
    826     Goto(&if_rejectpromise);
    827   }
    828 
    829   // 9.a Return RejectPromise(promise, then.[[Value]]).
    830   Bind(&if_rejectpromise);
    831   {
    832     InternalPromiseReject(context, promise, var_reason.value(), true);
    833     Goto(&out);
    834   }
    835 
    836   Bind(&out);
    837 }
    838 
    839 void PromiseBuiltinsAssembler::PromiseFulfill(
    840     Node* context, Node* promise, Node* result,
    841     v8::Promise::PromiseState status) {
    842   Label do_promisereset(this), debug_async_event_enqueue_recurring(this);
    843 
    844   Node* const status_smi = SmiConstant(static_cast<int>(status));
    845   Node* const deferred_promise =
    846       LoadObjectField(promise, JSPromise::kDeferredPromiseOffset);
    847 
    848   GotoIf(IsUndefined(deferred_promise), &debug_async_event_enqueue_recurring);
    849 
    850   Node* const tasks =
    851       status == v8::Promise::kFulfilled
    852           ? LoadObjectField(promise, JSPromise::kFulfillReactionsOffset)
    853           : LoadObjectField(promise, JSPromise::kRejectReactionsOffset);
    854 
    855   Node* const deferred_on_resolve =
    856       LoadObjectField(promise, JSPromise::kDeferredOnResolveOffset);
    857   Node* const deferred_on_reject =
    858       LoadObjectField(promise, JSPromise::kDeferredOnRejectOffset);
    859 
    860   Node* const info = AllocatePromiseReactionJobInfo(
    861       result, tasks, deferred_promise, deferred_on_resolve, deferred_on_reject,
    862       context);
    863 
    864   CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info);
    865   Goto(&debug_async_event_enqueue_recurring);
    866 
    867   Bind(&debug_async_event_enqueue_recurring);
    868   {
    869     GotoIfNot(IsDebugActive(), &do_promisereset);
    870     CallRuntime(Runtime::kDebugAsyncEventEnqueueRecurring, context, promise,
    871                 status_smi);
    872     Goto(&do_promisereset);
    873   }
    874 
    875   Bind(&do_promisereset);
    876   {
    877     StoreObjectField(promise, JSPromise::kStatusOffset, status_smi);
    878     StoreObjectField(promise, JSPromise::kResultOffset, result);
    879     StoreObjectFieldRoot(promise, JSPromise::kDeferredPromiseOffset,
    880                          Heap::kUndefinedValueRootIndex);
    881     StoreObjectFieldRoot(promise, JSPromise::kDeferredOnResolveOffset,
    882                          Heap::kUndefinedValueRootIndex);
    883     StoreObjectFieldRoot(promise, JSPromise::kDeferredOnRejectOffset,
    884                          Heap::kUndefinedValueRootIndex);
    885     StoreObjectFieldRoot(promise, JSPromise::kFulfillReactionsOffset,
    886                          Heap::kUndefinedValueRootIndex);
    887     StoreObjectFieldRoot(promise, JSPromise::kRejectReactionsOffset,
    888                          Heap::kUndefinedValueRootIndex);
    889   }
    890 }
    891 
    892 void PromiseBuiltinsAssembler::BranchIfAccessCheckFailed(
    893     Node* context, Node* native_context, Node* promise_constructor,
    894     Node* executor, Label* if_noaccess) {
    895   Variable var_executor(this, MachineRepresentation::kTagged);
    896   var_executor.Bind(executor);
    897   Label has_access(this), call_runtime(this, Label::kDeferred);
    898 
    899   // If executor is a bound function, load the bound function until we've
    900   // reached an actual function.
    901   Label found_function(this), loop_over_bound_function(this, &var_executor);
    902   Goto(&loop_over_bound_function);
    903   Bind(&loop_over_bound_function);
    904   {
    905     Node* executor_type = LoadInstanceType(var_executor.value());
    906     GotoIf(InstanceTypeEqual(executor_type, JS_FUNCTION_TYPE), &found_function);
    907     GotoIfNot(InstanceTypeEqual(executor_type, JS_BOUND_FUNCTION_TYPE),
    908               &call_runtime);
    909     var_executor.Bind(LoadObjectField(
    910         var_executor.value(), JSBoundFunction::kBoundTargetFunctionOffset));
    911     Goto(&loop_over_bound_function);
    912   }
    913 
    914   // Load the context from the function and compare it to the Promise
    915   // constructor's context. If they match, everything is fine, otherwise, bail
    916   // out to the runtime.
    917   Bind(&found_function);
    918   {
    919     Node* function_context =
    920         LoadObjectField(var_executor.value(), JSFunction::kContextOffset);
    921     Node* native_function_context = LoadNativeContext(function_context);
    922     Branch(WordEqual(native_context, native_function_context), &has_access,
    923            &call_runtime);
    924   }
    925 
    926   Bind(&call_runtime);
    927   {
    928     Branch(WordEqual(CallRuntime(Runtime::kAllowDynamicFunction, context,
    929                                  promise_constructor),
    930                      BooleanConstant(true)),
    931            &has_access, if_noaccess);
    932   }
    933 
    934   Bind(&has_access);
    935 }
    936 
    937 void PromiseBuiltinsAssembler::InternalPromiseReject(Node* context,
    938                                                      Node* promise, Node* value,
    939                                                      Node* debug_event) {
    940   Label out(this);
    941   GotoIfNot(IsDebugActive(), &out);
    942   GotoIfNot(WordEqual(TrueConstant(), debug_event), &out);
    943   CallRuntime(Runtime::kDebugPromiseReject, context, promise, value);
    944   Goto(&out);
    945 
    946   Bind(&out);
    947   InternalPromiseReject(context, promise, value, false);
    948 }
    949 
    950 // This duplicates a lot of logic from PromiseRejectEvent in
    951 // runtime-promise.cc
    952 void PromiseBuiltinsAssembler::InternalPromiseReject(Node* context,
    953                                                      Node* promise, Node* value,
    954                                                      bool debug_event) {
    955   Label fulfill(this), report_unhandledpromise(this), run_promise_hook(this);
    956 
    957   if (debug_event) {
    958     GotoIfNot(IsDebugActive(), &run_promise_hook);
    959     CallRuntime(Runtime::kDebugPromiseReject, context, promise, value);
    960     Goto(&run_promise_hook);
    961   } else {
    962     Goto(&run_promise_hook);
    963   }
    964 
    965   Bind(&run_promise_hook);
    966   {
    967     GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &report_unhandledpromise);
    968     CallRuntime(Runtime::kPromiseHookResolve, context, promise);
    969     Goto(&report_unhandledpromise);
    970   }
    971 
    972   Bind(&report_unhandledpromise);
    973   {
    974     GotoIf(PromiseHasHandler(promise), &fulfill);
    975     CallRuntime(Runtime::kReportPromiseReject, context, promise, value);
    976     Goto(&fulfill);
    977   }
    978 
    979   Bind(&fulfill);
    980   PromiseFulfill(context, promise, value, v8::Promise::kRejected);
    981 }
    982 
    983 // ES#sec-promise-reject-functions
    984 // Promise Reject Functions
    985 TF_BUILTIN(PromiseRejectClosure, PromiseBuiltinsAssembler) {
    986   Node* const value = Parameter(1);
    987   Node* const context = Parameter(4);
    988 
    989   Label out(this);
    990 
    991   // 3. Let alreadyResolved be F.[[AlreadyResolved]].
    992   int has_already_visited_slot = kAlreadyVisitedSlot;
    993 
    994   Node* const has_already_visited =
    995       LoadContextElement(context, has_already_visited_slot);
    996 
    997   // 4. If alreadyResolved.[[Value]] is true, return undefined.
    998   GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out);
    999 
   1000   // 5.Set alreadyResolved.[[Value]] to true.
   1001   StoreContextElementNoWriteBarrier(context, has_already_visited_slot,
   1002                                     SmiConstant(1));
   1003 
   1004   // 2. Let promise be F.[[Promise]].
   1005   Node* const promise =
   1006       LoadContextElement(context, IntPtrConstant(kPromiseSlot));
   1007   Node* const debug_event =
   1008       LoadContextElement(context, IntPtrConstant(kDebugEventSlot));
   1009 
   1010   InternalPromiseReject(context, promise, value, debug_event);
   1011   Return(UndefinedConstant());
   1012 
   1013   Bind(&out);
   1014   Return(UndefinedConstant());
   1015 }
   1016 
   1017 TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
   1018   Node* const executor = Parameter(1);
   1019   Node* const new_target = Parameter(2);
   1020   Node* const context = Parameter(4);
   1021   Isolate* isolate = this->isolate();
   1022 
   1023   Label if_targetisundefined(this, Label::kDeferred);
   1024 
   1025   GotoIf(IsUndefined(new_target), &if_targetisundefined);
   1026 
   1027   Label if_notcallable(this, Label::kDeferred);
   1028 
   1029   GotoIf(TaggedIsSmi(executor), &if_notcallable);
   1030 
   1031   Node* const executor_map = LoadMap(executor);
   1032   GotoIfNot(IsCallableMap(executor_map), &if_notcallable);
   1033 
   1034   Node* const native_context = LoadNativeContext(context);
   1035   Node* const promise_fun =
   1036       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
   1037   Node* const is_debug_active = IsDebugActive();
   1038   Label if_targetisnotmodified(this),
   1039       if_targetismodified(this, Label::kDeferred), run_executor(this),
   1040       debug_push(this), if_noaccess(this, Label::kDeferred);
   1041 
   1042   BranchIfAccessCheckFailed(context, native_context, promise_fun, executor,
   1043                             &if_noaccess);
   1044 
   1045   Branch(WordEqual(promise_fun, new_target), &if_targetisnotmodified,
   1046          &if_targetismodified);
   1047 
   1048   Variable var_result(this, MachineRepresentation::kTagged),
   1049       var_reject_call(this, MachineRepresentation::kTagged),
   1050       var_reason(this, MachineRepresentation::kTagged);
   1051 
   1052   Bind(&if_targetisnotmodified);
   1053   {
   1054     Node* const instance = AllocateAndInitJSPromise(context);
   1055     var_result.Bind(instance);
   1056     Goto(&debug_push);
   1057   }
   1058 
   1059   Bind(&if_targetismodified);
   1060   {
   1061     ConstructorBuiltinsAssembler constructor_assembler(this->state());
   1062     Node* const instance = constructor_assembler.EmitFastNewObject(
   1063         context, promise_fun, new_target);
   1064     PromiseInit(instance);
   1065     var_result.Bind(instance);
   1066 
   1067     GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &debug_push);
   1068     CallRuntime(Runtime::kPromiseHookInit, context, instance,
   1069                 UndefinedConstant());
   1070     Goto(&debug_push);
   1071   }
   1072 
   1073   Bind(&debug_push);
   1074   {
   1075     GotoIfNot(is_debug_active, &run_executor);
   1076     CallRuntime(Runtime::kDebugPushPromise, context, var_result.value());
   1077     Goto(&run_executor);
   1078   }
   1079 
   1080   Bind(&run_executor);
   1081   {
   1082     Label out(this), if_rejectpromise(this), debug_pop(this, Label::kDeferred);
   1083 
   1084     Node *resolve, *reject;
   1085     std::tie(resolve, reject) = CreatePromiseResolvingFunctions(
   1086         var_result.value(), TrueConstant(), native_context);
   1087     Callable call_callable = CodeFactory::Call(isolate);
   1088 
   1089     Node* const maybe_exception = CallJS(call_callable, context, executor,
   1090                                          UndefinedConstant(), resolve, reject);
   1091 
   1092     GotoIfException(maybe_exception, &if_rejectpromise, &var_reason);
   1093     Branch(is_debug_active, &debug_pop, &out);
   1094 
   1095     Bind(&if_rejectpromise);
   1096     {
   1097       Callable call_callable = CodeFactory::Call(isolate);
   1098       CallJS(call_callable, context, reject, UndefinedConstant(),
   1099              var_reason.value());
   1100       Branch(is_debug_active, &debug_pop, &out);
   1101     }
   1102 
   1103     Bind(&debug_pop);
   1104     {
   1105       CallRuntime(Runtime::kDebugPopPromise, context);
   1106       Goto(&out);
   1107     }
   1108     Bind(&out);
   1109     Return(var_result.value());
   1110   }
   1111 
   1112   // 1. If NewTarget is undefined, throw a TypeError exception.
   1113   Bind(&if_targetisundefined);
   1114   {
   1115     Node* const message_id = SmiConstant(MessageTemplate::kNotAPromise);
   1116     CallRuntime(Runtime::kThrowTypeError, context, message_id, new_target);
   1117     Unreachable();
   1118   }
   1119 
   1120   // 2. If IsCallable(executor) is false, throw a TypeError exception.
   1121   Bind(&if_notcallable);
   1122   {
   1123     Node* const message_id =
   1124         SmiConstant(MessageTemplate::kResolverNotAFunction);
   1125     CallRuntime(Runtime::kThrowTypeError, context, message_id, executor);
   1126     Unreachable();
   1127   }
   1128 
   1129   // Silently fail if the stack looks fishy.
   1130   Bind(&if_noaccess);
   1131   {
   1132     Node* const counter_id =
   1133         SmiConstant(v8::Isolate::kPromiseConstructorReturnedUndefined);
   1134     CallRuntime(Runtime::kIncrementUseCounter, context, counter_id);
   1135     Return(UndefinedConstant());
   1136   }
   1137 }
   1138 
   1139 TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) {
   1140   Node* const parent = Parameter(1);
   1141   Node* const context = Parameter(4);
   1142   Return(AllocateAndInitJSPromise(context, parent));
   1143 }
   1144 
   1145 TF_BUILTIN(IsPromise, PromiseBuiltinsAssembler) {
   1146   Node* const maybe_promise = Parameter(1);
   1147   Label if_notpromise(this, Label::kDeferred);
   1148 
   1149   GotoIf(TaggedIsSmi(maybe_promise), &if_notpromise);
   1150 
   1151   Node* const result =
   1152       SelectBooleanConstant(HasInstanceType(maybe_promise, JS_PROMISE_TYPE));
   1153   Return(result);
   1154 
   1155   Bind(&if_notpromise);
   1156   Return(FalseConstant());
   1157 }
   1158 
   1159 // ES#sec-promise.prototype.then
   1160 // Promise.prototype.catch ( onFulfilled, onRejected )
   1161 TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) {
   1162   // 1. Let promise be the this value.
   1163   Node* const promise = Parameter(0);
   1164   Node* const on_resolve = Parameter(1);
   1165   Node* const on_reject = Parameter(2);
   1166   Node* const context = Parameter(5);
   1167 
   1168   Node* const result =
   1169       InternalPromiseThen(context, promise, on_resolve, on_reject);
   1170   Return(result);
   1171 }
   1172 
   1173 // ES#sec-promise-resolve-functions
   1174 // Promise Resolve Functions
   1175 TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) {
   1176   Node* const value = Parameter(1);
   1177   Node* const context = Parameter(4);
   1178 
   1179   Label out(this);
   1180 
   1181   // 3. Let alreadyResolved be F.[[AlreadyResolved]].
   1182   int has_already_visited_slot = kAlreadyVisitedSlot;
   1183 
   1184   Node* const has_already_visited =
   1185       LoadContextElement(context, has_already_visited_slot);
   1186 
   1187   // 4. If alreadyResolved.[[Value]] is true, return undefined.
   1188   GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out);
   1189 
   1190   // 5.Set alreadyResolved.[[Value]] to true.
   1191   StoreContextElementNoWriteBarrier(context, has_already_visited_slot,
   1192                                     SmiConstant(1));
   1193 
   1194   // 2. Let promise be F.[[Promise]].
   1195   Node* const promise =
   1196       LoadContextElement(context, IntPtrConstant(kPromiseSlot));
   1197 
   1198   InternalResolvePromise(context, promise, value);
   1199   Return(UndefinedConstant());
   1200 
   1201   Bind(&out);
   1202   Return(UndefinedConstant());
   1203 }
   1204 
   1205 TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
   1206   Node* const promise = Parameter(1);
   1207   Node* const result = Parameter(2);
   1208   Node* const context = Parameter(5);
   1209 
   1210   InternalResolvePromise(context, promise, result);
   1211   Return(UndefinedConstant());
   1212 }
   1213 
   1214 TF_BUILTIN(PromiseHandleReject, PromiseBuiltinsAssembler) {
   1215   typedef PromiseHandleRejectDescriptor Descriptor;
   1216 
   1217   Node* const promise = Parameter(Descriptor::kPromise);
   1218   Node* const on_reject = Parameter(Descriptor::kOnReject);
   1219   Node* const exception = Parameter(Descriptor::kException);
   1220   Node* const context = Parameter(Descriptor::kContext);
   1221 
   1222   Callable call_callable = CodeFactory::Call(isolate());
   1223   Variable var_unused(this, MachineRepresentation::kTagged);
   1224 
   1225   Label if_internalhandler(this), if_customhandler(this, Label::kDeferred);
   1226   Branch(IsUndefined(on_reject), &if_internalhandler, &if_customhandler);
   1227 
   1228   Bind(&if_internalhandler);
   1229   {
   1230     InternalPromiseReject(context, promise, exception, false);
   1231     Return(UndefinedConstant());
   1232   }
   1233 
   1234   Bind(&if_customhandler);
   1235   {
   1236     CallJS(call_callable, context, on_reject, UndefinedConstant(), exception);
   1237     Return(UndefinedConstant());
   1238   }
   1239 }
   1240 
   1241 TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) {
   1242   Node* const value = Parameter(1);
   1243   Node* const handler = Parameter(2);
   1244   Node* const deferred_promise = Parameter(3);
   1245   Node* const deferred_on_resolve = Parameter(4);
   1246   Node* const deferred_on_reject = Parameter(5);
   1247   Node* const context = Parameter(8);
   1248   Isolate* isolate = this->isolate();
   1249 
   1250   Variable var_reason(this, MachineRepresentation::kTagged);
   1251 
   1252   Node* const is_debug_active = IsDebugActive();
   1253   Label run_handler(this), if_rejectpromise(this), promisehook_before(this),
   1254       promisehook_after(this), debug_pop(this);
   1255 
   1256   GotoIfNot(is_debug_active, &promisehook_before);
   1257   CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise);
   1258   Goto(&promisehook_before);
   1259 
   1260   Bind(&promisehook_before);
   1261   {
   1262     GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &run_handler);
   1263     CallRuntime(Runtime::kPromiseHookBefore, context, deferred_promise);
   1264     Goto(&run_handler);
   1265   }
   1266 
   1267   Bind(&run_handler);
   1268   {
   1269     Label if_defaulthandler(this), if_callablehandler(this),
   1270         if_internalhandler(this), if_customhandler(this, Label::kDeferred);
   1271     Variable var_result(this, MachineRepresentation::kTagged);
   1272 
   1273     Branch(IsSymbol(handler), &if_defaulthandler, &if_callablehandler);
   1274 
   1275     Bind(&if_defaulthandler);
   1276     {
   1277       Label if_resolve(this), if_reject(this);
   1278       Node* const default_resolve_handler_symbol = HeapConstant(
   1279           isolate->factory()->promise_default_resolve_handler_symbol());
   1280       Branch(WordEqual(default_resolve_handler_symbol, handler), &if_resolve,
   1281              &if_reject);
   1282 
   1283       Bind(&if_resolve);
   1284       {
   1285         var_result.Bind(value);
   1286         Branch(IsUndefined(deferred_on_resolve), &if_internalhandler,
   1287                &if_customhandler);
   1288       }
   1289 
   1290       Bind(&if_reject);
   1291       {
   1292         var_reason.Bind(value);
   1293         Goto(&if_rejectpromise);
   1294       }
   1295     }
   1296 
   1297     Bind(&if_callablehandler);
   1298     {
   1299       Callable call_callable = CodeFactory::Call(isolate);
   1300       Node* const result =
   1301           CallJS(call_callable, context, handler, UndefinedConstant(), value);
   1302       var_result.Bind(result);
   1303       GotoIfException(result, &if_rejectpromise, &var_reason);
   1304       Branch(IsUndefined(deferred_on_resolve), &if_internalhandler,
   1305              &if_customhandler);
   1306     }
   1307 
   1308     Bind(&if_internalhandler);
   1309     InternalResolvePromise(context, deferred_promise, var_result.value());
   1310     Goto(&promisehook_after);
   1311 
   1312     Bind(&if_customhandler);
   1313     {
   1314       Callable call_callable = CodeFactory::Call(isolate);
   1315       Node* const maybe_exception =
   1316           CallJS(call_callable, context, deferred_on_resolve,
   1317                  UndefinedConstant(), var_result.value());
   1318       GotoIfException(maybe_exception, &if_rejectpromise, &var_reason);
   1319       Goto(&promisehook_after);
   1320     }
   1321   }
   1322 
   1323   Bind(&if_rejectpromise);
   1324   {
   1325     Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate);
   1326     CallStub(promise_handle_reject, context, deferred_promise,
   1327              deferred_on_reject, var_reason.value());
   1328     Goto(&promisehook_after);
   1329   }
   1330 
   1331   Bind(&promisehook_after);
   1332   {
   1333     GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &debug_pop);
   1334     CallRuntime(Runtime::kPromiseHookAfter, context, deferred_promise);
   1335     Goto(&debug_pop);
   1336   }
   1337 
   1338   Bind(&debug_pop);
   1339   {
   1340     Label out(this);
   1341 
   1342     GotoIfNot(is_debug_active, &out);
   1343     CallRuntime(Runtime::kDebugPopPromise, context);
   1344     Goto(&out);
   1345 
   1346     Bind(&out);
   1347     Return(UndefinedConstant());
   1348   }
   1349 }
   1350 
   1351 // ES#sec-promise.prototype.catch
   1352 // Promise.prototype.catch ( onRejected )
   1353 TF_BUILTIN(PromiseCatch, PromiseBuiltinsAssembler) {
   1354   // 1. Let promise be the this value.
   1355   Node* const promise = Parameter(0);
   1356   Node* const on_resolve = UndefinedConstant();
   1357   Node* const on_reject = Parameter(1);
   1358   Node* const context = Parameter(4);
   1359 
   1360   Label if_internalthen(this), if_customthen(this, Label::kDeferred);
   1361   GotoIf(TaggedIsSmi(promise), &if_customthen);
   1362   BranchIfFastPath(context, promise, &if_internalthen, &if_customthen);
   1363 
   1364   Bind(&if_internalthen);
   1365   {
   1366     Node* const result =
   1367         InternalPromiseThen(context, promise, on_resolve, on_reject);
   1368     Return(result);
   1369   }
   1370 
   1371   Bind(&if_customthen);
   1372   {
   1373     Isolate* isolate = this->isolate();
   1374     Node* const then_str = HeapConstant(isolate->factory()->then_string());
   1375     Callable getproperty_callable = CodeFactory::GetProperty(isolate);
   1376     Node* const then =
   1377         CallStub(getproperty_callable, context, promise, then_str);
   1378     Callable call_callable = CodeFactory::Call(isolate);
   1379     Node* const result =
   1380         CallJS(call_callable, context, then, promise, on_resolve, on_reject);
   1381     Return(result);
   1382   }
   1383 }
   1384 
   1385 TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
   1386   //  1. Let C be the this value.
   1387   Node* receiver = Parameter(0);
   1388   Node* value = Parameter(1);
   1389   Node* context = Parameter(4);
   1390   Isolate* isolate = this->isolate();
   1391 
   1392   // 2. If Type(C) is not Object, throw a TypeError exception.
   1393   ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
   1394                        "PromiseResolve");
   1395 
   1396   Label if_valueisnativepromise(this), if_valueisnotnativepromise(this),
   1397       if_valueisnotpromise(this);
   1398 
   1399   // 3.If IsPromise(x) is true, then
   1400   GotoIf(TaggedIsSmi(value), &if_valueisnotpromise);
   1401 
   1402   // This shortcircuits the constructor lookups.
   1403   GotoIfNot(HasInstanceType(value, JS_PROMISE_TYPE), &if_valueisnotpromise);
   1404 
   1405   // This adds a fast path as non-subclassed native promises don't have
   1406   // an observable constructor lookup.
   1407   Node* const native_context = LoadNativeContext(context);
   1408   Node* const promise_fun =
   1409       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
   1410   BranchIfFastPath(native_context, promise_fun, value, &if_valueisnativepromise,
   1411                    &if_valueisnotnativepromise);
   1412 
   1413   Bind(&if_valueisnativepromise);
   1414   {
   1415     GotoIfNot(WordEqual(promise_fun, receiver), &if_valueisnotnativepromise);
   1416     Return(value);
   1417   }
   1418 
   1419   // At this point, value or/and receiver are not native promises, but
   1420   // they could be of the same subclass.
   1421   Bind(&if_valueisnotnativepromise);
   1422   {
   1423     // 3.a Let xConstructor be ? Get(x, "constructor").
   1424     // The constructor lookup is observable.
   1425     Node* const constructor_str =
   1426         HeapConstant(isolate->factory()->constructor_string());
   1427     Callable getproperty_callable = CodeFactory::GetProperty(isolate);
   1428     Node* const constructor =
   1429         CallStub(getproperty_callable, context, value, constructor_str);
   1430 
   1431     // 3.b If SameValue(xConstructor, C) is true, return x.
   1432     GotoIfNot(SameValue(constructor, receiver, context), &if_valueisnotpromise);
   1433 
   1434     Return(value);
   1435   }
   1436 
   1437   Bind(&if_valueisnotpromise);
   1438   {
   1439     Label if_nativepromise(this), if_notnativepromise(this);
   1440     BranchIfFastPath(context, receiver, &if_nativepromise,
   1441                      &if_notnativepromise);
   1442 
   1443     // This adds a fast path for native promises that don't need to
   1444     // create NewPromiseCapability.
   1445     Bind(&if_nativepromise);
   1446     {
   1447       Label do_resolve(this);
   1448 
   1449       Node* const result = AllocateAndInitJSPromise(context);
   1450       InternalResolvePromise(context, result, value);
   1451       Return(result);
   1452     }
   1453 
   1454     Bind(&if_notnativepromise);
   1455     {
   1456       // 4. Let promiseCapability be ? NewPromiseCapability(C).
   1457       Node* const capability = NewPromiseCapability(context, receiver);
   1458 
   1459       // 5. Perform ? Call(promiseCapability.[[Resolve]], undefined,  x ).
   1460       Callable call_callable = CodeFactory::Call(isolate);
   1461       Node* const resolve =
   1462           LoadObjectField(capability, JSPromiseCapability::kResolveOffset);
   1463       CallJS(call_callable, context, resolve, UndefinedConstant(), value);
   1464 
   1465       // 6. Return promiseCapability.[[Promise]].
   1466       Node* const result =
   1467           LoadObjectField(capability, JSPromiseCapability::kPromiseOffset);
   1468       Return(result);
   1469     }
   1470   }
   1471 }
   1472 
   1473 TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
   1474   Node* const resolve = Parameter(1);
   1475   Node* const reject = Parameter(2);
   1476   Node* const context = Parameter(5);
   1477 
   1478   Node* const capability = LoadContextElement(context, kCapabilitySlot);
   1479 
   1480   Label if_alreadyinvoked(this, Label::kDeferred);
   1481   GotoIf(WordNotEqual(
   1482              LoadObjectField(capability, JSPromiseCapability::kResolveOffset),
   1483              UndefinedConstant()),
   1484          &if_alreadyinvoked);
   1485   GotoIf(WordNotEqual(
   1486              LoadObjectField(capability, JSPromiseCapability::kRejectOffset),
   1487              UndefinedConstant()),
   1488          &if_alreadyinvoked);
   1489 
   1490   StoreObjectField(capability, JSPromiseCapability::kResolveOffset, resolve);
   1491   StoreObjectField(capability, JSPromiseCapability::kRejectOffset, reject);
   1492 
   1493   Return(UndefinedConstant());
   1494 
   1495   Bind(&if_alreadyinvoked);
   1496   Node* message = SmiConstant(MessageTemplate::kPromiseExecutorAlreadyInvoked);
   1497   CallRuntime(Runtime::kThrowTypeError, context, message);
   1498   Unreachable();
   1499 }
   1500 
   1501 TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
   1502   Node* constructor = Parameter(1);
   1503   Node* debug_event = Parameter(2);
   1504   Node* context = Parameter(5);
   1505 
   1506   CSA_ASSERT_JS_ARGC_EQ(this, 2);
   1507 
   1508   Return(NewPromiseCapability(context, constructor, debug_event));
   1509 }
   1510 
   1511 TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) {
   1512   // 1. Let C be the this value.
   1513   Node* const receiver = Parameter(0);
   1514   Node* const reason = Parameter(1);
   1515   Node* const context = Parameter(4);
   1516 
   1517   // 2. If Type(C) is not Object, throw a TypeError exception.
   1518   ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
   1519                        "PromiseReject");
   1520 
   1521   Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
   1522   Node* const native_context = LoadNativeContext(context);
   1523   Node* const promise_fun =
   1524       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
   1525   Branch(WordEqual(promise_fun, receiver), &if_nativepromise,
   1526          &if_custompromise);
   1527 
   1528   Bind(&if_nativepromise);
   1529   {
   1530     Node* const promise = AllocateAndSetJSPromise(
   1531         context, SmiConstant(v8::Promise::kRejected), reason);
   1532     CallRuntime(Runtime::kPromiseRejectEventFromStack, context, promise,
   1533                 reason);
   1534     Return(promise);
   1535   }
   1536 
   1537   Bind(&if_custompromise);
   1538   {
   1539     // 3. Let promiseCapability be ? NewPromiseCapability(C).
   1540     Node* const capability = NewPromiseCapability(context, receiver);
   1541 
   1542     // 4. Perform ? Call(promiseCapability.[[Reject]], undefined,  r ).
   1543     Node* const reject =
   1544         LoadObjectField(capability, JSPromiseCapability::kRejectOffset);
   1545     Callable call_callable = CodeFactory::Call(isolate());
   1546     CallJS(call_callable, context, reject, UndefinedConstant(), reason);
   1547 
   1548     // 5. Return promiseCapability.[[Promise]].
   1549     Node* const promise =
   1550         LoadObjectField(capability, JSPromiseCapability::kPromiseOffset);
   1551     Return(promise);
   1552   }
   1553 }
   1554 
   1555 TF_BUILTIN(InternalPromiseReject, PromiseBuiltinsAssembler) {
   1556   Node* const promise = Parameter(1);
   1557   Node* const reason = Parameter(2);
   1558   Node* const debug_event = Parameter(3);
   1559   Node* const context = Parameter(6);
   1560 
   1561   InternalPromiseReject(context, promise, reason, debug_event);
   1562   Return(UndefinedConstant());
   1563 }
   1564 
   1565 Node* PromiseBuiltinsAssembler::CreatePromiseFinallyContext(
   1566     Node* on_finally, Node* native_context) {
   1567   Node* const context =
   1568       CreatePromiseContext(native_context, kOnFinallyContextLength);
   1569   StoreContextElementNoWriteBarrier(context, kOnFinallySlot, on_finally);
   1570   return context;
   1571 }
   1572 
   1573 std::pair<Node*, Node*> PromiseBuiltinsAssembler::CreatePromiseFinallyFunctions(
   1574     Node* on_finally, Node* native_context) {
   1575   Node* const promise_context =
   1576       CreatePromiseFinallyContext(on_finally, native_context);
   1577   Node* const map = LoadContextElement(
   1578       native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
   1579   Node* const then_finally_info = LoadContextElement(
   1580       native_context, Context::PROMISE_THEN_FINALLY_SHARED_FUN);
   1581   Node* const then_finally = AllocateFunctionWithMapAndContext(
   1582       map, then_finally_info, promise_context);
   1583   Node* const catch_finally_info = LoadContextElement(
   1584       native_context, Context::PROMISE_CATCH_FINALLY_SHARED_FUN);
   1585   Node* const catch_finally = AllocateFunctionWithMapAndContext(
   1586       map, catch_finally_info, promise_context);
   1587   return std::make_pair(then_finally, catch_finally);
   1588 }
   1589 
   1590 TF_BUILTIN(PromiseValueThunkFinally, PromiseBuiltinsAssembler) {
   1591   Node* const context = Parameter(3);
   1592 
   1593   Node* const value = LoadContextElement(context, kOnFinallySlot);
   1594   Return(value);
   1595 }
   1596 
   1597 Node* PromiseBuiltinsAssembler::CreateValueThunkFunctionContext(
   1598     Node* value, Node* native_context) {
   1599   Node* const context =
   1600       CreatePromiseContext(native_context, kOnFinallyContextLength);
   1601   StoreContextElementNoWriteBarrier(context, kOnFinallySlot, value);
   1602   return context;
   1603 }
   1604 
   1605 Node* PromiseBuiltinsAssembler::CreateValueThunkFunction(Node* value,
   1606                                                          Node* native_context) {
   1607   Node* const value_thunk_context =
   1608       CreateValueThunkFunctionContext(value, native_context);
   1609   Node* const map = LoadContextElement(
   1610       native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
   1611   Node* const value_thunk_info = LoadContextElement(
   1612       native_context, Context::PROMISE_VALUE_THUNK_FINALLY_SHARED_FUN);
   1613   Node* const value_thunk = AllocateFunctionWithMapAndContext(
   1614       map, value_thunk_info, value_thunk_context);
   1615   return value_thunk;
   1616 }
   1617 
   1618 TF_BUILTIN(PromiseThenFinally, PromiseBuiltinsAssembler) {
   1619   CSA_ASSERT_JS_ARGC_EQ(this, 1);
   1620 
   1621   Node* const value = Parameter(1);
   1622   Node* const context = Parameter(4);
   1623 
   1624   Node* const on_finally = LoadContextElement(context, kOnFinallySlot);
   1625 
   1626   // 2.a Let result be ?  Call(onFinally, undefined).
   1627   Callable call_callable = CodeFactory::Call(isolate());
   1628   Node* result =
   1629       CallJS(call_callable, context, on_finally, UndefinedConstant());
   1630 
   1631   // 2.b Let promise be !  PromiseResolve( %Promise%, result).
   1632   Node* const promise = AllocateAndInitJSPromise(context);
   1633   InternalResolvePromise(context, promise, result);
   1634 
   1635   // 2.c Let valueThunk be equivalent to a function that returns value.
   1636   Node* native_context = LoadNativeContext(context);
   1637   Node* const value_thunk = CreateValueThunkFunction(value, native_context);
   1638 
   1639   // 2.d Let promiseCapability be !  NewPromiseCapability( %Promise%).
   1640   Node* const promise_capability = AllocateAndInitJSPromise(context, promise);
   1641 
   1642   // 2.e Return PerformPromiseThen(promise, valueThunk, undefined,
   1643   // promiseCapability).
   1644   InternalPerformPromiseThen(context, promise, value_thunk, UndefinedConstant(),
   1645                              promise_capability, UndefinedConstant(),
   1646                              UndefinedConstant());
   1647   Return(promise_capability);
   1648 }
   1649 
   1650 TF_BUILTIN(PromiseThrowerFinally, PromiseBuiltinsAssembler) {
   1651   Node* const context = Parameter(3);
   1652 
   1653   Node* const reason = LoadContextElement(context, kOnFinallySlot);
   1654   CallRuntime(Runtime::kThrow, context, reason);
   1655   Unreachable();
   1656 }
   1657 
   1658 Node* PromiseBuiltinsAssembler::CreateThrowerFunctionContext(
   1659     Node* reason, Node* native_context) {
   1660   Node* const context =
   1661       CreatePromiseContext(native_context, kOnFinallyContextLength);
   1662   StoreContextElementNoWriteBarrier(context, kOnFinallySlot, reason);
   1663   return context;
   1664 }
   1665 
   1666 Node* PromiseBuiltinsAssembler::CreateThrowerFunction(Node* reason,
   1667                                                       Node* native_context) {
   1668   Node* const thrower_context =
   1669       CreateThrowerFunctionContext(reason, native_context);
   1670   Node* const map = LoadContextElement(
   1671       native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
   1672   Node* const thrower_info = LoadContextElement(
   1673       native_context, Context::PROMISE_THROWER_FINALLY_SHARED_FUN);
   1674   Node* const thrower =
   1675       AllocateFunctionWithMapAndContext(map, thrower_info, thrower_context);
   1676   return thrower;
   1677 }
   1678 
   1679 TF_BUILTIN(PromiseCatchFinally, PromiseBuiltinsAssembler) {
   1680   CSA_ASSERT_JS_ARGC_EQ(this, 1);
   1681 
   1682   Node* const reason = Parameter(1);
   1683   Node* const context = Parameter(4);
   1684 
   1685   Node* const on_finally = LoadContextElement(context, kOnFinallySlot);
   1686 
   1687   // 2.a Let result be ?  Call(onFinally, undefined).
   1688   Callable call_callable = CodeFactory::Call(isolate());
   1689   Node* result =
   1690       CallJS(call_callable, context, on_finally, UndefinedConstant());
   1691 
   1692   // 2.b Let promise be !  PromiseResolve( %Promise%, result).
   1693   Node* const promise = AllocateAndInitJSPromise(context);
   1694   InternalResolvePromise(context, promise, result);
   1695 
   1696   // 2.c Let thrower be equivalent to a function that throws reason.
   1697   Node* native_context = LoadNativeContext(context);
   1698   Node* const thrower = CreateThrowerFunction(reason, native_context);
   1699 
   1700   // 2.d Let promiseCapability be !  NewPromiseCapability( %Promise%).
   1701   Node* const promise_capability = AllocateAndInitJSPromise(context, promise);
   1702 
   1703   // 2.e Return PerformPromiseThen(promise, thrower, undefined,
   1704   // promiseCapability).
   1705   InternalPerformPromiseThen(context, promise, thrower, UndefinedConstant(),
   1706                              promise_capability, UndefinedConstant(),
   1707                              UndefinedConstant());
   1708   Return(promise_capability);
   1709 }
   1710 
   1711 TF_BUILTIN(PromiseFinally, PromiseBuiltinsAssembler) {
   1712   CSA_ASSERT_JS_ARGC_EQ(this, 1);
   1713 
   1714   // 1.  Let promise be the this value.
   1715   Node* const promise = Parameter(0);
   1716   Node* const on_finally = Parameter(1);
   1717   Node* const context = Parameter(4);
   1718 
   1719   // 2. If IsPromise(promise) is false, throw a TypeError exception.
   1720   ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
   1721                          "Promise.prototype.finally");
   1722 
   1723   Variable var_then_finally(this, MachineRepresentation::kTagged),
   1724       var_catch_finally(this, MachineRepresentation::kTagged);
   1725 
   1726   Label if_notcallable(this, Label::kDeferred), perform_finally(this);
   1727 
   1728   // 3. Let thenFinally be !  CreateThenFinally(onFinally).
   1729   // 4. Let catchFinally be !  CreateCatchFinally(onFinally).
   1730   GotoIf(TaggedIsSmi(on_finally), &if_notcallable);
   1731   Node* const on_finally_map = LoadMap(on_finally);
   1732   GotoIfNot(IsCallableMap(on_finally_map), &if_notcallable);
   1733 
   1734   Node* const native_context = LoadNativeContext(context);
   1735   Node* then_finally = nullptr;
   1736   Node* catch_finally = nullptr;
   1737   std::tie(then_finally, catch_finally) =
   1738       CreatePromiseFinallyFunctions(on_finally, native_context);
   1739   var_then_finally.Bind(then_finally);
   1740   var_catch_finally.Bind(catch_finally);
   1741   Goto(&perform_finally);
   1742 
   1743   Bind(&if_notcallable);
   1744   {
   1745     var_then_finally.Bind(on_finally);
   1746     var_catch_finally.Bind(on_finally);
   1747     Goto(&perform_finally);
   1748   }
   1749 
   1750   // 5. Return PerformPromiseThen(promise, valueThunk, undefined,
   1751   // promiseCapability).
   1752   Bind(&perform_finally);
   1753   Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
   1754   BranchIfFastPath(context, promise, &if_nativepromise, &if_custompromise);
   1755 
   1756   Bind(&if_nativepromise);
   1757   {
   1758     Node* deferred_promise = AllocateAndInitJSPromise(context, promise);
   1759     InternalPerformPromiseThen(context, promise, var_then_finally.value(),
   1760                                var_catch_finally.value(), deferred_promise,
   1761                                UndefinedConstant(), UndefinedConstant());
   1762     Return(deferred_promise);
   1763   }
   1764 
   1765   Bind(&if_custompromise);
   1766   {
   1767     Isolate* isolate = this->isolate();
   1768     Node* const then_str = HeapConstant(isolate->factory()->then_string());
   1769     Callable getproperty_callable = CodeFactory::GetProperty(isolate);
   1770     Node* const then =
   1771         CallStub(getproperty_callable, context, promise, then_str);
   1772     Callable call_callable = CodeFactory::Call(isolate);
   1773     // 5. Return ?  Invoke(promise, "then",  thenFinally, catchFinally ).
   1774     Node* const result =
   1775         CallJS(call_callable, context, then, promise, var_then_finally.value(),
   1776                var_catch_finally.value());
   1777     Return(result);
   1778   }
   1779 }
   1780 
   1781 }  // namespace internal
   1782 }  // namespace v8
   1783