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-gen.h"
6 
7 #include "src/builtins/builtins-constructor-gen.h"
8 #include "src/builtins/builtins-iterator-gen.h"
9 #include "src/builtins/builtins-utils-gen.h"
10 #include "src/builtins/builtins.h"
11 #include "src/code-factory.h"
12 #include "src/code-stub-assembler.h"
13 #include "src/objects-inl.h"
14 #include "src/objects/js-promise.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 using compiler::Node;
20 
AllocateJSPromise(Node * context)21 Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) {
22   Node* const native_context = LoadNativeContext(context);
23   Node* const promise_fun =
24       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
25   CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(promise_fun)));
26   Node* const promise_map =
27       LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
28   Node* const promise = Allocate(JSPromise::kSizeWithEmbedderFields);
29   StoreMapNoWriteBarrier(promise, promise_map);
30   StoreObjectFieldRoot(promise, JSPromise::kPropertiesOrHashOffset,
31                        Heap::kEmptyFixedArrayRootIndex);
32   StoreObjectFieldRoot(promise, JSPromise::kElementsOffset,
33                        Heap::kEmptyFixedArrayRootIndex);
34   return promise;
35 }
36 
PromiseInit(Node * promise)37 void PromiseBuiltinsAssembler::PromiseInit(Node* promise) {
38   STATIC_ASSERT(v8::Promise::kPending == 0);
39   StoreObjectFieldNoWriteBarrier(promise, JSPromise::kReactionsOrResultOffset,
40                                  SmiConstant(Smi::kZero));
41   StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset,
42                                  SmiConstant(Smi::kZero));
43   for (int i = 0; i < v8::Promise::kEmbedderFieldCount; i++) {
44     int offset = JSPromise::kSize + i * kPointerSize;
45     StoreObjectFieldNoWriteBarrier(promise, offset, SmiConstant(Smi::kZero));
46   }
47 }
48 
AllocateAndInitJSPromise(Node * context)49 Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context) {
50   return AllocateAndInitJSPromise(context, UndefinedConstant());
51 }
52 
AllocateAndInitJSPromise(Node * context,Node * parent)53 Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context,
54                                                          Node* parent) {
55   Node* const instance = AllocateJSPromise(context);
56   PromiseInit(instance);
57 
58   Label out(this);
59   GotoIfNot(IsPromiseHookEnabledOrHasAsyncEventDelegate(), &out);
60   CallRuntime(Runtime::kPromiseHookInit, context, instance, parent);
61   Goto(&out);
62 
63   BIND(&out);
64   return instance;
65 }
66 
AllocateAndSetJSPromise(Node * context,v8::Promise::PromiseState status,Node * result)67 Node* PromiseBuiltinsAssembler::AllocateAndSetJSPromise(
68     Node* context, v8::Promise::PromiseState status, Node* result) {
69   DCHECK_NE(Promise::kPending, status);
70 
71   Node* const instance = AllocateJSPromise(context);
72   StoreObjectFieldNoWriteBarrier(instance, JSPromise::kReactionsOrResultOffset,
73                                  result);
74   STATIC_ASSERT(JSPromise::kStatusShift == 0);
75   StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset,
76                                  SmiConstant(status));
77   for (int i = 0; i < v8::Promise::kEmbedderFieldCount; i++) {
78     int offset = JSPromise::kSize + i * kPointerSize;
79     StoreObjectFieldNoWriteBarrier(instance, offset, SmiConstant(0));
80   }
81 
82   Label out(this);
83   GotoIfNot(IsPromiseHookEnabledOrHasAsyncEventDelegate(), &out);
84   CallRuntime(Runtime::kPromiseHookInit, context, instance,
85               UndefinedConstant());
86   Goto(&out);
87 
88   BIND(&out);
89   return instance;
90 }
91 
92 std::pair<Node*, Node*>
CreatePromiseResolvingFunctions(Node * promise,Node * debug_event,Node * native_context)93 PromiseBuiltinsAssembler::CreatePromiseResolvingFunctions(
94     Node* promise, Node* debug_event, Node* native_context) {
95   Node* const promise_context = CreatePromiseResolvingFunctionsContext(
96       promise, debug_event, native_context);
97   Node* const map = LoadContextElement(
98       native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
99   Node* const resolve_info = LoadContextElement(
100       native_context,
101       Context::PROMISE_CAPABILITY_DEFAULT_RESOLVE_SHARED_FUN_INDEX);
102   Node* const resolve =
103       AllocateFunctionWithMapAndContext(map, resolve_info, promise_context);
104   Node* const reject_info = LoadContextElement(
105       native_context,
106       Context::PROMISE_CAPABILITY_DEFAULT_REJECT_SHARED_FUN_INDEX);
107   Node* const reject =
108       AllocateFunctionWithMapAndContext(map, reject_info, promise_context);
109   return std::make_pair(resolve, reject);
110 }
111 
112 // ES #sec-newpromisecapability
TF_BUILTIN(NewPromiseCapability,PromiseBuiltinsAssembler)113 TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
114   Node* const context = Parameter(Descriptor::kContext);
115   Node* const constructor = Parameter(Descriptor::kConstructor);
116   Node* const debug_event = Parameter(Descriptor::kDebugEvent);
117   Node* const native_context = LoadNativeContext(context);
118 
119   Label if_not_constructor(this, Label::kDeferred),
120       if_notcallable(this, Label::kDeferred), if_fast_promise_capability(this),
121       if_slow_promise_capability(this, Label::kDeferred);
122   GotoIf(TaggedIsSmi(constructor), &if_not_constructor);
123   GotoIfNot(IsConstructorMap(LoadMap(constructor)), &if_not_constructor);
124   Branch(WordEqual(constructor,
125                    LoadContextElement(native_context,
126                                       Context::PROMISE_FUNCTION_INDEX)),
127          &if_fast_promise_capability, &if_slow_promise_capability);
128 
129   BIND(&if_fast_promise_capability);
130   {
131     Node* promise =
132         AllocateAndInitJSPromise(native_context, UndefinedConstant());
133 
134     Node* resolve = nullptr;
135     Node* reject = nullptr;
136     std::tie(resolve, reject) =
137         CreatePromiseResolvingFunctions(promise, debug_event, native_context);
138 
139     Node* capability = Allocate(PromiseCapability::kSize);
140     StoreMapNoWriteBarrier(capability, Heap::kPromiseCapabilityMapRootIndex);
141     StoreObjectFieldNoWriteBarrier(capability,
142                                    PromiseCapability::kPromiseOffset, promise);
143     StoreObjectFieldNoWriteBarrier(capability,
144                                    PromiseCapability::kResolveOffset, resolve);
145     StoreObjectFieldNoWriteBarrier(capability, PromiseCapability::kRejectOffset,
146                                    reject);
147     Return(capability);
148   }
149 
150   BIND(&if_slow_promise_capability);
151   {
152     Node* capability = Allocate(PromiseCapability::kSize);
153     StoreMapNoWriteBarrier(capability, Heap::kPromiseCapabilityMapRootIndex);
154     StoreObjectFieldRoot(capability, PromiseCapability::kPromiseOffset,
155                          Heap::kUndefinedValueRootIndex);
156     StoreObjectFieldRoot(capability, PromiseCapability::kResolveOffset,
157                          Heap::kUndefinedValueRootIndex);
158     StoreObjectFieldRoot(capability, PromiseCapability::kRejectOffset,
159                          Heap::kUndefinedValueRootIndex);
160 
161     Node* executor_context =
162         CreatePromiseGetCapabilitiesExecutorContext(capability, native_context);
163     Node* executor_info = LoadContextElement(
164         native_context, Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN);
165     Node* function_map = LoadContextElement(
166         native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
167     Node* executor = AllocateFunctionWithMapAndContext(
168         function_map, executor_info, executor_context);
169 
170     Node* promise = ConstructJS(CodeFactory::Construct(isolate()),
171                                 native_context, constructor, executor);
172     StoreObjectField(capability, PromiseCapability::kPromiseOffset, promise);
173 
174     Node* resolve =
175         LoadObjectField(capability, PromiseCapability::kResolveOffset);
176     GotoIf(TaggedIsSmi(resolve), &if_notcallable);
177     GotoIfNot(IsCallable(resolve), &if_notcallable);
178 
179     Node* reject =
180         LoadObjectField(capability, PromiseCapability::kRejectOffset);
181     GotoIf(TaggedIsSmi(reject), &if_notcallable);
182     GotoIfNot(IsCallable(reject), &if_notcallable);
183     Return(capability);
184   }
185 
186   BIND(&if_not_constructor);
187   ThrowTypeError(context, MessageTemplate::kNotConstructor, constructor);
188 
189   BIND(&if_notcallable);
190   ThrowTypeError(context, MessageTemplate::kPromiseNonCallable);
191 }
192 
CreatePromiseContext(Node * native_context,int slots)193 Node* PromiseBuiltinsAssembler::CreatePromiseContext(Node* native_context,
194                                                      int slots) {
195   DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
196 
197   Node* const context = AllocateInNewSpace(FixedArray::SizeFor(slots));
198   InitializeFunctionContext(native_context, context, slots);
199   return context;
200 }
201 
CreatePromiseAllResolveElementContext(Node * promise_capability,Node * native_context)202 Node* PromiseBuiltinsAssembler::CreatePromiseAllResolveElementContext(
203     Node* promise_capability, Node* native_context) {
204   CSA_ASSERT(this, IsNativeContext(native_context));
205 
206   // TODO(bmeurer): Manually fold this into a single allocation.
207   Node* const array_map = LoadContextElement(
208       native_context, Context::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
209   Node* const values_array = AllocateJSArray(PACKED_ELEMENTS, array_map,
210                                              IntPtrConstant(0), SmiConstant(0));
211 
212   Node* const context =
213       CreatePromiseContext(native_context, kPromiseAllResolveElementLength);
214   StoreContextElementNoWriteBarrier(
215       context, kPromiseAllResolveElementRemainingSlot, SmiConstant(1));
216   StoreContextElementNoWriteBarrier(
217       context, kPromiseAllResolveElementCapabilitySlot, promise_capability);
218   StoreContextElementNoWriteBarrier(
219       context, kPromiseAllResolveElementValuesArraySlot, values_array);
220 
221   return context;
222 }
223 
CreatePromiseAllResolveElementFunction(Node * context,TNode<Smi> index,Node * native_context)224 Node* PromiseBuiltinsAssembler::CreatePromiseAllResolveElementFunction(
225     Node* context, TNode<Smi> index, Node* native_context) {
226   CSA_ASSERT(this, SmiGreaterThan(index, SmiConstant(0)));
227   CSA_ASSERT(this, SmiLessThanOrEqual(
228                        index, SmiConstant(PropertyArray::HashField::kMax)));
229   CSA_ASSERT(this, IsNativeContext(native_context));
230 
231   Node* const map = LoadContextElement(
232       native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
233   Node* const resolve_info = LoadContextElement(
234       native_context, Context::PROMISE_ALL_RESOLVE_ELEMENT_SHARED_FUN);
235   Node* const resolve =
236       AllocateFunctionWithMapAndContext(map, resolve_info, context);
237 
238   STATIC_ASSERT(PropertyArray::kNoHashSentinel == 0);
239   StoreObjectFieldNoWriteBarrier(resolve, JSFunction::kPropertiesOrHashOffset,
240                                  index);
241 
242   return resolve;
243 }
244 
CreatePromiseResolvingFunctionsContext(Node * promise,Node * debug_event,Node * native_context)245 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
246     Node* promise, Node* debug_event, Node* native_context) {
247   Node* const context =
248       CreatePromiseContext(native_context, kPromiseContextLength);
249   StoreContextElementNoWriteBarrier(context, kPromiseSlot, promise);
250   StoreContextElementNoWriteBarrier(context, kAlreadyResolvedSlot,
251                                     FalseConstant());
252   StoreContextElementNoWriteBarrier(context, kDebugEventSlot, debug_event);
253   return context;
254 }
255 
CreatePromiseGetCapabilitiesExecutorContext(Node * promise_capability,Node * native_context)256 Node* PromiseBuiltinsAssembler::CreatePromiseGetCapabilitiesExecutorContext(
257     Node* promise_capability, Node* native_context) {
258   int kContextLength = kCapabilitiesContextLength;
259   Node* context = CreatePromiseContext(native_context, kContextLength);
260   StoreContextElementNoWriteBarrier(context, kCapabilitySlot,
261                                     promise_capability);
262   return context;
263 }
264 
PromiseHasHandler(Node * promise)265 Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) {
266   Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
267   return IsSetWord(SmiUntag(flags), 1 << JSPromise::kHasHandlerBit);
268 }
269 
PromiseSetHasHandler(Node * promise)270 void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) {
271   TNode<Smi> const flags =
272       CAST(LoadObjectField(promise, JSPromise::kFlagsOffset));
273   TNode<Smi> const new_flags =
274       SmiOr(flags, SmiConstant(1 << JSPromise::kHasHandlerBit));
275   StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
276 }
277 
IsPromiseStatus(Node * actual,v8::Promise::PromiseState expected)278 Node* PromiseBuiltinsAssembler::IsPromiseStatus(
279     Node* actual, v8::Promise::PromiseState expected) {
280   return Word32Equal(actual, Int32Constant(expected));
281 }
282 
PromiseStatus(Node * promise)283 Node* PromiseBuiltinsAssembler::PromiseStatus(Node* promise) {
284   STATIC_ASSERT(JSPromise::kStatusShift == 0);
285   TNode<Smi> const flags =
286       CAST(LoadObjectField(promise, JSPromise::kFlagsOffset));
287   return Word32And(SmiToInt32(flags), Int32Constant(JSPromise::kStatusMask));
288 }
289 
PromiseSetStatus(Node * promise,v8::Promise::PromiseState const status)290 void PromiseBuiltinsAssembler::PromiseSetStatus(
291     Node* promise, v8::Promise::PromiseState const status) {
292   CSA_ASSERT(this,
293              IsPromiseStatus(PromiseStatus(promise), v8::Promise::kPending));
294   CHECK_NE(status, v8::Promise::kPending);
295 
296   TNode<Smi> mask = SmiConstant(status);
297   TNode<Smi> const flags =
298       CAST(LoadObjectField(promise, JSPromise::kFlagsOffset));
299   StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset,
300                                  SmiOr(flags, mask));
301 }
302 
PromiseSetHandledHint(Node * promise)303 void PromiseBuiltinsAssembler::PromiseSetHandledHint(Node* promise) {
304   TNode<Smi> const flags =
305       CAST(LoadObjectField(promise, JSPromise::kFlagsOffset));
306   TNode<Smi> const new_flags =
307       SmiOr(flags, SmiConstant(1 << JSPromise::kHandledHintBit));
308   StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
309 }
310 
311 // ES #sec-performpromisethen
PerformPromiseThen(Node * context,Node * promise,Node * on_fulfilled,Node * on_rejected,Node * result_promise_or_capability)312 void PromiseBuiltinsAssembler::PerformPromiseThen(
313     Node* context, Node* promise, Node* on_fulfilled, Node* on_rejected,
314     Node* result_promise_or_capability) {
315   CSA_ASSERT(this, TaggedIsNotSmi(promise));
316   CSA_ASSERT(this, IsJSPromise(promise));
317   CSA_ASSERT(this,
318              Word32Or(IsCallable(on_fulfilled), IsUndefined(on_fulfilled)));
319   CSA_ASSERT(this, Word32Or(IsCallable(on_rejected), IsUndefined(on_rejected)));
320   CSA_ASSERT(this, TaggedIsNotSmi(result_promise_or_capability));
321   CSA_ASSERT(this, Word32Or(IsJSPromise(result_promise_or_capability),
322                             IsPromiseCapability(result_promise_or_capability)));
323 
324   Label if_pending(this), if_notpending(this), done(this);
325   Node* const status = PromiseStatus(promise);
326   Branch(IsPromiseStatus(status, v8::Promise::kPending), &if_pending,
327          &if_notpending);
328 
329   BIND(&if_pending);
330   {
331     // The {promise} is still in "Pending" state, so we just record a new
332     // PromiseReaction holding both the onFulfilled and onRejected callbacks.
333     // Once the {promise} is resolved we decide on the concrete handler to
334     // push onto the microtask queue.
335     Node* const promise_reactions =
336         LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
337     Node* const reaction =
338         AllocatePromiseReaction(promise_reactions, result_promise_or_capability,
339                                 on_fulfilled, on_rejected);
340     StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reaction);
341     Goto(&done);
342   }
343 
344   BIND(&if_notpending);
345   {
346     VARIABLE(var_map, MachineRepresentation::kTagged);
347     VARIABLE(var_handler, MachineRepresentation::kTagged);
348     Label if_fulfilled(this), if_rejected(this, Label::kDeferred),
349         enqueue(this);
350     Branch(IsPromiseStatus(status, v8::Promise::kFulfilled), &if_fulfilled,
351            &if_rejected);
352 
353     BIND(&if_fulfilled);
354     {
355       var_map.Bind(LoadRoot(Heap::kPromiseFulfillReactionJobTaskMapRootIndex));
356       var_handler.Bind(on_fulfilled);
357       Goto(&enqueue);
358     }
359 
360     BIND(&if_rejected);
361     {
362       CSA_ASSERT(this, IsPromiseStatus(status, v8::Promise::kRejected));
363       var_map.Bind(LoadRoot(Heap::kPromiseRejectReactionJobTaskMapRootIndex));
364       var_handler.Bind(on_rejected);
365       GotoIf(PromiseHasHandler(promise), &enqueue);
366       CallRuntime(Runtime::kPromiseRevokeReject, context, promise);
367       Goto(&enqueue);
368     }
369 
370     BIND(&enqueue);
371     Node* argument =
372         LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
373     Node* microtask = AllocatePromiseReactionJobTask(
374         var_map.value(), context, argument, var_handler.value(),
375         result_promise_or_capability);
376     CallBuiltin(Builtins::kEnqueueMicrotask, NoContextConstant(), microtask);
377     Goto(&done);
378   }
379 
380   BIND(&done);
381   PromiseSetHasHandler(promise);
382 }
383 
384 // ES #sec-performpromisethen
TF_BUILTIN(PerformPromiseThen,PromiseBuiltinsAssembler)385 TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) {
386   Node* const context = Parameter(Descriptor::kContext);
387   Node* const promise = Parameter(Descriptor::kPromise);
388   Node* const on_fulfilled = Parameter(Descriptor::kOnFulfilled);
389   Node* const on_rejected = Parameter(Descriptor::kOnRejected);
390   Node* const result_promise = Parameter(Descriptor::kResultPromise);
391 
392   CSA_ASSERT(this, TaggedIsNotSmi(result_promise));
393   CSA_ASSERT(this, IsJSPromise(result_promise));
394 
395   PerformPromiseThen(context, promise, on_fulfilled, on_rejected,
396                      result_promise);
397   Return(result_promise);
398 }
399 
AllocatePromiseReaction(Node * next,Node * promise_or_capability,Node * fulfill_handler,Node * reject_handler)400 Node* PromiseBuiltinsAssembler::AllocatePromiseReaction(
401     Node* next, Node* promise_or_capability, Node* fulfill_handler,
402     Node* reject_handler) {
403   Node* const reaction = Allocate(PromiseReaction::kSize);
404   StoreMapNoWriteBarrier(reaction, Heap::kPromiseReactionMapRootIndex);
405   StoreObjectFieldNoWriteBarrier(reaction, PromiseReaction::kNextOffset, next);
406   StoreObjectFieldNoWriteBarrier(reaction,
407                                  PromiseReaction::kPromiseOrCapabilityOffset,
408                                  promise_or_capability);
409   StoreObjectFieldNoWriteBarrier(
410       reaction, PromiseReaction::kFulfillHandlerOffset, fulfill_handler);
411   StoreObjectFieldNoWriteBarrier(
412       reaction, PromiseReaction::kRejectHandlerOffset, reject_handler);
413   return reaction;
414 }
415 
AllocatePromiseReactionJobTask(Node * map,Node * context,Node * argument,Node * handler,Node * promise_or_capability)416 Node* PromiseBuiltinsAssembler::AllocatePromiseReactionJobTask(
417     Node* map, Node* context, Node* argument, Node* handler,
418     Node* promise_or_capability) {
419   Node* const microtask = Allocate(PromiseReactionJobTask::kSize);
420   StoreMapNoWriteBarrier(microtask, map);
421   StoreObjectFieldNoWriteBarrier(
422       microtask, PromiseReactionJobTask::kArgumentOffset, argument);
423   StoreObjectFieldNoWriteBarrier(
424       microtask, PromiseReactionJobTask::kContextOffset, context);
425   StoreObjectFieldNoWriteBarrier(
426       microtask, PromiseReactionJobTask::kHandlerOffset, handler);
427   StoreObjectFieldNoWriteBarrier(
428       microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset,
429       promise_or_capability);
430   return microtask;
431 }
432 
AllocatePromiseReactionJobTask(Heap::RootListIndex map_root_index,Node * context,Node * argument,Node * handler,Node * promise_or_capability)433 Node* PromiseBuiltinsAssembler::AllocatePromiseReactionJobTask(
434     Heap::RootListIndex map_root_index, Node* context, Node* argument,
435     Node* handler, Node* promise_or_capability) {
436   DCHECK(map_root_index == Heap::kPromiseFulfillReactionJobTaskMapRootIndex ||
437          map_root_index == Heap::kPromiseRejectReactionJobTaskMapRootIndex);
438   Node* const map = LoadRoot(map_root_index);
439   return AllocatePromiseReactionJobTask(map, context, argument, handler,
440                                         promise_or_capability);
441 }
442 
AllocatePromiseResolveThenableJobTask(Node * promise_to_resolve,Node * then,Node * thenable,Node * context)443 Node* PromiseBuiltinsAssembler::AllocatePromiseResolveThenableJobTask(
444     Node* promise_to_resolve, Node* then, Node* thenable, Node* context) {
445   Node* const microtask = Allocate(PromiseResolveThenableJobTask::kSize);
446   StoreMapNoWriteBarrier(microtask,
447                          Heap::kPromiseResolveThenableJobTaskMapRootIndex);
448   StoreObjectFieldNoWriteBarrier(
449       microtask, PromiseResolveThenableJobTask::kContextOffset, context);
450   StoreObjectFieldNoWriteBarrier(
451       microtask, PromiseResolveThenableJobTask::kPromiseToResolveOffset,
452       promise_to_resolve);
453   StoreObjectFieldNoWriteBarrier(
454       microtask, PromiseResolveThenableJobTask::kThenOffset, then);
455   StoreObjectFieldNoWriteBarrier(
456       microtask, PromiseResolveThenableJobTask::kThenableOffset, thenable);
457   return microtask;
458 }
459 
460 // ES #sec-triggerpromisereactions
TriggerPromiseReactions(Node * context,Node * reactions,Node * argument,PromiseReaction::Type type)461 Node* PromiseBuiltinsAssembler::TriggerPromiseReactions(
462     Node* context, Node* reactions, Node* argument,
463     PromiseReaction::Type type) {
464   // We need to reverse the {reactions} here, since we record them on the
465   // JSPromise in the reverse order.
466   {
467     VARIABLE(var_current, MachineRepresentation::kTagged, reactions);
468     VARIABLE(var_reversed, MachineRepresentation::kTagged,
469              SmiConstant(Smi::kZero));
470 
471     Label loop(this, {&var_current, &var_reversed}), done_loop(this);
472     Goto(&loop);
473     BIND(&loop);
474     {
475       Node* current = var_current.value();
476       GotoIf(TaggedIsSmi(current), &done_loop);
477       var_current.Bind(LoadObjectField(current, PromiseReaction::kNextOffset));
478       StoreObjectField(current, PromiseReaction::kNextOffset,
479                        var_reversed.value());
480       var_reversed.Bind(current);
481       Goto(&loop);
482     }
483     BIND(&done_loop);
484     reactions = var_reversed.value();
485   }
486 
487   // Morph the {reactions} into PromiseReactionJobTasks and push them
488   // onto the microtask queue.
489   {
490     VARIABLE(var_current, MachineRepresentation::kTagged, reactions);
491 
492     Label loop(this, {&var_current}), done_loop(this);
493     Goto(&loop);
494     BIND(&loop);
495     {
496       Node* current = var_current.value();
497       GotoIf(TaggedIsSmi(current), &done_loop);
498       var_current.Bind(LoadObjectField(current, PromiseReaction::kNextOffset));
499 
500       // Morph {current} from a PromiseReaction into a PromiseReactionJobTask
501       // and schedule that on the microtask queue. We try to minimize the number
502       // of stores here to avoid screwing up the store buffer.
503       STATIC_ASSERT(PromiseReaction::kSize == PromiseReactionJobTask::kSize);
504       if (type == PromiseReaction::kFulfill) {
505         StoreMapNoWriteBarrier(
506             current, Heap::kPromiseFulfillReactionJobTaskMapRootIndex);
507         StoreObjectField(current, PromiseReactionJobTask::kArgumentOffset,
508                          argument);
509         StoreObjectField(current, PromiseReactionJobTask::kContextOffset,
510                          context);
511         STATIC_ASSERT(PromiseReaction::kFulfillHandlerOffset ==
512                       PromiseReactionJobTask::kHandlerOffset);
513         STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset ==
514                       PromiseReactionJobTask::kPromiseOrCapabilityOffset);
515       } else {
516         Node* handler =
517             LoadObjectField(current, PromiseReaction::kRejectHandlerOffset);
518         StoreMapNoWriteBarrier(current,
519                                Heap::kPromiseRejectReactionJobTaskMapRootIndex);
520         StoreObjectField(current, PromiseReactionJobTask::kArgumentOffset,
521                          argument);
522         StoreObjectField(current, PromiseReactionJobTask::kContextOffset,
523                          context);
524         StoreObjectField(current, PromiseReactionJobTask::kHandlerOffset,
525                          handler);
526         STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset ==
527                       PromiseReactionJobTask::kPromiseOrCapabilityOffset);
528       }
529       CallBuiltin(Builtins::kEnqueueMicrotask, NoContextConstant(), current);
530       Goto(&loop);
531     }
532     BIND(&done_loop);
533   }
534 
535   return UndefinedConstant();
536 }
537 
538 template <typename... TArgs>
InvokeThen(Node * native_context,Node * receiver,TArgs...args)539 Node* PromiseBuiltinsAssembler::InvokeThen(Node* native_context, Node* receiver,
540                                            TArgs... args) {
541   CSA_ASSERT(this, IsNativeContext(native_context));
542 
543   VARIABLE(var_result, MachineRepresentation::kTagged);
544   Label if_fast(this), if_slow(this, Label::kDeferred), done(this, &var_result);
545   GotoIf(TaggedIsSmi(receiver), &if_slow);
546   Node* const receiver_map = LoadMap(receiver);
547   // We can skip the "then" lookup on {receiver} if it's [[Prototype]]
548   // is the (initial) Promise.prototype and the Promise#then protector
549   // is intact, as that guards the lookup path for the "then" property
550   // on JSPromise instances which have the (initial) %PromisePrototype%.
551   BranchIfPromiseThenLookupChainIntact(native_context, receiver_map, &if_fast,
552                                        &if_slow);
553 
554   BIND(&if_fast);
555   {
556     Node* const then =
557         LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
558     Node* const result =
559         CallJS(CodeFactory::CallFunction(
560                    isolate(), ConvertReceiverMode::kNotNullOrUndefined),
561                native_context, then, receiver, args...);
562     var_result.Bind(result);
563     Goto(&done);
564   }
565 
566   BIND(&if_slow);
567   {
568     Node* const then = GetProperty(native_context, receiver,
569                                    isolate()->factory()->then_string());
570     Node* const result = CallJS(
571         CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
572         native_context, then, receiver, args...);
573     var_result.Bind(result);
574     Goto(&done);
575   }
576 
577   BIND(&done);
578   return var_result.value();
579 }
580 
InvokeResolve(Node * native_context,Node * constructor,Node * value,Label * if_exception,Variable * var_exception)581 Node* PromiseBuiltinsAssembler::InvokeResolve(Node* native_context,
582                                               Node* constructor, Node* value,
583                                               Label* if_exception,
584                                               Variable* var_exception) {
585   CSA_ASSERT(this, IsNativeContext(native_context));
586 
587   VARIABLE(var_result, MachineRepresentation::kTagged);
588   Label if_fast(this), if_slow(this, Label::kDeferred), done(this, &var_result);
589   // We can skip the "resolve" lookup on {constructor} if it's the
590   // Promise constructor and the Promise.resolve protector is intact,
591   // as that guards the lookup path for the "resolve" property on the
592   // Promise constructor.
593   BranchIfPromiseResolveLookupChainIntact(native_context, constructor, &if_fast,
594                                           &if_slow);
595 
596   BIND(&if_fast);
597   {
598     Node* const result = CallBuiltin(Builtins::kPromiseResolve, native_context,
599                                      constructor, value);
600     GotoIfException(result, if_exception, var_exception);
601 
602     var_result.Bind(result);
603     Goto(&done);
604   }
605 
606   BIND(&if_slow);
607   {
608     Node* const resolve =
609         GetProperty(native_context, constructor, factory()->resolve_string());
610     GotoIfException(resolve, if_exception, var_exception);
611 
612     Node* const result = CallJS(
613         CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
614         native_context, resolve, constructor, value);
615     GotoIfException(result, if_exception, var_exception);
616 
617     var_result.Bind(result);
618     Goto(&done);
619   }
620 
621   BIND(&done);
622   return var_result.value();
623 }
624 
BranchIfPromiseResolveLookupChainIntact(Node * native_context,Node * constructor,Label * if_fast,Label * if_slow)625 void PromiseBuiltinsAssembler::BranchIfPromiseResolveLookupChainIntact(
626     Node* native_context, Node* constructor, Label* if_fast, Label* if_slow) {
627   CSA_ASSERT(this, IsNativeContext(native_context));
628 
629   GotoIfForceSlowPath(if_slow);
630   Node* const promise_fun =
631       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
632   GotoIfNot(WordEqual(promise_fun, constructor), if_slow);
633   Branch(IsPromiseResolveProtectorCellInvalid(), if_slow, if_fast);
634 }
635 
BranchIfPromiseSpeciesLookupChainIntact(Node * native_context,Node * promise_map,Label * if_fast,Label * if_slow)636 void PromiseBuiltinsAssembler::BranchIfPromiseSpeciesLookupChainIntact(
637     Node* native_context, Node* promise_map, Label* if_fast, Label* if_slow) {
638   CSA_ASSERT(this, IsNativeContext(native_context));
639   CSA_ASSERT(this, IsJSPromiseMap(promise_map));
640 
641   Node* const promise_prototype =
642       LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
643   GotoIfForceSlowPath(if_slow);
644   GotoIfNot(WordEqual(LoadMapPrototype(promise_map), promise_prototype),
645             if_slow);
646   Branch(IsPromiseSpeciesProtectorCellInvalid(), if_slow, if_fast);
647 }
648 
BranchIfPromiseThenLookupChainIntact(Node * native_context,Node * receiver_map,Label * if_fast,Label * if_slow)649 void PromiseBuiltinsAssembler::BranchIfPromiseThenLookupChainIntact(
650     Node* native_context, Node* receiver_map, Label* if_fast, Label* if_slow) {
651   CSA_ASSERT(this, IsMap(receiver_map));
652   CSA_ASSERT(this, IsNativeContext(native_context));
653 
654   GotoIfForceSlowPath(if_slow);
655   GotoIfNot(IsJSPromiseMap(receiver_map), if_slow);
656   Node* const promise_prototype =
657       LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
658   GotoIfNot(WordEqual(LoadMapPrototype(receiver_map), promise_prototype),
659             if_slow);
660   Branch(IsPromiseThenProtectorCellInvalid(), if_slow, if_fast);
661 }
662 
BranchIfAccessCheckFailed(Node * context,Node * native_context,Node * promise_constructor,Node * executor,Label * if_noaccess)663 void PromiseBuiltinsAssembler::BranchIfAccessCheckFailed(
664     Node* context, Node* native_context, Node* promise_constructor,
665     Node* executor, Label* if_noaccess) {
666   VARIABLE(var_executor, MachineRepresentation::kTagged);
667   var_executor.Bind(executor);
668   Label has_access(this), call_runtime(this, Label::kDeferred);
669 
670   // If executor is a bound function, load the bound function until we've
671   // reached an actual function.
672   Label found_function(this), loop_over_bound_function(this, &var_executor);
673   Goto(&loop_over_bound_function);
674   BIND(&loop_over_bound_function);
675   {
676     Node* executor_type = LoadInstanceType(var_executor.value());
677     GotoIf(InstanceTypeEqual(executor_type, JS_FUNCTION_TYPE), &found_function);
678     GotoIfNot(InstanceTypeEqual(executor_type, JS_BOUND_FUNCTION_TYPE),
679               &call_runtime);
680     var_executor.Bind(LoadObjectField(
681         var_executor.value(), JSBoundFunction::kBoundTargetFunctionOffset));
682     Goto(&loop_over_bound_function);
683   }
684 
685   // Load the context from the function and compare it to the Promise
686   // constructor's context. If they match, everything is fine, otherwise, bail
687   // out to the runtime.
688   BIND(&found_function);
689   {
690     Node* function_context =
691         LoadObjectField(var_executor.value(), JSFunction::kContextOffset);
692     Node* native_function_context = LoadNativeContext(function_context);
693     Branch(WordEqual(native_context, native_function_context), &has_access,
694            &call_runtime);
695   }
696 
697   BIND(&call_runtime);
698   {
699     Branch(WordEqual(CallRuntime(Runtime::kAllowDynamicFunction, context,
700                                  promise_constructor),
701                      TrueConstant()),
702            &has_access, if_noaccess);
703   }
704 
705   BIND(&has_access);
706 }
707 
SetForwardingHandlerIfTrue(Node * context,Node * condition,const NodeGenerator & object)708 void PromiseBuiltinsAssembler::SetForwardingHandlerIfTrue(
709     Node* context, Node* condition, const NodeGenerator& object) {
710   Label done(this);
711   GotoIfNot(condition, &done);
712   SetPropertyStrict(
713       CAST(context), CAST(object()),
714       HeapConstant(factory()->promise_forwarding_handler_symbol()),
715       TrueConstant());
716   Goto(&done);
717   BIND(&done);
718 }
719 
SetPromiseHandledByIfTrue(Node * context,Node * condition,Node * promise,const NodeGenerator & handled_by)720 void PromiseBuiltinsAssembler::SetPromiseHandledByIfTrue(
721     Node* context, Node* condition, Node* promise,
722     const NodeGenerator& handled_by) {
723   Label done(this);
724   GotoIfNot(condition, &done);
725   GotoIf(TaggedIsSmi(promise), &done);
726   GotoIfNot(HasInstanceType(promise, JS_PROMISE_TYPE), &done);
727   SetPropertyStrict(CAST(context), CAST(promise),
728                     HeapConstant(factory()->promise_handled_by_symbol()),
729                     CAST(handled_by()));
730   Goto(&done);
731   BIND(&done);
732 }
733 
734 // ES #sec-promise-reject-functions
TF_BUILTIN(PromiseCapabilityDefaultReject,PromiseBuiltinsAssembler)735 TF_BUILTIN(PromiseCapabilityDefaultReject, PromiseBuiltinsAssembler) {
736   Node* const reason = Parameter(Descriptor::kReason);
737   Node* const context = Parameter(Descriptor::kContext);
738 
739   // 2. Let promise be F.[[Promise]].
740   Node* const promise = LoadContextElement(context, kPromiseSlot);
741 
742   // 3. Let alreadyResolved be F.[[AlreadyResolved]].
743   Label if_already_resolved(this, Label::kDeferred);
744   Node* const already_resolved =
745       LoadContextElement(context, kAlreadyResolvedSlot);
746 
747   // 4. If alreadyResolved.[[Value]] is true, return undefined.
748   GotoIf(IsTrue(already_resolved), &if_already_resolved);
749 
750   // 5. Set alreadyResolved.[[Value]] to true.
751   StoreContextElementNoWriteBarrier(context, kAlreadyResolvedSlot,
752                                     TrueConstant());
753 
754   // 6. Return RejectPromise(promise, reason).
755   Node* const debug_event = LoadContextElement(context, kDebugEventSlot);
756   Return(CallBuiltin(Builtins::kRejectPromise, context, promise, reason,
757                      debug_event));
758 
759   BIND(&if_already_resolved);
760   {
761     Return(CallRuntime(Runtime::kPromiseRejectAfterResolved, context, promise,
762                        reason));
763   }
764 }
765 
766 // ES #sec-promise-resolve-functions
TF_BUILTIN(PromiseCapabilityDefaultResolve,PromiseBuiltinsAssembler)767 TF_BUILTIN(PromiseCapabilityDefaultResolve, PromiseBuiltinsAssembler) {
768   Node* const resolution = Parameter(Descriptor::kResolution);
769   Node* const context = Parameter(Descriptor::kContext);
770 
771   // 2. Let promise be F.[[Promise]].
772   Node* const promise = LoadContextElement(context, kPromiseSlot);
773 
774   // 3. Let alreadyResolved be F.[[AlreadyResolved]].
775   Label if_already_resolved(this, Label::kDeferred);
776   Node* const already_resolved =
777       LoadContextElement(context, kAlreadyResolvedSlot);
778 
779   // 4. If alreadyResolved.[[Value]] is true, return undefined.
780   GotoIf(IsTrue(already_resolved), &if_already_resolved);
781 
782   // 5. Set alreadyResolved.[[Value]] to true.
783   StoreContextElementNoWriteBarrier(context, kAlreadyResolvedSlot,
784                                     TrueConstant());
785 
786   // The rest of the logic (and the catch prediction) is
787   // encapsulated in the dedicated ResolvePromise builtin.
788   Return(CallBuiltin(Builtins::kResolvePromise, context, promise, resolution));
789 
790   BIND(&if_already_resolved);
791   {
792     Return(CallRuntime(Runtime::kPromiseResolveAfterResolved, context, promise,
793                        resolution));
794   }
795 }
796 
TF_BUILTIN(PromiseConstructorLazyDeoptContinuation,PromiseBuiltinsAssembler)797 TF_BUILTIN(PromiseConstructorLazyDeoptContinuation, PromiseBuiltinsAssembler) {
798   Node* promise = Parameter(Descriptor::kPromise);
799   Node* reject = Parameter(Descriptor::kReject);
800   Node* exception = Parameter(Descriptor::kException);
801   Node* const context = Parameter(Descriptor::kContext);
802 
803   Label finally(this);
804 
805   GotoIf(IsTheHole(exception), &finally);
806   CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
807          context, reject, UndefinedConstant(), exception);
808   Goto(&finally);
809 
810   BIND(&finally);
811   Return(promise);
812 }
813 
814 // ES6 #sec-promise-executor
TF_BUILTIN(PromiseConstructor,PromiseBuiltinsAssembler)815 TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
816   Node* const executor = Parameter(Descriptor::kExecutor);
817   Node* const new_target = Parameter(Descriptor::kJSNewTarget);
818   Node* const context = Parameter(Descriptor::kContext);
819   Isolate* isolate = this->isolate();
820 
821   Label if_targetisundefined(this, Label::kDeferred);
822 
823   GotoIf(IsUndefined(new_target), &if_targetisundefined);
824 
825   Label if_notcallable(this, Label::kDeferred);
826 
827   GotoIf(TaggedIsSmi(executor), &if_notcallable);
828 
829   Node* const executor_map = LoadMap(executor);
830   GotoIfNot(IsCallableMap(executor_map), &if_notcallable);
831 
832   Node* const native_context = LoadNativeContext(context);
833   Node* const promise_fun =
834       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
835   Node* const is_debug_active = IsDebugActive();
836   Label if_targetisnotmodified(this),
837       if_targetismodified(this, Label::kDeferred), run_executor(this),
838       debug_push(this), if_noaccess(this, Label::kDeferred);
839 
840   BranchIfAccessCheckFailed(context, native_context, promise_fun, executor,
841                             &if_noaccess);
842 
843   Branch(WordEqual(promise_fun, new_target), &if_targetisnotmodified,
844          &if_targetismodified);
845 
846   VARIABLE(var_result, MachineRepresentation::kTagged);
847   VARIABLE(var_reject_call, MachineRepresentation::kTagged);
848   VARIABLE(var_reason, MachineRepresentation::kTagged);
849 
850   BIND(&if_targetisnotmodified);
851   {
852     Node* const instance = AllocateAndInitJSPromise(context);
853     var_result.Bind(instance);
854     Goto(&debug_push);
855   }
856 
857   BIND(&if_targetismodified);
858   {
859     ConstructorBuiltinsAssembler constructor_assembler(this->state());
860     Node* const instance = constructor_assembler.EmitFastNewObject(
861         context, promise_fun, new_target);
862     PromiseInit(instance);
863     var_result.Bind(instance);
864 
865     GotoIfNot(IsPromiseHookEnabledOrHasAsyncEventDelegate(), &debug_push);
866     CallRuntime(Runtime::kPromiseHookInit, context, instance,
867                 UndefinedConstant());
868     Goto(&debug_push);
869   }
870 
871   BIND(&debug_push);
872   {
873     GotoIfNot(is_debug_active, &run_executor);
874     CallRuntime(Runtime::kDebugPushPromise, context, var_result.value());
875     Goto(&run_executor);
876   }
877 
878   BIND(&run_executor);
879   {
880     Label out(this), if_rejectpromise(this), debug_pop(this, Label::kDeferred);
881 
882     Node *resolve, *reject;
883     std::tie(resolve, reject) = CreatePromiseResolvingFunctions(
884         var_result.value(), TrueConstant(), native_context);
885 
886     Node* const maybe_exception = CallJS(
887         CodeFactory::Call(isolate, ConvertReceiverMode::kNullOrUndefined),
888         context, executor, UndefinedConstant(), resolve, reject);
889 
890     GotoIfException(maybe_exception, &if_rejectpromise, &var_reason);
891     Branch(is_debug_active, &debug_pop, &out);
892 
893     BIND(&if_rejectpromise);
894     {
895       CallJS(CodeFactory::Call(isolate, ConvertReceiverMode::kNullOrUndefined),
896              context, reject, UndefinedConstant(), var_reason.value());
897       Branch(is_debug_active, &debug_pop, &out);
898     }
899 
900     BIND(&debug_pop);
901     {
902       CallRuntime(Runtime::kDebugPopPromise, context);
903       Goto(&out);
904     }
905     BIND(&out);
906     Return(var_result.value());
907   }
908 
909   // 1. If NewTarget is undefined, throw a TypeError exception.
910   BIND(&if_targetisundefined);
911   ThrowTypeError(context, MessageTemplate::kNotAPromise, new_target);
912 
913   // 2. If IsCallable(executor) is false, throw a TypeError exception.
914   BIND(&if_notcallable);
915   ThrowTypeError(context, MessageTemplate::kResolverNotAFunction, executor);
916 
917   // Silently fail if the stack looks fishy.
918   BIND(&if_noaccess);
919   {
920     Node* const counter_id =
921         SmiConstant(v8::Isolate::kPromiseConstructorReturnedUndefined);
922     CallRuntime(Runtime::kIncrementUseCounter, context, counter_id);
923     Return(UndefinedConstant());
924   }
925 }
926 
927 // V8 Extras: v8.createPromise(parent)
TF_BUILTIN(PromiseInternalConstructor,PromiseBuiltinsAssembler)928 TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) {
929   Node* const parent = Parameter(Descriptor::kParent);
930   Node* const context = Parameter(Descriptor::kContext);
931   Return(AllocateAndInitJSPromise(context, parent));
932 }
933 
934 // V8 Extras: v8.rejectPromise(promise, reason)
TF_BUILTIN(PromiseInternalReject,PromiseBuiltinsAssembler)935 TF_BUILTIN(PromiseInternalReject, PromiseBuiltinsAssembler) {
936   Node* const promise = Parameter(Descriptor::kPromise);
937   Node* const reason = Parameter(Descriptor::kReason);
938   Node* const context = Parameter(Descriptor::kContext);
939   // We pass true to trigger the debugger's on exception handler.
940   Return(CallBuiltin(Builtins::kRejectPromise, context, promise, reason,
941                      TrueConstant()));
942 }
943 
944 // V8 Extras: v8.resolvePromise(promise, resolution)
TF_BUILTIN(PromiseInternalResolve,PromiseBuiltinsAssembler)945 TF_BUILTIN(PromiseInternalResolve, PromiseBuiltinsAssembler) {
946   Node* const promise = Parameter(Descriptor::kPromise);
947   Node* const resolution = Parameter(Descriptor::kResolution);
948   Node* const context = Parameter(Descriptor::kContext);
949   Return(CallBuiltin(Builtins::kResolvePromise, context, promise, resolution));
950 }
951 
952 // ES#sec-promise.prototype.then
953 // Promise.prototype.then ( onFulfilled, onRejected )
TF_BUILTIN(PromisePrototypeThen,PromiseBuiltinsAssembler)954 TF_BUILTIN(PromisePrototypeThen, PromiseBuiltinsAssembler) {
955   // 1. Let promise be the this value.
956   Node* const promise = Parameter(Descriptor::kReceiver);
957   Node* const on_fulfilled = Parameter(Descriptor::kOnFulfilled);
958   Node* const on_rejected = Parameter(Descriptor::kOnRejected);
959   Node* const context = Parameter(Descriptor::kContext);
960 
961   // 2. If IsPromise(promise) is false, throw a TypeError exception.
962   ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
963                          "Promise.prototype.then");
964 
965   // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
966   Label fast_promise_capability(this), slow_constructor(this, Label::kDeferred),
967       slow_promise_capability(this, Label::kDeferred);
968   Node* const native_context = LoadNativeContext(context);
969   Node* const promise_fun =
970       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
971   Node* const promise_map = LoadMap(promise);
972   BranchIfPromiseSpeciesLookupChainIntact(
973       native_context, promise_map, &fast_promise_capability, &slow_constructor);
974 
975   BIND(&slow_constructor);
976   Node* const constructor =
977       SpeciesConstructor(native_context, promise, promise_fun);
978   Branch(WordEqual(constructor, promise_fun), &fast_promise_capability,
979          &slow_promise_capability);
980 
981   // 4. Let resultCapability be ? NewPromiseCapability(C).
982   Label perform_promise_then(this);
983   VARIABLE(var_result_promise, MachineRepresentation::kTagged);
984   VARIABLE(var_result_promise_or_capability, MachineRepresentation::kTagged);
985 
986   BIND(&fast_promise_capability);
987   {
988     Node* const result_promise = AllocateAndInitJSPromise(context, promise);
989     var_result_promise_or_capability.Bind(result_promise);
990     var_result_promise.Bind(result_promise);
991     Goto(&perform_promise_then);
992   }
993 
994   BIND(&slow_promise_capability);
995   {
996     Node* const debug_event = TrueConstant();
997     Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability,
998                                          context, constructor, debug_event);
999     var_result_promise.Bind(
1000         LoadObjectField(capability, PromiseCapability::kPromiseOffset));
1001     var_result_promise_or_capability.Bind(capability);
1002     Goto(&perform_promise_then);
1003   }
1004 
1005   // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
1006   //    resultCapability).
1007   BIND(&perform_promise_then);
1008   {
1009     // We do some work of the PerformPromiseThen operation here, in that
1010     // we check the handlers and turn non-callable handlers into undefined.
1011     // This is because this is the one and only callsite of PerformPromiseThen
1012     // that has to do this.
1013 
1014     // 3. If IsCallable(onFulfilled) is false, then
1015     //    a. Set onFulfilled to undefined.
1016     VARIABLE(var_on_fulfilled, MachineRepresentation::kTagged, on_fulfilled);
1017     Label if_fulfilled_done(this), if_fulfilled_notcallable(this);
1018     GotoIf(TaggedIsSmi(on_fulfilled), &if_fulfilled_notcallable);
1019     Branch(IsCallable(on_fulfilled), &if_fulfilled_done,
1020            &if_fulfilled_notcallable);
1021     BIND(&if_fulfilled_notcallable);
1022     var_on_fulfilled.Bind(UndefinedConstant());
1023     Goto(&if_fulfilled_done);
1024     BIND(&if_fulfilled_done);
1025 
1026     // 4. If IsCallable(onRejected) is false, then
1027     //    a. Set onRejected to undefined.
1028     VARIABLE(var_on_rejected, MachineRepresentation::kTagged, on_rejected);
1029     Label if_rejected_done(this), if_rejected_notcallable(this);
1030     GotoIf(TaggedIsSmi(on_rejected), &if_rejected_notcallable);
1031     Branch(IsCallable(on_rejected), &if_rejected_done,
1032            &if_rejected_notcallable);
1033     BIND(&if_rejected_notcallable);
1034     var_on_rejected.Bind(UndefinedConstant());
1035     Goto(&if_rejected_done);
1036     BIND(&if_rejected_done);
1037 
1038     PerformPromiseThen(context, promise, var_on_fulfilled.value(),
1039                        var_on_rejected.value(),
1040                        var_result_promise_or_capability.value());
1041     Return(var_result_promise.value());
1042   }
1043 }
1044 
1045 // ES#sec-promise.prototype.catch
1046 // Promise.prototype.catch ( onRejected )
TF_BUILTIN(PromisePrototypeCatch,PromiseBuiltinsAssembler)1047 TF_BUILTIN(PromisePrototypeCatch, PromiseBuiltinsAssembler) {
1048   // 1. Let promise be the this value.
1049   Node* const receiver = Parameter(Descriptor::kReceiver);
1050   Node* const on_fulfilled = UndefinedConstant();
1051   Node* const on_rejected = Parameter(Descriptor::kOnRejected);
1052   Node* const context = Parameter(Descriptor::kContext);
1053 
1054   // 2. Return ? Invoke(promise, "then", « undefined, onRejected »).
1055   Node* const native_context = LoadNativeContext(context);
1056   Return(InvokeThen(native_context, receiver, on_fulfilled, on_rejected));
1057 }
1058 
1059 // ES #sec-promiseresolvethenablejob
TF_BUILTIN(PromiseResolveThenableJob,PromiseBuiltinsAssembler)1060 TF_BUILTIN(PromiseResolveThenableJob, PromiseBuiltinsAssembler) {
1061   Node* const native_context = Parameter(Descriptor::kContext);
1062   Node* const promise_to_resolve = Parameter(Descriptor::kPromiseToResolve);
1063   Node* const thenable = Parameter(Descriptor::kThenable);
1064   Node* const then = Parameter(Descriptor::kThen);
1065 
1066   CSA_ASSERT(this, TaggedIsNotSmi(thenable));
1067   CSA_ASSERT(this, IsJSReceiver(thenable));
1068   CSA_ASSERT(this, IsJSPromise(promise_to_resolve));
1069   CSA_ASSERT(this, IsNativeContext(native_context));
1070 
1071   // We can use a simple optimization here if we know that {then} is the initial
1072   // Promise.prototype.then method, and {thenable} is a JSPromise whose
1073   // @@species lookup chain is intact: We can connect {thenable} and
1074   // {promise_to_resolve} directly in that case and avoid the allocation of a
1075   // temporary JSPromise and the closures plus context.
1076   //
1077   // We take the generic (slow-)path if a PromiseHook is enabled or the debugger
1078   // is active, to make sure we expose spec compliant behavior.
1079   Label if_fast(this), if_slow(this, Label::kDeferred);
1080   Node* const promise_then =
1081       LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
1082   GotoIfNot(WordEqual(then, promise_then), &if_slow);
1083   Node* const thenable_map = LoadMap(thenable);
1084   GotoIfNot(IsJSPromiseMap(thenable_map), &if_slow);
1085   GotoIf(IsPromiseHookEnabled(), &if_slow);
1086   GotoIf(IsDebugActive(), &if_slow);
1087   BranchIfPromiseSpeciesLookupChainIntact(native_context, thenable_map,
1088                                           &if_fast, &if_slow);
1089 
1090   BIND(&if_fast);
1091   {
1092     // We know that the {thenable} is a JSPromise, which doesn't require
1093     // any special treatment and that {then} corresponds to the initial
1094     // Promise.prototype.then method. So instead of allocating a temporary
1095     // JSPromise to connect the {thenable} with the {promise_to_resolve},
1096     // we can directly schedule the {promise_to_resolve} with default
1097     // handlers onto the {thenable} promise. This does not only save the
1098     // JSPromise allocation, but also avoids the allocation of the two
1099     // resolving closures and the shared context.
1100     //
1101     // What happens normally in this case is
1102     //
1103     //   resolve, reject = CreateResolvingFunctions(promise_to_resolve)
1104     //   result_capability = NewPromiseCapability(%Promise%)
1105     //   PerformPromiseThen(thenable, resolve, reject, result_capability)
1106     //
1107     // which means that PerformPromiseThen will either schedule a new
1108     // PromiseReaction with resolve and reject or a PromiseReactionJob
1109     // with resolve or reject based on the state of {thenable}. And
1110     // resolve or reject will just invoke the default [[Resolve]] or
1111     // [[Reject]] functions on the {promise_to_resolve}.
1112     //
1113     // This is the same as just doing
1114     //
1115     //   PerformPromiseThen(thenable, undefined, undefined, promise_to_resolve)
1116     //
1117     // which performs exactly the same (observable) steps.
1118     TailCallBuiltin(Builtins::kPerformPromiseThen, native_context, thenable,
1119                     UndefinedConstant(), UndefinedConstant(),
1120                     promise_to_resolve);
1121   }
1122 
1123   BIND(&if_slow);
1124   {
1125     Node* resolve = nullptr;
1126     Node* reject = nullptr;
1127     std::tie(resolve, reject) = CreatePromiseResolvingFunctions(
1128         promise_to_resolve, FalseConstant(), native_context);
1129 
1130     Label if_exception(this, Label::kDeferred);
1131     VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
1132     Node* const result = CallJS(
1133         CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
1134         native_context, then, thenable, resolve, reject);
1135     GotoIfException(result, &if_exception, &var_exception);
1136     Return(result);
1137 
1138     BIND(&if_exception);
1139     {
1140       // We need to reject the {thenable}.
1141       Node* const result = CallJS(
1142           CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1143           native_context, reject, UndefinedConstant(), var_exception.value());
1144       Return(result);
1145     }
1146   }
1147 }
1148 
1149 // ES #sec-promisereactionjob
PromiseReactionJob(Node * context,Node * argument,Node * handler,Node * promise_or_capability,PromiseReaction::Type type)1150 void PromiseBuiltinsAssembler::PromiseReactionJob(Node* context, Node* argument,
1151                                                   Node* handler,
1152                                                   Node* promise_or_capability,
1153                                                   PromiseReaction::Type type) {
1154   CSA_ASSERT(this, TaggedIsNotSmi(handler));
1155   CSA_ASSERT(this, Word32Or(IsUndefined(handler), IsCallable(handler)));
1156   CSA_ASSERT(this, TaggedIsNotSmi(promise_or_capability));
1157   CSA_ASSERT(this, Word32Or(IsJSPromise(promise_or_capability),
1158                             IsPromiseCapability(promise_or_capability)));
1159 
1160   VARIABLE(var_handler_result, MachineRepresentation::kTagged, argument);
1161   Label if_handler_callable(this), if_fulfill(this), if_reject(this);
1162   Branch(IsUndefined(handler),
1163          type == PromiseReaction::kFulfill ? &if_fulfill : &if_reject,
1164          &if_handler_callable);
1165 
1166   BIND(&if_handler_callable);
1167   {
1168     Node* const result = CallJS(
1169         CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1170         context, handler, UndefinedConstant(), argument);
1171     GotoIfException(result, &if_reject, &var_handler_result);
1172     var_handler_result.Bind(result);
1173     Goto(&if_fulfill);
1174   }
1175 
1176   BIND(&if_fulfill);
1177   {
1178     Label if_promise(this), if_promise_capability(this, Label::kDeferred);
1179     Node* const value = var_handler_result.value();
1180     Branch(IsPromiseCapability(promise_or_capability), &if_promise_capability,
1181            &if_promise);
1182 
1183     BIND(&if_promise);
1184     {
1185       // For fast native promises we can skip the indirection
1186       // via the promiseCapability.[[Resolve]] function and
1187       // run the resolve logic directly from here.
1188       TailCallBuiltin(Builtins::kResolvePromise, context, promise_or_capability,
1189                       value);
1190     }
1191 
1192     BIND(&if_promise_capability);
1193     {
1194       // In the general case we need to call the (user provided)
1195       // promiseCapability.[[Resolve]] function.
1196       Node* const resolve = LoadObjectField(promise_or_capability,
1197                                             PromiseCapability::kResolveOffset);
1198       Node* const result = CallJS(
1199           CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1200           context, resolve, UndefinedConstant(), value);
1201       GotoIfException(result, &if_reject, &var_handler_result);
1202       Return(result);
1203     }
1204   }
1205 
1206   BIND(&if_reject);
1207   if (type == PromiseReaction::kReject) {
1208     Label if_promise(this), if_promise_capability(this, Label::kDeferred);
1209     Node* const reason = var_handler_result.value();
1210     Branch(IsPromiseCapability(promise_or_capability), &if_promise_capability,
1211            &if_promise);
1212 
1213     BIND(&if_promise);
1214     {
1215       // For fast native promises we can skip the indirection
1216       // via the promiseCapability.[[Reject]] function and
1217       // run the resolve logic directly from here.
1218       TailCallBuiltin(Builtins::kRejectPromise, context, promise_or_capability,
1219                       reason, FalseConstant());
1220     }
1221 
1222     BIND(&if_promise_capability);
1223     {
1224       // In the general case we need to call the (user provided)
1225       // promiseCapability.[[Reject]] function.
1226       Label if_exception(this, Label::kDeferred);
1227       VARIABLE(var_exception, MachineRepresentation::kTagged,
1228                TheHoleConstant());
1229       Node* const reject = LoadObjectField(promise_or_capability,
1230                                            PromiseCapability::kRejectOffset);
1231       Node* const result = CallJS(
1232           CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1233           context, reject, UndefinedConstant(), reason);
1234       GotoIfException(result, &if_exception, &var_exception);
1235       Return(result);
1236 
1237       // Swallow the exception here.
1238       BIND(&if_exception);
1239       TailCallRuntime(Runtime::kReportMessage, context, var_exception.value());
1240     }
1241   } else {
1242     // We have to call out to the dedicated PromiseRejectReactionJob builtin
1243     // here, instead of just doing the work inline, as otherwise the catch
1244     // predictions in the debugger will be wrong, which just walks the stack
1245     // and checks for certain builtins.
1246     TailCallBuiltin(Builtins::kPromiseRejectReactionJob, context,
1247                     var_handler_result.value(), UndefinedConstant(),
1248                     promise_or_capability);
1249   }
1250 }
1251 
1252 // ES #sec-promisereactionjob
TF_BUILTIN(PromiseFulfillReactionJob,PromiseBuiltinsAssembler)1253 TF_BUILTIN(PromiseFulfillReactionJob, PromiseBuiltinsAssembler) {
1254   Node* const context = Parameter(Descriptor::kContext);
1255   Node* const value = Parameter(Descriptor::kValue);
1256   Node* const handler = Parameter(Descriptor::kHandler);
1257   Node* const promise_or_capability =
1258       Parameter(Descriptor::kPromiseOrCapability);
1259 
1260   PromiseReactionJob(context, value, handler, promise_or_capability,
1261                      PromiseReaction::kFulfill);
1262 }
1263 
1264 // ES #sec-promisereactionjob
TF_BUILTIN(PromiseRejectReactionJob,PromiseBuiltinsAssembler)1265 TF_BUILTIN(PromiseRejectReactionJob, PromiseBuiltinsAssembler) {
1266   Node* const context = Parameter(Descriptor::kContext);
1267   Node* const reason = Parameter(Descriptor::kReason);
1268   Node* const handler = Parameter(Descriptor::kHandler);
1269   Node* const promise_or_capability =
1270       Parameter(Descriptor::kPromiseOrCapability);
1271 
1272   PromiseReactionJob(context, reason, handler, promise_or_capability,
1273                      PromiseReaction::kReject);
1274 }
1275 
TF_BUILTIN(PromiseResolveTrampoline,PromiseBuiltinsAssembler)1276 TF_BUILTIN(PromiseResolveTrampoline, PromiseBuiltinsAssembler) {
1277   //  1. Let C be the this value.
1278   Node* receiver = Parameter(Descriptor::kReceiver);
1279   Node* value = Parameter(Descriptor::kValue);
1280   Node* context = Parameter(Descriptor::kContext);
1281 
1282   // 2. If Type(C) is not Object, throw a TypeError exception.
1283   ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1284                        "PromiseResolve");
1285 
1286   // 3. Return ? PromiseResolve(C, x).
1287   Return(CallBuiltin(Builtins::kPromiseResolve, context, receiver, value));
1288 }
1289 
TF_BUILTIN(PromiseResolve,PromiseBuiltinsAssembler)1290 TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
1291   Node* constructor = Parameter(Descriptor::kConstructor);
1292   Node* value = Parameter(Descriptor::kValue);
1293   Node* context = Parameter(Descriptor::kContext);
1294 
1295   CSA_ASSERT(this, IsJSReceiver(constructor));
1296 
1297   Node* const native_context = LoadNativeContext(context);
1298   Node* const promise_fun =
1299       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1300 
1301   Label if_slow_constructor(this, Label::kDeferred), if_need_to_allocate(this);
1302 
1303   // Check if {value} is a JSPromise.
1304   GotoIf(TaggedIsSmi(value), &if_need_to_allocate);
1305   Node* const value_map = LoadMap(value);
1306   GotoIfNot(IsJSPromiseMap(value_map), &if_need_to_allocate);
1307 
1308   // We can skip the "constructor" lookup on {value} if it's [[Prototype]]
1309   // is the (initial) Promise.prototype and the @@species protector is
1310   // intact, as that guards the lookup path for "constructor" on
1311   // JSPromise instances which have the (initial) Promise.prototype.
1312   Node* const promise_prototype =
1313       LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
1314   GotoIfNot(WordEqual(LoadMapPrototype(value_map), promise_prototype),
1315             &if_slow_constructor);
1316   GotoIf(IsPromiseSpeciesProtectorCellInvalid(), &if_slow_constructor);
1317 
1318   // If the {constructor} is the Promise function, we just immediately
1319   // return the {value} here and don't bother wrapping it into a
1320   // native Promise.
1321   GotoIfNot(WordEqual(promise_fun, constructor), &if_slow_constructor);
1322   Return(value);
1323 
1324   // At this point, value or/and constructor are not native promises, but
1325   // they could be of the same subclass.
1326   BIND(&if_slow_constructor);
1327   {
1328     Node* const value_constructor =
1329         GetProperty(context, value, isolate()->factory()->constructor_string());
1330     GotoIfNot(WordEqual(value_constructor, constructor), &if_need_to_allocate);
1331     Return(value);
1332   }
1333 
1334   BIND(&if_need_to_allocate);
1335   {
1336     Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred);
1337     Branch(WordEqual(promise_fun, constructor), &if_nativepromise,
1338            &if_notnativepromise);
1339 
1340     // This adds a fast path for native promises that don't need to
1341     // create NewPromiseCapability.
1342     BIND(&if_nativepromise);
1343     {
1344       Node* const result = AllocateAndInitJSPromise(context);
1345       CallBuiltin(Builtins::kResolvePromise, context, result, value);
1346       Return(result);
1347     }
1348 
1349     BIND(&if_notnativepromise);
1350     {
1351       Node* const debug_event = TrueConstant();
1352       Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability,
1353                                            context, constructor, debug_event);
1354 
1355       Node* const resolve =
1356           LoadObjectField(capability, PromiseCapability::kResolveOffset);
1357       CallJS(
1358           CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1359           context, resolve, UndefinedConstant(), value);
1360 
1361       Node* const result =
1362           LoadObjectField(capability, PromiseCapability::kPromiseOffset);
1363       Return(result);
1364     }
1365   }
1366 }
1367 
1368 // ES6 #sec-getcapabilitiesexecutor-functions
TF_BUILTIN(PromiseGetCapabilitiesExecutor,PromiseBuiltinsAssembler)1369 TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
1370   Node* const resolve = Parameter(Descriptor::kResolve);
1371   Node* const reject = Parameter(Descriptor::kReject);
1372   Node* const context = Parameter(Descriptor::kContext);
1373 
1374   Node* const capability = LoadContextElement(context, kCapabilitySlot);
1375 
1376   Label if_alreadyinvoked(this, Label::kDeferred);
1377   GotoIfNot(IsUndefined(
1378                 LoadObjectField(capability, PromiseCapability::kResolveOffset)),
1379             &if_alreadyinvoked);
1380   GotoIfNot(IsUndefined(
1381                 LoadObjectField(capability, PromiseCapability::kRejectOffset)),
1382             &if_alreadyinvoked);
1383 
1384   StoreObjectField(capability, PromiseCapability::kResolveOffset, resolve);
1385   StoreObjectField(capability, PromiseCapability::kRejectOffset, reject);
1386 
1387   Return(UndefinedConstant());
1388 
1389   BIND(&if_alreadyinvoked);
1390   ThrowTypeError(context, MessageTemplate::kPromiseExecutorAlreadyInvoked);
1391 }
1392 
TF_BUILTIN(PromiseReject,PromiseBuiltinsAssembler)1393 TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) {
1394   // 1. Let C be the this value.
1395   Node* const receiver = Parameter(Descriptor::kReceiver);
1396   Node* const reason = Parameter(Descriptor::kReason);
1397   Node* const context = Parameter(Descriptor::kContext);
1398 
1399   // 2. If Type(C) is not Object, throw a TypeError exception.
1400   ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1401                        "PromiseReject");
1402 
1403   Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
1404   Node* const native_context = LoadNativeContext(context);
1405 
1406   Node* const promise_fun =
1407       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1408   Branch(WordEqual(promise_fun, receiver), &if_nativepromise,
1409          &if_custompromise);
1410 
1411   BIND(&if_nativepromise);
1412   {
1413     Node* const promise =
1414         AllocateAndSetJSPromise(context, v8::Promise::kRejected, reason);
1415     CallRuntime(Runtime::kPromiseRejectEventFromStack, context, promise,
1416                 reason);
1417     Return(promise);
1418   }
1419 
1420   BIND(&if_custompromise);
1421   {
1422     // 3. Let promiseCapability be ? NewPromiseCapability(C).
1423     Node* const debug_event = TrueConstant();
1424     Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability,
1425                                          context, receiver, debug_event);
1426 
1427     // 4. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
1428     Node* const reject =
1429         LoadObjectField(capability, PromiseCapability::kRejectOffset);
1430     CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1431            context, reject, UndefinedConstant(), reason);
1432 
1433     // 5. Return promiseCapability.[[Promise]].
1434     Node* const promise =
1435         LoadObjectField(capability, PromiseCapability::kPromiseOffset);
1436     Return(promise);
1437   }
1438 }
1439 
CreatePromiseFinallyFunctions(Node * on_finally,Node * constructor,Node * native_context)1440 std::pair<Node*, Node*> PromiseBuiltinsAssembler::CreatePromiseFinallyFunctions(
1441     Node* on_finally, Node* constructor, Node* native_context) {
1442   Node* const promise_context =
1443       CreatePromiseContext(native_context, kPromiseFinallyContextLength);
1444   StoreContextElementNoWriteBarrier(promise_context, kOnFinallySlot,
1445                                     on_finally);
1446   StoreContextElementNoWriteBarrier(promise_context, kConstructorSlot,
1447                                     constructor);
1448   Node* const map = LoadContextElement(
1449       native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1450   Node* const then_finally_info = LoadContextElement(
1451       native_context, Context::PROMISE_THEN_FINALLY_SHARED_FUN);
1452   Node* const then_finally = AllocateFunctionWithMapAndContext(
1453       map, then_finally_info, promise_context);
1454   Node* const catch_finally_info = LoadContextElement(
1455       native_context, Context::PROMISE_CATCH_FINALLY_SHARED_FUN);
1456   Node* const catch_finally = AllocateFunctionWithMapAndContext(
1457       map, catch_finally_info, promise_context);
1458   return std::make_pair(then_finally, catch_finally);
1459 }
1460 
TF_BUILTIN(PromiseValueThunkFinally,PromiseBuiltinsAssembler)1461 TF_BUILTIN(PromiseValueThunkFinally, PromiseBuiltinsAssembler) {
1462   Node* const context = Parameter(Descriptor::kContext);
1463 
1464   Node* const value = LoadContextElement(context, kValueSlot);
1465   Return(value);
1466 }
1467 
CreateValueThunkFunction(Node * value,Node * native_context)1468 Node* PromiseBuiltinsAssembler::CreateValueThunkFunction(Node* value,
1469                                                          Node* native_context) {
1470   Node* const value_thunk_context = CreatePromiseContext(
1471       native_context, kPromiseValueThunkOrReasonContextLength);
1472   StoreContextElementNoWriteBarrier(value_thunk_context, kValueSlot, value);
1473   Node* const map = LoadContextElement(
1474       native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1475   Node* const value_thunk_info = LoadContextElement(
1476       native_context, Context::PROMISE_VALUE_THUNK_FINALLY_SHARED_FUN);
1477   Node* const value_thunk = AllocateFunctionWithMapAndContext(
1478       map, value_thunk_info, value_thunk_context);
1479   return value_thunk;
1480 }
1481 
TF_BUILTIN(PromiseThenFinally,PromiseBuiltinsAssembler)1482 TF_BUILTIN(PromiseThenFinally, PromiseBuiltinsAssembler) {
1483   CSA_ASSERT_JS_ARGC_EQ(this, 1);
1484 
1485   Node* const value = Parameter(Descriptor::kValue);
1486   Node* const context = Parameter(Descriptor::kContext);
1487 
1488   // 1. Let onFinally be F.[[OnFinally]].
1489   Node* const on_finally = LoadContextElement(context, kOnFinallySlot);
1490 
1491   // 2.  Assert: IsCallable(onFinally) is true.
1492   CSA_ASSERT(this, IsCallable(on_finally));
1493 
1494   // 3. Let result be ?  Call(onFinally).
1495   Node* const result = CallJS(
1496       CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1497       context, on_finally, UndefinedConstant());
1498 
1499   // 4. Let C be F.[[Constructor]].
1500   Node* const constructor = LoadContextElement(context, kConstructorSlot);
1501 
1502   // 5. Assert: IsConstructor(C) is true.
1503   CSA_ASSERT(this, IsConstructor(constructor));
1504 
1505   // 6. Let promise be ? PromiseResolve(C, result).
1506   Node* const promise =
1507     CallBuiltin(Builtins::kPromiseResolve, context, constructor, result);
1508 
1509   // 7. Let valueThunk be equivalent to a function that returns value.
1510   Node* const native_context = LoadNativeContext(context);
1511   Node* const value_thunk = CreateValueThunkFunction(value, native_context);
1512 
1513   // 8. Return ? Invoke(promise, "then", « valueThunk »).
1514   Return(InvokeThen(native_context, promise, value_thunk));
1515 }
1516 
TF_BUILTIN(PromiseThrowerFinally,PromiseBuiltinsAssembler)1517 TF_BUILTIN(PromiseThrowerFinally, PromiseBuiltinsAssembler) {
1518   Node* const context = Parameter(Descriptor::kContext);
1519 
1520   Node* const reason = LoadContextElement(context, kValueSlot);
1521   CallRuntime(Runtime::kThrow, context, reason);
1522   Unreachable();
1523 }
1524 
CreateThrowerFunction(Node * reason,Node * native_context)1525 Node* PromiseBuiltinsAssembler::CreateThrowerFunction(Node* reason,
1526                                                       Node* native_context) {
1527   Node* const thrower_context = CreatePromiseContext(
1528       native_context, kPromiseValueThunkOrReasonContextLength);
1529   StoreContextElementNoWriteBarrier(thrower_context, kValueSlot, reason);
1530   Node* const map = LoadContextElement(
1531       native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1532   Node* const thrower_info = LoadContextElement(
1533       native_context, Context::PROMISE_THROWER_FINALLY_SHARED_FUN);
1534   Node* const thrower =
1535       AllocateFunctionWithMapAndContext(map, thrower_info, thrower_context);
1536   return thrower;
1537 }
1538 
TF_BUILTIN(PromiseCatchFinally,PromiseBuiltinsAssembler)1539 TF_BUILTIN(PromiseCatchFinally, PromiseBuiltinsAssembler) {
1540   CSA_ASSERT_JS_ARGC_EQ(this, 1);
1541 
1542   Node* const reason = Parameter(Descriptor::kReason);
1543   Node* const context = Parameter(Descriptor::kContext);
1544 
1545   // 1. Let onFinally be F.[[OnFinally]].
1546   Node* const on_finally = LoadContextElement(context, kOnFinallySlot);
1547 
1548   // 2. Assert: IsCallable(onFinally) is true.
1549   CSA_ASSERT(this, IsCallable(on_finally));
1550 
1551   // 3. Let result be ? Call(onFinally).
1552   Node* result = CallJS(
1553       CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1554       context, on_finally, UndefinedConstant());
1555 
1556   // 4. Let C be F.[[Constructor]].
1557   Node* const constructor = LoadContextElement(context, kConstructorSlot);
1558 
1559   // 5. Assert: IsConstructor(C) is true.
1560   CSA_ASSERT(this, IsConstructor(constructor));
1561 
1562   // 6. Let promise be ? PromiseResolve(C, result).
1563   Node* const promise =
1564     CallBuiltin(Builtins::kPromiseResolve, context, constructor, result);
1565 
1566   // 7. Let thrower be equivalent to a function that throws reason.
1567   Node* const native_context = LoadNativeContext(context);
1568   Node* const thrower = CreateThrowerFunction(reason, native_context);
1569 
1570   // 8. Return ? Invoke(promise, "then", « thrower »).
1571   Return(InvokeThen(native_context, promise, thrower));
1572 }
1573 
TF_BUILTIN(PromisePrototypeFinally,PromiseBuiltinsAssembler)1574 TF_BUILTIN(PromisePrototypeFinally, PromiseBuiltinsAssembler) {
1575   CSA_ASSERT_JS_ARGC_EQ(this, 1);
1576 
1577   // 1.  Let promise be the this value.
1578   Node* const receiver = Parameter(Descriptor::kReceiver);
1579   Node* const on_finally = Parameter(Descriptor::kOnFinally);
1580   Node* const context = Parameter(Descriptor::kContext);
1581 
1582   // 2. If Type(promise) is not Object, throw a TypeError exception.
1583   ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1584                        "Promise.prototype.finally");
1585 
1586   // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
1587   Node* const native_context = LoadNativeContext(context);
1588   Node* const promise_fun =
1589       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1590   VARIABLE(var_constructor, MachineRepresentation::kTagged, promise_fun);
1591   Label slow_constructor(this, Label::kDeferred), done_constructor(this);
1592   Node* const receiver_map = LoadMap(receiver);
1593   GotoIfNot(IsJSPromiseMap(receiver_map), &slow_constructor);
1594   BranchIfPromiseSpeciesLookupChainIntact(native_context, receiver_map,
1595                                           &done_constructor, &slow_constructor);
1596   BIND(&slow_constructor);
1597   {
1598     Node* const constructor =
1599         SpeciesConstructor(context, receiver, promise_fun);
1600     var_constructor.Bind(constructor);
1601     Goto(&done_constructor);
1602   }
1603   BIND(&done_constructor);
1604   Node* const constructor = var_constructor.value();
1605 
1606   // 4. Assert: IsConstructor(C) is true.
1607   CSA_ASSERT(this, IsConstructor(constructor));
1608 
1609   VARIABLE(var_then_finally, MachineRepresentation::kTagged);
1610   VARIABLE(var_catch_finally, MachineRepresentation::kTagged);
1611 
1612   Label if_notcallable(this, Label::kDeferred), perform_finally(this);
1613 
1614   GotoIf(TaggedIsSmi(on_finally), &if_notcallable);
1615   GotoIfNot(IsCallable(on_finally), &if_notcallable);
1616 
1617   // 6. Else,
1618   //   a. Let thenFinally be a new built-in function object as defined
1619   //   in ThenFinally Function.
1620   //   b. Let catchFinally be a new built-in function object as
1621   //   defined in CatchFinally Function.
1622   //   c. Set thenFinally and catchFinally's [[Constructor]] internal
1623   //   slots to C.
1624   //   d. Set thenFinally and catchFinally's [[OnFinally]] internal
1625   //   slots to onFinally.
1626   Node* then_finally = nullptr;
1627   Node* catch_finally = nullptr;
1628   std::tie(then_finally, catch_finally) =
1629     CreatePromiseFinallyFunctions(on_finally, constructor, native_context);
1630   var_then_finally.Bind(then_finally);
1631   var_catch_finally.Bind(catch_finally);
1632   Goto(&perform_finally);
1633 
1634   // 5. If IsCallable(onFinally) is not true,
1635   //    a. Let thenFinally be onFinally.
1636   //    b. Let catchFinally be onFinally.
1637   BIND(&if_notcallable);
1638   {
1639     var_then_finally.Bind(on_finally);
1640     var_catch_finally.Bind(on_finally);
1641     Goto(&perform_finally);
1642   }
1643 
1644   // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »).
1645   BIND(&perform_finally);
1646   Return(InvokeThen(native_context, receiver, var_then_finally.value(),
1647                     var_catch_finally.value()));
1648 }
1649 
1650 // ES #sec-fulfillpromise
TF_BUILTIN(FulfillPromise,PromiseBuiltinsAssembler)1651 TF_BUILTIN(FulfillPromise, PromiseBuiltinsAssembler) {
1652   Node* const promise = Parameter(Descriptor::kPromise);
1653   Node* const value = Parameter(Descriptor::kValue);
1654   Node* const context = Parameter(Descriptor::kContext);
1655 
1656   CSA_ASSERT(this, TaggedIsNotSmi(promise));
1657   CSA_ASSERT(this, IsJSPromise(promise));
1658 
1659   // 2. Let reactions be promise.[[PromiseFulfillReactions]].
1660   Node* const reactions =
1661       LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
1662 
1663   // 3. Set promise.[[PromiseResult]] to value.
1664   // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
1665   // 5. Set promise.[[PromiseRejectReactions]] to undefined.
1666   StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, value);
1667 
1668   // 6. Set promise.[[PromiseState]] to "fulfilled".
1669   PromiseSetStatus(promise, Promise::kFulfilled);
1670 
1671   // 7. Return TriggerPromiseReactions(reactions, value).
1672   Return(TriggerPromiseReactions(context, reactions, value,
1673                                  PromiseReaction::kFulfill));
1674 }
1675 
1676 // ES #sec-rejectpromise
TF_BUILTIN(RejectPromise,PromiseBuiltinsAssembler)1677 TF_BUILTIN(RejectPromise, PromiseBuiltinsAssembler) {
1678   Node* const promise = Parameter(Descriptor::kPromise);
1679   Node* const reason = Parameter(Descriptor::kReason);
1680   Node* const debug_event = Parameter(Descriptor::kDebugEvent);
1681   Node* const context = Parameter(Descriptor::kContext);
1682 
1683   CSA_ASSERT(this, TaggedIsNotSmi(promise));
1684   CSA_ASSERT(this, IsJSPromise(promise));
1685   CSA_ASSERT(this, IsBoolean(debug_event));
1686   Label if_runtime(this, Label::kDeferred);
1687 
1688   // If promise hook is enabled or the debugger is active, let
1689   // the runtime handle this operation, which greatly reduces
1690   // the complexity here and also avoids a couple of back and
1691   // forth between JavaScript and C++ land.
1692   GotoIf(IsPromiseHookEnabled(), &if_runtime);
1693   GotoIf(IsDebugActive(), &if_runtime);
1694 
1695   // 7. If promise.[[PromiseIsHandled]] is false, perform
1696   //    HostPromiseRejectionTracker(promise, "reject").
1697   // We don't try to handle rejecting {promise} without handler
1698   // here, but we let the C++ code take care of this completely.
1699   GotoIfNot(PromiseHasHandler(promise), &if_runtime);
1700 
1701   // 2. Let reactions be promise.[[PromiseRejectReactions]].
1702   Node* reactions =
1703       LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
1704 
1705   // 3. Set promise.[[PromiseResult]] to reason.
1706   // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
1707   // 5. Set promise.[[PromiseRejectReactions]] to undefined.
1708   StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reason);
1709 
1710   // 6. Set promise.[[PromiseState]] to "rejected".
1711   PromiseSetStatus(promise, Promise::kRejected);
1712 
1713   // 7. Return TriggerPromiseReactions(reactions, reason).
1714   Return(TriggerPromiseReactions(context, reactions, reason,
1715                                  PromiseReaction::kReject));
1716 
1717   BIND(&if_runtime);
1718   TailCallRuntime(Runtime::kRejectPromise, context, promise, reason,
1719                   debug_event);
1720 }
1721 
1722 // ES #sec-promise-resolve-functions
TF_BUILTIN(ResolvePromise,PromiseBuiltinsAssembler)1723 TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
1724   Node* const promise = Parameter(Descriptor::kPromise);
1725   Node* const resolution = Parameter(Descriptor::kResolution);
1726   Node* const context = Parameter(Descriptor::kContext);
1727 
1728   CSA_ASSERT(this, TaggedIsNotSmi(promise));
1729   CSA_ASSERT(this, IsJSPromise(promise));
1730 
1731   Label do_enqueue(this), if_fulfill(this), if_reject(this, Label::kDeferred),
1732       if_runtime(this, Label::kDeferred);
1733   VARIABLE(var_reason, MachineRepresentation::kTagged);
1734   VARIABLE(var_then, MachineRepresentation::kTagged);
1735 
1736   // If promise hook is enabled or the debugger is active, let
1737   // the runtime handle this operation, which greatly reduces
1738   // the complexity here and also avoids a couple of back and
1739   // forth between JavaScript and C++ land.
1740   GotoIf(IsPromiseHookEnabled(), &if_runtime);
1741   GotoIf(IsDebugActive(), &if_runtime);
1742 
1743   // 6. If SameValue(resolution, promise) is true, then
1744   // We can use pointer comparison here, since the {promise} is guaranteed
1745   // to be a JSPromise inside this function and thus is reference comparable.
1746   GotoIf(WordEqual(promise, resolution), &if_runtime);
1747 
1748   // 7. If Type(resolution) is not Object, then
1749   GotoIf(TaggedIsSmi(resolution), &if_fulfill);
1750   Node* const resolution_map = LoadMap(resolution);
1751   GotoIfNot(IsJSReceiverMap(resolution_map), &if_fulfill);
1752 
1753   // We can skip the "then" lookup on {resolution} if its [[Prototype]]
1754   // is the (initial) Promise.prototype and the Promise#then protector
1755   // is intact, as that guards the lookup path for the "then" property
1756   // on JSPromise instances which have the (initial) %PromisePrototype%.
1757   Label if_fast(this), if_receiver(this), if_slow(this, Label::kDeferred);
1758   Node* const native_context = LoadNativeContext(context);
1759   GotoIfForceSlowPath(&if_slow);
1760   GotoIf(IsPromiseThenProtectorCellInvalid(), &if_slow);
1761   GotoIfNot(IsJSPromiseMap(resolution_map), &if_receiver);
1762   Node* const promise_prototype =
1763       LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
1764   Branch(WordEqual(LoadMapPrototype(resolution_map), promise_prototype),
1765          &if_fast, &if_slow);
1766 
1767   BIND(&if_fast);
1768   {
1769     // The {resolution} is a native Promise in this case.
1770     Node* const then =
1771         LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
1772     var_then.Bind(then);
1773     Goto(&do_enqueue);
1774   }
1775 
1776   BIND(&if_receiver);
1777   {
1778     // We can skip the lookup of "then" if the {resolution} is a (newly
1779     // created) IterResultObject, as the Promise#then() protector also
1780     // ensures that the intrinsic %ObjectPrototype% doesn't contain any
1781     // "then" property. This helps to avoid negative lookups on iterator
1782     // results from async generators.
1783     CSA_ASSERT(this, IsJSReceiverMap(resolution_map));
1784     CSA_ASSERT(this, Word32BinaryNot(IsPromiseThenProtectorCellInvalid()));
1785     Node* const iterator_result_map =
1786         LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
1787     Branch(WordEqual(resolution_map, iterator_result_map), &if_fulfill,
1788            &if_slow);
1789   }
1790 
1791   BIND(&if_slow);
1792   {
1793     // 8. Let then be Get(resolution, "then").
1794     Node* const then =
1795         GetProperty(context, resolution, isolate()->factory()->then_string());
1796 
1797     // 9. If then is an abrupt completion, then
1798     GotoIfException(then, &if_reject, &var_reason);
1799 
1800     // 11. If IsCallable(thenAction) is false, then
1801     GotoIf(TaggedIsSmi(then), &if_fulfill);
1802     Node* const then_map = LoadMap(then);
1803     GotoIfNot(IsCallableMap(then_map), &if_fulfill);
1804     var_then.Bind(then);
1805     Goto(&do_enqueue);
1806   }
1807 
1808   BIND(&do_enqueue);
1809   {
1810     // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob,
1811     //                        «promise, resolution, thenAction»).
1812     Node* const task = AllocatePromiseResolveThenableJobTask(
1813         promise, var_then.value(), resolution, native_context);
1814     TailCallBuiltin(Builtins::kEnqueueMicrotask, native_context, task);
1815   }
1816 
1817   BIND(&if_fulfill);
1818   {
1819     // 7.b Return FulfillPromise(promise, resolution).
1820     TailCallBuiltin(Builtins::kFulfillPromise, context, promise, resolution);
1821   }
1822 
1823   BIND(&if_runtime);
1824   Return(CallRuntime(Runtime::kResolvePromise, context, promise, resolution));
1825 
1826   BIND(&if_reject);
1827   {
1828     // 9.a Return RejectPromise(promise, then.[[Value]]).
1829     TailCallBuiltin(Builtins::kRejectPromise, context, promise,
1830                     var_reason.value(), FalseConstant());
1831   }
1832 }
1833 
PerformPromiseAll(Node * context,Node * constructor,Node * capability,const IteratorRecord & iterator,Label * if_exception,Variable * var_exception)1834 Node* PromiseBuiltinsAssembler::PerformPromiseAll(
1835     Node* context, Node* constructor, Node* capability,
1836     const IteratorRecord& iterator, Label* if_exception,
1837     Variable* var_exception) {
1838   IteratorBuiltinsAssembler iter_assembler(state());
1839 
1840   Node* const instrumenting = IsDebugActive();
1841   Node* const native_context = LoadNativeContext(context);
1842 
1843   // For catch prediction, don't treat the .then calls as handling it;
1844   // instead, recurse outwards.
1845   SetForwardingHandlerIfTrue(
1846       native_context, instrumenting,
1847       LoadObjectField(capability, PromiseCapability::kRejectOffset));
1848 
1849   Node* const resolve_element_context =
1850       CreatePromiseAllResolveElementContext(capability, native_context);
1851 
1852   TVARIABLE(Smi, var_index, SmiConstant(1));
1853   Label loop(this, &var_index), done_loop(this),
1854       too_many_elements(this, Label::kDeferred),
1855       close_iterator(this, Label::kDeferred);
1856   Goto(&loop);
1857   BIND(&loop);
1858   {
1859     // Let next be IteratorStep(iteratorRecord.[[Iterator]]).
1860     // If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
1861     // ReturnIfAbrupt(next).
1862     Node* const fast_iterator_result_map =
1863         LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
1864     Node* const next = iter_assembler.IteratorStep(
1865         native_context, iterator, &done_loop, fast_iterator_result_map,
1866         if_exception, var_exception);
1867 
1868     // Let nextValue be IteratorValue(next).
1869     // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to
1870     //     true.
1871     // ReturnIfAbrupt(nextValue).
1872     Node* const next_value = iter_assembler.IteratorValue(
1873         native_context, next, fast_iterator_result_map, if_exception,
1874         var_exception);
1875 
1876     // Let nextPromise be ? Invoke(constructor, "resolve", « nextValue »).
1877     Node* const next_promise =
1878         InvokeResolve(native_context, constructor, next_value, &close_iterator,
1879                       var_exception);
1880 
1881     // Check if we reached the limit.
1882     TNode<Smi> const index = var_index.value();
1883     GotoIf(SmiEqual(index, SmiConstant(PropertyArray::HashField::kMax)),
1884            &too_many_elements);
1885 
1886     // Set remainingElementsCount.[[Value]] to
1887     //     remainingElementsCount.[[Value]] + 1.
1888     TNode<Smi> const remaining_elements_count = CAST(LoadContextElement(
1889         resolve_element_context, kPromiseAllResolveElementRemainingSlot));
1890     StoreContextElementNoWriteBarrier(
1891         resolve_element_context, kPromiseAllResolveElementRemainingSlot,
1892         SmiAdd(remaining_elements_count, SmiConstant(1)));
1893 
1894     // Let resolveElement be CreateBuiltinFunction(steps,
1895     //                                             « [[AlreadyCalled]],
1896     //                                               [[Index]],
1897     //                                               [[Values]],
1898     //                                               [[Capability]],
1899     //                                               [[RemainingElements]] »).
1900     // Set resolveElement.[[AlreadyCalled]] to a Record { [[Value]]: false }.
1901     // Set resolveElement.[[Index]] to index.
1902     // Set resolveElement.[[Values]] to values.
1903     // Set resolveElement.[[Capability]] to resultCapability.
1904     // Set resolveElement.[[RemainingElements]] to remainingElementsCount.
1905     Node* const resolve_element_fun = CreatePromiseAllResolveElementFunction(
1906         resolve_element_context, index, native_context);
1907 
1908     // Perform ? Invoke(nextPromise, "then", « resolveElement,
1909     //                  resultCapability.[[Reject]] »).
1910     Node* const then =
1911         GetProperty(native_context, next_promise, factory()->then_string());
1912     GotoIfException(then, &close_iterator, var_exception);
1913 
1914     Node* const then_call = CallJS(
1915         CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
1916         native_context, then, next_promise, resolve_element_fun,
1917         LoadObjectField(capability, PromiseCapability::kRejectOffset));
1918     GotoIfException(then_call, &close_iterator, var_exception);
1919 
1920     // For catch prediction, mark that rejections here are semantically
1921     // handled by the combined Promise.
1922     SetPromiseHandledByIfTrue(native_context, instrumenting, then_call, [=]() {
1923       // Load promiseCapability.[[Promise]]
1924       return LoadObjectField(capability, PromiseCapability::kPromiseOffset);
1925     });
1926 
1927     // Set index to index + 1.
1928     var_index = SmiAdd(index, SmiConstant(1));
1929     Goto(&loop);
1930   }
1931 
1932   BIND(&too_many_elements);
1933   {
1934     // If there are too many elements (currently more than 2**21-1), raise a
1935     // RangeError here (which is caught directly and turned into a rejection)
1936     // of the resulting promise. We could gracefully handle this case as well
1937     // and support more than this number of elements by going to a separate
1938     // function and pass the larger indices via a separate context, but it
1939     // doesn't seem likely that we need this, and it's unclear how the rest
1940     // of the system deals with 2**21 live Promises anyways.
1941     Node* const result =
1942         CallRuntime(Runtime::kThrowRangeError, native_context,
1943                     SmiConstant(MessageTemplate::kTooManyElementsInPromiseAll));
1944     GotoIfException(result, &close_iterator, var_exception);
1945     Unreachable();
1946   }
1947 
1948   BIND(&close_iterator);
1949   {
1950     // Exception must be bound to a JS value.
1951     CSA_ASSERT(this, IsNotTheHole(var_exception->value()));
1952     iter_assembler.IteratorCloseOnException(native_context, iterator,
1953                                             if_exception, var_exception);
1954   }
1955 
1956   BIND(&done_loop);
1957   {
1958     Label resolve_promise(this, Label::kDeferred), return_promise(this);
1959     // Set iteratorRecord.[[Done]] to true.
1960     // Set remainingElementsCount.[[Value]] to
1961     //    remainingElementsCount.[[Value]] - 1.
1962     TNode<Smi> remaining_elements_count = CAST(LoadContextElement(
1963         resolve_element_context, kPromiseAllResolveElementRemainingSlot));
1964     remaining_elements_count = SmiSub(remaining_elements_count, SmiConstant(1));
1965     StoreContextElementNoWriteBarrier(resolve_element_context,
1966                                       kPromiseAllResolveElementRemainingSlot,
1967                                       remaining_elements_count);
1968     GotoIf(SmiEqual(remaining_elements_count, SmiConstant(0)),
1969            &resolve_promise);
1970 
1971     // Pre-allocate the backing store for the {values_array} to the desired
1972     // capacity here. We may already have elements here in case of some
1973     // fancy Thenable that calls the resolve callback immediately, so we need
1974     // to handle that correctly here.
1975     Node* const values_array = LoadContextElement(
1976         resolve_element_context, kPromiseAllResolveElementValuesArraySlot);
1977     Node* const old_elements = LoadElements(values_array);
1978     TNode<Smi> const old_capacity = LoadFixedArrayBaseLength(old_elements);
1979     TNode<Smi> const new_capacity = var_index.value();
1980     GotoIf(SmiGreaterThanOrEqual(old_capacity, new_capacity), &return_promise);
1981     Node* const new_elements =
1982         AllocateFixedArray(PACKED_ELEMENTS, new_capacity, SMI_PARAMETERS,
1983                            AllocationFlag::kAllowLargeObjectAllocation);
1984     CopyFixedArrayElements(PACKED_ELEMENTS, old_elements, PACKED_ELEMENTS,
1985                            new_elements, SmiConstant(0), old_capacity,
1986                            new_capacity, UPDATE_WRITE_BARRIER, SMI_PARAMETERS);
1987     StoreObjectField(values_array, JSArray::kElementsOffset, new_elements);
1988     Goto(&return_promise);
1989 
1990     // If remainingElementsCount.[[Value]] is 0, then
1991     //     Let valuesArray be CreateArrayFromList(values).
1992     //     Perform ? Call(resultCapability.[[Resolve]], undefined,
1993     //                    « valuesArray »).
1994     BIND(&resolve_promise);
1995     {
1996       Node* const resolve =
1997           LoadObjectField(capability, PromiseCapability::kResolveOffset);
1998       Node* const values_array = LoadContextElement(
1999           resolve_element_context, kPromiseAllResolveElementValuesArraySlot);
2000       Node* const resolve_call = CallJS(
2001           CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
2002           native_context, resolve, UndefinedConstant(), values_array);
2003       GotoIfException(resolve_call, if_exception, var_exception);
2004       Goto(&return_promise);
2005     }
2006 
2007     // Return resultCapability.[[Promise]].
2008     BIND(&return_promise);
2009   }
2010 
2011   Node* const promise =
2012       LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2013   return promise;
2014 }
2015 
2016 // ES#sec-promise.all
2017 // Promise.all ( iterable )
TF_BUILTIN(PromiseAll,PromiseBuiltinsAssembler)2018 TF_BUILTIN(PromiseAll, PromiseBuiltinsAssembler) {
2019   IteratorBuiltinsAssembler iter_assembler(state());
2020 
2021   // Let C be the this value.
2022   // If Type(C) is not Object, throw a TypeError exception.
2023   Node* const receiver = Parameter(Descriptor::kReceiver);
2024   Node* const context = Parameter(Descriptor::kContext);
2025   ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
2026                        "Promise.all");
2027 
2028   // Let promiseCapability be ? NewPromiseCapability(C).
2029   // Don't fire debugEvent so that forwarding the rejection through all does not
2030   // trigger redundant ExceptionEvents
2031   Node* const debug_event = FalseConstant();
2032   Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability, context,
2033                                        receiver, debug_event);
2034 
2035   VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
2036   Label reject_promise(this, &var_exception, Label::kDeferred);
2037 
2038   // Let iterator be GetIterator(iterable).
2039   // IfAbruptRejectPromise(iterator, promiseCapability).
2040   Node* const iterable = Parameter(Descriptor::kIterable);
2041   IteratorRecord iterator = iter_assembler.GetIterator(
2042       context, iterable, &reject_promise, &var_exception);
2043 
2044   // Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability).
2045   // If result is an abrupt completion, then
2046   //   If iteratorRecord.[[Done]] is false, let result be
2047   //       IteratorClose(iterator, result).
2048   //    IfAbruptRejectPromise(result, promiseCapability).
2049   Node* const result = PerformPromiseAll(
2050       context, receiver, capability, iterator, &reject_promise, &var_exception);
2051 
2052   Return(result);
2053 
2054   BIND(&reject_promise);
2055   {
2056     // Exception must be bound to a JS value.
2057     CSA_SLOW_ASSERT(this, IsNotTheHole(var_exception.value()));
2058     Node* const reject =
2059         LoadObjectField(capability, PromiseCapability::kRejectOffset);
2060     CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
2061            context, reject, UndefinedConstant(), var_exception.value());
2062 
2063     Node* const promise =
2064         LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2065     Return(promise);
2066   }
2067 }
2068 
TF_BUILTIN(PromiseAllResolveElementClosure,PromiseBuiltinsAssembler)2069 TF_BUILTIN(PromiseAllResolveElementClosure, PromiseBuiltinsAssembler) {
2070   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
2071   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2072   TNode<JSFunction> function = CAST(Parameter(Descriptor::kJSTarget));
2073 
2074   Label already_called(this, Label::kDeferred), resolve_promise(this);
2075 
2076   // We use the {function}s context as the marker to remember whether this
2077   // resolve element closure was already called. It points to the resolve
2078   // element context (which is a FunctionContext) until it was called the
2079   // first time, in which case we make it point to the native context here
2080   // to mark this resolve element closure as done.
2081   GotoIf(IsNativeContext(context), &already_called);
2082   CSA_ASSERT(this, SmiEqual(LoadFixedArrayBaseLength(context),
2083                             SmiConstant(kPromiseAllResolveElementLength)));
2084   TNode<Context> native_context = LoadNativeContext(context);
2085   StoreObjectField(function, JSFunction::kContextOffset, native_context);
2086 
2087   // Determine the index from the {function}.
2088   Label unreachable(this, Label::kDeferred);
2089   STATIC_ASSERT(PropertyArray::kNoHashSentinel == 0);
2090   TNode<IntPtrT> identity_hash =
2091       LoadJSReceiverIdentityHash(function, &unreachable);
2092   CSA_ASSERT(this, IntPtrGreaterThan(identity_hash, IntPtrConstant(0)));
2093   TNode<IntPtrT> index = IntPtrSub(identity_hash, IntPtrConstant(1));
2094 
2095   // Check if we need to grow the [[ValuesArray]] to store {value} at {index}.
2096   TNode<JSArray> values_array = CAST(
2097       LoadContextElement(context, kPromiseAllResolveElementValuesArraySlot));
2098   TNode<FixedArray> elements = CAST(LoadElements(values_array));
2099   TNode<IntPtrT> values_length =
2100       LoadAndUntagObjectField(values_array, JSArray::kLengthOffset);
2101   Label if_inbounds(this), if_outofbounds(this), done(this);
2102   Branch(IntPtrLessThan(index, values_length), &if_inbounds, &if_outofbounds);
2103 
2104   BIND(&if_outofbounds);
2105   {
2106     // Check if we need to grow the backing store.
2107     TNode<IntPtrT> new_length = IntPtrAdd(index, IntPtrConstant(1));
2108     TNode<IntPtrT> elements_length =
2109         LoadAndUntagObjectField(elements, FixedArray::kLengthOffset);
2110     Label if_grow(this, Label::kDeferred), if_nogrow(this);
2111     Branch(IntPtrLessThan(index, elements_length), &if_nogrow, &if_grow);
2112 
2113     BIND(&if_grow);
2114     {
2115       // We need to grow the backing store to fit the {index} as well.
2116       TNode<IntPtrT> new_elements_length =
2117           IntPtrMin(CalculateNewElementsCapacity(new_length),
2118                     IntPtrConstant(PropertyArray::HashField::kMax + 1));
2119       CSA_ASSERT(this, IntPtrLessThan(index, new_elements_length));
2120       CSA_ASSERT(this, IntPtrLessThan(elements_length, new_elements_length));
2121       TNode<FixedArray> new_elements =
2122           CAST(AllocateFixedArray(PACKED_ELEMENTS, new_elements_length,
2123                                   AllocationFlag::kAllowLargeObjectAllocation));
2124       CopyFixedArrayElements(PACKED_ELEMENTS, elements, PACKED_ELEMENTS,
2125                              new_elements, elements_length,
2126                              new_elements_length);
2127       StoreFixedArrayElement(new_elements, index, value);
2128 
2129       // Update backing store and "length" on {values_array}.
2130       StoreObjectField(values_array, JSArray::kElementsOffset, new_elements);
2131       StoreObjectFieldNoWriteBarrier(values_array, JSArray::kLengthOffset,
2132                                      SmiTag(new_length));
2133       Goto(&done);
2134     }
2135 
2136     BIND(&if_nogrow);
2137     {
2138       // The {index} is within bounds of the {elements} backing store, so
2139       // just store the {value} and update the "length" of the {values_array}.
2140       StoreObjectFieldNoWriteBarrier(values_array, JSArray::kLengthOffset,
2141                                      SmiTag(new_length));
2142       StoreFixedArrayElement(elements, index, value);
2143       Goto(&done);
2144     }
2145   }
2146 
2147   BIND(&if_inbounds);
2148   {
2149     // The {index} is in bounds of the {values_array},
2150     // just store the {value} and continue.
2151     StoreFixedArrayElement(elements, index, value);
2152     Goto(&done);
2153   }
2154 
2155   BIND(&done);
2156   TNode<Smi> remaining_elements_count =
2157       CAST(LoadContextElement(context, kPromiseAllResolveElementRemainingSlot));
2158   remaining_elements_count = SmiSub(remaining_elements_count, SmiConstant(1));
2159   StoreContextElement(context, kPromiseAllResolveElementRemainingSlot,
2160                       remaining_elements_count);
2161   GotoIf(SmiEqual(remaining_elements_count, SmiConstant(0)), &resolve_promise);
2162   Return(UndefinedConstant());
2163 
2164   BIND(&resolve_promise);
2165   TNode<PromiseCapability> capability = CAST(
2166       LoadContextElement(context, kPromiseAllResolveElementCapabilitySlot));
2167   TNode<Object> resolve =
2168       LoadObjectField(capability, PromiseCapability::kResolveOffset);
2169   CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
2170          context, resolve, UndefinedConstant(), values_array);
2171   Return(UndefinedConstant());
2172 
2173   BIND(&already_called);
2174   Return(UndefinedConstant());
2175 
2176   BIND(&unreachable);
2177   Unreachable();
2178 }
2179 
2180 // ES#sec-promise.race
2181 // Promise.race ( iterable )
TF_BUILTIN(PromiseRace,PromiseBuiltinsAssembler)2182 TF_BUILTIN(PromiseRace, PromiseBuiltinsAssembler) {
2183   IteratorBuiltinsAssembler iter_assembler(state());
2184   VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
2185 
2186   Node* const receiver = Parameter(Descriptor::kReceiver);
2187   Node* const context = Parameter(Descriptor::kContext);
2188   ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
2189                        "Promise.race");
2190 
2191   // Let promiseCapability be ? NewPromiseCapability(C).
2192   // Don't fire debugEvent so that forwarding the rejection through all does not
2193   // trigger redundant ExceptionEvents
2194   Node* const debug_event = FalseConstant();
2195   Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability, context,
2196                                        receiver, debug_event);
2197 
2198   Node* const resolve =
2199       LoadObjectField(capability, PromiseCapability::kResolveOffset);
2200   Node* const reject =
2201       LoadObjectField(capability, PromiseCapability::kRejectOffset);
2202 
2203   Node* const instrumenting = IsDebugActive();
2204 
2205   Label close_iterator(this, Label::kDeferred);
2206   Label reject_promise(this, Label::kDeferred);
2207 
2208   // For catch prediction, don't treat the .then calls as handling it;
2209   // instead, recurse outwards.
2210   SetForwardingHandlerIfTrue(context, instrumenting, reject);
2211 
2212   // Let iterator be GetIterator(iterable).
2213   // IfAbruptRejectPromise(iterator, promiseCapability).
2214   Node* const iterable = Parameter(Descriptor::kIterable);
2215   IteratorRecord iterator = iter_assembler.GetIterator(
2216       context, iterable, &reject_promise, &var_exception);
2217 
2218   // Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability).
2219   {
2220     Label loop(this), break_loop(this);
2221     Goto(&loop);
2222     BIND(&loop);
2223     {
2224       Node* const native_context = LoadNativeContext(context);
2225       Node* const fast_iterator_result_map = LoadContextElement(
2226           native_context, Context::ITERATOR_RESULT_MAP_INDEX);
2227 
2228       // Let next be IteratorStep(iteratorRecord.[[Iterator]]).
2229       // If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
2230       // ReturnIfAbrupt(next).
2231       Node* const next = iter_assembler.IteratorStep(
2232           context, iterator, &break_loop, fast_iterator_result_map,
2233           &reject_promise, &var_exception);
2234 
2235       // Let nextValue be IteratorValue(next).
2236       // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to
2237       //     true.
2238       // ReturnIfAbrupt(nextValue).
2239       Node* const next_value =
2240           iter_assembler.IteratorValue(context, next, fast_iterator_result_map,
2241                                        &reject_promise, &var_exception);
2242 
2243       // Let nextPromise be ? Invoke(constructor, "resolve", « nextValue »).
2244       Node* const next_promise =
2245           InvokeResolve(native_context, receiver, next_value, &close_iterator,
2246                         &var_exception);
2247 
2248       // Perform ? Invoke(nextPromise, "then", « resolveElement,
2249       //                  resultCapability.[[Reject]] »).
2250       Node* const then =
2251           GetProperty(context, next_promise, factory()->then_string());
2252       GotoIfException(then, &close_iterator, &var_exception);
2253 
2254       Node* const then_call =
2255           CallJS(CodeFactory::Call(isolate(),
2256                                    ConvertReceiverMode::kNotNullOrUndefined),
2257                  context, then, next_promise, resolve, reject);
2258       GotoIfException(then_call, &close_iterator, &var_exception);
2259 
2260       // For catch prediction, mark that rejections here are semantically
2261       // handled by the combined Promise.
2262       SetPromiseHandledByIfTrue(context, instrumenting, then_call, [=]() {
2263         // Load promiseCapability.[[Promise]]
2264         return LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2265       });
2266       Goto(&loop);
2267     }
2268 
2269     BIND(&break_loop);
2270     Return(LoadObjectField(capability, PromiseCapability::kPromiseOffset));
2271   }
2272 
2273   BIND(&close_iterator);
2274   {
2275     CSA_ASSERT(this, IsNotTheHole(var_exception.value()));
2276     iter_assembler.IteratorCloseOnException(context, iterator, &reject_promise,
2277                                             &var_exception);
2278   }
2279 
2280   BIND(&reject_promise);
2281   {
2282     Node* const reject =
2283         LoadObjectField(capability, PromiseCapability::kRejectOffset);
2284     CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
2285            context, reject, UndefinedConstant(), var_exception.value());
2286 
2287     Node* const promise =
2288         LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2289     Return(promise);
2290   }
2291 }
2292 
2293 }  // namespace internal
2294 }  // namespace v8
2295