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