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 864 : Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) {
25 864 : Node* const native_context = LoadNativeContext(context);
26 : Node* const promise_fun =
27 864 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
28 : CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(promise_fun)));
29 : Node* const promise_map =
30 864 : LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
31 864 : Node* const promise = Allocate(JSPromise::kSizeWithEmbedderFields);
32 864 : StoreMapNoWriteBarrier(promise, promise_map);
33 : StoreObjectFieldRoot(promise, JSPromise::kPropertiesOrHashOffset,
34 864 : RootIndex::kEmptyFixedArray);
35 : StoreObjectFieldRoot(promise, JSPromise::kElementsOffset,
36 864 : RootIndex::kEmptyFixedArray);
37 864 : return promise;
38 : }
39 :
40 1252 : void PromiseBuiltinsAssembler::PromiseInit(Node* promise) {
41 : STATIC_ASSERT(v8::Promise::kPending == 0);
42 : StoreObjectFieldNoWriteBarrier(promise, JSPromise::kReactionsOrResultOffset,
43 1252 : SmiConstant(Smi::zero()));
44 : StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset,
45 1252 : SmiConstant(Smi::zero()));
46 1252 : for (int offset = JSPromise::kSize;
47 : offset < JSPromise::kSizeWithEmbedderFields; offset += kTaggedSize) {
48 0 : StoreObjectFieldNoWriteBarrier(promise, offset, SmiConstant(Smi::zero()));
49 : }
50 1252 : }
51 :
52 620 : Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context) {
53 620 : return AllocateAndInitJSPromise(context, UndefinedConstant());
54 : }
55 :
56 804 : Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context,
57 : Node* parent) {
58 804 : Node* const instance = AllocateJSPromise(context);
59 804 : PromiseInit(instance);
60 :
61 804 : Label out(this);
62 804 : GotoIfNot(IsPromiseHookEnabledOrHasAsyncEventDelegate(), &out);
63 804 : CallRuntime(Runtime::kPromiseHookInit, context, instance, parent);
64 804 : Goto(&out);
65 :
66 804 : BIND(&out);
67 804 : return instance;
68 : }
69 :
70 60 : Node* PromiseBuiltinsAssembler::AllocateAndSetJSPromise(
71 : Node* context, v8::Promise::PromiseState status, Node* result) {
72 : DCHECK_NE(Promise::kPending, status);
73 :
74 60 : Node* const instance = AllocateJSPromise(context);
75 : StoreObjectFieldNoWriteBarrier(instance, JSPromise::kReactionsOrResultOffset,
76 60 : result);
77 : STATIC_ASSERT(JSPromise::kStatusShift == 0);
78 : StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset,
79 60 : SmiConstant(status));
80 60 : for (int offset = JSPromise::kSize;
81 : offset < JSPromise::kSizeWithEmbedderFields; offset += kTaggedSize) {
82 0 : StoreObjectFieldNoWriteBarrier(instance, offset, SmiConstant(0));
83 : }
84 :
85 60 : Label out(this);
86 60 : GotoIfNot(IsPromiseHookEnabledOrHasAsyncEventDelegate(), &out);
87 : CallRuntime(Runtime::kPromiseHookInit, context, instance,
88 60 : UndefinedConstant());
89 60 : Goto(&out);
90 :
91 60 : BIND(&out);
92 60 : return instance;
93 : }
94 :
95 : std::pair<Node*, Node*>
96 172 : PromiseBuiltinsAssembler::CreatePromiseResolvingFunctions(
97 : Node* promise, Node* debug_event, Node* native_context) {
98 : Node* const promise_context = CreatePromiseResolvingFunctionsContext(
99 172 : promise, debug_event, native_context);
100 : Node* const map = LoadContextElement(
101 172 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
102 : Node* const resolve_info = LoadContextElement(
103 : native_context,
104 172 : Context::PROMISE_CAPABILITY_DEFAULT_RESOLVE_SHARED_FUN_INDEX);
105 : Node* const resolve =
106 172 : AllocateFunctionWithMapAndContext(map, resolve_info, promise_context);
107 : Node* const reject_info = LoadContextElement(
108 : native_context,
109 172 : Context::PROMISE_CAPABILITY_DEFAULT_REJECT_SHARED_FUN_INDEX);
110 : Node* const reject =
111 172 : AllocateFunctionWithMapAndContext(map, reject_info, promise_context);
112 172 : return std::make_pair(resolve, reject);
113 : }
114 :
115 : // ES #sec-newpromisecapability
116 392 : TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
117 56 : Node* const context = Parameter(Descriptor::kContext);
118 56 : Node* const constructor = Parameter(Descriptor::kConstructor);
119 56 : Node* const debug_event = Parameter(Descriptor::kDebugEvent);
120 56 : TNode<Context> const native_context = LoadNativeContext(context);
121 :
122 56 : Label if_not_constructor(this, Label::kDeferred),
123 112 : if_notcallable(this, Label::kDeferred), if_fast_promise_capability(this),
124 112 : if_slow_promise_capability(this, Label::kDeferred);
125 56 : GotoIf(TaggedIsSmi(constructor), &if_not_constructor);
126 56 : 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 56 : AllocateAndInitJSPromise(native_context, UndefinedConstant());
136 :
137 56 : Node* resolve = nullptr;
138 56 : Node* reject = nullptr;
139 112 : std::tie(resolve, reject) =
140 112 : CreatePromiseResolvingFunctions(promise, debug_event, native_context);
141 :
142 56 : 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 56 : 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 56 : native_context, Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN);
168 : Node* function_map = LoadContextElement(
169 56 : 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 56 : Node* promise = Construct(native_context, CAST(constructor), executor);
174 56 : StoreObjectField(capability, PromiseCapability::kPromiseOffset, promise);
175 :
176 : Node* resolve =
177 56 : LoadObjectField(capability, PromiseCapability::kResolveOffset);
178 56 : GotoIf(TaggedIsSmi(resolve), &if_notcallable);
179 56 : GotoIfNot(IsCallable(resolve), &if_notcallable);
180 :
181 : Node* reject =
182 56 : LoadObjectField(capability, PromiseCapability::kRejectOffset);
183 56 : GotoIf(TaggedIsSmi(reject), &if_notcallable);
184 56 : 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 632 : Node* PromiseBuiltinsAssembler::CreatePromiseContext(Node* native_context,
196 : int slots) {
197 : DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
198 :
199 632 : Node* const context = AllocateInNewSpace(FixedArray::SizeFor(slots));
200 632 : InitializeFunctionContext(native_context, context, slots);
201 632 : 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 56 : 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 56 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
238 : Node* const resolve_info = LoadContextElement(
239 56 : 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 180 : Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
251 : Node* promise, Node* debug_event, Node* native_context) {
252 : Node* const context = CreatePromiseContext(
253 180 : native_context, PromiseBuiltins::kPromiseContextLength);
254 : StoreContextElementNoWriteBarrier(context, PromiseBuiltins::kPromiseSlot,
255 180 : promise);
256 : StoreContextElementNoWriteBarrier(
257 180 : context, PromiseBuiltins::kAlreadyResolvedSlot, FalseConstant());
258 : StoreContextElementNoWriteBarrier(context, PromiseBuiltins::kDebugEventSlot,
259 180 : debug_event);
260 180 : return context;
261 : }
262 :
263 60 : Node* PromiseBuiltinsAssembler::CreatePromiseGetCapabilitiesExecutorContext(
264 : Node* promise_capability, Node* native_context) {
265 60 : int kContextLength = PromiseBuiltins::kCapabilitiesContextLength;
266 60 : Node* context = CreatePromiseContext(native_context, kContextLength);
267 : StoreContextElementNoWriteBarrier(context, PromiseBuiltins::kCapabilitySlot,
268 60 : promise_capability);
269 60 : return context;
270 : }
271 :
272 228 : Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) {
273 228 : Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
274 228 : return IsSetWord(SmiUntag(flags), 1 << JSPromise::kHasHandlerBit);
275 : }
276 :
277 168 : void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) {
278 : TNode<Smi> const flags =
279 168 : 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 448 : Node* PromiseBuiltinsAssembler::IsPromiseStatus(
286 : Node* actual, v8::Promise::PromiseState expected) {
287 448 : return Word32Equal(actual, Int32Constant(expected));
288 : }
289 :
290 280 : Node* PromiseBuiltinsAssembler::PromiseStatus(Node* promise) {
291 : STATIC_ASSERT(JSPromise::kStatusShift == 0);
292 : TNode<Smi> const flags =
293 280 : CAST(LoadObjectField(promise, JSPromise::kFlagsOffset));
294 280 : 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 112 : TNode<Smi> mask = SmiConstant(status);
304 : TNode<Smi> const flags =
305 112 : CAST(LoadObjectField(promise, JSPromise::kFlagsOffset));
306 : StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset,
307 112 : 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 168 : &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 168 : 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 336 : Label if_fulfilled(this), if_rejected(this, Label::kDeferred),
359 336 : enqueue(this);
360 : Branch(IsPromiseStatus(status, v8::Promise::kFulfilled), &if_fulfilled,
361 168 : &if_rejected);
362 :
363 168 : BIND(&if_fulfilled);
364 : {
365 168 : 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 168 : var_map.Bind(LoadRoot(RootIndex::kPromiseRejectReactionJobTaskMap));
374 168 : var_handler.Bind(on_rejected);
375 168 : GotoIf(PromiseHasHandler(promise), &enqueue);
376 168 : CallRuntime(Runtime::kPromiseRevokeReject, context, promise);
377 168 : Goto(&enqueue);
378 : }
379 :
380 168 : BIND(&enqueue);
381 : Node* argument =
382 168 : 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 504 : TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) {
396 56 : Node* const context = Parameter(Descriptor::kContext);
397 56 : Node* const promise = Parameter(Descriptor::kPromise);
398 56 : Node* const on_fulfilled = Parameter(Descriptor::kOnFulfilled);
399 56 : Node* const on_rejected = Parameter(Descriptor::kOnRejected);
400 56 : 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 168 : 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 168 : 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 56 : 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 224 : VARIABLE(var_reversed, MachineRepresentation::kTagged,
480 : SmiConstant(Smi::zero()));
481 :
482 224 : 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 112 : 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 224 : 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 112 : 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 56 : 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 112 : 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 448 : Label if_fast(this), if_slow(this, Label::kDeferred), done(this, &var_result);
562 224 : GotoIf(TaggedIsSmi(receiver), &if_slow);
563 224 : 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 224 : LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
575 : Node* const result =
576 : CallJS(CodeFactory::CallFunction(
577 : isolate(), ConvertReceiverMode::kNotNullOrUndefined),
578 224 : 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 448 : isolate()->factory()->then_string());
587 : Node* const result = CallJS(
588 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
589 224 : 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 224 : 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 112 : 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 224 : 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 112 : 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 168 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
649 168 : GotoIfNot(WordEqual(promise_fun, constructor), if_slow);
650 168 : 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 168 : LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
668 168 : GotoIfForceSlowPath(if_slow);
669 336 : GotoIfNot(WordEqual(LoadMapPrototype(promise_map), promise_prototype),
670 168 : if_slow);
671 168 : 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 280 : GotoIfNot(IsJSPromiseMap(receiver_map), if_slow);
681 : Node* const promise_prototype =
682 280 : LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
683 560 : GotoIfNot(WordEqual(LoadMapPrototype(receiver_map), promise_prototype),
684 280 : if_slow);
685 280 : 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 112 : 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 112 : 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 56 : Node* executor_type = LoadInstanceType(var_executor.value());
702 56 : GotoIf(InstanceTypeEqual(executor_type, JS_FUNCTION_TYPE), &found_function);
703 112 : GotoIfNot(InstanceTypeEqual(executor_type, JS_BOUND_FUNCTION_TYPE),
704 56 : &call_runtime);
705 : var_executor.Bind(LoadObjectField(
706 56 : 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 56 : Node* native_function_context = LoadNativeContext(function_context);
718 112 : Branch(WordEqual(native_context, native_function_context), &has_access,
719 56 : &call_runtime);
720 : }
721 :
722 56 : BIND(&call_runtime);
723 : {
724 : Branch(WordEqual(CallRuntime(Runtime::kAllowDynamicFunction, context,
725 : promise_constructor),
726 112 : 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 224 : CAST(context), CAST(object()),
739 112 : HeapConstant(factory()->promise_forwarding_handler_symbol()),
740 448 : 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 112 : GotoIf(TaggedIsSmi(promise), &done);
751 112 : GotoIfNot(HasInstanceType(promise, JS_PROMISE_TYPE), &done);
752 224 : SetPropertyStrict(CAST(context), CAST(promise),
753 112 : HeapConstant(factory()->promise_handled_by_symbol()),
754 448 : CAST(handled_by()));
755 112 : Goto(&done);
756 112 : BIND(&done);
757 112 : }
758 :
759 : // ES #sec-promise-reject-functions
760 336 : TF_BUILTIN(PromiseCapabilityDefaultReject, PromiseBuiltinsAssembler) {
761 56 : Node* const reason = Parameter(Descriptor::kReason);
762 56 : Node* const context = Parameter(Descriptor::kContext);
763 :
764 : // 2. Let promise be F.[[Promise]].
765 : Node* const promise =
766 56 : LoadContextElement(context, PromiseBuiltins::kPromiseSlot);
767 :
768 : // 3. Let alreadyResolved be F.[[AlreadyResolved]].
769 56 : Label if_already_resolved(this, Label::kDeferred);
770 : Node* const already_resolved =
771 56 : LoadContextElement(context, PromiseBuiltins::kAlreadyResolvedSlot);
772 :
773 : // 4. If alreadyResolved.[[Value]] is true, return undefined.
774 56 : GotoIf(IsTrue(already_resolved), &if_already_resolved);
775 :
776 : // 5. Set alreadyResolved.[[Value]] to true.
777 : StoreContextElementNoWriteBarrier(
778 56 : context, PromiseBuiltins::kAlreadyResolvedSlot, TrueConstant());
779 :
780 : // 6. Return RejectPromise(promise, reason).
781 : Node* const debug_event =
782 56 : LoadContextElement(context, PromiseBuiltins::kDebugEventSlot);
783 : Return(CallBuiltin(Builtins::kRejectPromise, context, promise, reason,
784 56 : 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 336 : TF_BUILTIN(PromiseCapabilityDefaultResolve, PromiseBuiltinsAssembler) {
795 56 : Node* const resolution = Parameter(Descriptor::kResolution);
796 56 : Node* const context = Parameter(Descriptor::kContext);
797 :
798 : // 2. Let promise be F.[[Promise]].
799 : Node* const promise =
800 56 : LoadContextElement(context, PromiseBuiltins::kPromiseSlot);
801 :
802 : // 3. Let alreadyResolved be F.[[AlreadyResolved]].
803 56 : Label if_already_resolved(this, Label::kDeferred);
804 : Node* const already_resolved =
805 56 : LoadContextElement(context, PromiseBuiltins::kAlreadyResolvedSlot);
806 :
807 : // 4. If alreadyResolved.[[Value]] is true, return undefined.
808 56 : GotoIf(IsTrue(already_resolved), &if_already_resolved);
809 :
810 : // 5. Set alreadyResolved.[[Value]] to true.
811 : StoreContextElementNoWriteBarrier(
812 56 : context, PromiseBuiltins::kAlreadyResolvedSlot, TrueConstant());
813 :
814 : // The rest of the logic (and the catch prediction) is
815 : // encapsulated in the dedicated ResolvePromise builtin.
816 56 : 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 448 : TF_BUILTIN(PromiseConstructorLazyDeoptContinuation, PromiseBuiltinsAssembler) {
826 56 : Node* promise = Parameter(Descriptor::kPromise);
827 56 : Node* reject = Parameter(Descriptor::kReject);
828 56 : Node* exception = Parameter(Descriptor::kException);
829 56 : Node* const context = Parameter(Descriptor::kContext);
830 :
831 56 : Label finally(this);
832 :
833 56 : GotoIf(IsTheHole(exception), &finally);
834 : CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
835 56 : 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 392 : TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
844 56 : Node* const executor = Parameter(Descriptor::kExecutor);
845 56 : Node* const new_target = Parameter(Descriptor::kJSNewTarget);
846 56 : Node* const context = Parameter(Descriptor::kContext);
847 56 : Isolate* isolate = this->isolate();
848 :
849 56 : Label if_targetisundefined(this, Label::kDeferred);
850 :
851 56 : GotoIf(IsUndefined(new_target), &if_targetisundefined);
852 :
853 112 : Label if_notcallable(this, Label::kDeferred);
854 :
855 56 : GotoIf(TaggedIsSmi(executor), &if_notcallable);
856 :
857 56 : Node* const executor_map = LoadMap(executor);
858 56 : GotoIfNot(IsCallableMap(executor_map), &if_notcallable);
859 :
860 56 : Node* const native_context = LoadNativeContext(context);
861 : Node* const promise_fun =
862 56 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
863 56 : Node* const is_debug_active = IsDebugActive();
864 112 : Label if_targetisnotmodified(this),
865 112 : if_targetismodified(this, Label::kDeferred), run_executor(this),
866 112 : debug_push(this), if_noaccess(this, Label::kDeferred);
867 :
868 : BranchIfAccessCheckFailed(context, native_context, promise_fun, executor,
869 56 : &if_noaccess);
870 :
871 112 : Branch(WordEqual(promise_fun, new_target), &if_targetisnotmodified,
872 56 : &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 56 : 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 56 : 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 112 : 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 56 : 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 56 : context, reject, UndefinedConstant(), var_reason.value());
925 56 : Branch(is_debug_active, &debug_pop, &out);
926 : }
927 :
928 56 : BIND(&debug_pop);
929 : {
930 56 : CallRuntime(Runtime::kDebugPopPromise, context);
931 56 : Goto(&out);
932 : }
933 56 : BIND(&out);
934 112 : 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 56 : SmiConstant(v8::Isolate::kPromiseConstructorReturnedUndefined);
950 56 : CallRuntime(Runtime::kIncrementUseCounter, context, counter_id);
951 56 : Return(UndefinedConstant());
952 56 : }
953 56 : }
954 :
955 : // V8 Extras: v8.createPromise(parent)
956 336 : TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) {
957 56 : Node* const parent = Parameter(Descriptor::kParent);
958 56 : Node* const context = Parameter(Descriptor::kContext);
959 56 : Return(AllocateAndInitJSPromise(context, parent));
960 56 : }
961 :
962 : // V8 Extras: v8.rejectPromise(promise, reason)
963 392 : TF_BUILTIN(PromiseInternalReject, PromiseBuiltinsAssembler) {
964 56 : Node* const promise = Parameter(Descriptor::kPromise);
965 56 : Node* const reason = Parameter(Descriptor::kReason);
966 56 : Node* const context = Parameter(Descriptor::kContext);
967 :
968 : // Main V8 Extras invariant that {promise} is still "pending" at
969 : // this point, aka that {promise} is not resolved multiple times.
970 56 : Label if_promise_is_settled(this, Label::kDeferred);
971 : GotoIfNot(IsPromiseStatus(PromiseStatus(promise), v8::Promise::kPending),
972 56 : &if_promise_is_settled);
973 :
974 : // We pass true to trigger the debugger's on exception handler.
975 : Return(CallBuiltin(Builtins::kRejectPromise, context, promise, reason,
976 56 : TrueConstant()));
977 :
978 56 : BIND(&if_promise_is_settled);
979 56 : Abort(AbortReason::kPromiseAlreadySettled);
980 56 : }
981 :
982 : // V8 Extras: v8.resolvePromise(promise, resolution)
983 392 : TF_BUILTIN(PromiseInternalResolve, PromiseBuiltinsAssembler) {
984 56 : Node* const promise = Parameter(Descriptor::kPromise);
985 56 : Node* const resolution = Parameter(Descriptor::kResolution);
986 56 : Node* const context = Parameter(Descriptor::kContext);
987 :
988 : // Main V8 Extras invariant that {promise} is still "pending" at
989 : // this point, aka that {promise} is not resolved multiple times.
990 56 : Label if_promise_is_settled(this, Label::kDeferred);
991 : GotoIfNot(IsPromiseStatus(PromiseStatus(promise), v8::Promise::kPending),
992 56 : &if_promise_is_settled);
993 :
994 56 : Return(CallBuiltin(Builtins::kResolvePromise, context, promise, resolution));
995 :
996 56 : BIND(&if_promise_is_settled);
997 56 : Abort(AbortReason::kPromiseAlreadySettled);
998 56 : }
999 :
1000 : // ES#sec-promise.prototype.then
1001 : // Promise.prototype.then ( onFulfilled, onRejected )
1002 448 : TF_BUILTIN(PromisePrototypeThen, PromiseBuiltinsAssembler) {
1003 : // 1. Let promise be the this value.
1004 56 : Node* const promise = Parameter(Descriptor::kReceiver);
1005 56 : Node* const on_fulfilled = Parameter(Descriptor::kOnFulfilled);
1006 56 : Node* const on_rejected = Parameter(Descriptor::kOnRejected);
1007 56 : Node* const context = Parameter(Descriptor::kContext);
1008 :
1009 : // 2. If IsPromise(promise) is false, throw a TypeError exception.
1010 : ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
1011 56 : "Promise.prototype.then");
1012 :
1013 : // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
1014 112 : Label fast_promise_capability(this), slow_constructor(this, Label::kDeferred),
1015 112 : slow_promise_capability(this, Label::kDeferred);
1016 56 : Node* const native_context = LoadNativeContext(context);
1017 : Node* const promise_fun =
1018 56 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1019 56 : Node* const promise_map = LoadMap(promise);
1020 : BranchIfPromiseSpeciesLookupChainIntact(
1021 56 : native_context, promise_map, &fast_promise_capability, &slow_constructor);
1022 :
1023 56 : BIND(&slow_constructor);
1024 : Node* const constructor =
1025 56 : SpeciesConstructor(native_context, promise, promise_fun);
1026 112 : Branch(WordEqual(constructor, promise_fun), &fast_promise_capability,
1027 56 : &slow_promise_capability);
1028 :
1029 : // 4. Let resultCapability be ? NewPromiseCapability(C).
1030 112 : Label perform_promise_then(this);
1031 112 : VARIABLE(var_result_promise, MachineRepresentation::kTagged);
1032 112 : VARIABLE(var_result_promise_or_capability, MachineRepresentation::kTagged);
1033 :
1034 56 : BIND(&fast_promise_capability);
1035 : {
1036 56 : Node* const result_promise = AllocateAndInitJSPromise(context, promise);
1037 56 : var_result_promise_or_capability.Bind(result_promise);
1038 56 : var_result_promise.Bind(result_promise);
1039 56 : Goto(&perform_promise_then);
1040 : }
1041 :
1042 56 : BIND(&slow_promise_capability);
1043 : {
1044 56 : Node* const debug_event = TrueConstant();
1045 : Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability,
1046 56 : context, constructor, debug_event);
1047 : var_result_promise.Bind(
1048 56 : LoadObjectField(capability, PromiseCapability::kPromiseOffset));
1049 56 : var_result_promise_or_capability.Bind(capability);
1050 56 : Goto(&perform_promise_then);
1051 : }
1052 :
1053 : // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
1054 : // resultCapability).
1055 56 : BIND(&perform_promise_then);
1056 : {
1057 : // We do some work of the PerformPromiseThen operation here, in that
1058 : // we check the handlers and turn non-callable handlers into undefined.
1059 : // This is because this is the one and only callsite of PerformPromiseThen
1060 : // that has to do this.
1061 :
1062 : // 3. If IsCallable(onFulfilled) is false, then
1063 : // a. Set onFulfilled to undefined.
1064 56 : VARIABLE(var_on_fulfilled, MachineRepresentation::kTagged, on_fulfilled);
1065 112 : Label if_fulfilled_done(this), if_fulfilled_notcallable(this);
1066 56 : GotoIf(TaggedIsSmi(on_fulfilled), &if_fulfilled_notcallable);
1067 112 : Branch(IsCallable(on_fulfilled), &if_fulfilled_done,
1068 56 : &if_fulfilled_notcallable);
1069 56 : BIND(&if_fulfilled_notcallable);
1070 56 : var_on_fulfilled.Bind(UndefinedConstant());
1071 56 : Goto(&if_fulfilled_done);
1072 56 : BIND(&if_fulfilled_done);
1073 :
1074 : // 4. If IsCallable(onRejected) is false, then
1075 : // a. Set onRejected to undefined.
1076 112 : VARIABLE(var_on_rejected, MachineRepresentation::kTagged, on_rejected);
1077 112 : Label if_rejected_done(this), if_rejected_notcallable(this);
1078 56 : GotoIf(TaggedIsSmi(on_rejected), &if_rejected_notcallable);
1079 112 : Branch(IsCallable(on_rejected), &if_rejected_done,
1080 56 : &if_rejected_notcallable);
1081 56 : BIND(&if_rejected_notcallable);
1082 56 : var_on_rejected.Bind(UndefinedConstant());
1083 56 : Goto(&if_rejected_done);
1084 56 : BIND(&if_rejected_done);
1085 :
1086 : PerformPromiseThen(context, promise, var_on_fulfilled.value(),
1087 : var_on_rejected.value(),
1088 56 : var_result_promise_or_capability.value());
1089 112 : Return(var_result_promise.value());
1090 56 : }
1091 56 : }
1092 :
1093 : // ES#sec-promise.prototype.catch
1094 : // Promise.prototype.catch ( onRejected )
1095 392 : TF_BUILTIN(PromisePrototypeCatch, PromiseBuiltinsAssembler) {
1096 : // 1. Let promise be the this value.
1097 56 : Node* const receiver = Parameter(Descriptor::kReceiver);
1098 56 : Node* const on_fulfilled = UndefinedConstant();
1099 56 : Node* const on_rejected = Parameter(Descriptor::kOnRejected);
1100 56 : Node* const context = Parameter(Descriptor::kContext);
1101 :
1102 : // 2. Return ? Invoke(promise, "then", « undefined, onRejected »).
1103 56 : Node* const native_context = LoadNativeContext(context);
1104 56 : Return(InvokeThen(native_context, receiver, on_fulfilled, on_rejected));
1105 56 : }
1106 :
1107 : // ES #sec-promiseresolvethenablejob
1108 448 : TF_BUILTIN(PromiseResolveThenableJob, PromiseBuiltinsAssembler) {
1109 56 : Node* const native_context = Parameter(Descriptor::kContext);
1110 56 : Node* const promise_to_resolve = Parameter(Descriptor::kPromiseToResolve);
1111 56 : Node* const thenable = Parameter(Descriptor::kThenable);
1112 56 : Node* const then = Parameter(Descriptor::kThen);
1113 :
1114 : CSA_ASSERT(this, TaggedIsNotSmi(thenable));
1115 : CSA_ASSERT(this, IsJSReceiver(thenable));
1116 : CSA_ASSERT(this, IsJSPromise(promise_to_resolve));
1117 : CSA_ASSERT(this, IsNativeContext(native_context));
1118 :
1119 : // We can use a simple optimization here if we know that {then} is the initial
1120 : // Promise.prototype.then method, and {thenable} is a JSPromise whose
1121 : // @@species lookup chain is intact: We can connect {thenable} and
1122 : // {promise_to_resolve} directly in that case and avoid the allocation of a
1123 : // temporary JSPromise and the closures plus context.
1124 : //
1125 : // We take the generic (slow-)path if a PromiseHook is enabled or the debugger
1126 : // is active, to make sure we expose spec compliant behavior.
1127 112 : Label if_fast(this), if_slow(this, Label::kDeferred);
1128 : Node* const promise_then =
1129 56 : LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
1130 56 : GotoIfNot(WordEqual(then, promise_then), &if_slow);
1131 56 : Node* const thenable_map = LoadMap(thenable);
1132 56 : GotoIfNot(IsJSPromiseMap(thenable_map), &if_slow);
1133 : GotoIf(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
1134 56 : &if_slow);
1135 : BranchIfPromiseSpeciesLookupChainIntact(native_context, thenable_map,
1136 56 : &if_fast, &if_slow);
1137 :
1138 56 : BIND(&if_fast);
1139 : {
1140 : // We know that the {thenable} is a JSPromise, which doesn't require
1141 : // any special treatment and that {then} corresponds to the initial
1142 : // Promise.prototype.then method. So instead of allocating a temporary
1143 : // JSPromise to connect the {thenable} with the {promise_to_resolve},
1144 : // we can directly schedule the {promise_to_resolve} with default
1145 : // handlers onto the {thenable} promise. This does not only save the
1146 : // JSPromise allocation, but also avoids the allocation of the two
1147 : // resolving closures and the shared context.
1148 : //
1149 : // What happens normally in this case is
1150 : //
1151 : // resolve, reject = CreateResolvingFunctions(promise_to_resolve)
1152 : // result_capability = NewPromiseCapability(%Promise%)
1153 : // PerformPromiseThen(thenable, resolve, reject, result_capability)
1154 : //
1155 : // which means that PerformPromiseThen will either schedule a new
1156 : // PromiseReaction with resolve and reject or a PromiseReactionJob
1157 : // with resolve or reject based on the state of {thenable}. And
1158 : // resolve or reject will just invoke the default [[Resolve]] or
1159 : // [[Reject]] functions on the {promise_to_resolve}.
1160 : //
1161 : // This is the same as just doing
1162 : //
1163 : // PerformPromiseThen(thenable, undefined, undefined, promise_to_resolve)
1164 : //
1165 : // which performs exactly the same (observable) steps.
1166 : TailCallBuiltin(Builtins::kPerformPromiseThen, native_context, thenable,
1167 : UndefinedConstant(), UndefinedConstant(),
1168 56 : promise_to_resolve);
1169 : }
1170 :
1171 56 : BIND(&if_slow);
1172 : {
1173 56 : Node* resolve = nullptr;
1174 56 : Node* reject = nullptr;
1175 112 : std::tie(resolve, reject) = CreatePromiseResolvingFunctions(
1176 168 : promise_to_resolve, FalseConstant(), native_context);
1177 :
1178 56 : Label if_exception(this, Label::kDeferred);
1179 112 : VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
1180 : Node* const result = CallJS(
1181 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
1182 56 : native_context, then, thenable, resolve, reject);
1183 56 : GotoIfException(result, &if_exception, &var_exception);
1184 56 : Return(result);
1185 :
1186 56 : BIND(&if_exception);
1187 : {
1188 : // We need to reject the {thenable}.
1189 : Node* const result = CallJS(
1190 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1191 56 : native_context, reject, UndefinedConstant(), var_exception.value());
1192 56 : Return(result);
1193 56 : }
1194 56 : }
1195 56 : }
1196 :
1197 : // ES #sec-promisereactionjob
1198 112 : void PromiseBuiltinsAssembler::PromiseReactionJob(Node* context, Node* argument,
1199 : Node* handler,
1200 : Node* promise_or_capability,
1201 : PromiseReaction::Type type) {
1202 : CSA_ASSERT(this, TaggedIsNotSmi(handler));
1203 : CSA_ASSERT(this, Word32Or(IsUndefined(handler), IsCallable(handler)));
1204 : CSA_ASSERT(this, TaggedIsNotSmi(promise_or_capability));
1205 : CSA_ASSERT(this,
1206 : Word32Or(Word32Or(IsJSPromise(promise_or_capability),
1207 : IsPromiseCapability(promise_or_capability)),
1208 : IsUndefined(promise_or_capability)));
1209 :
1210 112 : VARIABLE(var_handler_result, MachineRepresentation::kTagged, argument);
1211 224 : Label if_handler_callable(this), if_fulfill(this), if_reject(this),
1212 224 : if_internal(this);
1213 224 : Branch(IsUndefined(handler),
1214 : type == PromiseReaction::kFulfill ? &if_fulfill : &if_reject,
1215 224 : &if_handler_callable);
1216 :
1217 112 : BIND(&if_handler_callable);
1218 : {
1219 : Node* const result = CallJS(
1220 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1221 112 : context, handler, UndefinedConstant(), argument);
1222 112 : GotoIfException(result, &if_reject, &var_handler_result);
1223 112 : var_handler_result.Bind(result);
1224 112 : Branch(IsUndefined(promise_or_capability), &if_internal, &if_fulfill);
1225 : }
1226 :
1227 112 : BIND(&if_internal);
1228 : {
1229 : // There's no [[Capability]] for this promise reaction job, which
1230 : // means that this is a specification-internal operation (aka await)
1231 : // where the result does not matter (see the specification change in
1232 : // https://github.com/tc39/ecma262/pull/1146 for details).
1233 112 : Return(UndefinedConstant());
1234 : }
1235 :
1236 112 : BIND(&if_fulfill);
1237 : {
1238 224 : Label if_promise(this), if_promise_capability(this, Label::kDeferred);
1239 112 : Node* const value = var_handler_result.value();
1240 224 : Branch(IsPromiseCapability(promise_or_capability), &if_promise_capability,
1241 112 : &if_promise);
1242 :
1243 112 : BIND(&if_promise);
1244 : {
1245 : // For fast native promises we can skip the indirection
1246 : // via the promiseCapability.[[Resolve]] function and
1247 : // run the resolve logic directly from here.
1248 : TailCallBuiltin(Builtins::kResolvePromise, context, promise_or_capability,
1249 112 : value);
1250 : }
1251 :
1252 112 : BIND(&if_promise_capability);
1253 : {
1254 : // In the general case we need to call the (user provided)
1255 : // promiseCapability.[[Resolve]] function.
1256 : Node* const resolve = LoadObjectField(promise_or_capability,
1257 112 : PromiseCapability::kResolveOffset);
1258 : Node* const result = CallJS(
1259 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1260 112 : context, resolve, UndefinedConstant(), value);
1261 112 : GotoIfException(result, &if_reject, &var_handler_result);
1262 112 : Return(result);
1263 112 : }
1264 : }
1265 :
1266 112 : BIND(&if_reject);
1267 112 : if (type == PromiseReaction::kReject) {
1268 112 : Label if_promise(this), if_promise_capability(this, Label::kDeferred);
1269 56 : Node* const reason = var_handler_result.value();
1270 112 : Branch(IsPromiseCapability(promise_or_capability), &if_promise_capability,
1271 56 : &if_promise);
1272 :
1273 56 : BIND(&if_promise);
1274 : {
1275 : // For fast native promises we can skip the indirection
1276 : // via the promiseCapability.[[Reject]] function and
1277 : // run the resolve logic directly from here.
1278 : TailCallBuiltin(Builtins::kRejectPromise, context, promise_or_capability,
1279 56 : reason, FalseConstant());
1280 : }
1281 :
1282 56 : BIND(&if_promise_capability);
1283 : {
1284 : // In the general case we need to call the (user provided)
1285 : // promiseCapability.[[Reject]] function.
1286 56 : Label if_exception(this, Label::kDeferred);
1287 112 : VARIABLE(var_exception, MachineRepresentation::kTagged,
1288 : TheHoleConstant());
1289 : Node* const reject = LoadObjectField(promise_or_capability,
1290 56 : PromiseCapability::kRejectOffset);
1291 : Node* const result = CallJS(
1292 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1293 56 : context, reject, UndefinedConstant(), reason);
1294 56 : GotoIfException(result, &if_exception, &var_exception);
1295 56 : Return(result);
1296 :
1297 : // Swallow the exception here.
1298 56 : BIND(&if_exception);
1299 112 : TailCallRuntime(Runtime::kReportMessage, context, var_exception.value());
1300 56 : }
1301 : } else {
1302 : // We have to call out to the dedicated PromiseRejectReactionJob builtin
1303 : // here, instead of just doing the work inline, as otherwise the catch
1304 : // predictions in the debugger will be wrong, which just walks the stack
1305 : // and checks for certain builtins.
1306 : TailCallBuiltin(Builtins::kPromiseRejectReactionJob, context,
1307 : var_handler_result.value(), UndefinedConstant(),
1308 56 : promise_or_capability);
1309 112 : }
1310 112 : }
1311 :
1312 : // ES #sec-promisereactionjob
1313 448 : TF_BUILTIN(PromiseFulfillReactionJob, PromiseBuiltinsAssembler) {
1314 56 : Node* const context = Parameter(Descriptor::kContext);
1315 56 : Node* const value = Parameter(Descriptor::kValue);
1316 56 : Node* const handler = Parameter(Descriptor::kHandler);
1317 : Node* const promise_or_capability =
1318 56 : Parameter(Descriptor::kPromiseOrCapability);
1319 :
1320 : PromiseReactionJob(context, value, handler, promise_or_capability,
1321 56 : PromiseReaction::kFulfill);
1322 56 : }
1323 :
1324 : // ES #sec-promisereactionjob
1325 448 : TF_BUILTIN(PromiseRejectReactionJob, PromiseBuiltinsAssembler) {
1326 56 : Node* const context = Parameter(Descriptor::kContext);
1327 56 : Node* const reason = Parameter(Descriptor::kReason);
1328 56 : Node* const handler = Parameter(Descriptor::kHandler);
1329 : Node* const promise_or_capability =
1330 56 : Parameter(Descriptor::kPromiseOrCapability);
1331 :
1332 : PromiseReactionJob(context, reason, handler, promise_or_capability,
1333 56 : PromiseReaction::kReject);
1334 56 : }
1335 :
1336 392 : TF_BUILTIN(PromiseResolveTrampoline, PromiseBuiltinsAssembler) {
1337 : // 1. Let C be the this value.
1338 56 : Node* receiver = Parameter(Descriptor::kReceiver);
1339 56 : Node* value = Parameter(Descriptor::kValue);
1340 56 : Node* context = Parameter(Descriptor::kContext);
1341 :
1342 : // 2. If Type(C) is not Object, throw a TypeError exception.
1343 : ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1344 56 : "PromiseResolve");
1345 :
1346 : // 3. Return ? PromiseResolve(C, x).
1347 56 : Return(CallBuiltin(Builtins::kPromiseResolve, context, receiver, value));
1348 56 : }
1349 :
1350 392 : TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
1351 56 : Node* constructor = Parameter(Descriptor::kConstructor);
1352 56 : Node* value = Parameter(Descriptor::kValue);
1353 56 : Node* context = Parameter(Descriptor::kContext);
1354 :
1355 : CSA_ASSERT(this, IsJSReceiver(constructor));
1356 :
1357 56 : Node* const native_context = LoadNativeContext(context);
1358 : Node* const promise_fun =
1359 56 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1360 :
1361 112 : Label if_slow_constructor(this, Label::kDeferred), if_need_to_allocate(this);
1362 :
1363 : // Check if {value} is a JSPromise.
1364 56 : GotoIf(TaggedIsSmi(value), &if_need_to_allocate);
1365 56 : Node* const value_map = LoadMap(value);
1366 56 : GotoIfNot(IsJSPromiseMap(value_map), &if_need_to_allocate);
1367 :
1368 : // We can skip the "constructor" lookup on {value} if it's [[Prototype]]
1369 : // is the (initial) Promise.prototype and the @@species protector is
1370 : // intact, as that guards the lookup path for "constructor" on
1371 : // JSPromise instances which have the (initial) Promise.prototype.
1372 : Node* const promise_prototype =
1373 56 : LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
1374 112 : GotoIfNot(WordEqual(LoadMapPrototype(value_map), promise_prototype),
1375 56 : &if_slow_constructor);
1376 56 : GotoIf(IsPromiseSpeciesProtectorCellInvalid(), &if_slow_constructor);
1377 :
1378 : // If the {constructor} is the Promise function, we just immediately
1379 : // return the {value} here and don't bother wrapping it into a
1380 : // native Promise.
1381 56 : GotoIfNot(WordEqual(promise_fun, constructor), &if_slow_constructor);
1382 56 : Return(value);
1383 :
1384 : // At this point, value or/and constructor are not native promises, but
1385 : // they could be of the same subclass.
1386 56 : BIND(&if_slow_constructor);
1387 : {
1388 : Node* const value_constructor =
1389 112 : GetProperty(context, value, isolate()->factory()->constructor_string());
1390 56 : GotoIfNot(WordEqual(value_constructor, constructor), &if_need_to_allocate);
1391 56 : Return(value);
1392 : }
1393 :
1394 56 : BIND(&if_need_to_allocate);
1395 : {
1396 112 : Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred);
1397 112 : Branch(WordEqual(promise_fun, constructor), &if_nativepromise,
1398 56 : &if_notnativepromise);
1399 :
1400 : // This adds a fast path for native promises that don't need to
1401 : // create NewPromiseCapability.
1402 56 : BIND(&if_nativepromise);
1403 : {
1404 56 : Node* const result = AllocateAndInitJSPromise(context);
1405 56 : CallBuiltin(Builtins::kResolvePromise, context, result, value);
1406 56 : Return(result);
1407 : }
1408 :
1409 56 : BIND(&if_notnativepromise);
1410 : {
1411 56 : Node* const debug_event = TrueConstant();
1412 : Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability,
1413 56 : context, constructor, debug_event);
1414 :
1415 : Node* const resolve =
1416 56 : LoadObjectField(capability, PromiseCapability::kResolveOffset);
1417 : CallJS(
1418 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1419 56 : context, resolve, UndefinedConstant(), value);
1420 :
1421 : Node* const result =
1422 56 : LoadObjectField(capability, PromiseCapability::kPromiseOffset);
1423 56 : Return(result);
1424 56 : }
1425 56 : }
1426 56 : }
1427 :
1428 : // ES6 #sec-getcapabilitiesexecutor-functions
1429 392 : TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
1430 56 : Node* const resolve = Parameter(Descriptor::kResolve);
1431 56 : Node* const reject = Parameter(Descriptor::kReject);
1432 56 : Node* const context = Parameter(Descriptor::kContext);
1433 :
1434 : Node* const capability =
1435 56 : LoadContextElement(context, PromiseBuiltins::kCapabilitySlot);
1436 :
1437 56 : Label if_alreadyinvoked(this, Label::kDeferred);
1438 : GotoIfNot(IsUndefined(
1439 112 : LoadObjectField(capability, PromiseCapability::kResolveOffset)),
1440 56 : &if_alreadyinvoked);
1441 : GotoIfNot(IsUndefined(
1442 112 : LoadObjectField(capability, PromiseCapability::kRejectOffset)),
1443 56 : &if_alreadyinvoked);
1444 :
1445 56 : StoreObjectField(capability, PromiseCapability::kResolveOffset, resolve);
1446 56 : StoreObjectField(capability, PromiseCapability::kRejectOffset, reject);
1447 :
1448 56 : Return(UndefinedConstant());
1449 :
1450 56 : BIND(&if_alreadyinvoked);
1451 56 : ThrowTypeError(context, MessageTemplate::kPromiseExecutorAlreadyInvoked);
1452 56 : }
1453 :
1454 392 : TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) {
1455 : // 1. Let C be the this value.
1456 56 : Node* const receiver = Parameter(Descriptor::kReceiver);
1457 56 : Node* const reason = Parameter(Descriptor::kReason);
1458 56 : Node* const context = Parameter(Descriptor::kContext);
1459 :
1460 : // 2. If Type(C) is not Object, throw a TypeError exception.
1461 : ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1462 56 : "PromiseReject");
1463 :
1464 112 : Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
1465 56 : Node* const native_context = LoadNativeContext(context);
1466 :
1467 : Node* const promise_fun =
1468 56 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1469 112 : Branch(WordEqual(promise_fun, receiver), &if_nativepromise,
1470 56 : &if_custompromise);
1471 :
1472 56 : BIND(&if_nativepromise);
1473 : {
1474 : Node* const promise =
1475 56 : AllocateAndSetJSPromise(context, v8::Promise::kRejected, reason);
1476 : CallRuntime(Runtime::kPromiseRejectEventFromStack, context, promise,
1477 56 : reason);
1478 56 : Return(promise);
1479 : }
1480 :
1481 56 : BIND(&if_custompromise);
1482 : {
1483 : // 3. Let promiseCapability be ? NewPromiseCapability(C).
1484 56 : Node* const debug_event = TrueConstant();
1485 : Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability,
1486 56 : context, receiver, debug_event);
1487 :
1488 : // 4. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
1489 : Node* const reject =
1490 56 : LoadObjectField(capability, PromiseCapability::kRejectOffset);
1491 : CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1492 56 : context, reject, UndefinedConstant(), reason);
1493 :
1494 : // 5. Return promiseCapability.[[Promise]].
1495 : Node* const promise =
1496 56 : LoadObjectField(capability, PromiseCapability::kPromiseOffset);
1497 56 : Return(promise);
1498 56 : }
1499 56 : }
1500 :
1501 56 : std::pair<Node*, Node*> PromiseBuiltinsAssembler::CreatePromiseFinallyFunctions(
1502 : Node* on_finally, Node* constructor, Node* native_context) {
1503 : Node* const promise_context = CreatePromiseContext(
1504 56 : native_context, PromiseBuiltins::kPromiseFinallyContextLength);
1505 : StoreContextElementNoWriteBarrier(
1506 56 : promise_context, PromiseBuiltins::kOnFinallySlot, on_finally);
1507 : StoreContextElementNoWriteBarrier(
1508 56 : promise_context, PromiseBuiltins::kConstructorSlot, constructor);
1509 : Node* const map = LoadContextElement(
1510 56 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1511 : Node* const then_finally_info = LoadContextElement(
1512 56 : native_context, Context::PROMISE_THEN_FINALLY_SHARED_FUN);
1513 : Node* const then_finally = AllocateFunctionWithMapAndContext(
1514 56 : map, then_finally_info, promise_context);
1515 : Node* const catch_finally_info = LoadContextElement(
1516 56 : native_context, Context::PROMISE_CATCH_FINALLY_SHARED_FUN);
1517 : Node* const catch_finally = AllocateFunctionWithMapAndContext(
1518 56 : map, catch_finally_info, promise_context);
1519 56 : return std::make_pair(then_finally, catch_finally);
1520 : }
1521 :
1522 280 : TF_BUILTIN(PromiseValueThunkFinally, PromiseBuiltinsAssembler) {
1523 56 : Node* const context = Parameter(Descriptor::kContext);
1524 :
1525 56 : Node* const value = LoadContextElement(context, PromiseBuiltins::kValueSlot);
1526 56 : Return(value);
1527 56 : }
1528 :
1529 56 : Node* PromiseBuiltinsAssembler::CreateValueThunkFunction(Node* value,
1530 : Node* native_context) {
1531 : Node* const value_thunk_context = CreatePromiseContext(
1532 56 : native_context, PromiseBuiltins::kPromiseValueThunkOrReasonContextLength);
1533 : StoreContextElementNoWriteBarrier(value_thunk_context,
1534 56 : PromiseBuiltins::kValueSlot, value);
1535 : Node* const map = LoadContextElement(
1536 56 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1537 : Node* const value_thunk_info = LoadContextElement(
1538 56 : native_context, Context::PROMISE_VALUE_THUNK_FINALLY_SHARED_FUN);
1539 : Node* const value_thunk = AllocateFunctionWithMapAndContext(
1540 56 : map, value_thunk_info, value_thunk_context);
1541 56 : return value_thunk;
1542 : }
1543 :
1544 336 : TF_BUILTIN(PromiseThenFinally, PromiseBuiltinsAssembler) {
1545 : CSA_ASSERT_JS_ARGC_EQ(this, 1);
1546 :
1547 56 : Node* const value = Parameter(Descriptor::kValue);
1548 56 : Node* const context = Parameter(Descriptor::kContext);
1549 :
1550 : // 1. Let onFinally be F.[[OnFinally]].
1551 : Node* const on_finally =
1552 56 : LoadContextElement(context, PromiseBuiltins::kOnFinallySlot);
1553 :
1554 : // 2. Assert: IsCallable(onFinally) is true.
1555 : CSA_ASSERT(this, IsCallable(on_finally));
1556 :
1557 : // 3. Let result be ? Call(onFinally).
1558 : Node* const result = CallJS(
1559 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1560 56 : context, on_finally, UndefinedConstant());
1561 :
1562 : // 4. Let C be F.[[Constructor]].
1563 : Node* const constructor =
1564 56 : LoadContextElement(context, PromiseBuiltins::kConstructorSlot);
1565 :
1566 : // 5. Assert: IsConstructor(C) is true.
1567 : CSA_ASSERT(this, IsConstructor(constructor));
1568 :
1569 : // 6. Let promise be ? PromiseResolve(C, result).
1570 : Node* const promise =
1571 56 : CallBuiltin(Builtins::kPromiseResolve, context, constructor, result);
1572 :
1573 : // 7. Let valueThunk be equivalent to a function that returns value.
1574 56 : Node* const native_context = LoadNativeContext(context);
1575 56 : Node* const value_thunk = CreateValueThunkFunction(value, native_context);
1576 :
1577 : // 8. Return ? Invoke(promise, "then", « valueThunk »).
1578 56 : Return(InvokeThen(native_context, promise, value_thunk));
1579 56 : }
1580 :
1581 280 : TF_BUILTIN(PromiseThrowerFinally, PromiseBuiltinsAssembler) {
1582 56 : Node* const context = Parameter(Descriptor::kContext);
1583 :
1584 56 : Node* const reason = LoadContextElement(context, PromiseBuiltins::kValueSlot);
1585 56 : CallRuntime(Runtime::kThrow, context, reason);
1586 56 : Unreachable();
1587 56 : }
1588 :
1589 56 : Node* PromiseBuiltinsAssembler::CreateThrowerFunction(Node* reason,
1590 : Node* native_context) {
1591 : Node* const thrower_context = CreatePromiseContext(
1592 56 : native_context, PromiseBuiltins::kPromiseValueThunkOrReasonContextLength);
1593 : StoreContextElementNoWriteBarrier(thrower_context,
1594 56 : PromiseBuiltins::kValueSlot, reason);
1595 : Node* const map = LoadContextElement(
1596 56 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1597 : Node* const thrower_info = LoadContextElement(
1598 56 : native_context, Context::PROMISE_THROWER_FINALLY_SHARED_FUN);
1599 : Node* const thrower =
1600 56 : AllocateFunctionWithMapAndContext(map, thrower_info, thrower_context);
1601 56 : return thrower;
1602 : }
1603 :
1604 336 : TF_BUILTIN(PromiseCatchFinally, PromiseBuiltinsAssembler) {
1605 : CSA_ASSERT_JS_ARGC_EQ(this, 1);
1606 :
1607 56 : Node* const reason = Parameter(Descriptor::kReason);
1608 56 : Node* const context = Parameter(Descriptor::kContext);
1609 :
1610 : // 1. Let onFinally be F.[[OnFinally]].
1611 : Node* const on_finally =
1612 56 : LoadContextElement(context, PromiseBuiltins::kOnFinallySlot);
1613 :
1614 : // 2. Assert: IsCallable(onFinally) is true.
1615 : CSA_ASSERT(this, IsCallable(on_finally));
1616 :
1617 : // 3. Let result be ? Call(onFinally).
1618 : Node* result = CallJS(
1619 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
1620 56 : context, on_finally, UndefinedConstant());
1621 :
1622 : // 4. Let C be F.[[Constructor]].
1623 : Node* const constructor =
1624 56 : LoadContextElement(context, PromiseBuiltins::kConstructorSlot);
1625 :
1626 : // 5. Assert: IsConstructor(C) is true.
1627 : CSA_ASSERT(this, IsConstructor(constructor));
1628 :
1629 : // 6. Let promise be ? PromiseResolve(C, result).
1630 : Node* const promise =
1631 56 : CallBuiltin(Builtins::kPromiseResolve, context, constructor, result);
1632 :
1633 : // 7. Let thrower be equivalent to a function that throws reason.
1634 56 : Node* const native_context = LoadNativeContext(context);
1635 56 : Node* const thrower = CreateThrowerFunction(reason, native_context);
1636 :
1637 : // 8. Return ? Invoke(promise, "then", « thrower »).
1638 56 : Return(InvokeThen(native_context, promise, thrower));
1639 56 : }
1640 :
1641 392 : TF_BUILTIN(PromisePrototypeFinally, PromiseBuiltinsAssembler) {
1642 : CSA_ASSERT_JS_ARGC_EQ(this, 1);
1643 :
1644 : // 1. Let promise be the this value.
1645 56 : Node* const receiver = Parameter(Descriptor::kReceiver);
1646 56 : Node* const on_finally = Parameter(Descriptor::kOnFinally);
1647 56 : Node* const context = Parameter(Descriptor::kContext);
1648 :
1649 : // 2. If Type(promise) is not Object, throw a TypeError exception.
1650 : ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1651 56 : "Promise.prototype.finally");
1652 :
1653 : // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
1654 56 : Node* const native_context = LoadNativeContext(context);
1655 : Node* const promise_fun =
1656 56 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1657 56 : VARIABLE(var_constructor, MachineRepresentation::kTagged, promise_fun);
1658 112 : Label slow_constructor(this, Label::kDeferred), done_constructor(this);
1659 56 : Node* const receiver_map = LoadMap(receiver);
1660 56 : GotoIfNot(IsJSPromiseMap(receiver_map), &slow_constructor);
1661 : BranchIfPromiseSpeciesLookupChainIntact(native_context, receiver_map,
1662 56 : &done_constructor, &slow_constructor);
1663 56 : BIND(&slow_constructor);
1664 : {
1665 : Node* const constructor =
1666 56 : SpeciesConstructor(context, receiver, promise_fun);
1667 56 : var_constructor.Bind(constructor);
1668 56 : Goto(&done_constructor);
1669 : }
1670 56 : BIND(&done_constructor);
1671 56 : Node* const constructor = var_constructor.value();
1672 :
1673 : // 4. Assert: IsConstructor(C) is true.
1674 : CSA_ASSERT(this, IsConstructor(constructor));
1675 :
1676 112 : VARIABLE(var_then_finally, MachineRepresentation::kTagged);
1677 112 : VARIABLE(var_catch_finally, MachineRepresentation::kTagged);
1678 :
1679 112 : Label if_notcallable(this, Label::kDeferred), perform_finally(this);
1680 :
1681 56 : GotoIf(TaggedIsSmi(on_finally), &if_notcallable);
1682 56 : GotoIfNot(IsCallable(on_finally), &if_notcallable);
1683 :
1684 : // 6. Else,
1685 : // a. Let thenFinally be a new built-in function object as defined
1686 : // in ThenFinally Function.
1687 : // b. Let catchFinally be a new built-in function object as
1688 : // defined in CatchFinally Function.
1689 : // c. Set thenFinally and catchFinally's [[Constructor]] internal
1690 : // slots to C.
1691 : // d. Set thenFinally and catchFinally's [[OnFinally]] internal
1692 : // slots to onFinally.
1693 56 : Node* then_finally = nullptr;
1694 56 : Node* catch_finally = nullptr;
1695 112 : std::tie(then_finally, catch_finally) =
1696 112 : CreatePromiseFinallyFunctions(on_finally, constructor, native_context);
1697 56 : var_then_finally.Bind(then_finally);
1698 56 : var_catch_finally.Bind(catch_finally);
1699 56 : Goto(&perform_finally);
1700 :
1701 : // 5. If IsCallable(onFinally) is not true,
1702 : // a. Let thenFinally be onFinally.
1703 : // b. Let catchFinally be onFinally.
1704 56 : BIND(&if_notcallable);
1705 : {
1706 56 : var_then_finally.Bind(on_finally);
1707 56 : var_catch_finally.Bind(on_finally);
1708 56 : Goto(&perform_finally);
1709 : }
1710 :
1711 : // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »).
1712 56 : BIND(&perform_finally);
1713 : Return(InvokeThen(native_context, receiver, var_then_finally.value(),
1714 112 : var_catch_finally.value()));
1715 56 : }
1716 :
1717 : // ES #sec-fulfillpromise
1718 392 : TF_BUILTIN(FulfillPromise, PromiseBuiltinsAssembler) {
1719 56 : Node* const promise = Parameter(Descriptor::kPromise);
1720 56 : Node* const value = Parameter(Descriptor::kValue);
1721 56 : Node* const context = Parameter(Descriptor::kContext);
1722 :
1723 : CSA_ASSERT(this, TaggedIsNotSmi(promise));
1724 : CSA_ASSERT(this, IsJSPromise(promise));
1725 :
1726 : // 2. Let reactions be promise.[[PromiseFulfillReactions]].
1727 : Node* const reactions =
1728 56 : LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
1729 :
1730 : // 3. Set promise.[[PromiseResult]] to value.
1731 : // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
1732 : // 5. Set promise.[[PromiseRejectReactions]] to undefined.
1733 56 : StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, value);
1734 :
1735 : // 6. Set promise.[[PromiseState]] to "fulfilled".
1736 56 : PromiseSetStatus(promise, Promise::kFulfilled);
1737 :
1738 : // 7. Return TriggerPromiseReactions(reactions, value).
1739 : Return(TriggerPromiseReactions(context, reactions, value,
1740 56 : PromiseReaction::kFulfill));
1741 56 : }
1742 :
1743 : // ES #sec-rejectpromise
1744 448 : TF_BUILTIN(RejectPromise, PromiseBuiltinsAssembler) {
1745 56 : Node* const promise = Parameter(Descriptor::kPromise);
1746 56 : Node* const reason = Parameter(Descriptor::kReason);
1747 56 : Node* const debug_event = Parameter(Descriptor::kDebugEvent);
1748 56 : Node* const context = Parameter(Descriptor::kContext);
1749 :
1750 : CSA_ASSERT(this, TaggedIsNotSmi(promise));
1751 : CSA_ASSERT(this, IsJSPromise(promise));
1752 : CSA_ASSERT(this, IsBoolean(debug_event));
1753 56 : Label if_runtime(this, Label::kDeferred);
1754 :
1755 : // If promise hook is enabled or the debugger is active, let
1756 : // the runtime handle this operation, which greatly reduces
1757 : // the complexity here and also avoids a couple of back and
1758 : // forth between JavaScript and C++ land.
1759 : GotoIf(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
1760 56 : &if_runtime);
1761 :
1762 : // 7. If promise.[[PromiseIsHandled]] is false, perform
1763 : // HostPromiseRejectionTracker(promise, "reject").
1764 : // We don't try to handle rejecting {promise} without handler
1765 : // here, but we let the C++ code take care of this completely.
1766 56 : GotoIfNot(PromiseHasHandler(promise), &if_runtime);
1767 :
1768 : // 2. Let reactions be promise.[[PromiseRejectReactions]].
1769 : Node* reactions =
1770 56 : LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
1771 :
1772 : // 3. Set promise.[[PromiseResult]] to reason.
1773 : // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
1774 : // 5. Set promise.[[PromiseRejectReactions]] to undefined.
1775 56 : StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reason);
1776 :
1777 : // 6. Set promise.[[PromiseState]] to "rejected".
1778 56 : PromiseSetStatus(promise, Promise::kRejected);
1779 :
1780 : // 7. Return TriggerPromiseReactions(reactions, reason).
1781 : Return(TriggerPromiseReactions(context, reactions, reason,
1782 56 : PromiseReaction::kReject));
1783 :
1784 56 : BIND(&if_runtime);
1785 : TailCallRuntime(Runtime::kRejectPromise, context, promise, reason,
1786 56 : debug_event);
1787 56 : }
1788 :
1789 : // ES #sec-promise-resolve-functions
1790 392 : TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
1791 56 : Node* const promise = Parameter(Descriptor::kPromise);
1792 56 : Node* const resolution = Parameter(Descriptor::kResolution);
1793 56 : Node* const context = Parameter(Descriptor::kContext);
1794 :
1795 : CSA_ASSERT(this, TaggedIsNotSmi(promise));
1796 : CSA_ASSERT(this, IsJSPromise(promise));
1797 :
1798 112 : Label do_enqueue(this), if_fulfill(this), if_reject(this, Label::kDeferred),
1799 112 : if_runtime(this, Label::kDeferred);
1800 112 : VARIABLE(var_reason, MachineRepresentation::kTagged);
1801 112 : VARIABLE(var_then, MachineRepresentation::kTagged);
1802 :
1803 : // If promise hook is enabled or the debugger is active, let
1804 : // the runtime handle this operation, which greatly reduces
1805 : // the complexity here and also avoids a couple of back and
1806 : // forth between JavaScript and C++ land.
1807 : GotoIf(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
1808 56 : &if_runtime);
1809 :
1810 : // 6. If SameValue(resolution, promise) is true, then
1811 : // We can use pointer comparison here, since the {promise} is guaranteed
1812 : // to be a JSPromise inside this function and thus is reference comparable.
1813 56 : GotoIf(WordEqual(promise, resolution), &if_runtime);
1814 :
1815 : // 7. If Type(resolution) is not Object, then
1816 56 : GotoIf(TaggedIsSmi(resolution), &if_fulfill);
1817 56 : Node* const resolution_map = LoadMap(resolution);
1818 56 : GotoIfNot(IsJSReceiverMap(resolution_map), &if_fulfill);
1819 :
1820 : // We can skip the "then" lookup on {resolution} if its [[Prototype]]
1821 : // is the (initial) Promise.prototype and the Promise#then protector
1822 : // is intact, as that guards the lookup path for the "then" property
1823 : // on JSPromise instances which have the (initial) %PromisePrototype%.
1824 112 : Label if_fast(this), if_receiver(this), if_slow(this, Label::kDeferred);
1825 56 : Node* const native_context = LoadNativeContext(context);
1826 56 : GotoIfForceSlowPath(&if_slow);
1827 56 : GotoIf(IsPromiseThenProtectorCellInvalid(), &if_slow);
1828 56 : GotoIfNot(IsJSPromiseMap(resolution_map), &if_receiver);
1829 : Node* const promise_prototype =
1830 56 : LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
1831 112 : Branch(WordEqual(LoadMapPrototype(resolution_map), promise_prototype),
1832 56 : &if_fast, &if_slow);
1833 :
1834 56 : BIND(&if_fast);
1835 : {
1836 : // The {resolution} is a native Promise in this case.
1837 : Node* const then =
1838 56 : LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
1839 56 : var_then.Bind(then);
1840 56 : Goto(&do_enqueue);
1841 : }
1842 :
1843 56 : BIND(&if_receiver);
1844 : {
1845 : // We can skip the lookup of "then" if the {resolution} is a (newly
1846 : // created) IterResultObject, as the Promise#then() protector also
1847 : // ensures that the intrinsic %ObjectPrototype% doesn't contain any
1848 : // "then" property. This helps to avoid negative lookups on iterator
1849 : // results from async generators.
1850 : CSA_ASSERT(this, IsJSReceiverMap(resolution_map));
1851 : CSA_ASSERT(this, Word32BinaryNot(IsPromiseThenProtectorCellInvalid()));
1852 : Node* const iterator_result_map =
1853 56 : LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
1854 112 : Branch(WordEqual(resolution_map, iterator_result_map), &if_fulfill,
1855 56 : &if_slow);
1856 : }
1857 :
1858 56 : BIND(&if_slow);
1859 : {
1860 : // 8. Let then be Get(resolution, "then").
1861 : Node* const then =
1862 112 : GetProperty(context, resolution, isolate()->factory()->then_string());
1863 :
1864 : // 9. If then is an abrupt completion, then
1865 56 : GotoIfException(then, &if_reject, &var_reason);
1866 :
1867 : // 11. If IsCallable(thenAction) is false, then
1868 56 : GotoIf(TaggedIsSmi(then), &if_fulfill);
1869 56 : Node* const then_map = LoadMap(then);
1870 56 : GotoIfNot(IsCallableMap(then_map), &if_fulfill);
1871 56 : var_then.Bind(then);
1872 56 : Goto(&do_enqueue);
1873 : }
1874 :
1875 56 : BIND(&do_enqueue);
1876 : {
1877 : // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob,
1878 : // «promise, resolution, thenAction»).
1879 : Node* const task = AllocatePromiseResolveThenableJobTask(
1880 56 : promise, var_then.value(), resolution, native_context);
1881 56 : TailCallBuiltin(Builtins::kEnqueueMicrotask, native_context, task);
1882 : }
1883 :
1884 56 : BIND(&if_fulfill);
1885 : {
1886 : // 7.b Return FulfillPromise(promise, resolution).
1887 56 : TailCallBuiltin(Builtins::kFulfillPromise, context, promise, resolution);
1888 : }
1889 :
1890 56 : BIND(&if_runtime);
1891 56 : Return(CallRuntime(Runtime::kResolvePromise, context, promise, resolution));
1892 :
1893 56 : BIND(&if_reject);
1894 : {
1895 : // 9.a Return RejectPromise(promise, then.[[Value]]).
1896 : TailCallBuiltin(Builtins::kRejectPromise, context, promise,
1897 56 : var_reason.value(), FalseConstant());
1898 56 : }
1899 56 : }
1900 :
1901 56 : Node* PromiseBuiltinsAssembler::PerformPromiseAll(
1902 : Node* context, Node* constructor, Node* capability,
1903 : const IteratorRecord& iterator, Label* if_exception,
1904 : Variable* var_exception) {
1905 56 : IteratorBuiltinsAssembler iter_assembler(state());
1906 :
1907 56 : Node* const native_context = LoadNativeContext(context);
1908 :
1909 : // For catch prediction, don't treat the .then calls as handling it;
1910 : // instead, recurse outwards.
1911 : SetForwardingHandlerIfTrue(
1912 : native_context, IsDebugActive(),
1913 56 : LoadObjectField(capability, PromiseCapability::kRejectOffset));
1914 :
1915 : Node* const resolve_element_context =
1916 56 : CreatePromiseAllResolveElementContext(capability, native_context);
1917 :
1918 112 : TVARIABLE(Smi, var_index, SmiConstant(1));
1919 112 : Label loop(this, &var_index), done_loop(this),
1920 112 : too_many_elements(this, Label::kDeferred),
1921 112 : close_iterator(this, Label::kDeferred);
1922 56 : Goto(&loop);
1923 56 : BIND(&loop);
1924 : {
1925 : // Let next be IteratorStep(iteratorRecord.[[Iterator]]).
1926 : // If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
1927 : // ReturnIfAbrupt(next).
1928 : Node* const fast_iterator_result_map =
1929 56 : LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
1930 : Node* const next = iter_assembler.IteratorStep(
1931 : native_context, iterator, &done_loop, fast_iterator_result_map,
1932 56 : if_exception, var_exception);
1933 :
1934 : // Let nextValue be IteratorValue(next).
1935 : // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to
1936 : // true.
1937 : // ReturnIfAbrupt(nextValue).
1938 : Node* const next_value = iter_assembler.IteratorValue(
1939 : native_context, next, fast_iterator_result_map, if_exception,
1940 56 : var_exception);
1941 :
1942 : // Check if we reached the limit.
1943 56 : TNode<Smi> const index = var_index.value();
1944 56 : GotoIf(SmiEqual(index, SmiConstant(PropertyArray::HashField::kMax)),
1945 56 : &too_many_elements);
1946 :
1947 : // Set index to index + 1.
1948 56 : var_index = SmiAdd(index, SmiConstant(1));
1949 :
1950 : // Set remainingElementsCount.[[Value]] to
1951 : // remainingElementsCount.[[Value]] + 1.
1952 56 : TNode<Smi> const remaining_elements_count = CAST(LoadContextElement(
1953 : resolve_element_context,
1954 : PromiseBuiltins::kPromiseAllResolveElementRemainingSlot));
1955 : StoreContextElementNoWriteBarrier(
1956 : resolve_element_context,
1957 : PromiseBuiltins::kPromiseAllResolveElementRemainingSlot,
1958 56 : SmiAdd(remaining_elements_count, SmiConstant(1)));
1959 :
1960 : // Let resolveElement be CreateBuiltinFunction(steps,
1961 : // « [[AlreadyCalled]],
1962 : // [[Index]],
1963 : // [[Values]],
1964 : // [[Capability]],
1965 : // [[RemainingElements]] »).
1966 : // Set resolveElement.[[AlreadyCalled]] to a Record { [[Value]]: false }.
1967 : // Set resolveElement.[[Index]] to index.
1968 : // Set resolveElement.[[Values]] to values.
1969 : // Set resolveElement.[[Capability]] to resultCapability.
1970 : // Set resolveElement.[[RemainingElements]] to remainingElementsCount.
1971 : Node* const resolve_element_fun = CreatePromiseAllResolveElementFunction(
1972 56 : resolve_element_context, index, native_context);
1973 :
1974 : // We can skip the "resolve" lookup on the {constructor} as well as the
1975 : // "then" lookup on the result of the "resolve" call, and immediately
1976 : // chain continuation onto the {next_value} if:
1977 : //
1978 : // (a) The {constructor} is the intrinsic %Promise% function, and
1979 : // looking up "resolve" on {constructor} yields the initial
1980 : // Promise.resolve() builtin, and
1981 : // (b) the promise @@species protector cell is valid, meaning that
1982 : // no one messed with the Symbol.species property on any
1983 : // intrinsic promise or on the Promise.prototype, and
1984 : // (c) the {next_value} is a JSPromise whose [[Prototype]] field
1985 : // contains the intrinsic %PromisePrototype%, and
1986 : // (d) we're not running with async_hooks or DevTools enabled.
1987 : //
1988 : // In that case we also don't need to allocate a chained promise for
1989 : // the PromiseReaction (aka we can pass undefined to PerformPromiseThen),
1990 : // since this is only necessary for DevTools and PromiseHooks.
1991 112 : Label if_fast(this), if_slow(this);
1992 : GotoIfNotPromiseResolveLookupChainIntact(native_context, constructor,
1993 56 : &if_slow);
1994 : GotoIf(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
1995 56 : &if_slow);
1996 56 : GotoIf(IsPromiseSpeciesProtectorCellInvalid(), &if_slow);
1997 56 : GotoIf(TaggedIsSmi(next_value), &if_slow);
1998 56 : Node* const next_value_map = LoadMap(next_value);
1999 : BranchIfPromiseThenLookupChainIntact(native_context, next_value_map,
2000 56 : &if_fast, &if_slow);
2001 :
2002 56 : BIND(&if_fast);
2003 : {
2004 : // Register the PromiseReaction immediately on the {next_value}, not
2005 : // passing any chained promise since neither async_hooks nor DevTools
2006 : // are enabled, so there's no use of the resulting promise.
2007 : PerformPromiseThen(
2008 : native_context, next_value, resolve_element_fun,
2009 112 : LoadObjectField(capability, PromiseCapability::kRejectOffset),
2010 168 : UndefinedConstant());
2011 56 : Goto(&loop);
2012 : }
2013 :
2014 56 : BIND(&if_slow);
2015 : {
2016 : // Let nextPromise be ? Invoke(constructor, "resolve", « nextValue »).
2017 : Node* const next_promise =
2018 : InvokeResolve(native_context, constructor, next_value,
2019 56 : &close_iterator, var_exception);
2020 :
2021 : // Perform ? Invoke(nextPromise, "then", « resolveElement,
2022 : // resultCapability.[[Reject]] »).
2023 : Node* const then =
2024 112 : GetProperty(native_context, next_promise, factory()->then_string());
2025 56 : GotoIfException(then, &close_iterator, var_exception);
2026 :
2027 : Node* const then_call =
2028 : CallJS(CodeFactory::Call(isolate(),
2029 : ConvertReceiverMode::kNotNullOrUndefined),
2030 : native_context, then, next_promise, resolve_element_fun,
2031 56 : LoadObjectField(capability, PromiseCapability::kRejectOffset));
2032 56 : GotoIfException(then_call, &close_iterator, var_exception);
2033 :
2034 : // For catch prediction, mark that rejections here are semantically
2035 : // handled by the combined Promise.
2036 : SetPromiseHandledByIfTrue(
2037 56 : native_context, IsDebugActive(), then_call, [=]() {
2038 : // Load promiseCapability.[[Promise]]
2039 : return LoadObjectField(capability,
2040 112 : PromiseCapability::kPromiseOffset);
2041 168 : });
2042 :
2043 56 : Goto(&loop);
2044 56 : }
2045 : }
2046 :
2047 56 : BIND(&too_many_elements);
2048 : {
2049 : // If there are too many elements (currently more than 2**21-1), raise a
2050 : // RangeError here (which is caught directly and turned into a rejection)
2051 : // of the resulting promise. We could gracefully handle this case as well
2052 : // and support more than this number of elements by going to a separate
2053 : // function and pass the larger indices via a separate context, but it
2054 : // doesn't seem likely that we need this, and it's unclear how the rest
2055 : // of the system deals with 2**21 live Promises anyways.
2056 : Node* const result =
2057 : CallRuntime(Runtime::kThrowRangeError, native_context,
2058 56 : SmiConstant(MessageTemplate::kTooManyElementsInPromiseAll));
2059 56 : GotoIfException(result, &close_iterator, var_exception);
2060 56 : Unreachable();
2061 : }
2062 :
2063 56 : BIND(&close_iterator);
2064 : {
2065 : // Exception must be bound to a JS value.
2066 : CSA_ASSERT(this, IsNotTheHole(var_exception->value()));
2067 : iter_assembler.IteratorCloseOnException(native_context, iterator,
2068 56 : if_exception, var_exception);
2069 : }
2070 :
2071 56 : BIND(&done_loop);
2072 : {
2073 112 : Label resolve_promise(this, Label::kDeferred), return_promise(this);
2074 : // Set iteratorRecord.[[Done]] to true.
2075 : // Set remainingElementsCount.[[Value]] to
2076 : // remainingElementsCount.[[Value]] - 1.
2077 56 : TNode<Smi> remaining_elements_count = CAST(LoadContextElement(
2078 : resolve_element_context,
2079 : PromiseBuiltins::kPromiseAllResolveElementRemainingSlot));
2080 56 : remaining_elements_count = SmiSub(remaining_elements_count, SmiConstant(1));
2081 : StoreContextElementNoWriteBarrier(
2082 : resolve_element_context,
2083 : PromiseBuiltins::kPromiseAllResolveElementRemainingSlot,
2084 56 : remaining_elements_count);
2085 56 : GotoIf(SmiEqual(remaining_elements_count, SmiConstant(0)),
2086 56 : &resolve_promise);
2087 :
2088 : // Pre-allocate the backing store for the {values_array} to the desired
2089 : // capacity here. We may already have elements here in case of some
2090 : // fancy Thenable that calls the resolve callback immediately, so we need
2091 : // to handle that correctly here.
2092 : Node* const values_array = LoadContextElement(
2093 : resolve_element_context,
2094 56 : PromiseBuiltins::kPromiseAllResolveElementValuesArraySlot);
2095 56 : Node* const old_elements = LoadElements(values_array);
2096 56 : TNode<Smi> const old_capacity = LoadFixedArrayBaseLength(old_elements);
2097 56 : TNode<Smi> const new_capacity = var_index.value();
2098 56 : GotoIf(SmiGreaterThanOrEqual(old_capacity, new_capacity), &return_promise);
2099 : Node* const new_elements =
2100 : AllocateFixedArray(PACKED_ELEMENTS, new_capacity, SMI_PARAMETERS,
2101 56 : AllocationFlag::kAllowLargeObjectAllocation);
2102 : CopyFixedArrayElements(PACKED_ELEMENTS, old_elements, PACKED_ELEMENTS,
2103 56 : new_elements, SmiConstant(0), old_capacity,
2104 112 : new_capacity, UPDATE_WRITE_BARRIER, SMI_PARAMETERS);
2105 56 : StoreObjectField(values_array, JSArray::kElementsOffset, new_elements);
2106 56 : Goto(&return_promise);
2107 :
2108 : // If remainingElementsCount.[[Value]] is 0, then
2109 : // Let valuesArray be CreateArrayFromList(values).
2110 : // Perform ? Call(resultCapability.[[Resolve]], undefined,
2111 : // « valuesArray »).
2112 56 : BIND(&resolve_promise);
2113 : {
2114 : Node* const resolve =
2115 56 : LoadObjectField(capability, PromiseCapability::kResolveOffset);
2116 : Node* const values_array = LoadContextElement(
2117 : resolve_element_context,
2118 56 : PromiseBuiltins::kPromiseAllResolveElementValuesArraySlot);
2119 : Node* const resolve_call = CallJS(
2120 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
2121 56 : native_context, resolve, UndefinedConstant(), values_array);
2122 56 : GotoIfException(resolve_call, if_exception, var_exception);
2123 56 : Goto(&return_promise);
2124 : }
2125 :
2126 : // Return resultCapability.[[Promise]].
2127 112 : BIND(&return_promise);
2128 : }
2129 :
2130 : Node* const promise =
2131 56 : LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2132 112 : return promise;
2133 : }
2134 :
2135 : // ES#sec-promise.all
2136 : // Promise.all ( iterable )
2137 392 : TF_BUILTIN(PromiseAll, PromiseBuiltinsAssembler) {
2138 56 : IteratorBuiltinsAssembler iter_assembler(state());
2139 :
2140 : // Let C be the this value.
2141 : // If Type(C) is not Object, throw a TypeError exception.
2142 56 : Node* const receiver = Parameter(Descriptor::kReceiver);
2143 56 : Node* const context = Parameter(Descriptor::kContext);
2144 : ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
2145 56 : "Promise.all");
2146 :
2147 : // Let promiseCapability be ? NewPromiseCapability(C).
2148 : // Don't fire debugEvent so that forwarding the rejection through all does not
2149 : // trigger redundant ExceptionEvents
2150 56 : Node* const debug_event = FalseConstant();
2151 : Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability, context,
2152 56 : receiver, debug_event);
2153 :
2154 112 : VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
2155 112 : Label reject_promise(this, &var_exception, Label::kDeferred);
2156 :
2157 : // Let iterator be GetIterator(iterable).
2158 : // IfAbruptRejectPromise(iterator, promiseCapability).
2159 56 : Node* const iterable = Parameter(Descriptor::kIterable);
2160 : IteratorRecord iterator = iter_assembler.GetIterator(
2161 56 : context, iterable, &reject_promise, &var_exception);
2162 :
2163 : // Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability).
2164 : // If result is an abrupt completion, then
2165 : // If iteratorRecord.[[Done]] is false, let result be
2166 : // IteratorClose(iterator, result).
2167 : // IfAbruptRejectPromise(result, promiseCapability).
2168 : Node* const result = PerformPromiseAll(
2169 56 : context, receiver, capability, iterator, &reject_promise, &var_exception);
2170 :
2171 56 : Return(result);
2172 :
2173 56 : BIND(&reject_promise);
2174 : {
2175 : // Exception must be bound to a JS value.
2176 : CSA_SLOW_ASSERT(this, IsNotTheHole(var_exception.value()));
2177 : Node* const reject =
2178 56 : LoadObjectField(capability, PromiseCapability::kRejectOffset);
2179 : CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
2180 56 : context, reject, UndefinedConstant(), var_exception.value());
2181 :
2182 : Node* const promise =
2183 56 : LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2184 56 : Return(promise);
2185 56 : }
2186 56 : }
2187 :
2188 392 : TF_BUILTIN(PromiseAllResolveElementClosure, PromiseBuiltinsAssembler) {
2189 56 : TNode<Object> value = CAST(Parameter(Descriptor::kValue));
2190 56 : TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2191 56 : TNode<JSFunction> function = CAST(Parameter(Descriptor::kJSTarget));
2192 :
2193 112 : Label already_called(this, Label::kDeferred), resolve_promise(this);
2194 :
2195 : // We use the {function}s context as the marker to remember whether this
2196 : // resolve element closure was already called. It points to the resolve
2197 : // element context (which is a FunctionContext) until it was called the
2198 : // first time, in which case we make it point to the native context here
2199 : // to mark this resolve element closure as done.
2200 56 : GotoIf(IsNativeContext(context), &already_called);
2201 : CSA_ASSERT(
2202 : this,
2203 : SmiEqual(LoadObjectField<Smi>(context, Context::kLengthOffset),
2204 : SmiConstant(PromiseBuiltins::kPromiseAllResolveElementLength)));
2205 56 : TNode<Context> native_context = LoadNativeContext(context);
2206 56 : StoreObjectField(function, JSFunction::kContextOffset, native_context);
2207 :
2208 : // Determine the index from the {function}.
2209 112 : Label unreachable(this, Label::kDeferred);
2210 : STATIC_ASSERT(PropertyArray::kNoHashSentinel == 0);
2211 : TNode<IntPtrT> identity_hash =
2212 56 : LoadJSReceiverIdentityHash(function, &unreachable);
2213 : CSA_ASSERT(this, IntPtrGreaterThan(identity_hash, IntPtrConstant(0)));
2214 56 : TNode<IntPtrT> index = IntPtrSub(identity_hash, IntPtrConstant(1));
2215 :
2216 : // Check if we need to grow the [[ValuesArray]] to store {value} at {index}.
2217 56 : TNode<JSArray> values_array = CAST(LoadContextElement(
2218 : context, PromiseBuiltins::kPromiseAllResolveElementValuesArraySlot));
2219 56 : TNode<FixedArray> elements = CAST(LoadElements(values_array));
2220 : TNode<IntPtrT> values_length =
2221 56 : LoadAndUntagObjectField(values_array, JSArray::kLengthOffset);
2222 112 : Label if_inbounds(this), if_outofbounds(this), done(this);
2223 56 : Branch(IntPtrLessThan(index, values_length), &if_inbounds, &if_outofbounds);
2224 :
2225 56 : BIND(&if_outofbounds);
2226 : {
2227 : // Check if we need to grow the backing store.
2228 56 : TNode<IntPtrT> new_length = IntPtrAdd(index, IntPtrConstant(1));
2229 : TNode<IntPtrT> elements_length =
2230 56 : LoadAndUntagObjectField(elements, FixedArray::kLengthOffset);
2231 112 : Label if_grow(this, Label::kDeferred), if_nogrow(this);
2232 56 : Branch(IntPtrLessThan(index, elements_length), &if_nogrow, &if_grow);
2233 :
2234 56 : BIND(&if_grow);
2235 : {
2236 : // We need to grow the backing store to fit the {index} as well.
2237 : TNode<IntPtrT> new_elements_length =
2238 : IntPtrMin(CalculateNewElementsCapacity(new_length),
2239 56 : IntPtrConstant(PropertyArray::HashField::kMax + 1));
2240 : CSA_ASSERT(this, IntPtrLessThan(index, new_elements_length));
2241 : CSA_ASSERT(this, IntPtrLessThan(elements_length, new_elements_length));
2242 : TNode<FixedArray> new_elements =
2243 56 : CAST(AllocateFixedArray(PACKED_ELEMENTS, new_elements_length,
2244 : AllocationFlag::kAllowLargeObjectAllocation));
2245 : CopyFixedArrayElements(PACKED_ELEMENTS, elements, PACKED_ELEMENTS,
2246 : new_elements, elements_length,
2247 56 : new_elements_length);
2248 56 : StoreFixedArrayElement(new_elements, index, value);
2249 :
2250 : // Update backing store and "length" on {values_array}.
2251 56 : StoreObjectField(values_array, JSArray::kElementsOffset, new_elements);
2252 : StoreObjectFieldNoWriteBarrier(values_array, JSArray::kLengthOffset,
2253 56 : SmiTag(new_length));
2254 56 : Goto(&done);
2255 : }
2256 :
2257 56 : BIND(&if_nogrow);
2258 : {
2259 : // The {index} is within bounds of the {elements} backing store, so
2260 : // just store the {value} and update the "length" of the {values_array}.
2261 : StoreObjectFieldNoWriteBarrier(values_array, JSArray::kLengthOffset,
2262 56 : SmiTag(new_length));
2263 56 : StoreFixedArrayElement(elements, index, value);
2264 56 : Goto(&done);
2265 56 : }
2266 : }
2267 :
2268 56 : BIND(&if_inbounds);
2269 : {
2270 : // The {index} is in bounds of the {values_array},
2271 : // just store the {value} and continue.
2272 56 : StoreFixedArrayElement(elements, index, value);
2273 56 : Goto(&done);
2274 : }
2275 :
2276 56 : BIND(&done);
2277 56 : TNode<Smi> remaining_elements_count = CAST(LoadContextElement(
2278 : context, PromiseBuiltins::kPromiseAllResolveElementRemainingSlot));
2279 56 : remaining_elements_count = SmiSub(remaining_elements_count, SmiConstant(1));
2280 : StoreContextElement(context,
2281 : PromiseBuiltins::kPromiseAllResolveElementRemainingSlot,
2282 56 : remaining_elements_count);
2283 56 : GotoIf(SmiEqual(remaining_elements_count, SmiConstant(0)), &resolve_promise);
2284 56 : Return(UndefinedConstant());
2285 :
2286 56 : BIND(&resolve_promise);
2287 56 : TNode<PromiseCapability> capability = CAST(LoadContextElement(
2288 : context, PromiseBuiltins::kPromiseAllResolveElementCapabilitySlot));
2289 : TNode<Object> resolve =
2290 56 : LoadObjectField(capability, PromiseCapability::kResolveOffset);
2291 : CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
2292 56 : context, resolve, UndefinedConstant(), values_array);
2293 56 : Return(UndefinedConstant());
2294 :
2295 56 : BIND(&already_called);
2296 56 : Return(UndefinedConstant());
2297 :
2298 56 : BIND(&unreachable);
2299 112 : Unreachable();
2300 56 : }
2301 :
2302 : // ES#sec-promise.race
2303 : // Promise.race ( iterable )
2304 392 : TF_BUILTIN(PromiseRace, PromiseBuiltinsAssembler) {
2305 56 : IteratorBuiltinsAssembler iter_assembler(state());
2306 112 : VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
2307 :
2308 56 : Node* const receiver = Parameter(Descriptor::kReceiver);
2309 56 : Node* const context = Parameter(Descriptor::kContext);
2310 : ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
2311 56 : "Promise.race");
2312 :
2313 : // Let promiseCapability be ? NewPromiseCapability(C).
2314 : // Don't fire debugEvent so that forwarding the rejection through all does not
2315 : // trigger redundant ExceptionEvents
2316 56 : Node* const debug_event = FalseConstant();
2317 : Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability, context,
2318 56 : receiver, debug_event);
2319 :
2320 : Node* const resolve =
2321 56 : LoadObjectField(capability, PromiseCapability::kResolveOffset);
2322 : Node* const reject =
2323 56 : LoadObjectField(capability, PromiseCapability::kRejectOffset);
2324 :
2325 112 : Label close_iterator(this, Label::kDeferred);
2326 112 : Label reject_promise(this, Label::kDeferred);
2327 :
2328 : // For catch prediction, don't treat the .then calls as handling it;
2329 : // instead, recurse outwards.
2330 56 : SetForwardingHandlerIfTrue(context, IsDebugActive(), reject);
2331 :
2332 : // Let iterator be GetIterator(iterable).
2333 : // IfAbruptRejectPromise(iterator, promiseCapability).
2334 56 : Node* const iterable = Parameter(Descriptor::kIterable);
2335 : IteratorRecord iterator = iter_assembler.GetIterator(
2336 56 : context, iterable, &reject_promise, &var_exception);
2337 :
2338 : // Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability).
2339 : {
2340 112 : Label loop(this), break_loop(this);
2341 56 : Goto(&loop);
2342 56 : BIND(&loop);
2343 : {
2344 56 : Node* const native_context = LoadNativeContext(context);
2345 : Node* const fast_iterator_result_map = LoadContextElement(
2346 56 : native_context, Context::ITERATOR_RESULT_MAP_INDEX);
2347 :
2348 : // Let next be IteratorStep(iteratorRecord.[[Iterator]]).
2349 : // If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
2350 : // ReturnIfAbrupt(next).
2351 : Node* const next = iter_assembler.IteratorStep(
2352 : context, iterator, &break_loop, fast_iterator_result_map,
2353 56 : &reject_promise, &var_exception);
2354 :
2355 : // Let nextValue be IteratorValue(next).
2356 : // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to
2357 : // true.
2358 : // ReturnIfAbrupt(nextValue).
2359 : Node* const next_value =
2360 : iter_assembler.IteratorValue(context, next, fast_iterator_result_map,
2361 56 : &reject_promise, &var_exception);
2362 :
2363 : // Let nextPromise be ? Invoke(constructor, "resolve", « nextValue »).
2364 : Node* const next_promise =
2365 : InvokeResolve(native_context, receiver, next_value, &close_iterator,
2366 56 : &var_exception);
2367 :
2368 : // Perform ? Invoke(nextPromise, "then", « resolveElement,
2369 : // resultCapability.[[Reject]] »).
2370 : Node* const then =
2371 112 : GetProperty(context, next_promise, factory()->then_string());
2372 56 : GotoIfException(then, &close_iterator, &var_exception);
2373 :
2374 : Node* const then_call =
2375 : CallJS(CodeFactory::Call(isolate(),
2376 : ConvertReceiverMode::kNotNullOrUndefined),
2377 56 : context, then, next_promise, resolve, reject);
2378 56 : GotoIfException(then_call, &close_iterator, &var_exception);
2379 :
2380 : // For catch prediction, mark that rejections here are semantically
2381 : // handled by the combined Promise.
2382 56 : SetPromiseHandledByIfTrue(context, IsDebugActive(), then_call, [=]() {
2383 : // Load promiseCapability.[[Promise]]
2384 112 : return LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2385 168 : });
2386 56 : Goto(&loop);
2387 : }
2388 :
2389 56 : BIND(&break_loop);
2390 112 : Return(LoadObjectField(capability, PromiseCapability::kPromiseOffset));
2391 : }
2392 :
2393 56 : BIND(&close_iterator);
2394 : {
2395 : CSA_ASSERT(this, IsNotTheHole(var_exception.value()));
2396 : iter_assembler.IteratorCloseOnException(context, iterator, &reject_promise,
2397 56 : &var_exception);
2398 : }
2399 :
2400 56 : BIND(&reject_promise);
2401 : {
2402 : Node* const reject =
2403 56 : LoadObjectField(capability, PromiseCapability::kRejectOffset);
2404 : CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
2405 56 : context, reject, UndefinedConstant(), var_exception.value());
2406 :
2407 : Node* const promise =
2408 56 : LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2409 56 : Return(promise);
2410 56 : }
2411 56 : }
2412 :
2413 : } // namespace internal
2414 86739 : } // namespace v8
|