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-utils-gen.h"
10 : #include "src/builtins/builtins.h"
11 : #include "src/code-factory.h"
12 : #include "src/code-stub-assembler.h"
13 : #include "src/objects-inl.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : using compiler::Node;
19 :
20 767 : Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) {
21 1534 : Node* const native_context = LoadNativeContext(context);
22 : Node* const promise_fun =
23 1534 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
24 : CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(promise_fun)));
25 : Node* const initial_map =
26 : LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
27 767 : Node* const instance = AllocateJSObjectFromMap(initial_map);
28 767 : return instance;
29 : }
30 :
31 1133 : void PromiseBuiltinsAssembler::PromiseInit(Node* promise) {
32 : STATIC_ASSERT(v8::Promise::kPending == 0);
33 : StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset,
34 2266 : SmiConstant(0));
35 : for (int i = 0; i < v8::Promise::kEmbedderFieldCount; i++) {
36 : int offset = JSPromise::kSize + i * kPointerSize;
37 : StoreObjectFieldNoWriteBarrier(promise, offset, SmiConstant(0));
38 : }
39 1133 : }
40 :
41 384 : Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context) {
42 768 : return AllocateAndInitJSPromise(context, UndefinedConstant());
43 : }
44 :
45 501 : Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context,
46 : Node* parent) {
47 501 : Node* const instance = AllocateJSPromise(context);
48 501 : PromiseInit(instance);
49 :
50 501 : Label out(this);
51 1002 : GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &out);
52 : CallRuntime(Runtime::kPromiseHookInit, context, instance, parent);
53 501 : Goto(&out);
54 :
55 501 : BIND(&out);
56 501 : return instance;
57 : }
58 :
59 37 : Node* PromiseBuiltinsAssembler::AllocateAndSetJSPromise(
60 : Node* context, v8::Promise::PromiseState status, Node* result) {
61 37 : Node* const instance = AllocateJSPromise(context);
62 :
63 37 : StoreObjectFieldNoWriteBarrier(instance, JSPromise::kResultOffset, result);
64 : STATIC_ASSERT(JSPromise::kStatusShift == 0);
65 : StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset,
66 74 : SmiConstant(status));
67 : for (int i = 0; i < v8::Promise::kEmbedderFieldCount; i++) {
68 : int offset = JSPromise::kSize + i * kPointerSize;
69 : StoreObjectFieldNoWriteBarrier(instance, offset, SmiConstant(0));
70 : }
71 :
72 : Label out(this);
73 74 : GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &out);
74 : CallRuntime(Runtime::kPromiseHookInit, context, instance,
75 37 : UndefinedConstant());
76 37 : Goto(&out);
77 :
78 37 : BIND(&out);
79 37 : return instance;
80 : }
81 :
82 : std::pair<Node*, Node*>
83 427 : PromiseBuiltinsAssembler::CreatePromiseResolvingFunctions(
84 : Node* promise, Node* debug_event, Node* native_context) {
85 : Node* const promise_context = CreatePromiseResolvingFunctionsContext(
86 427 : promise, debug_event, native_context);
87 : Node* const map = LoadContextElement(
88 854 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
89 : Node* const resolve_info =
90 854 : LoadContextElement(native_context, Context::PROMISE_RESOLVE_SHARED_FUN);
91 : Node* const resolve =
92 427 : AllocateFunctionWithMapAndContext(map, resolve_info, promise_context);
93 : Node* const reject_info =
94 854 : LoadContextElement(native_context, Context::PROMISE_REJECT_SHARED_FUN);
95 : Node* const reject =
96 427 : AllocateFunctionWithMapAndContext(map, reject_info, promise_context);
97 427 : return std::make_pair(resolve, reject);
98 : }
99 :
100 229 : Node* PromiseBuiltinsAssembler::NewPromiseCapability(Node* context,
101 : Node* constructor,
102 : Node* debug_event) {
103 229 : if (debug_event == nullptr) {
104 272 : debug_event = TrueConstant();
105 : }
106 :
107 229 : Label if_not_constructor(this, Label::kDeferred);
108 458 : GotoIf(TaggedIsSmi(constructor), &if_not_constructor);
109 687 : GotoIfNot(IsConstructorMap(LoadMap(constructor)), &if_not_constructor);
110 :
111 458 : Node* native_context = LoadNativeContext(context);
112 :
113 458 : Node* map = LoadRoot(Heap::kPromiseCapabilityMapRootIndex);
114 229 : Node* capability = AllocateStruct(map);
115 :
116 458 : VARIABLE(var_result, MachineRepresentation::kTagged);
117 229 : var_result.Bind(capability);
118 :
119 229 : Label if_builtin_promise(this), if_custom_promise(this, Label::kDeferred),
120 229 : out(this);
121 : Branch(WordEqual(constructor,
122 : LoadContextElement(native_context,
123 458 : Context::PROMISE_FUNCTION_INDEX)),
124 229 : &if_builtin_promise, &if_custom_promise);
125 :
126 229 : BIND(&if_builtin_promise);
127 : {
128 229 : Node* promise = AllocateJSPromise(context);
129 229 : PromiseInit(promise);
130 229 : StoreObjectField(capability, PromiseCapability::kPromiseOffset, promise);
131 :
132 229 : Node* resolve = nullptr;
133 229 : Node* reject = nullptr;
134 :
135 458 : std::tie(resolve, reject) =
136 : CreatePromiseResolvingFunctions(promise, debug_event, native_context);
137 229 : StoreObjectField(capability, PromiseCapability::kResolveOffset, resolve);
138 229 : StoreObjectField(capability, PromiseCapability::kRejectOffset, reject);
139 :
140 458 : GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &out);
141 : CallRuntime(Runtime::kPromiseHookInit, context, promise,
142 229 : UndefinedConstant());
143 229 : Goto(&out);
144 : }
145 :
146 229 : BIND(&if_custom_promise);
147 : {
148 : Label if_notcallable(this, Label::kDeferred);
149 : Node* executor_context =
150 229 : CreatePromiseGetCapabilitiesExecutorContext(capability, native_context);
151 : Node* executor_info = LoadContextElement(
152 458 : native_context, Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN);
153 : Node* function_map = LoadContextElement(
154 458 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
155 : Node* executor = AllocateFunctionWithMapAndContext(
156 229 : function_map, executor_info, executor_context);
157 :
158 : Node* promise = ConstructJS(CodeFactory::Construct(isolate()), context,
159 458 : constructor, executor);
160 :
161 : Node* resolve =
162 : LoadObjectField(capability, PromiseCapability::kResolveOffset);
163 458 : GotoIf(TaggedIsSmi(resolve), &if_notcallable);
164 687 : GotoIfNot(IsCallableMap(LoadMap(resolve)), &if_notcallable);
165 :
166 : Node* reject =
167 : LoadObjectField(capability, PromiseCapability::kRejectOffset);
168 458 : GotoIf(TaggedIsSmi(reject), &if_notcallable);
169 687 : GotoIfNot(IsCallableMap(LoadMap(reject)), &if_notcallable);
170 :
171 229 : StoreObjectField(capability, PromiseCapability::kPromiseOffset, promise);
172 :
173 229 : Goto(&out);
174 :
175 229 : BIND(&if_notcallable);
176 : StoreObjectField(capability, PromiseCapability::kPromiseOffset,
177 458 : UndefinedConstant());
178 : StoreObjectField(capability, PromiseCapability::kResolveOffset,
179 458 : UndefinedConstant());
180 : StoreObjectField(capability, PromiseCapability::kRejectOffset,
181 458 : UndefinedConstant());
182 229 : ThrowTypeError(context, MessageTemplate::kPromiseNonCallable);
183 : }
184 :
185 229 : BIND(&if_not_constructor);
186 229 : ThrowTypeError(context, MessageTemplate::kNotConstructor, constructor);
187 :
188 229 : BIND(&out);
189 458 : return var_result.value();
190 : }
191 :
192 1077 : void PromiseBuiltinsAssembler::InitializeFunctionContext(Node* native_context,
193 : Node* context,
194 : int slots) {
195 : DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
196 1077 : StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex);
197 : StoreObjectFieldNoWriteBarrier(context, FixedArray::kLengthOffset,
198 2154 : SmiConstant(slots));
199 :
200 : Node* const empty_fn =
201 2154 : LoadContextElement(native_context, Context::CLOSURE_INDEX);
202 1077 : StoreContextElementNoWriteBarrier(context, Context::CLOSURE_INDEX, empty_fn);
203 : StoreContextElementNoWriteBarrier(context, Context::PREVIOUS_INDEX,
204 2154 : UndefinedConstant());
205 : StoreContextElementNoWriteBarrier(context, Context::EXTENSION_INDEX,
206 2154 : TheHoleConstant());
207 : StoreContextElementNoWriteBarrier(context, Context::NATIVE_CONTEXT_INDEX,
208 1077 : native_context);
209 1077 : }
210 :
211 891 : Node* PromiseBuiltinsAssembler::CreatePromiseContext(Node* native_context,
212 : int slots) {
213 : DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
214 :
215 891 : Node* const context = AllocateInNewSpace(FixedArray::SizeFor(slots));
216 891 : InitializeFunctionContext(native_context, context, slots);
217 891 : return context;
218 : }
219 :
220 439 : Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
221 : Node* promise, Node* debug_event, Node* native_context) {
222 : Node* const context =
223 439 : CreatePromiseContext(native_context, kPromiseContextLength);
224 : StoreContextElementNoWriteBarrier(context, kAlreadyVisitedSlot,
225 878 : SmiConstant(0));
226 439 : StoreContextElementNoWriteBarrier(context, kPromiseSlot, promise);
227 439 : StoreContextElementNoWriteBarrier(context, kDebugEventSlot, debug_event);
228 439 : return context;
229 : }
230 :
231 235 : Node* PromiseBuiltinsAssembler::CreatePromiseGetCapabilitiesExecutorContext(
232 : Node* promise_capability, Node* native_context) {
233 : int kContextLength = kCapabilitiesContextLength;
234 235 : Node* context = CreatePromiseContext(native_context, kContextLength);
235 : StoreContextElementNoWriteBarrier(context, kCapabilitySlot,
236 235 : promise_capability);
237 235 : return context;
238 : }
239 :
240 688 : Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) {
241 688 : Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
242 1376 : return IsSetWord(SmiUntag(flags), 1 << JSPromise::kHasHandlerBit);
243 : }
244 :
245 589 : void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) {
246 589 : Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
247 : Node* const new_flags =
248 1767 : SmiOr(flags, SmiConstant(1 << JSPromise::kHasHandlerBit));
249 589 : StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
250 589 : }
251 :
252 496 : Node* PromiseBuiltinsAssembler::IsPromiseStatus(
253 : Node* actual, v8::Promise::PromiseState expected) {
254 1488 : return Word32Equal(actual, Int32Constant(expected));
255 : }
256 :
257 248 : Node* PromiseBuiltinsAssembler::PromiseStatus(Node* promise) {
258 : STATIC_ASSERT(JSPromise::kStatusShift == 0);
259 248 : Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
260 992 : return Word32And(SmiToWord32(flags), Int32Constant(JSPromise::kStatusMask));
261 : }
262 :
263 775 : void PromiseBuiltinsAssembler::PromiseSetStatus(
264 : Node* promise, v8::Promise::PromiseState const status) {
265 : CSA_ASSERT(this,
266 : IsPromiseStatus(PromiseStatus(promise), v8::Promise::kPending));
267 775 : CHECK_NE(status, v8::Promise::kPending);
268 :
269 1550 : Node* mask = SmiConstant(status);
270 775 : Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
271 : StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset,
272 1550 : SmiOr(flags, mask));
273 775 : }
274 :
275 186 : void PromiseBuiltinsAssembler::PromiseSetHandledHint(Node* promise) {
276 186 : Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
277 : Node* const new_flags =
278 558 : SmiOr(flags, SmiConstant(1 << JSPromise::kHandledHintBit));
279 186 : StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
280 186 : }
281 :
282 93 : Node* PromiseBuiltinsAssembler::SpeciesConstructor(Node* context, Node* object,
283 : Node* default_constructor) {
284 93 : Isolate* isolate = this->isolate();
285 93 : VARIABLE(var_result, MachineRepresentation::kTagged);
286 93 : var_result.Bind(default_constructor);
287 :
288 : // 2. Let C be ? Get(O, "constructor").
289 : Node* const constructor =
290 93 : GetProperty(context, object, isolate->factory()->constructor_string());
291 :
292 : // 3. If C is undefined, return defaultConstructor.
293 93 : Label out(this);
294 186 : GotoIf(IsUndefined(constructor), &out);
295 :
296 : // 4. If Type(C) is not Object, throw a TypeError exception.
297 : ThrowIfNotJSReceiver(context, constructor,
298 93 : MessageTemplate::kConstructorNotReceiver);
299 :
300 : // 5. Let S be ? Get(C, @@species).
301 : Node* const species =
302 93 : GetProperty(context, constructor, isolate->factory()->species_symbol());
303 :
304 : // 6. If S is either undefined or null, return defaultConstructor.
305 186 : GotoIf(IsUndefined(species), &out);
306 186 : GotoIf(WordEqual(species, NullConstant()), &out);
307 :
308 : // 7. If IsConstructor(S) is true, return S.
309 93 : Label throw_error(this);
310 186 : GotoIf(TaggedIsSmi(species), &throw_error);
311 279 : GotoIfNot(IsConstructorMap(LoadMap(species)), &throw_error);
312 93 : var_result.Bind(species);
313 93 : Goto(&out);
314 :
315 : // 8. Throw a TypeError exception.
316 93 : BIND(&throw_error);
317 93 : ThrowTypeError(context, MessageTemplate::kSpeciesNotConstructor);
318 :
319 93 : BIND(&out);
320 186 : return var_result.value();
321 : }
322 :
323 465 : void PromiseBuiltinsAssembler::AppendPromiseCallback(int offset, Node* promise,
324 : Node* value) {
325 465 : Node* elements = LoadObjectField(promise, offset);
326 930 : Node* length = LoadFixedArrayBaseLength(elements);
327 : CodeStubAssembler::ParameterMode mode = OptimalParameterMode();
328 : length = TaggedToParameter(length, mode);
329 :
330 465 : Node* delta = IntPtrOrSmiConstant(1, mode);
331 465 : Node* new_capacity = IntPtrOrSmiAdd(length, delta, mode);
332 :
333 : const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER;
334 : int additional_offset = 0;
335 :
336 : ExtractFixedArrayFlags flags;
337 : flags |= ExtractFixedArrayFlag::kFixedArrays;
338 : Node* new_elements =
339 465 : ExtractFixedArray(elements, nullptr, length, new_capacity, flags, mode);
340 :
341 : StoreFixedArrayElement(new_elements, length, value, barrier_mode,
342 465 : additional_offset, mode);
343 :
344 465 : StoreObjectField(promise, offset, new_elements);
345 465 : }
346 :
347 62 : Node* PromiseBuiltinsAssembler::InternalPromiseThen(Node* context,
348 : Node* promise,
349 : Node* on_resolve,
350 : Node* on_reject) {
351 62 : Isolate* isolate = this->isolate();
352 :
353 : // 2. If IsPromise(promise) is false, throw a TypeError exception.
354 : ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
355 62 : "Promise.prototype.then");
356 :
357 124 : Node* const native_context = LoadNativeContext(context);
358 : Node* const promise_fun =
359 124 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
360 :
361 : // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
362 62 : Node* constructor = SpeciesConstructor(context, promise, promise_fun);
363 :
364 : // 4. Let resultCapability be ? NewPromiseCapability(C).
365 62 : Callable call_callable = CodeFactory::Call(isolate);
366 62 : Label fast_promise_capability(this), promise_capability(this),
367 62 : perform_promise_then(this);
368 124 : VARIABLE(var_deferred_promise, MachineRepresentation::kTagged);
369 124 : VARIABLE(var_deferred_on_resolve, MachineRepresentation::kTagged);
370 124 : VARIABLE(var_deferred_on_reject, MachineRepresentation::kTagged);
371 :
372 62 : Branch(WordEqual(promise_fun, constructor), &fast_promise_capability,
373 124 : &promise_capability);
374 :
375 62 : BIND(&fast_promise_capability);
376 : {
377 62 : Node* const deferred_promise = AllocateAndInitJSPromise(context, promise);
378 62 : var_deferred_promise.Bind(deferred_promise);
379 124 : var_deferred_on_resolve.Bind(UndefinedConstant());
380 124 : var_deferred_on_reject.Bind(UndefinedConstant());
381 62 : Goto(&perform_promise_then);
382 : }
383 :
384 62 : BIND(&promise_capability);
385 : {
386 62 : Node* const capability = NewPromiseCapability(context, constructor);
387 : var_deferred_promise.Bind(
388 62 : LoadObjectField(capability, PromiseCapability::kPromiseOffset));
389 : var_deferred_on_resolve.Bind(
390 62 : LoadObjectField(capability, PromiseCapability::kResolveOffset));
391 : var_deferred_on_reject.Bind(
392 62 : LoadObjectField(capability, PromiseCapability::kRejectOffset));
393 62 : Goto(&perform_promise_then);
394 : }
395 :
396 : // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
397 : // resultCapability).
398 62 : BIND(&perform_promise_then);
399 : Node* const result = InternalPerformPromiseThen(
400 : context, promise, on_resolve, on_reject, var_deferred_promise.value(),
401 62 : var_deferred_on_resolve.value(), var_deferred_on_reject.value());
402 62 : return result;
403 : }
404 :
405 93 : Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
406 : Node* context, Node* promise, Node* on_resolve, Node* on_reject,
407 : Node* deferred_promise, Node* deferred_on_resolve,
408 : Node* deferred_on_reject) {
409 93 : VARIABLE(var_on_resolve, MachineRepresentation::kTagged);
410 186 : VARIABLE(var_on_reject, MachineRepresentation::kTagged);
411 :
412 93 : var_on_resolve.Bind(on_resolve);
413 93 : var_on_reject.Bind(on_reject);
414 :
415 93 : Label out(this), if_onresolvenotcallable(this), onrejectcheck(this),
416 93 : append_callbacks(this);
417 186 : GotoIf(TaggedIsSmi(on_resolve), &if_onresolvenotcallable);
418 :
419 93 : Isolate* isolate = this->isolate();
420 186 : Node* const on_resolve_map = LoadMap(on_resolve);
421 : Branch(IsCallableMap(on_resolve_map), &onrejectcheck,
422 186 : &if_onresolvenotcallable);
423 :
424 93 : BIND(&if_onresolvenotcallable);
425 : {
426 : Node* const default_resolve_handler_symbol = HeapConstant(
427 : isolate->factory()->promise_default_resolve_handler_symbol());
428 93 : var_on_resolve.Bind(default_resolve_handler_symbol);
429 93 : Goto(&onrejectcheck);
430 : }
431 :
432 93 : BIND(&onrejectcheck);
433 : {
434 : Label if_onrejectnotcallable(this);
435 186 : GotoIf(TaggedIsSmi(on_reject), &if_onrejectnotcallable);
436 :
437 186 : Node* const on_reject_map = LoadMap(on_reject);
438 : Branch(IsCallableMap(on_reject_map), &append_callbacks,
439 186 : &if_onrejectnotcallable);
440 :
441 93 : BIND(&if_onrejectnotcallable);
442 : {
443 : Node* const default_reject_handler_symbol = HeapConstant(
444 : isolate->factory()->promise_default_reject_handler_symbol());
445 93 : var_on_reject.Bind(default_reject_handler_symbol);
446 93 : Goto(&append_callbacks);
447 93 : }
448 : }
449 :
450 93 : BIND(&append_callbacks);
451 : {
452 : Label fulfilled_check(this);
453 93 : Node* const status = PromiseStatus(promise);
454 186 : GotoIfNot(IsPromiseStatus(status, v8::Promise::kPending), &fulfilled_check);
455 :
456 : Node* const existing_deferred_promise =
457 : LoadObjectField(promise, JSPromise::kDeferredPromiseOffset);
458 :
459 93 : Label if_noexistingcallbacks(this), if_existingcallbacks(this);
460 93 : Branch(IsUndefined(existing_deferred_promise), &if_noexistingcallbacks,
461 186 : &if_existingcallbacks);
462 :
463 93 : BIND(&if_noexistingcallbacks);
464 : {
465 : // Store callbacks directly in the slots.
466 : StoreObjectField(promise, JSPromise::kDeferredPromiseOffset,
467 93 : deferred_promise);
468 : StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset,
469 93 : deferred_on_resolve);
470 : StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset,
471 93 : deferred_on_reject);
472 : StoreObjectField(promise, JSPromise::kFulfillReactionsOffset,
473 93 : var_on_resolve.value());
474 : StoreObjectField(promise, JSPromise::kRejectReactionsOffset,
475 93 : var_on_reject.value());
476 93 : Goto(&out);
477 : }
478 :
479 93 : BIND(&if_existingcallbacks);
480 : {
481 93 : Label if_singlecallback(this), if_multiplecallbacks(this);
482 : BranchIfJSObject(existing_deferred_promise, &if_singlecallback,
483 93 : &if_multiplecallbacks);
484 :
485 93 : BIND(&if_singlecallback);
486 : {
487 : // Create new FixedArrays to store callbacks, and migrate
488 : // existing callbacks.
489 : Node* const deferred_promise_arr =
490 186 : AllocateFixedArray(PACKED_ELEMENTS, IntPtrConstant(2));
491 : StoreFixedArrayElement(deferred_promise_arr, 0,
492 93 : existing_deferred_promise);
493 93 : StoreFixedArrayElement(deferred_promise_arr, 1, deferred_promise);
494 :
495 : Node* const deferred_on_resolve_arr =
496 186 : AllocateFixedArray(PACKED_ELEMENTS, IntPtrConstant(2));
497 : StoreFixedArrayElement(
498 : deferred_on_resolve_arr, 0,
499 93 : LoadObjectField(promise, JSPromise::kDeferredOnResolveOffset));
500 93 : StoreFixedArrayElement(deferred_on_resolve_arr, 1, deferred_on_resolve);
501 :
502 : Node* const deferred_on_reject_arr =
503 186 : AllocateFixedArray(PACKED_ELEMENTS, IntPtrConstant(2));
504 : StoreFixedArrayElement(
505 : deferred_on_reject_arr, 0,
506 93 : LoadObjectField(promise, JSPromise::kDeferredOnRejectOffset));
507 93 : StoreFixedArrayElement(deferred_on_reject_arr, 1, deferred_on_reject);
508 :
509 : Node* const fulfill_reactions =
510 186 : AllocateFixedArray(PACKED_ELEMENTS, IntPtrConstant(2));
511 : StoreFixedArrayElement(
512 : fulfill_reactions, 0,
513 93 : LoadObjectField(promise, JSPromise::kFulfillReactionsOffset));
514 93 : StoreFixedArrayElement(fulfill_reactions, 1, var_on_resolve.value());
515 :
516 : Node* const reject_reactions =
517 186 : AllocateFixedArray(PACKED_ELEMENTS, IntPtrConstant(2));
518 : StoreFixedArrayElement(
519 : reject_reactions, 0,
520 93 : LoadObjectField(promise, JSPromise::kRejectReactionsOffset));
521 93 : StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value());
522 :
523 : // Store new FixedArrays in promise.
524 : StoreObjectField(promise, JSPromise::kDeferredPromiseOffset,
525 93 : deferred_promise_arr);
526 : StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset,
527 93 : deferred_on_resolve_arr);
528 : StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset,
529 93 : deferred_on_reject_arr);
530 : StoreObjectField(promise, JSPromise::kFulfillReactionsOffset,
531 93 : fulfill_reactions);
532 : StoreObjectField(promise, JSPromise::kRejectReactionsOffset,
533 93 : reject_reactions);
534 93 : Goto(&out);
535 : }
536 :
537 93 : BIND(&if_multiplecallbacks);
538 : {
539 : AppendPromiseCallback(JSPromise::kDeferredPromiseOffset, promise,
540 93 : deferred_promise);
541 : AppendPromiseCallback(JSPromise::kDeferredOnResolveOffset, promise,
542 93 : deferred_on_resolve);
543 : AppendPromiseCallback(JSPromise::kDeferredOnRejectOffset, promise,
544 93 : deferred_on_reject);
545 : AppendPromiseCallback(JSPromise::kFulfillReactionsOffset, promise,
546 93 : var_on_resolve.value());
547 : AppendPromiseCallback(JSPromise::kRejectReactionsOffset, promise,
548 93 : var_on_reject.value());
549 93 : Goto(&out);
550 93 : }
551 : }
552 :
553 93 : BIND(&fulfilled_check);
554 : {
555 : Label reject(this);
556 : Node* const result = LoadObjectField(promise, JSPromise::kResultOffset);
557 186 : GotoIfNot(IsPromiseStatus(status, v8::Promise::kFulfilled), &reject);
558 :
559 : Node* info = AllocatePromiseReactionJobInfo(
560 : result, var_on_resolve.value(), deferred_promise, deferred_on_resolve,
561 93 : deferred_on_reject, context);
562 : // TODO(gsathya): Move this to TF
563 : CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info);
564 93 : Goto(&out);
565 :
566 93 : BIND(&reject);
567 : {
568 : CSA_ASSERT(this, IsPromiseStatus(status, v8::Promise::kRejected));
569 93 : Node* const has_handler = PromiseHasHandler(promise);
570 : Label enqueue(this);
571 :
572 : // TODO(gsathya): Fold these runtime calls and move to TF.
573 93 : GotoIf(has_handler, &enqueue);
574 : CallRuntime(Runtime::kPromiseRevokeReject, context, promise);
575 93 : Goto(&enqueue);
576 :
577 93 : BIND(&enqueue);
578 : {
579 : Node* info = AllocatePromiseReactionJobInfo(
580 : result, var_on_reject.value(), deferred_promise,
581 93 : deferred_on_resolve, deferred_on_reject, context);
582 : // TODO(gsathya): Move this to TF
583 : CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info);
584 93 : Goto(&out);
585 93 : }
586 93 : }
587 93 : }
588 : }
589 :
590 93 : BIND(&out);
591 93 : PromiseSetHasHandler(promise);
592 93 : return deferred_promise;
593 : }
594 :
595 : // Promise fast path implementations rely on unmodified JSPromise instances.
596 : // We use a fairly coarse granularity for this and simply check whether both
597 : // the promise itself is unmodified (i.e. its map has not changed) and its
598 : // prototype is unmodified.
599 : // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp
600 31 : void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise,
601 : Label* if_isunmodified,
602 : Label* if_ismodified) {
603 62 : Node* const native_context = LoadNativeContext(context);
604 : Node* const promise_fun =
605 62 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
606 : BranchIfFastPath(native_context, promise_fun, promise, if_isunmodified,
607 31 : if_ismodified);
608 31 : }
609 :
610 217 : void PromiseBuiltinsAssembler::BranchIfFastPath(Node* native_context,
611 : Node* promise_fun,
612 : Node* promise,
613 : Label* if_isunmodified,
614 : Label* if_ismodified) {
615 : CSA_ASSERT(this, IsNativeContext(native_context));
616 : CSA_ASSERT(this,
617 : WordEqual(promise_fun,
618 : LoadContextElement(native_context,
619 : Context::PROMISE_FUNCTION_INDEX)));
620 :
621 434 : Node* const map = LoadMap(promise);
622 : Node* const initial_map =
623 : LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
624 434 : Node* const has_initialmap = WordEqual(map, initial_map);
625 :
626 217 : GotoIfNot(has_initialmap, if_ismodified);
627 :
628 : Node* const initial_proto_initial_map =
629 434 : LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX);
630 434 : Node* const proto_map = LoadMap(CAST(LoadMapPrototype(map)));
631 : Node* const proto_has_initialmap =
632 434 : WordEqual(proto_map, initial_proto_initial_map);
633 :
634 217 : Branch(proto_has_initialmap, if_isunmodified, if_ismodified);
635 217 : }
636 :
637 161 : Node* PromiseBuiltinsAssembler::AllocatePromiseResolveThenableJobInfo(
638 : Node* thenable, Node* then, Node* resolve, Node* reject, Node* context) {
639 161 : Node* const info = Allocate(PromiseResolveThenableJobInfo::kSize);
640 : StoreMapNoWriteBarrier(info,
641 161 : Heap::kPromiseResolveThenableJobInfoMapRootIndex);
642 : StoreObjectFieldNoWriteBarrier(
643 161 : info, PromiseResolveThenableJobInfo::kThenableOffset, thenable);
644 : StoreObjectFieldNoWriteBarrier(
645 161 : info, PromiseResolveThenableJobInfo::kThenOffset, then);
646 : StoreObjectFieldNoWriteBarrier(
647 161 : info, PromiseResolveThenableJobInfo::kResolveOffset, resolve);
648 : StoreObjectFieldNoWriteBarrier(
649 161 : info, PromiseResolveThenableJobInfo::kRejectOffset, reject);
650 : StoreObjectFieldNoWriteBarrier(
651 161 : info, PromiseResolveThenableJobInfo::kContextOffset, context);
652 161 : return info;
653 : }
654 :
655 155 : void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
656 : Node* promise,
657 : Node* result) {
658 155 : Isolate* isolate = this->isolate();
659 :
660 155 : VARIABLE(var_reason, MachineRepresentation::kTagged);
661 310 : VARIABLE(var_then, MachineRepresentation::kTagged);
662 :
663 155 : Label do_enqueue(this), fulfill(this), if_nocycle(this),
664 155 : if_cycle(this, Label::kDeferred),
665 155 : if_rejectpromise(this, Label::kDeferred), out(this);
666 :
667 155 : Label cycle_check(this);
668 310 : GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &cycle_check);
669 : CallRuntime(Runtime::kPromiseHookResolve, context, promise);
670 155 : Goto(&cycle_check);
671 :
672 155 : BIND(&cycle_check);
673 : // 6. If SameValue(resolution, promise) is true, then
674 155 : BranchIfSameValue(promise, result, &if_cycle, &if_nocycle);
675 155 : BIND(&if_nocycle);
676 :
677 : // 7. If Type(resolution) is not Object, then
678 310 : GotoIf(TaggedIsSmi(result), &fulfill);
679 310 : GotoIfNot(IsJSReceiver(result), &fulfill);
680 :
681 155 : Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred);
682 310 : Node* const native_context = LoadNativeContext(context);
683 : Node* const promise_fun =
684 310 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
685 : BranchIfFastPath(native_context, promise_fun, result, &if_nativepromise,
686 155 : &if_notnativepromise);
687 :
688 : // Resolution is a native promise and if it's already resolved or
689 : // rejected, shortcircuit the resolution procedure by directly
690 : // reusing the value from the promise.
691 155 : BIND(&if_nativepromise);
692 : {
693 155 : Node* const thenable_status = PromiseStatus(result);
694 : Node* const thenable_value =
695 : LoadObjectField(result, JSPromise::kResultOffset);
696 :
697 : Label if_isnotpending(this);
698 : GotoIfNot(IsPromiseStatus(thenable_status, v8::Promise::kPending),
699 310 : &if_isnotpending);
700 :
701 : // TODO(gsathya): Use a marker here instead of the actual then
702 : // callback, and check for the marker in PromiseResolveThenableJob
703 : // and perform PromiseThen.
704 : Node* const then =
705 310 : LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
706 155 : var_then.Bind(then);
707 155 : Goto(&do_enqueue);
708 :
709 155 : BIND(&if_isnotpending);
710 : {
711 155 : Label if_fulfilled(this), if_rejected(this);
712 : Branch(IsPromiseStatus(thenable_status, v8::Promise::kFulfilled),
713 310 : &if_fulfilled, &if_rejected);
714 :
715 155 : BIND(&if_fulfilled);
716 : {
717 : PromiseFulfill(context, promise, thenable_value,
718 155 : v8::Promise::kFulfilled);
719 155 : PromiseSetHasHandler(promise);
720 155 : Goto(&out);
721 : }
722 :
723 155 : BIND(&if_rejected);
724 : {
725 : Label reject(this);
726 155 : Node* const has_handler = PromiseHasHandler(result);
727 :
728 : // Promise has already been rejected, but had no handler.
729 : // Revoke previously triggered reject event.
730 155 : GotoIf(has_handler, &reject);
731 : CallRuntime(Runtime::kPromiseRevokeReject, context, result);
732 155 : Goto(&reject);
733 :
734 155 : BIND(&reject);
735 : // Don't cause a debug event as this case is forwarding a rejection.
736 155 : InternalPromiseReject(context, promise, thenable_value, false);
737 155 : PromiseSetHasHandler(result);
738 155 : Goto(&out);
739 155 : }
740 155 : }
741 : }
742 :
743 155 : BIND(&if_notnativepromise);
744 : {
745 : // 8. Let then be Get(resolution, "then").
746 : Node* const then =
747 155 : GetProperty(context, result, isolate->factory()->then_string());
748 :
749 : // 9. If then is an abrupt completion, then
750 155 : GotoIfException(then, &if_rejectpromise, &var_reason);
751 :
752 : // 11. If IsCallable(thenAction) is false, then
753 310 : GotoIf(TaggedIsSmi(then), &fulfill);
754 310 : Node* const then_map = LoadMap(then);
755 310 : GotoIfNot(IsCallableMap(then_map), &fulfill);
756 155 : var_then.Bind(then);
757 155 : Goto(&do_enqueue);
758 : }
759 :
760 155 : BIND(&do_enqueue);
761 : {
762 : // TODO(gsathya): Add fast path for native promises with unmodified
763 : // PromiseThen (which don't need these resolving functions, but
764 : // instead can just call resolve/reject directly).
765 155 : Node* resolve = nullptr;
766 155 : Node* reject = nullptr;
767 310 : std::tie(resolve, reject) = CreatePromiseResolvingFunctions(
768 310 : promise, FalseConstant(), native_context);
769 :
770 : Node* const info = AllocatePromiseResolveThenableJobInfo(
771 155 : result, var_then.value(), resolve, reject, context);
772 :
773 : Label enqueue(this);
774 310 : GotoIfNot(IsDebugActive(), &enqueue);
775 :
776 310 : GotoIf(TaggedIsSmi(result), &enqueue);
777 310 : GotoIfNot(HasInstanceType(result, JS_PROMISE_TYPE), &enqueue);
778 :
779 : // Mark the dependency of the new promise on the resolution
780 : Node* const key =
781 : HeapConstant(isolate->factory()->promise_handled_by_symbol());
782 : CallRuntime(Runtime::kSetProperty, context, result, key, promise,
783 155 : SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
784 155 : Goto(&enqueue);
785 :
786 : // 12. Perform EnqueueJob("PromiseJobs",
787 : // PromiseResolveThenableJob, « promise, resolution, thenAction»).
788 155 : BIND(&enqueue);
789 : // TODO(gsathya): Move this to TF
790 : CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, info);
791 155 : Goto(&out);
792 : }
793 :
794 : // 7.b Return FulfillPromise(promise, resolution).
795 155 : BIND(&fulfill);
796 : {
797 155 : PromiseFulfill(context, promise, result, v8::Promise::kFulfilled);
798 155 : Goto(&out);
799 : }
800 :
801 155 : BIND(&if_cycle);
802 : {
803 : // 6.a Let selfResolutionError be a newly created TypeError object.
804 310 : Node* const message_id = SmiConstant(MessageTemplate::kPromiseCyclic);
805 : Node* const error =
806 : CallRuntime(Runtime::kNewTypeError, context, message_id, result);
807 155 : var_reason.Bind(error);
808 :
809 : // 6.b Return RejectPromise(promise, selfResolutionError).
810 155 : Goto(&if_rejectpromise);
811 : }
812 :
813 : // 9.a Return RejectPromise(promise, then.[[Value]]).
814 155 : BIND(&if_rejectpromise);
815 : {
816 : // Don't cause a debug event as this case is forwarding a rejection.
817 155 : InternalPromiseReject(context, promise, var_reason.value(), false);
818 155 : Goto(&out);
819 : }
820 :
821 310 : BIND(&out);
822 155 : }
823 :
824 775 : void PromiseBuiltinsAssembler::PromiseFulfill(
825 : Node* context, Node* promise, Node* result,
826 : v8::Promise::PromiseState status) {
827 1550 : Label do_promisereset(this), debug_async_event_enqueue_recurring(this);
828 :
829 : Node* const deferred_promise =
830 775 : LoadObjectField(promise, JSPromise::kDeferredPromiseOffset);
831 :
832 1550 : GotoIf(IsUndefined(deferred_promise), &debug_async_event_enqueue_recurring);
833 :
834 : Node* const tasks =
835 : status == v8::Promise::kFulfilled
836 : ? LoadObjectField(promise, JSPromise::kFulfillReactionsOffset)
837 775 : : LoadObjectField(promise, JSPromise::kRejectReactionsOffset);
838 :
839 : Node* const deferred_on_resolve =
840 : LoadObjectField(promise, JSPromise::kDeferredOnResolveOffset);
841 : Node* const deferred_on_reject =
842 : LoadObjectField(promise, JSPromise::kDeferredOnRejectOffset);
843 :
844 : Node* const info = AllocatePromiseReactionJobInfo(
845 : result, tasks, deferred_promise, deferred_on_resolve, deferred_on_reject,
846 775 : context);
847 :
848 : CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info);
849 775 : Goto(&debug_async_event_enqueue_recurring);
850 :
851 775 : BIND(&debug_async_event_enqueue_recurring);
852 : {
853 1550 : GotoIfNot(IsDebugActive(), &do_promisereset);
854 : CallRuntime(Runtime::kDebugAsyncEventEnqueueRecurring, context, promise,
855 775 : SmiConstant(status));
856 775 : Goto(&do_promisereset);
857 : }
858 :
859 775 : BIND(&do_promisereset);
860 : {
861 775 : PromiseSetStatus(promise, status);
862 775 : StoreObjectField(promise, JSPromise::kResultOffset, result);
863 : StoreObjectFieldRoot(promise, JSPromise::kDeferredPromiseOffset,
864 775 : Heap::kUndefinedValueRootIndex);
865 : StoreObjectFieldRoot(promise, JSPromise::kDeferredOnResolveOffset,
866 775 : Heap::kUndefinedValueRootIndex);
867 : StoreObjectFieldRoot(promise, JSPromise::kDeferredOnRejectOffset,
868 775 : Heap::kUndefinedValueRootIndex);
869 : StoreObjectFieldRoot(promise, JSPromise::kFulfillReactionsOffset,
870 775 : Heap::kUndefinedValueRootIndex);
871 : StoreObjectFieldRoot(promise, JSPromise::kRejectReactionsOffset,
872 775 : Heap::kUndefinedValueRootIndex);
873 775 : }
874 775 : }
875 :
876 31 : void PromiseBuiltinsAssembler::BranchIfAccessCheckFailed(
877 : Node* context, Node* native_context, Node* promise_constructor,
878 : Node* executor, Label* if_noaccess) {
879 31 : VARIABLE(var_executor, MachineRepresentation::kTagged);
880 31 : var_executor.Bind(executor);
881 31 : Label has_access(this), call_runtime(this, Label::kDeferred);
882 :
883 : // If executor is a bound function, load the bound function until we've
884 : // reached an actual function.
885 31 : Label found_function(this), loop_over_bound_function(this, &var_executor);
886 31 : Goto(&loop_over_bound_function);
887 31 : BIND(&loop_over_bound_function);
888 : {
889 93 : Node* executor_type = LoadInstanceType(var_executor.value());
890 62 : GotoIf(InstanceTypeEqual(executor_type, JS_FUNCTION_TYPE), &found_function);
891 : GotoIfNot(InstanceTypeEqual(executor_type, JS_BOUND_FUNCTION_TYPE),
892 62 : &call_runtime);
893 : var_executor.Bind(LoadObjectField(
894 62 : var_executor.value(), JSBoundFunction::kBoundTargetFunctionOffset));
895 31 : Goto(&loop_over_bound_function);
896 : }
897 :
898 : // Load the context from the function and compare it to the Promise
899 : // constructor's context. If they match, everything is fine, otherwise, bail
900 : // out to the runtime.
901 31 : BIND(&found_function);
902 : {
903 : Node* function_context =
904 31 : LoadObjectField(var_executor.value(), JSFunction::kContextOffset);
905 62 : Node* native_function_context = LoadNativeContext(function_context);
906 31 : Branch(WordEqual(native_context, native_function_context), &has_access,
907 62 : &call_runtime);
908 : }
909 :
910 31 : BIND(&call_runtime);
911 : {
912 : Branch(WordEqual(CallRuntime(Runtime::kAllowDynamicFunction, context,
913 : promise_constructor),
914 31 : BooleanConstant(true)),
915 31 : &has_access, if_noaccess);
916 : }
917 :
918 62 : BIND(&has_access);
919 31 : }
920 :
921 93 : void PromiseBuiltinsAssembler::InternalPromiseReject(Node* context,
922 : Node* promise, Node* value,
923 : Node* debug_event) {
924 93 : Label out(this);
925 186 : GotoIfNot(IsDebugActive(), &out);
926 186 : GotoIfNot(WordEqual(TrueConstant(), debug_event), &out);
927 : CallRuntime(Runtime::kDebugPromiseReject, context, promise, value);
928 93 : Goto(&out);
929 :
930 93 : BIND(&out);
931 93 : InternalPromiseReject(context, promise, value, false);
932 93 : }
933 :
934 : // This duplicates a lot of logic from PromiseRejectEvent in
935 : // runtime-promise.cc
936 434 : void PromiseBuiltinsAssembler::InternalPromiseReject(Node* context,
937 : Node* promise, Node* value,
938 : bool debug_event) {
939 868 : Label fulfill(this), exit(this);
940 :
941 868 : GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &fulfill);
942 434 : if (debug_event) {
943 : CallRuntime(Runtime::kDebugPromiseReject, context, promise, value);
944 : }
945 : CallRuntime(Runtime::kPromiseHookResolve, context, promise);
946 434 : Goto(&fulfill);
947 :
948 434 : BIND(&fulfill);
949 434 : PromiseFulfill(context, promise, value, v8::Promise::kRejected);
950 :
951 868 : GotoIf(PromiseHasHandler(promise), &exit);
952 : CallRuntime(Runtime::kReportPromiseReject, context, promise, value);
953 434 : Goto(&exit);
954 :
955 868 : BIND(&exit);
956 434 : }
957 :
958 62 : void PromiseBuiltinsAssembler::SetForwardingHandlerIfTrue(
959 : Node* context, Node* condition, const NodeGenerator& object) {
960 62 : Label done(this);
961 62 : GotoIfNot(condition, &done);
962 : CallRuntime(Runtime::kSetProperty, context, object(),
963 : HeapConstant(factory()->promise_forwarding_handler_symbol()),
964 : TrueConstant(),
965 124 : SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
966 62 : Goto(&done);
967 62 : BIND(&done);
968 62 : }
969 :
970 62 : void PromiseBuiltinsAssembler::SetPromiseHandledByIfTrue(
971 : Node* context, Node* condition, Node* promise,
972 : const NodeGenerator& handled_by) {
973 62 : Label done(this);
974 62 : GotoIfNot(condition, &done);
975 124 : GotoIf(TaggedIsSmi(promise), &done);
976 124 : GotoIfNot(HasInstanceType(promise, JS_PROMISE_TYPE), &done);
977 : CallRuntime(Runtime::kSetProperty, context, promise,
978 : HeapConstant(factory()->promise_handled_by_symbol()),
979 62 : handled_by(), SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
980 62 : Goto(&done);
981 62 : BIND(&done);
982 62 : }
983 :
984 : // ES#sec-promise-reject-functions
985 : // Promise Reject Functions
986 124 : TF_BUILTIN(PromiseRejectClosure, PromiseBuiltinsAssembler) {
987 : Node* const value = Parameter(Descriptor::kValue);
988 : Node* const context = Parameter(Descriptor::kContext);
989 :
990 : Label out(this);
991 :
992 : // 3. Let alreadyResolved be F.[[AlreadyResolved]].
993 : int has_already_visited_slot = kAlreadyVisitedSlot;
994 :
995 : Node* const has_already_visited =
996 62 : LoadContextElement(context, has_already_visited_slot);
997 :
998 : // 4. If alreadyResolved.[[Value]] is true, return undefined.
999 93 : GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out);
1000 :
1001 : // 5.Set alreadyResolved.[[Value]] to true.
1002 : StoreContextElementNoWriteBarrier(context, has_already_visited_slot,
1003 62 : SmiConstant(1));
1004 :
1005 : // 2. Let promise be F.[[Promise]].
1006 : Node* const promise =
1007 93 : LoadContextElement(context, IntPtrConstant(kPromiseSlot));
1008 : Node* const debug_event =
1009 93 : LoadContextElement(context, IntPtrConstant(kDebugEventSlot));
1010 :
1011 31 : InternalPromiseReject(context, promise, value, debug_event);
1012 62 : Return(UndefinedConstant());
1013 :
1014 31 : BIND(&out);
1015 62 : Return(UndefinedConstant());
1016 31 : }
1017 :
1018 : // ES6 #sec-promise-executor
1019 124 : TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
1020 : Node* const executor = Parameter(Descriptor::kExecutor);
1021 : Node* const new_target = Parameter(Descriptor::kNewTarget);
1022 : Node* const context = Parameter(Descriptor::kContext);
1023 31 : Isolate* isolate = this->isolate();
1024 :
1025 : Label if_targetisundefined(this, Label::kDeferred);
1026 :
1027 62 : GotoIf(IsUndefined(new_target), &if_targetisundefined);
1028 :
1029 31 : Label if_notcallable(this, Label::kDeferred);
1030 :
1031 62 : GotoIf(TaggedIsSmi(executor), &if_notcallable);
1032 :
1033 62 : Node* const executor_map = LoadMap(executor);
1034 62 : GotoIfNot(IsCallableMap(executor_map), &if_notcallable);
1035 :
1036 62 : Node* const native_context = LoadNativeContext(context);
1037 : Node* const promise_fun =
1038 62 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1039 31 : Node* const is_debug_active = IsDebugActive();
1040 31 : Label if_targetisnotmodified(this),
1041 31 : if_targetismodified(this, Label::kDeferred), run_executor(this),
1042 31 : debug_push(this), if_noaccess(this, Label::kDeferred);
1043 :
1044 : BranchIfAccessCheckFailed(context, native_context, promise_fun, executor,
1045 31 : &if_noaccess);
1046 :
1047 31 : Branch(WordEqual(promise_fun, new_target), &if_targetisnotmodified,
1048 62 : &if_targetismodified);
1049 :
1050 62 : VARIABLE(var_result, MachineRepresentation::kTagged);
1051 62 : VARIABLE(var_reject_call, MachineRepresentation::kTagged);
1052 62 : VARIABLE(var_reason, MachineRepresentation::kTagged);
1053 :
1054 31 : BIND(&if_targetisnotmodified);
1055 : {
1056 31 : Node* const instance = AllocateAndInitJSPromise(context);
1057 31 : var_result.Bind(instance);
1058 31 : Goto(&debug_push);
1059 : }
1060 :
1061 31 : BIND(&if_targetismodified);
1062 : {
1063 : ConstructorBuiltinsAssembler constructor_assembler(this->state());
1064 : Node* const instance = constructor_assembler.EmitFastNewObject(
1065 31 : context, promise_fun, new_target);
1066 31 : PromiseInit(instance);
1067 31 : var_result.Bind(instance);
1068 :
1069 62 : GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &debug_push);
1070 : CallRuntime(Runtime::kPromiseHookInit, context, instance,
1071 31 : UndefinedConstant());
1072 31 : Goto(&debug_push);
1073 : }
1074 :
1075 31 : BIND(&debug_push);
1076 : {
1077 31 : GotoIfNot(is_debug_active, &run_executor);
1078 31 : CallRuntime(Runtime::kDebugPushPromise, context, var_result.value());
1079 31 : Goto(&run_executor);
1080 : }
1081 :
1082 31 : BIND(&run_executor);
1083 : {
1084 31 : Label out(this), if_rejectpromise(this), debug_pop(this, Label::kDeferred);
1085 :
1086 : Node *resolve, *reject;
1087 62 : std::tie(resolve, reject) = CreatePromiseResolvingFunctions(
1088 93 : var_result.value(), TrueConstant(), native_context);
1089 31 : Callable call_callable = CodeFactory::Call(isolate);
1090 :
1091 : Node* const maybe_exception = CallJS(call_callable, context, executor,
1092 62 : UndefinedConstant(), resolve, reject);
1093 :
1094 31 : GotoIfException(maybe_exception, &if_rejectpromise, &var_reason);
1095 31 : Branch(is_debug_active, &debug_pop, &out);
1096 :
1097 31 : BIND(&if_rejectpromise);
1098 : {
1099 31 : Callable call_callable = CodeFactory::Call(isolate);
1100 : CallJS(call_callable, context, reject, UndefinedConstant(),
1101 62 : var_reason.value());
1102 31 : Branch(is_debug_active, &debug_pop, &out);
1103 : }
1104 :
1105 31 : BIND(&debug_pop);
1106 : {
1107 : CallRuntime(Runtime::kDebugPopPromise, context);
1108 31 : Goto(&out);
1109 : }
1110 31 : BIND(&out);
1111 93 : Return(var_result.value());
1112 : }
1113 :
1114 : // 1. If NewTarget is undefined, throw a TypeError exception.
1115 31 : BIND(&if_targetisundefined);
1116 31 : ThrowTypeError(context, MessageTemplate::kNotAPromise, new_target);
1117 :
1118 : // 2. If IsCallable(executor) is false, throw a TypeError exception.
1119 31 : BIND(&if_notcallable);
1120 31 : ThrowTypeError(context, MessageTemplate::kResolverNotAFunction, executor);
1121 :
1122 : // Silently fail if the stack looks fishy.
1123 31 : BIND(&if_noaccess);
1124 : {
1125 : Node* const counter_id =
1126 62 : SmiConstant(v8::Isolate::kPromiseConstructorReturnedUndefined);
1127 : CallRuntime(Runtime::kIncrementUseCounter, context, counter_id);
1128 62 : Return(UndefinedConstant());
1129 31 : }
1130 31 : }
1131 :
1132 124 : TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) {
1133 : Node* const parent = Parameter(Descriptor::kParent);
1134 : Node* const context = Parameter(Descriptor::kContext);
1135 62 : Return(AllocateAndInitJSPromise(context, parent));
1136 31 : }
1137 :
1138 : // ES#sec-promise.prototype.then
1139 : // Promise.prototype.catch ( onFulfilled, onRejected )
1140 124 : TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) {
1141 : // 1. Let promise be the this value.
1142 : Node* const promise = Parameter(Descriptor::kReceiver);
1143 : Node* const on_resolve = Parameter(Descriptor::kOnFullfilled);
1144 : Node* const on_reject = Parameter(Descriptor::kOnRejected);
1145 : Node* const context = Parameter(Descriptor::kContext);
1146 :
1147 : Node* const result =
1148 31 : InternalPromiseThen(context, promise, on_resolve, on_reject);
1149 31 : Return(result);
1150 31 : }
1151 :
1152 : // ES#sec-promise-resolve-functions
1153 : // Promise Resolve Functions
1154 124 : TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) {
1155 : Node* const value = Parameter(Descriptor::kValue);
1156 : Node* const context = Parameter(Descriptor::kContext);
1157 :
1158 : Label out(this);
1159 :
1160 : // 3. Let alreadyResolved be F.[[AlreadyResolved]].
1161 : int has_already_visited_slot = kAlreadyVisitedSlot;
1162 :
1163 : Node* const has_already_visited =
1164 62 : LoadContextElement(context, has_already_visited_slot);
1165 :
1166 : // 4. If alreadyResolved.[[Value]] is true, return undefined.
1167 93 : GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out);
1168 :
1169 : // 5.Set alreadyResolved.[[Value]] to true.
1170 : StoreContextElementNoWriteBarrier(context, has_already_visited_slot,
1171 62 : SmiConstant(1));
1172 :
1173 : // 2. Let promise be F.[[Promise]].
1174 : Node* const promise =
1175 93 : LoadContextElement(context, IntPtrConstant(kPromiseSlot));
1176 :
1177 31 : InternalResolvePromise(context, promise, value);
1178 62 : Return(UndefinedConstant());
1179 :
1180 31 : BIND(&out);
1181 62 : Return(UndefinedConstant());
1182 31 : }
1183 :
1184 : // ES #sec-fulfillpromise
1185 124 : TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
1186 : Node* const promise = Parameter(Descriptor::kPromise);
1187 : Node* const result = Parameter(Descriptor::kValue);
1188 : Node* const context = Parameter(Descriptor::kContext);
1189 :
1190 31 : InternalResolvePromise(context, promise, result);
1191 62 : Return(UndefinedConstant());
1192 31 : }
1193 :
1194 124 : TF_BUILTIN(PromiseHandleReject, PromiseBuiltinsAssembler) {
1195 : Node* const promise = Parameter(Descriptor::kPromise);
1196 : Node* const on_reject = Parameter(Descriptor::kOnReject);
1197 : Node* const exception = Parameter(Descriptor::kException);
1198 : Node* const context = Parameter(Descriptor::kContext);
1199 :
1200 31 : Callable call_callable = CodeFactory::Call(isolate());
1201 62 : VARIABLE(var_unused, MachineRepresentation::kTagged);
1202 :
1203 31 : Label if_internalhandler(this), if_customhandler(this, Label::kDeferred);
1204 62 : Branch(IsUndefined(on_reject), &if_internalhandler, &if_customhandler);
1205 :
1206 31 : BIND(&if_internalhandler);
1207 : {
1208 31 : InternalPromiseReject(context, promise, exception, false);
1209 62 : Return(UndefinedConstant());
1210 : }
1211 :
1212 31 : BIND(&if_customhandler);
1213 : {
1214 62 : CallJS(call_callable, context, on_reject, UndefinedConstant(), exception);
1215 62 : Return(UndefinedConstant());
1216 : }
1217 31 : }
1218 :
1219 124 : TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) {
1220 : Node* const value = Parameter(Descriptor::kValue);
1221 : Node* const handler = Parameter(Descriptor::kHandler);
1222 : Node* const deferred_promise = Parameter(Descriptor::kDeferredPromise);
1223 : Node* const deferred_on_resolve = Parameter(Descriptor::kDeferredOnResolve);
1224 : Node* const deferred_on_reject = Parameter(Descriptor::kDeferredOnReject);
1225 : Node* const context = Parameter(Descriptor::kContext);
1226 31 : Isolate* isolate = this->isolate();
1227 :
1228 31 : VARIABLE(var_reason, MachineRepresentation::kTagged);
1229 :
1230 31 : Node* const is_debug_active = IsDebugActive();
1231 31 : Label run_handler(this), if_rejectpromise(this), promisehook_before(this),
1232 31 : promisehook_after(this), debug_pop(this);
1233 :
1234 31 : GotoIfNot(is_debug_active, &promisehook_before);
1235 : CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise);
1236 31 : Goto(&promisehook_before);
1237 :
1238 31 : BIND(&promisehook_before);
1239 : {
1240 62 : GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &run_handler);
1241 : CallRuntime(Runtime::kPromiseHookBefore, context, deferred_promise);
1242 31 : Goto(&run_handler);
1243 : }
1244 :
1245 31 : BIND(&run_handler);
1246 : {
1247 31 : Label if_defaulthandler(this), if_callablehandler(this),
1248 31 : if_internalhandler(this), if_customhandler(this, Label::kDeferred);
1249 62 : VARIABLE(var_result, MachineRepresentation::kTagged);
1250 :
1251 62 : Branch(IsSymbol(handler), &if_defaulthandler, &if_callablehandler);
1252 :
1253 31 : BIND(&if_defaulthandler);
1254 : {
1255 31 : Label if_resolve(this), if_reject(this);
1256 : Node* const default_resolve_handler_symbol = HeapConstant(
1257 : isolate->factory()->promise_default_resolve_handler_symbol());
1258 31 : Branch(WordEqual(default_resolve_handler_symbol, handler), &if_resolve,
1259 62 : &if_reject);
1260 :
1261 31 : BIND(&if_resolve);
1262 : {
1263 31 : var_result.Bind(value);
1264 31 : Branch(IsUndefined(deferred_on_resolve), &if_internalhandler,
1265 62 : &if_customhandler);
1266 : }
1267 :
1268 31 : BIND(&if_reject);
1269 : {
1270 31 : var_reason.Bind(value);
1271 31 : Goto(&if_rejectpromise);
1272 31 : }
1273 : }
1274 :
1275 31 : BIND(&if_callablehandler);
1276 : {
1277 31 : Callable call_callable = CodeFactory::Call(isolate);
1278 : Node* const result =
1279 62 : CallJS(call_callable, context, handler, UndefinedConstant(), value);
1280 31 : var_result.Bind(result);
1281 31 : GotoIfException(result, &if_rejectpromise, &var_reason);
1282 31 : Branch(IsUndefined(deferred_on_resolve), &if_internalhandler,
1283 62 : &if_customhandler);
1284 : }
1285 :
1286 31 : BIND(&if_internalhandler);
1287 31 : InternalResolvePromise(context, deferred_promise, var_result.value());
1288 31 : Goto(&promisehook_after);
1289 :
1290 31 : BIND(&if_customhandler);
1291 : {
1292 31 : Callable call_callable = CodeFactory::Call(isolate);
1293 : Node* const maybe_exception =
1294 : CallJS(call_callable, context, deferred_on_resolve,
1295 62 : UndefinedConstant(), var_result.value());
1296 31 : GotoIfException(maybe_exception, &if_rejectpromise, &var_reason);
1297 31 : Goto(&promisehook_after);
1298 31 : }
1299 : }
1300 :
1301 31 : BIND(&if_rejectpromise);
1302 : {
1303 : CallBuiltin(Builtins::kPromiseHandleReject, context, deferred_promise,
1304 31 : deferred_on_reject, var_reason.value());
1305 31 : Goto(&promisehook_after);
1306 : }
1307 :
1308 31 : BIND(&promisehook_after);
1309 : {
1310 62 : GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &debug_pop);
1311 : CallRuntime(Runtime::kPromiseHookAfter, context, deferred_promise);
1312 31 : Goto(&debug_pop);
1313 : }
1314 :
1315 31 : BIND(&debug_pop);
1316 : {
1317 : Label out(this);
1318 :
1319 31 : GotoIfNot(is_debug_active, &out);
1320 : CallRuntime(Runtime::kDebugPopPromise, context);
1321 31 : Goto(&out);
1322 :
1323 31 : BIND(&out);
1324 62 : Return(UndefinedConstant());
1325 31 : }
1326 31 : }
1327 :
1328 : // ES#sec-promise.prototype.catch
1329 : // Promise.prototype.catch ( onRejected )
1330 155 : TF_BUILTIN(PromiseCatch, PromiseBuiltinsAssembler) {
1331 : // 1. Let promise be the this value.
1332 : Node* const promise = Parameter(Descriptor::kReceiver);
1333 62 : Node* const on_resolve = UndefinedConstant();
1334 : Node* const on_reject = Parameter(Descriptor::kOnRejected);
1335 : Node* const context = Parameter(Descriptor::kContext);
1336 :
1337 31 : Label if_internalthen(this), if_customthen(this, Label::kDeferred);
1338 62 : GotoIf(TaggedIsSmi(promise), &if_customthen);
1339 31 : BranchIfFastPath(context, promise, &if_internalthen, &if_customthen);
1340 :
1341 31 : BIND(&if_internalthen);
1342 : {
1343 : Node* const result =
1344 31 : InternalPromiseThen(context, promise, on_resolve, on_reject);
1345 31 : Return(result);
1346 : }
1347 :
1348 31 : BIND(&if_customthen);
1349 : {
1350 : Node* const then =
1351 62 : GetProperty(context, promise, isolate()->factory()->then_string());
1352 31 : Callable call_callable = CodeFactory::Call(isolate());
1353 : Node* const result =
1354 31 : CallJS(call_callable, context, then, promise, on_resolve, on_reject);
1355 31 : Return(result);
1356 31 : }
1357 31 : }
1358 :
1359 124 : TF_BUILTIN(PromiseResolveWrapper, PromiseBuiltinsAssembler) {
1360 : // 1. Let C be the this value.
1361 : Node* receiver = Parameter(Descriptor::kReceiver);
1362 : Node* value = Parameter(Descriptor::kValue);
1363 : Node* context = Parameter(Descriptor::kContext);
1364 :
1365 : // 2. If Type(C) is not Object, throw a TypeError exception.
1366 : ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1367 31 : "PromiseResolve");
1368 :
1369 : // 3. Return ? PromiseResolve(C, x).
1370 62 : Return(CallBuiltin(Builtins::kPromiseResolve, context, receiver, value));
1371 31 : }
1372 :
1373 124 : TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
1374 : Node* constructor = Parameter(Descriptor::kConstructor);
1375 : Node* value = Parameter(Descriptor::kValue);
1376 : Node* context = Parameter(Descriptor::kContext);
1377 31 : Isolate* isolate = this->isolate();
1378 :
1379 62 : Node* const native_context = LoadNativeContext(context);
1380 : Node* const promise_fun =
1381 62 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1382 :
1383 : Label if_value_is_native_promise(this),
1384 31 : if_value_or_constructor_are_not_native_promise(this),
1385 31 : if_need_to_allocate(this);
1386 :
1387 62 : GotoIf(TaggedIsSmi(value), &if_need_to_allocate);
1388 :
1389 : // This shortcircuits the constructor lookups.
1390 62 : GotoIfNot(HasInstanceType(value, JS_PROMISE_TYPE), &if_need_to_allocate);
1391 :
1392 : // This adds a fast path as non-subclassed native promises don't have
1393 : // an observable constructor lookup.
1394 : BranchIfFastPath(native_context, promise_fun, value,
1395 : &if_value_is_native_promise,
1396 31 : &if_value_or_constructor_are_not_native_promise);
1397 :
1398 31 : BIND(&if_value_is_native_promise);
1399 : {
1400 31 : GotoIfNot(WordEqual(promise_fun, constructor),
1401 62 : &if_value_or_constructor_are_not_native_promise);
1402 31 : Return(value);
1403 : }
1404 :
1405 : // At this point, value or/and constructor are not native promises, but
1406 : // they could be of the same subclass.
1407 31 : BIND(&if_value_or_constructor_are_not_native_promise);
1408 : {
1409 : Label if_return(this);
1410 : Node* const xConstructor =
1411 31 : GetProperty(context, value, isolate->factory()->constructor_string());
1412 : BranchIfSameValue(xConstructor, constructor, &if_return,
1413 31 : &if_need_to_allocate);
1414 :
1415 31 : BIND(&if_return);
1416 31 : Return(value);
1417 : }
1418 :
1419 31 : BIND(&if_need_to_allocate);
1420 : {
1421 31 : Label if_nativepromise(this), if_notnativepromise(this);
1422 31 : Branch(WordEqual(promise_fun, constructor), &if_nativepromise,
1423 62 : &if_notnativepromise);
1424 :
1425 : // This adds a fast path for native promises that don't need to
1426 : // create NewPromiseCapability.
1427 31 : BIND(&if_nativepromise);
1428 : {
1429 31 : Node* const result = AllocateAndInitJSPromise(context);
1430 31 : InternalResolvePromise(context, result, value);
1431 31 : Return(result);
1432 : }
1433 :
1434 31 : BIND(&if_notnativepromise);
1435 : {
1436 31 : Node* const capability = NewPromiseCapability(context, constructor);
1437 :
1438 31 : Callable call_callable = CodeFactory::Call(isolate);
1439 : Node* const resolve =
1440 : LoadObjectField(capability, PromiseCapability::kResolveOffset);
1441 62 : CallJS(call_callable, context, resolve, UndefinedConstant(), value);
1442 :
1443 : Node* const result =
1444 : LoadObjectField(capability, PromiseCapability::kPromiseOffset);
1445 31 : Return(result);
1446 31 : }
1447 31 : }
1448 31 : }
1449 :
1450 : // ES6 #sec-getcapabilitiesexecutor-functions
1451 124 : TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
1452 : Node* const resolve = Parameter(Descriptor::kResolve);
1453 : Node* const reject = Parameter(Descriptor::kReject);
1454 : Node* const context = Parameter(Descriptor::kContext);
1455 :
1456 62 : Node* const capability = LoadContextElement(context, kCapabilitySlot);
1457 :
1458 : Label if_alreadyinvoked(this, Label::kDeferred);
1459 : GotoIf(WordNotEqual(
1460 : LoadObjectField(capability, PromiseCapability::kResolveOffset),
1461 31 : UndefinedConstant()),
1462 31 : &if_alreadyinvoked);
1463 : GotoIf(WordNotEqual(
1464 : LoadObjectField(capability, PromiseCapability::kRejectOffset),
1465 31 : UndefinedConstant()),
1466 31 : &if_alreadyinvoked);
1467 :
1468 31 : StoreObjectField(capability, PromiseCapability::kResolveOffset, resolve);
1469 31 : StoreObjectField(capability, PromiseCapability::kRejectOffset, reject);
1470 :
1471 62 : Return(UndefinedConstant());
1472 :
1473 31 : BIND(&if_alreadyinvoked);
1474 31 : ThrowTypeError(context, MessageTemplate::kPromiseExecutorAlreadyInvoked);
1475 31 : }
1476 :
1477 : // ES6 #sec-newpromisecapability
1478 124 : TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
1479 : Node* constructor = Parameter(Descriptor::kConstructor);
1480 : Node* debug_event = Parameter(Descriptor::kDebugEvent);
1481 : Node* context = Parameter(Descriptor::kContext);
1482 :
1483 : CSA_ASSERT_JS_ARGC_EQ(this, 2);
1484 :
1485 62 : Return(NewPromiseCapability(context, constructor, debug_event));
1486 31 : }
1487 :
1488 124 : TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) {
1489 : // 1. Let C be the this value.
1490 : Node* const receiver = Parameter(Descriptor::kReceiver);
1491 : Node* const reason = Parameter(Descriptor::kReason);
1492 : Node* const context = Parameter(Descriptor::kContext);
1493 :
1494 : // 2. If Type(C) is not Object, throw a TypeError exception.
1495 : ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1496 31 : "PromiseReject");
1497 :
1498 31 : Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
1499 62 : Node* const native_context = LoadNativeContext(context);
1500 : Node* const promise_fun =
1501 62 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1502 31 : Branch(WordEqual(promise_fun, receiver), &if_nativepromise,
1503 62 : &if_custompromise);
1504 :
1505 31 : BIND(&if_nativepromise);
1506 : {
1507 : Node* const promise =
1508 31 : AllocateAndSetJSPromise(context, v8::Promise::kRejected, reason);
1509 : CallRuntime(Runtime::kPromiseRejectEventFromStack, context, promise,
1510 : reason);
1511 31 : Return(promise);
1512 : }
1513 :
1514 31 : BIND(&if_custompromise);
1515 : {
1516 : // 3. Let promiseCapability be ? NewPromiseCapability(C).
1517 31 : Node* const capability = NewPromiseCapability(context, receiver);
1518 :
1519 : // 4. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
1520 : Node* const reject =
1521 : LoadObjectField(capability, PromiseCapability::kRejectOffset);
1522 31 : Callable call_callable = CodeFactory::Call(isolate());
1523 62 : CallJS(call_callable, context, reject, UndefinedConstant(), reason);
1524 :
1525 : // 5. Return promiseCapability.[[Promise]].
1526 : Node* const promise =
1527 : LoadObjectField(capability, PromiseCapability::kPromiseOffset);
1528 31 : Return(promise);
1529 31 : }
1530 31 : }
1531 :
1532 124 : TF_BUILTIN(InternalPromiseReject, PromiseBuiltinsAssembler) {
1533 : Node* const promise = Parameter(Descriptor::kPromise);
1534 : Node* const reason = Parameter(Descriptor::kReason);
1535 : Node* const debug_event = Parameter(Descriptor::kDebugEvent);
1536 : Node* const context = Parameter(Descriptor::kContext);
1537 :
1538 31 : InternalPromiseReject(context, promise, reason, debug_event);
1539 62 : Return(UndefinedConstant());
1540 31 : }
1541 :
1542 31 : std::pair<Node*, Node*> PromiseBuiltinsAssembler::CreatePromiseFinallyFunctions(
1543 : Node* on_finally, Node* constructor, Node* native_context) {
1544 : Node* const promise_context =
1545 31 : CreatePromiseContext(native_context, kPromiseFinallyContextLength);
1546 : StoreContextElementNoWriteBarrier(promise_context, kOnFinallySlot,
1547 31 : on_finally);
1548 : StoreContextElementNoWriteBarrier(promise_context, kConstructorSlot,
1549 31 : constructor);
1550 : Node* const map = LoadContextElement(
1551 62 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1552 : Node* const then_finally_info = LoadContextElement(
1553 62 : native_context, Context::PROMISE_THEN_FINALLY_SHARED_FUN);
1554 : Node* const then_finally = AllocateFunctionWithMapAndContext(
1555 31 : map, then_finally_info, promise_context);
1556 : Node* const catch_finally_info = LoadContextElement(
1557 62 : native_context, Context::PROMISE_CATCH_FINALLY_SHARED_FUN);
1558 : Node* const catch_finally = AllocateFunctionWithMapAndContext(
1559 31 : map, catch_finally_info, promise_context);
1560 31 : return std::make_pair(then_finally, catch_finally);
1561 : }
1562 :
1563 124 : TF_BUILTIN(PromiseValueThunkFinally, PromiseBuiltinsAssembler) {
1564 : Node* const context = Parameter(Descriptor::kContext);
1565 :
1566 62 : Node* const value = LoadContextElement(context, kValueSlot);
1567 31 : Return(value);
1568 31 : }
1569 :
1570 31 : Node* PromiseBuiltinsAssembler::CreateValueThunkFunction(Node* value,
1571 : Node* native_context) {
1572 : Node* const value_thunk_context = CreatePromiseContext(
1573 31 : native_context, kPromiseValueThunkOrReasonContextLength);
1574 31 : StoreContextElementNoWriteBarrier(value_thunk_context, kValueSlot, value);
1575 : Node* const map = LoadContextElement(
1576 62 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1577 : Node* const value_thunk_info = LoadContextElement(
1578 62 : native_context, Context::PROMISE_VALUE_THUNK_FINALLY_SHARED_FUN);
1579 : Node* const value_thunk = AllocateFunctionWithMapAndContext(
1580 31 : map, value_thunk_info, value_thunk_context);
1581 31 : return value_thunk;
1582 : }
1583 :
1584 124 : TF_BUILTIN(PromiseThenFinally, PromiseBuiltinsAssembler) {
1585 : CSA_ASSERT_JS_ARGC_EQ(this, 1);
1586 :
1587 : Node* const value = Parameter(Descriptor::kValue);
1588 : Node* const context = Parameter(Descriptor::kContext);
1589 :
1590 : // 1. Let onFinally be F.[[OnFinally]].
1591 62 : Node* const on_finally = LoadContextElement(context, kOnFinallySlot);
1592 :
1593 : // 2. Assert: IsCallable(onFinally) is true.
1594 : CSA_ASSERT(this, IsCallable(on_finally));
1595 :
1596 : // 3. Let result be ? Call(onFinally).
1597 31 : Callable call_callable = CodeFactory::Call(isolate());
1598 : Node* const result =
1599 62 : CallJS(call_callable, context, on_finally, UndefinedConstant());
1600 :
1601 : // 4. Let C be F.[[Constructor]].
1602 62 : Node* const constructor = LoadContextElement(context, kConstructorSlot);
1603 :
1604 : // 5. Assert: IsConstructor(C) is true.
1605 : CSA_ASSERT(this, IsConstructor(constructor));
1606 :
1607 : // 6. Let promise be ? PromiseResolve(C, result).
1608 : Node* const promise =
1609 31 : CallBuiltin(Builtins::kPromiseResolve, context, constructor, result);
1610 :
1611 : // 7. Let valueThunk be equivalent to a function that returns value.
1612 62 : Node* native_context = LoadNativeContext(context);
1613 31 : Node* const value_thunk = CreateValueThunkFunction(value, native_context);
1614 :
1615 : // 8. Return ? Invoke(promise, "then", « valueThunk »).
1616 : Node* const promise_then =
1617 62 : GetProperty(context, promise, factory()->then_string());
1618 : Node* const result_promise = CallJS(call_callable, context,
1619 31 : promise_then, promise, value_thunk);
1620 31 : Return(result_promise);
1621 31 : }
1622 :
1623 124 : TF_BUILTIN(PromiseThrowerFinally, PromiseBuiltinsAssembler) {
1624 : Node* const context = Parameter(Descriptor::kContext);
1625 :
1626 62 : Node* const reason = LoadContextElement(context, kValueSlot);
1627 : CallRuntime(Runtime::kThrow, context, reason);
1628 31 : Unreachable();
1629 31 : }
1630 :
1631 31 : Node* PromiseBuiltinsAssembler::CreateThrowerFunction(Node* reason,
1632 : Node* native_context) {
1633 : Node* const thrower_context = CreatePromiseContext(
1634 31 : native_context, kPromiseValueThunkOrReasonContextLength);
1635 31 : StoreContextElementNoWriteBarrier(thrower_context, kValueSlot, reason);
1636 : Node* const map = LoadContextElement(
1637 62 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1638 : Node* const thrower_info = LoadContextElement(
1639 62 : native_context, Context::PROMISE_THROWER_FINALLY_SHARED_FUN);
1640 : Node* const thrower =
1641 31 : AllocateFunctionWithMapAndContext(map, thrower_info, thrower_context);
1642 31 : return thrower;
1643 : }
1644 :
1645 124 : TF_BUILTIN(PromiseCatchFinally, PromiseBuiltinsAssembler) {
1646 : CSA_ASSERT_JS_ARGC_EQ(this, 1);
1647 :
1648 : Node* const reason = Parameter(Descriptor::kReason);
1649 : Node* const context = Parameter(Descriptor::kContext);
1650 :
1651 : // 1. Let onFinally be F.[[OnFinally]].
1652 62 : Node* const on_finally = LoadContextElement(context, kOnFinallySlot);
1653 :
1654 : // 2. Assert: IsCallable(onFinally) is true.
1655 : CSA_ASSERT(this, IsCallable(on_finally));
1656 :
1657 : // 3. Let result be ? Call(onFinally).
1658 31 : Callable call_callable = CodeFactory::Call(isolate());
1659 : Node* result =
1660 62 : CallJS(call_callable, context, on_finally, UndefinedConstant());
1661 :
1662 : // 4. Let C be F.[[Constructor]].
1663 62 : Node* const constructor = LoadContextElement(context, kConstructorSlot);
1664 :
1665 : // 5. Assert: IsConstructor(C) is true.
1666 : CSA_ASSERT(this, IsConstructor(constructor));
1667 :
1668 : // 6. Let promise be ? PromiseResolve(C, result).
1669 : Node* const promise =
1670 31 : CallBuiltin(Builtins::kPromiseResolve, context, constructor, result);
1671 :
1672 : // 7. Let thrower be equivalent to a function that throws reason.
1673 62 : Node* native_context = LoadNativeContext(context);
1674 31 : Node* const thrower = CreateThrowerFunction(reason, native_context);
1675 :
1676 : // 8. Return ? Invoke(promise, "then", « thrower »).
1677 : Node* const promise_then =
1678 62 : GetProperty(context, promise, factory()->then_string());
1679 : Node* const result_promise = CallJS(call_callable, context,
1680 31 : promise_then, promise, thrower);
1681 31 : Return(result_promise);
1682 31 : }
1683 :
1684 124 : TF_BUILTIN(PromiseFinally, PromiseBuiltinsAssembler) {
1685 : CSA_ASSERT_JS_ARGC_EQ(this, 1);
1686 :
1687 : // 1. Let promise be the this value.
1688 : Node* const promise = Parameter(Descriptor::kReceiver);
1689 : Node* const on_finally = Parameter(Descriptor::kOnFinally);
1690 : Node* const context = Parameter(Descriptor::kContext);
1691 :
1692 : // 2. If IsPromise(promise) is false, throw a TypeError exception.
1693 : ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
1694 31 : "Promise.prototype.finally");
1695 :
1696 : // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
1697 62 : Node* const native_context = LoadNativeContext(context);
1698 : Node* const promise_fun =
1699 62 : LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1700 31 : Node* const constructor = SpeciesConstructor(context, promise, promise_fun);
1701 :
1702 : // 4. Assert: IsConstructor(C) is true.
1703 : CSA_ASSERT(this, IsConstructor(constructor));
1704 :
1705 31 : VARIABLE(var_then_finally, MachineRepresentation::kTagged);
1706 62 : VARIABLE(var_catch_finally, MachineRepresentation::kTagged);
1707 :
1708 31 : Label if_notcallable(this, Label::kDeferred), perform_finally(this);
1709 :
1710 62 : GotoIf(TaggedIsSmi(on_finally), &if_notcallable);
1711 62 : GotoIfNot(IsCallable(on_finally), &if_notcallable);
1712 :
1713 : // 6. Else,
1714 : // a. Let thenFinally be a new built-in function object as defined
1715 : // in ThenFinally Function.
1716 : // b. Let catchFinally be a new built-in function object as
1717 : // defined in CatchFinally Function.
1718 : // c. Set thenFinally and catchFinally's [[Constructor]] internal
1719 : // slots to C.
1720 : // d. Set thenFinally and catchFinally's [[OnFinally]] internal
1721 : // slots to onFinally.
1722 31 : Node* then_finally = nullptr;
1723 31 : Node* catch_finally = nullptr;
1724 62 : std::tie(then_finally, catch_finally) =
1725 : CreatePromiseFinallyFunctions(on_finally, constructor, native_context);
1726 31 : var_then_finally.Bind(then_finally);
1727 31 : var_catch_finally.Bind(catch_finally);
1728 31 : Goto(&perform_finally);
1729 :
1730 : // 5. If IsCallable(onFinally) is not true,
1731 : // a. Let thenFinally be onFinally.
1732 : // b. Let catchFinally be onFinally.
1733 31 : BIND(&if_notcallable);
1734 : {
1735 31 : var_then_finally.Bind(on_finally);
1736 31 : var_catch_finally.Bind(on_finally);
1737 31 : Goto(&perform_finally);
1738 : }
1739 :
1740 : // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »).
1741 31 : BIND(&perform_finally);
1742 : Node* const promise_then =
1743 62 : GetProperty(context, promise, factory()->then_string());
1744 : Node* const result_promise =
1745 : CallJS(CodeFactory::Call(isolate()), context, promise_then, promise,
1746 62 : var_then_finally.value(), var_catch_finally.value());
1747 62 : Return(result_promise);
1748 31 : }
1749 :
1750 124 : TF_BUILTIN(ResolveNativePromise, PromiseBuiltinsAssembler) {
1751 : Node* const promise = Parameter(Descriptor::kPromise);
1752 : Node* const value = Parameter(Descriptor::kValue);
1753 : Node* const context = Parameter(Descriptor::kContext);
1754 :
1755 : CSA_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE));
1756 31 : InternalResolvePromise(context, promise, value);
1757 62 : Return(UndefinedConstant());
1758 31 : }
1759 :
1760 124 : TF_BUILTIN(RejectNativePromise, PromiseBuiltinsAssembler) {
1761 : Node* const promise = Parameter(Descriptor::kPromise);
1762 : Node* const value = Parameter(Descriptor::kValue);
1763 : Node* const debug_event = Parameter(Descriptor::kDebugEvent);
1764 : Node* const context = Parameter(Descriptor::kContext);
1765 :
1766 : CSA_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE));
1767 : CSA_ASSERT(this, IsBoolean(debug_event));
1768 31 : InternalPromiseReject(context, promise, value, debug_event);
1769 62 : Return(UndefinedConstant());
1770 31 : }
1771 :
1772 124 : TF_BUILTIN(PerformNativePromiseThen, PromiseBuiltinsAssembler) {
1773 : Node* const promise = Parameter(Descriptor::kPromise);
1774 : Node* const resolve_reaction = Parameter(Descriptor::kResolveReaction);
1775 : Node* const reject_reaction = Parameter(Descriptor::kRejectReaction);
1776 : Node* const result_promise = Parameter(Descriptor::kResultPromise);
1777 : Node* const context = Parameter(Descriptor::kContext);
1778 :
1779 : CSA_ASSERT(this, HasInstanceType(result_promise, JS_PROMISE_TYPE));
1780 :
1781 : InternalPerformPromiseThen(context, promise, resolve_reaction,
1782 : reject_reaction, result_promise,
1783 93 : UndefinedConstant(), UndefinedConstant());
1784 31 : Return(result_promise);
1785 31 : }
1786 :
1787 31 : Node* PromiseBuiltinsAssembler::PerformPromiseAll(
1788 : Node* context, Node* constructor, Node* capability, Node* iterator,
1789 : Label* if_exception, Variable* var_exception) {
1790 : IteratorBuiltinsAssembler iter_assembler(state());
1791 62 : Label close_iterator(this);
1792 :
1793 31 : Node* const instrumenting = IsDebugActive();
1794 :
1795 : // For catch prediction, don't treat the .then calls as handling it;
1796 : // instead, recurse outwards.
1797 : SetForwardingHandlerIfTrue(
1798 : context, instrumenting,
1799 31 : LoadObjectField(capability, PromiseCapability::kRejectOffset));
1800 :
1801 62 : Node* const native_context = LoadNativeContext(context);
1802 : Node* const array_map = LoadContextElement(
1803 62 : native_context, Context::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
1804 : Node* const values_array = AllocateJSArray(PACKED_ELEMENTS, array_map,
1805 93 : IntPtrConstant(0), SmiConstant(0));
1806 31 : Node* const remaining_elements = AllocateSmiCell(1);
1807 :
1808 93 : VARIABLE(var_index, MachineRepresentation::kTagged, SmiConstant(0));
1809 :
1810 31 : Label loop(this, &var_index), break_loop(this);
1811 31 : Goto(&loop);
1812 31 : BIND(&loop);
1813 : {
1814 : // Let next be IteratorStep(iteratorRecord.[[Iterator]]).
1815 : // If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
1816 : // ReturnIfAbrupt(next).
1817 : Node* const fast_iterator_result_map =
1818 62 : LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
1819 : Node* const next = iter_assembler.IteratorStep(
1820 : context, iterator, &break_loop, fast_iterator_result_map, if_exception,
1821 31 : var_exception);
1822 :
1823 : // Let nextValue be IteratorValue(next).
1824 : // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to
1825 : // true.
1826 : // ReturnIfAbrupt(nextValue).
1827 : Node* const next_value = iter_assembler.IteratorValue(
1828 31 : context, next, fast_iterator_result_map, if_exception, var_exception);
1829 :
1830 : // Let nextPromise be ? Invoke(constructor, "resolve", « nextValue »).
1831 : Node* const promise_resolve =
1832 62 : GetProperty(context, constructor, factory()->resolve_string());
1833 31 : GotoIfException(promise_resolve, &close_iterator, var_exception);
1834 :
1835 : Node* const next_promise = CallJS(CodeFactory::Call(isolate()), context,
1836 62 : promise_resolve, constructor, next_value);
1837 31 : GotoIfException(next_promise, &close_iterator, var_exception);
1838 :
1839 : // Let resolveElement be a new built-in function object as defined in
1840 : // Promise.all Resolve Element Functions.
1841 : Node* const resolve_context =
1842 31 : CreatePromiseContext(native_context, kPromiseAllResolveElementLength);
1843 : StoreContextElementNoWriteBarrier(
1844 : resolve_context, kPromiseAllResolveElementAlreadyVisitedSlot,
1845 62 : SmiConstant(0));
1846 : StoreContextElementNoWriteBarrier(
1847 62 : resolve_context, kPromiseAllResolveElementIndexSlot, var_index.value());
1848 : StoreContextElementNoWriteBarrier(
1849 : resolve_context, kPromiseAllResolveElementRemainingElementsSlot,
1850 31 : remaining_elements);
1851 : StoreContextElementNoWriteBarrier(
1852 31 : resolve_context, kPromiseAllResolveElementCapabilitySlot, capability);
1853 : StoreContextElementNoWriteBarrier(resolve_context,
1854 : kPromiseAllResolveElementValuesArraySlot,
1855 31 : values_array);
1856 :
1857 : Node* const map = LoadContextElement(
1858 62 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1859 : Node* const resolve_info = LoadContextElement(
1860 62 : native_context, Context::PROMISE_ALL_RESOLVE_ELEMENT_SHARED_FUN);
1861 : Node* const resolve =
1862 31 : AllocateFunctionWithMapAndContext(map, resolve_info, resolve_context);
1863 :
1864 : // Set remainingElementsCount.[[Value]] to
1865 : // remainingElementsCount.[[Value]] + 1.
1866 : {
1867 31 : Label if_outofrange(this, Label::kDeferred), done(this);
1868 31 : IncrementSmiCell(remaining_elements, &if_outofrange);
1869 31 : Goto(&done);
1870 :
1871 31 : BIND(&if_outofrange);
1872 : {
1873 : // If the incremented value is out of Smi range, crash.
1874 31 : Abort(kOffsetOutOfRange);
1875 : }
1876 :
1877 62 : BIND(&done);
1878 : }
1879 :
1880 : // Perform ? Invoke(nextPromise, "then", « resolveElement,
1881 : // resultCapability.[[Reject]] »).
1882 : Node* const then =
1883 62 : GetProperty(context, next_promise, factory()->then_string());
1884 31 : GotoIfException(then, &close_iterator, var_exception);
1885 :
1886 : Node* const then_call = CallJS(
1887 : CodeFactory::Call(isolate()), context, then, next_promise, resolve,
1888 62 : LoadObjectField(capability, PromiseCapability::kRejectOffset));
1889 31 : GotoIfException(then_call, &close_iterator, var_exception);
1890 :
1891 : // For catch prediction, mark that rejections here are semantically
1892 : // handled by the combined Promise.
1893 31 : SetPromiseHandledByIfTrue(context, instrumenting, then_call, [=]() {
1894 : // Load promiseCapability.[[Promise]]
1895 31 : return LoadObjectField(capability, PromiseCapability::kPromiseOffset);
1896 93 : });
1897 :
1898 : // Set index to index + 1
1899 31 : var_index.Bind(NumberInc(var_index.value()));
1900 31 : Goto(&loop);
1901 : }
1902 :
1903 31 : BIND(&close_iterator);
1904 : {
1905 : // Exception must be bound to a JS value.
1906 : CSA_ASSERT(this, IsNotTheHole(var_exception->value()));
1907 : iter_assembler.IteratorCloseOnException(context, iterator, if_exception,
1908 31 : var_exception);
1909 : }
1910 :
1911 31 : BIND(&break_loop);
1912 : {
1913 31 : Label resolve_promise(this), return_promise(this);
1914 : // Set iteratorRecord.[[Done]] to true.
1915 : // Set remainingElementsCount.[[Value]] to
1916 : // remainingElementsCount.[[Value]] - 1.
1917 31 : Node* const remaining = DecrementSmiCell(remaining_elements);
1918 : Branch(SmiEqual(remaining, SmiConstant(0)), &resolve_promise,
1919 93 : &return_promise);
1920 :
1921 : // If remainingElementsCount.[[Value]] is 0, then
1922 : // Let valuesArray be CreateArrayFromList(values).
1923 : // Perform ? Call(resultCapability.[[Resolve]], undefined,
1924 : // « valuesArray »).
1925 31 : BIND(&resolve_promise);
1926 :
1927 : Node* const resolve =
1928 : LoadObjectField(capability, PromiseCapability::kResolveOffset);
1929 : Node* const resolve_call =
1930 : CallJS(CodeFactory::Call(isolate()), context, resolve,
1931 93 : UndefinedConstant(), values_array);
1932 31 : GotoIfException(resolve_call, if_exception, var_exception);
1933 31 : Goto(&return_promise);
1934 :
1935 : // Return resultCapability.[[Promise]].
1936 62 : BIND(&return_promise);
1937 : }
1938 :
1939 : Node* const promise =
1940 : LoadObjectField(capability, PromiseCapability::kPromiseOffset);
1941 31 : return promise;
1942 : }
1943 :
1944 31 : Node* PromiseBuiltinsAssembler::IncrementSmiCell(Node* cell,
1945 : Label* if_overflow) {
1946 : CSA_SLOW_ASSERT(this, HasInstanceType(cell, CELL_TYPE));
1947 31 : Node* value = LoadCellValue(cell);
1948 : CSA_SLOW_ASSERT(this, TaggedIsSmi(value));
1949 :
1950 31 : if (if_overflow != nullptr) {
1951 93 : GotoIf(SmiEqual(value, SmiConstant(Smi::kMaxValue)), if_overflow);
1952 : }
1953 :
1954 93 : Node* result = SmiAdd(value, SmiConstant(1));
1955 31 : StoreCellValue(cell, result, SKIP_WRITE_BARRIER);
1956 31 : return result;
1957 : }
1958 :
1959 62 : Node* PromiseBuiltinsAssembler::DecrementSmiCell(Node* cell) {
1960 : CSA_SLOW_ASSERT(this, HasInstanceType(cell, CELL_TYPE));
1961 62 : Node* value = LoadCellValue(cell);
1962 : CSA_SLOW_ASSERT(this, TaggedIsSmi(value));
1963 :
1964 186 : Node* result = SmiSub(value, SmiConstant(1));
1965 62 : StoreCellValue(cell, result, SKIP_WRITE_BARRIER);
1966 62 : return result;
1967 : }
1968 :
1969 : // ES#sec-promise.all
1970 : // Promise.all ( iterable )
1971 186 : TF_BUILTIN(PromiseAll, PromiseBuiltinsAssembler) {
1972 : IteratorBuiltinsAssembler iter_assembler(state());
1973 :
1974 : // Let C be the this value.
1975 : // If Type(C) is not Object, throw a TypeError exception.
1976 : Node* const receiver = Parameter(Descriptor::kReceiver);
1977 : Node* const context = Parameter(Descriptor::kContext);
1978 : ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1979 31 : "Promise.all");
1980 :
1981 : // Let promiseCapability be ? NewPromiseCapability(C).
1982 : // Don't fire debugEvent so that forwarding the rejection through all does not
1983 : // trigger redundant ExceptionEvents
1984 62 : Node* const debug_event = FalseConstant();
1985 31 : Node* const capability = NewPromiseCapability(context, receiver, debug_event);
1986 :
1987 93 : VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
1988 31 : Label reject_promise(this, &var_exception, Label::kDeferred);
1989 :
1990 : // Let iterator be GetIterator(iterable).
1991 : // IfAbruptRejectPromise(iterator, promiseCapability).
1992 : Node* const iterable = Parameter(Descriptor::kIterable);
1993 : Node* const iterator = iter_assembler.GetIterator(
1994 31 : context, iterable, &reject_promise, &var_exception);
1995 :
1996 : // Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability).
1997 : // If result is an abrupt completion, then
1998 : // If iteratorRecord.[[Done]] is false, let result be
1999 : // IteratorClose(iterator, result).
2000 : // IfAbruptRejectPromise(result, promiseCapability).
2001 : Node* const result = PerformPromiseAll(
2002 31 : context, receiver, capability, iterator, &reject_promise, &var_exception);
2003 :
2004 31 : Return(result);
2005 :
2006 31 : BIND(&reject_promise);
2007 : {
2008 : // Exception must be bound to a JS value.
2009 : CSA_SLOW_ASSERT(this, IsNotTheHole(var_exception.value()));
2010 : Node* const reject =
2011 : LoadObjectField(capability, PromiseCapability::kRejectOffset);
2012 31 : Callable callable = CodeFactory::Call(isolate());
2013 : CallJS(callable, context, reject, UndefinedConstant(),
2014 62 : var_exception.value());
2015 :
2016 : Node* const promise =
2017 : LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2018 31 : Return(promise);
2019 : }
2020 31 : }
2021 :
2022 124 : TF_BUILTIN(PromiseAllResolveElementClosure, PromiseBuiltinsAssembler) {
2023 : Node* const value = Parameter(Descriptor::kValue);
2024 : Node* const context = Parameter(Descriptor::kContext);
2025 :
2026 : CSA_ASSERT(this, SmiEqual(LoadFixedArrayBaseLength(context),
2027 : SmiConstant(kPromiseAllResolveElementLength)));
2028 :
2029 31 : Label already_called(this), resolve_promise(this);
2030 : GotoIf(SmiEqual(LoadContextElement(
2031 62 : context, kPromiseAllResolveElementAlreadyVisitedSlot),
2032 : SmiConstant(1)),
2033 155 : &already_called);
2034 : StoreContextElementNoWriteBarrier(
2035 62 : context, kPromiseAllResolveElementAlreadyVisitedSlot, SmiConstant(1));
2036 :
2037 : Node* const index =
2038 62 : LoadContextElement(context, kPromiseAllResolveElementIndexSlot);
2039 : Node* const values_array =
2040 62 : LoadContextElement(context, kPromiseAllResolveElementValuesArraySlot);
2041 :
2042 : // Set element in FixedArray
2043 31 : Label runtime_set_element(this), did_set_element(this);
2044 62 : GotoIfNot(TaggedIsPositiveSmi(index), &runtime_set_element);
2045 : {
2046 62 : VARIABLE(var_elements, MachineRepresentation::kTagged,
2047 : LoadElements(values_array));
2048 : PossiblyGrowElementsCapacity(SMI_PARAMETERS, PACKED_ELEMENTS, values_array,
2049 : index, &var_elements, SmiConstant(1),
2050 62 : &runtime_set_element);
2051 : StoreFixedArrayElement(var_elements.value(), index, value,
2052 31 : UPDATE_WRITE_BARRIER, 0, SMI_PARAMETERS);
2053 :
2054 : // Update array length
2055 31 : Label did_set_length(this);
2056 62 : Node* const length = LoadJSArrayLength(values_array);
2057 62 : GotoIfNot(TaggedIsPositiveSmi(length), &did_set_length);
2058 93 : Node* const new_length = SmiAdd(index, SmiConstant(1));
2059 62 : GotoIfNot(SmiLessThan(length, new_length), &did_set_length);
2060 : StoreObjectFieldNoWriteBarrier(values_array, JSArray::kLengthOffset,
2061 31 : new_length);
2062 : // Assert that valuesArray.[[Length]] is less than or equal to the
2063 : // elements backing-store length.e
2064 : CSA_SLOW_ASSERT(
2065 : this, SmiAboveOrEqual(LoadFixedArrayBaseLength(var_elements.value()),
2066 : new_length));
2067 31 : Goto(&did_set_length);
2068 62 : BIND(&did_set_length);
2069 : }
2070 31 : Goto(&did_set_element);
2071 31 : BIND(&runtime_set_element);
2072 : // New-space filled up or index too large, set element via runtime
2073 : CallRuntime(Runtime::kCreateDataProperty, context, values_array, index,
2074 : value);
2075 31 : Goto(&did_set_element);
2076 31 : BIND(&did_set_element);
2077 :
2078 : Node* const remaining_elements = LoadContextElement(
2079 62 : context, kPromiseAllResolveElementRemainingElementsSlot);
2080 31 : Node* const result = DecrementSmiCell(remaining_elements);
2081 93 : GotoIf(SmiEqual(result, SmiConstant(0)), &resolve_promise);
2082 62 : Return(UndefinedConstant());
2083 :
2084 31 : BIND(&resolve_promise);
2085 : Node* const capability =
2086 62 : LoadContextElement(context, kPromiseAllResolveElementCapabilitySlot);
2087 : Node* const resolve =
2088 : LoadObjectField(capability, PromiseCapability::kResolveOffset);
2089 : CallJS(CodeFactory::Call(isolate()), context, resolve, UndefinedConstant(),
2090 93 : values_array);
2091 62 : Return(UndefinedConstant());
2092 :
2093 31 : BIND(&already_called);
2094 93 : Return(UndefinedConstant());
2095 31 : }
2096 :
2097 : // ES#sec-promise.race
2098 : // Promise.race ( iterable )
2099 186 : TF_BUILTIN(PromiseRace, PromiseBuiltinsAssembler) {
2100 : IteratorBuiltinsAssembler iter_assembler(state());
2101 93 : VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
2102 :
2103 : Node* const receiver = Parameter(Descriptor::kReceiver);
2104 : Node* const context = Parameter(Descriptor::kContext);
2105 : ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
2106 31 : "Promise.race");
2107 :
2108 : // Let promiseCapability be ? NewPromiseCapability(C).
2109 : // Don't fire debugEvent so that forwarding the rejection through all does not
2110 : // trigger redundant ExceptionEvents
2111 62 : Node* const debug_event = FalseConstant();
2112 31 : Node* const capability = NewPromiseCapability(context, receiver, debug_event);
2113 :
2114 : Node* const resolve =
2115 : LoadObjectField(capability, PromiseCapability::kResolveOffset);
2116 : Node* const reject =
2117 : LoadObjectField(capability, PromiseCapability::kRejectOffset);
2118 :
2119 31 : Node* const instrumenting = IsDebugActive();
2120 :
2121 31 : Label close_iterator(this, Label::kDeferred);
2122 31 : Label reject_promise(this, Label::kDeferred);
2123 :
2124 : // For catch prediction, don't treat the .then calls as handling it;
2125 : // instead, recurse outwards.
2126 31 : SetForwardingHandlerIfTrue(context, instrumenting, reject);
2127 :
2128 : // Let iterator be GetIterator(iterable).
2129 : // IfAbruptRejectPromise(iterator, promiseCapability).
2130 : Node* const iterable = Parameter(Descriptor::kIterable);
2131 : Node* const iterator = iter_assembler.GetIterator(
2132 31 : context, iterable, &reject_promise, &var_exception);
2133 :
2134 : // Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability).
2135 : {
2136 31 : Label loop(this), break_loop(this);
2137 31 : Goto(&loop);
2138 31 : BIND(&loop);
2139 : {
2140 62 : Node* const native_context = LoadNativeContext(context);
2141 : Node* const fast_iterator_result_map = LoadContextElement(
2142 62 : native_context, Context::ITERATOR_RESULT_MAP_INDEX);
2143 :
2144 : // Let next be IteratorStep(iteratorRecord.[[Iterator]]).
2145 : // If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
2146 : // ReturnIfAbrupt(next).
2147 : Node* const next = iter_assembler.IteratorStep(
2148 : context, iterator, &break_loop, fast_iterator_result_map,
2149 31 : &reject_promise, &var_exception);
2150 :
2151 : // Let nextValue be IteratorValue(next).
2152 : // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to
2153 : // true.
2154 : // ReturnIfAbrupt(nextValue).
2155 : Node* const next_value =
2156 : iter_assembler.IteratorValue(context, next, fast_iterator_result_map,
2157 31 : &reject_promise, &var_exception);
2158 :
2159 : // Let nextPromise be ? Invoke(constructor, "resolve", « nextValue »).
2160 : Node* const promise_resolve =
2161 62 : GetProperty(context, receiver, factory()->resolve_string());
2162 31 : GotoIfException(promise_resolve, &close_iterator, &var_exception);
2163 :
2164 : Node* const next_promise = CallJS(CodeFactory::Call(isolate()), context,
2165 62 : promise_resolve, receiver, next_value);
2166 31 : GotoIfException(next_promise, &close_iterator, &var_exception);
2167 :
2168 : // Perform ? Invoke(nextPromise, "then", « resolveElement,
2169 : // resultCapability.[[Reject]] »).
2170 : Node* const then =
2171 62 : GetProperty(context, next_promise, factory()->then_string());
2172 31 : GotoIfException(then, &close_iterator, &var_exception);
2173 :
2174 : Node* const then_call = CallJS(CodeFactory::Call(isolate()), context,
2175 62 : then, next_promise, resolve, reject);
2176 31 : GotoIfException(then_call, &close_iterator, &var_exception);
2177 :
2178 : // For catch prediction, mark that rejections here are semantically
2179 : // handled by the combined Promise.
2180 31 : SetPromiseHandledByIfTrue(context, instrumenting, then_call, [=]() {
2181 : // Load promiseCapability.[[Promise]]
2182 31 : return LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2183 93 : });
2184 31 : Goto(&loop);
2185 : }
2186 :
2187 31 : BIND(&break_loop);
2188 62 : Return(LoadObjectField(capability, PromiseCapability::kPromiseOffset));
2189 : }
2190 :
2191 31 : BIND(&close_iterator);
2192 : {
2193 : CSA_ASSERT(this, IsNotTheHole(var_exception.value()));
2194 : iter_assembler.IteratorCloseOnException(context, iterator, &reject_promise,
2195 31 : &var_exception);
2196 : }
2197 :
2198 31 : BIND(&reject_promise);
2199 : {
2200 : Node* const reject =
2201 : LoadObjectField(capability, PromiseCapability::kRejectOffset);
2202 31 : Callable callable = CodeFactory::Call(isolate());
2203 : CallJS(callable, context, reject, UndefinedConstant(),
2204 62 : var_exception.value());
2205 :
2206 : Node* const promise =
2207 : LoadObjectField(capability, PromiseCapability::kPromiseOffset);
2208 31 : Return(promise);
2209 : }
2210 31 : }
2211 :
2212 : } // namespace internal
2213 : } // namespace v8
|