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