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