Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Side by Side Diff: src/builtins/builtins-promise.cc

Issue 2752143004: [refactor] Separate generated builtins and C++ builtins into separate files (Closed)
Patch Set: tentative gcmole fix Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins-promise.h ('k') | src/builtins/builtins-promise-gen.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.h"
6 #include "src/builtins/builtins-constructor.h"
7 #include "src/builtins/builtins-utils.h"
8 #include "src/builtins/builtins.h"
9 #include "src/code-factory.h"
10 #include "src/code-stub-assembler.h"
11 #include "src/objects-inl.h"
12
13 namespace v8 {
14 namespace internal {
15
16 Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) {
17 Node* const native_context = LoadNativeContext(context);
18 Node* const promise_fun =
19 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
20 Node* const initial_map =
21 LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
22 Node* const instance = AllocateJSObjectFromMap(initial_map);
23 return instance;
24 }
25
26 void PromiseBuiltinsAssembler::PromiseInit(Node* promise) {
27 StoreObjectField(promise, JSPromise::kStatusOffset,
28 SmiConstant(v8::Promise::kPending));
29 StoreObjectField(promise, JSPromise::kFlagsOffset, SmiConstant(0));
30 }
31
32 Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context) {
33 return AllocateAndInitJSPromise(context, UndefinedConstant());
34 }
35
36 Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context,
37 Node* parent) {
38 Node* const instance = AllocateJSPromise(context);
39 PromiseInit(instance);
40
41 Label out(this);
42 GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &out);
43 CallRuntime(Runtime::kPromiseHookInit, context, instance, parent);
44 Goto(&out);
45
46 Bind(&out);
47 return instance;
48 }
49
50 Node* PromiseBuiltinsAssembler::AllocateAndSetJSPromise(Node* context,
51 Node* status,
52 Node* result) {
53 CSA_ASSERT(this, TaggedIsSmi(status));
54
55 Node* const instance = AllocateJSPromise(context);
56
57 StoreObjectFieldNoWriteBarrier(instance, JSPromise::kStatusOffset, status);
58 StoreObjectFieldNoWriteBarrier(instance, JSPromise::kResultOffset, result);
59 StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset,
60 SmiConstant(0));
61
62 Label out(this);
63 GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &out);
64 CallRuntime(Runtime::kPromiseHookInit, context, instance,
65 UndefinedConstant());
66 Goto(&out);
67
68 Bind(&out);
69 return instance;
70 }
71
72 std::pair<Node*, Node*>
73 PromiseBuiltinsAssembler::CreatePromiseResolvingFunctions(
74 Node* promise, Node* debug_event, Node* native_context) {
75 Node* const promise_context = CreatePromiseResolvingFunctionsContext(
76 promise, debug_event, native_context);
77 Node* const map = LoadContextElement(
78 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
79 Node* const resolve_info =
80 LoadContextElement(native_context, Context::PROMISE_RESOLVE_SHARED_FUN);
81 Node* const resolve =
82 AllocateFunctionWithMapAndContext(map, resolve_info, promise_context);
83 Node* const reject_info =
84 LoadContextElement(native_context, Context::PROMISE_REJECT_SHARED_FUN);
85 Node* const reject =
86 AllocateFunctionWithMapAndContext(map, reject_info, promise_context);
87 return std::make_pair(resolve, reject);
88 }
89
90 Node* PromiseBuiltinsAssembler::NewPromiseCapability(Node* context,
91 Node* constructor,
92 Node* debug_event) {
93 if (debug_event == nullptr) {
94 debug_event = TrueConstant();
95 }
96
97 Node* native_context = LoadNativeContext(context);
98
99 Node* map = LoadRoot(Heap::kJSPromiseCapabilityMapRootIndex);
100 Node* capability = AllocateJSObjectFromMap(map);
101
102 StoreObjectFieldNoWriteBarrier(
103 capability, JSPromiseCapability::kPromiseOffset, UndefinedConstant());
104 StoreObjectFieldNoWriteBarrier(
105 capability, JSPromiseCapability::kResolveOffset, UndefinedConstant());
106 StoreObjectFieldNoWriteBarrier(capability, JSPromiseCapability::kRejectOffset,
107 UndefinedConstant());
108
109 Variable var_result(this, MachineRepresentation::kTagged);
110 var_result.Bind(capability);
111
112 Label if_builtin_promise(this), if_custom_promise(this, Label::kDeferred),
113 out(this);
114 Branch(WordEqual(constructor,
115 LoadContextElement(native_context,
116 Context::PROMISE_FUNCTION_INDEX)),
117 &if_builtin_promise, &if_custom_promise);
118
119 Bind(&if_builtin_promise);
120 {
121 Node* promise = AllocateJSPromise(context);
122 PromiseInit(promise);
123 StoreObjectFieldNoWriteBarrier(
124 capability, JSPromiseCapability::kPromiseOffset, promise);
125
126 Node* resolve = nullptr;
127 Node* reject = nullptr;
128
129 std::tie(resolve, reject) =
130 CreatePromiseResolvingFunctions(promise, debug_event, native_context);
131 StoreObjectField(capability, JSPromiseCapability::kResolveOffset, resolve);
132 StoreObjectField(capability, JSPromiseCapability::kRejectOffset, reject);
133
134 GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &out);
135 CallRuntime(Runtime::kPromiseHookInit, context, promise,
136 UndefinedConstant());
137 Goto(&out);
138 }
139
140 Bind(&if_custom_promise);
141 {
142 Label if_notcallable(this, Label::kDeferred);
143 Node* executor_context =
144 CreatePromiseGetCapabilitiesExecutorContext(capability, native_context);
145 Node* executor_info = LoadContextElement(
146 native_context, Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN);
147 Node* function_map = LoadContextElement(
148 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
149 Node* executor = AllocateFunctionWithMapAndContext(
150 function_map, executor_info, executor_context);
151
152 Node* promise = ConstructJS(CodeFactory::Construct(isolate()), context,
153 constructor, executor);
154
155 Node* resolve =
156 LoadObjectField(capability, JSPromiseCapability::kResolveOffset);
157 GotoIf(TaggedIsSmi(resolve), &if_notcallable);
158 GotoIfNot(IsCallableMap(LoadMap(resolve)), &if_notcallable);
159
160 Node* reject =
161 LoadObjectField(capability, JSPromiseCapability::kRejectOffset);
162 GotoIf(TaggedIsSmi(reject), &if_notcallable);
163 GotoIfNot(IsCallableMap(LoadMap(reject)), &if_notcallable);
164
165 StoreObjectField(capability, JSPromiseCapability::kPromiseOffset, promise);
166
167 Goto(&out);
168
169 Bind(&if_notcallable);
170 Node* message = SmiConstant(MessageTemplate::kPromiseNonCallable);
171 StoreObjectField(capability, JSPromiseCapability::kPromiseOffset,
172 UndefinedConstant());
173 StoreObjectField(capability, JSPromiseCapability::kResolveOffset,
174 UndefinedConstant());
175 StoreObjectField(capability, JSPromiseCapability::kRejectOffset,
176 UndefinedConstant());
177 CallRuntime(Runtime::kThrowTypeError, context, message);
178 Unreachable();
179 }
180
181 Bind(&out);
182 return var_result.value();
183 }
184
185 Node* PromiseBuiltinsAssembler::CreatePromiseContext(Node* native_context,
186 int slots) {
187 DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
188
189 Node* const context = Allocate(FixedArray::SizeFor(slots));
190 StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex);
191 StoreObjectFieldNoWriteBarrier(context, FixedArray::kLengthOffset,
192 SmiConstant(slots));
193
194 Node* const empty_fn =
195 LoadContextElement(native_context, Context::CLOSURE_INDEX);
196 StoreContextElementNoWriteBarrier(context, Context::CLOSURE_INDEX, empty_fn);
197 StoreContextElementNoWriteBarrier(context, Context::PREVIOUS_INDEX,
198 UndefinedConstant());
199 StoreContextElementNoWriteBarrier(context, Context::EXTENSION_INDEX,
200 TheHoleConstant());
201 StoreContextElementNoWriteBarrier(context, Context::NATIVE_CONTEXT_INDEX,
202 native_context);
203 return context;
204 }
205
206 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
207 Node* promise, Node* debug_event, Node* native_context) {
208 Node* const context =
209 CreatePromiseContext(native_context, kPromiseContextLength);
210 StoreContextElementNoWriteBarrier(context, kAlreadyVisitedSlot,
211 SmiConstant(0));
212 StoreContextElementNoWriteBarrier(context, kPromiseSlot, promise);
213 StoreContextElementNoWriteBarrier(context, kDebugEventSlot, debug_event);
214 return context;
215 }
216
217 Node* PromiseBuiltinsAssembler::CreatePromiseGetCapabilitiesExecutorContext(
218 Node* promise_capability, Node* native_context) {
219 int kContextLength = kCapabilitiesContextLength;
220 Node* context = CreatePromiseContext(native_context, kContextLength);
221 StoreContextElementNoWriteBarrier(context, kCapabilitySlot,
222 promise_capability);
223 return context;
224 }
225
226 Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver(
227 Node* context, Node* value, MessageTemplate::Template msg_template,
228 const char* method_name) {
229 Label out(this), throw_exception(this, Label::kDeferred);
230 Variable var_value_map(this, MachineRepresentation::kTagged);
231
232 GotoIf(TaggedIsSmi(value), &throw_exception);
233
234 // Load the instance type of the {value}.
235 var_value_map.Bind(LoadMap(value));
236 Node* const value_instance_type = LoadMapInstanceType(var_value_map.value());
237
238 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception);
239
240 // The {value} is not a compatible receiver for this method.
241 Bind(&throw_exception);
242 {
243 Node* const method =
244 method_name == nullptr
245 ? UndefinedConstant()
246 : HeapConstant(
247 isolate()->factory()->NewStringFromAsciiChecked(method_name));
248 Node* const message_id = SmiConstant(msg_template);
249 CallRuntime(Runtime::kThrowTypeError, context, message_id, method);
250 Unreachable();
251 }
252
253 Bind(&out);
254 return var_value_map.value();
255 }
256
257 Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) {
258 Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
259 return IsSetWord(SmiUntag(flags), 1 << JSPromise::kHasHandlerBit);
260 }
261
262 void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) {
263 Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
264 Node* const new_flags =
265 SmiOr(flags, SmiConstant(1 << JSPromise::kHasHandlerBit));
266 StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
267 }
268
269 void PromiseBuiltinsAssembler::PromiseSetHandledHint(Node* promise) {
270 Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
271 Node* const new_flags =
272 SmiOr(flags, SmiConstant(1 << JSPromise::kHandledHintBit));
273 StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
274 }
275
276 Node* PromiseBuiltinsAssembler::SpeciesConstructor(Node* context, Node* object,
277 Node* default_constructor) {
278 Isolate* isolate = this->isolate();
279 Variable var_result(this, MachineRepresentation::kTagged);
280 var_result.Bind(default_constructor);
281
282 // 2. Let C be ? Get(O, "constructor").
283 Node* const constructor =
284 GetProperty(context, object, isolate->factory()->constructor_string());
285
286 // 3. If C is undefined, return defaultConstructor.
287 Label out(this);
288 GotoIf(IsUndefined(constructor), &out);
289
290 // 4. If Type(C) is not Object, throw a TypeError exception.
291 ThrowIfNotJSReceiver(context, constructor,
292 MessageTemplate::kConstructorNotReceiver);
293
294 // 5. Let S be ? Get(C, @@species).
295 Node* const species =
296 GetProperty(context, constructor, isolate->factory()->species_symbol());
297
298 // 6. If S is either undefined or null, return defaultConstructor.
299 GotoIf(IsUndefined(species), &out);
300 GotoIf(WordEqual(species, NullConstant()), &out);
301
302 // 7. If IsConstructor(S) is true, return S.
303 Label throw_error(this);
304 Node* species_bitfield = LoadMapBitField(LoadMap(species));
305 GotoIfNot(Word32Equal(Word32And(species_bitfield,
306 Int32Constant((1 << Map::kIsConstructor))),
307 Int32Constant(1 << Map::kIsConstructor)),
308 &throw_error);
309 var_result.Bind(species);
310 Goto(&out);
311
312 // 8. Throw a TypeError exception.
313 Bind(&throw_error);
314 {
315 Node* const message_id =
316 SmiConstant(MessageTemplate::kSpeciesNotConstructor);
317 CallRuntime(Runtime::kThrowTypeError, context, message_id);
318 Unreachable();
319 }
320
321 Bind(&out);
322 return var_result.value();
323 }
324
325 void PromiseBuiltinsAssembler::AppendPromiseCallback(int offset, Node* promise,
326 Node* value) {
327 Node* elements = LoadObjectField(promise, offset);
328 Node* length = LoadFixedArrayBaseLength(elements);
329 CodeStubAssembler::ParameterMode mode = OptimalParameterMode();
330 length = TaggedToParameter(length, mode);
331
332 Node* delta = IntPtrOrSmiConstant(1, mode);
333 Node* new_capacity = IntPtrOrSmiAdd(length, delta, mode);
334
335 const ElementsKind kind = FAST_ELEMENTS;
336 const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER;
337 const CodeStubAssembler::AllocationFlags flags =
338 CodeStubAssembler::kAllowLargeObjectAllocation;
339 int additional_offset = 0;
340
341 Node* new_elements = AllocateFixedArray(kind, new_capacity, mode, flags);
342
343 CopyFixedArrayElements(kind, elements, new_elements, length, barrier_mode,
344 mode);
345 StoreFixedArrayElement(new_elements, length, value, barrier_mode,
346 additional_offset, mode);
347
348 StoreObjectField(promise, offset, new_elements);
349 }
350
351 Node* PromiseBuiltinsAssembler::InternalPromiseThen(Node* context,
352 Node* promise,
353 Node* on_resolve,
354 Node* on_reject) {
355 Isolate* isolate = this->isolate();
356
357 // 2. If IsPromise(promise) is false, throw a TypeError exception.
358 ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
359 "Promise.prototype.then");
360
361 Node* const native_context = LoadNativeContext(context);
362 Node* const promise_fun =
363 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
364
365 // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
366 Node* constructor = SpeciesConstructor(context, promise, promise_fun);
367
368 // 4. Let resultCapability be ? NewPromiseCapability(C).
369 Callable call_callable = CodeFactory::Call(isolate);
370 Label fast_promise_capability(this), promise_capability(this),
371 perform_promise_then(this);
372 Variable var_deferred_promise(this, MachineRepresentation::kTagged),
373 var_deferred_on_resolve(this, MachineRepresentation::kTagged),
374 var_deferred_on_reject(this, MachineRepresentation::kTagged);
375
376 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability,
377 &promise_capability);
378
379 Bind(&fast_promise_capability);
380 {
381 Node* const deferred_promise = AllocateAndInitJSPromise(context, promise);
382 var_deferred_promise.Bind(deferred_promise);
383 var_deferred_on_resolve.Bind(UndefinedConstant());
384 var_deferred_on_reject.Bind(UndefinedConstant());
385 Goto(&perform_promise_then);
386 }
387
388 Bind(&promise_capability);
389 {
390 Node* const capability = NewPromiseCapability(context, constructor);
391 var_deferred_promise.Bind(
392 LoadObjectField(capability, JSPromiseCapability::kPromiseOffset));
393 var_deferred_on_resolve.Bind(
394 LoadObjectField(capability, JSPromiseCapability::kResolveOffset));
395 var_deferred_on_reject.Bind(
396 LoadObjectField(capability, JSPromiseCapability::kRejectOffset));
397 Goto(&perform_promise_then);
398 }
399
400 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
401 // resultCapability).
402 Bind(&perform_promise_then);
403 Node* const result = InternalPerformPromiseThen(
404 context, promise, on_resolve, on_reject, var_deferred_promise.value(),
405 var_deferred_on_resolve.value(), var_deferred_on_reject.value());
406 return result;
407 }
408
409 Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
410 Node* context, Node* promise, Node* on_resolve, Node* on_reject,
411 Node* deferred_promise, Node* deferred_on_resolve,
412 Node* deferred_on_reject) {
413
414 Variable var_on_resolve(this, MachineRepresentation::kTagged),
415 var_on_reject(this, MachineRepresentation::kTagged);
416
417 var_on_resolve.Bind(on_resolve);
418 var_on_reject.Bind(on_reject);
419
420 Label out(this), if_onresolvenotcallable(this), onrejectcheck(this),
421 append_callbacks(this);
422 GotoIf(TaggedIsSmi(on_resolve), &if_onresolvenotcallable);
423
424 Isolate* isolate = this->isolate();
425 Node* const on_resolve_map = LoadMap(on_resolve);
426 Branch(IsCallableMap(on_resolve_map), &onrejectcheck,
427 &if_onresolvenotcallable);
428
429 Bind(&if_onresolvenotcallable);
430 {
431 Node* const default_resolve_handler_symbol = HeapConstant(
432 isolate->factory()->promise_default_resolve_handler_symbol());
433 var_on_resolve.Bind(default_resolve_handler_symbol);
434 Goto(&onrejectcheck);
435 }
436
437 Bind(&onrejectcheck);
438 {
439 Label if_onrejectnotcallable(this);
440 GotoIf(TaggedIsSmi(on_reject), &if_onrejectnotcallable);
441
442 Node* const on_reject_map = LoadMap(on_reject);
443 Branch(IsCallableMap(on_reject_map), &append_callbacks,
444 &if_onrejectnotcallable);
445
446 Bind(&if_onrejectnotcallable);
447 {
448 Node* const default_reject_handler_symbol = HeapConstant(
449 isolate->factory()->promise_default_reject_handler_symbol());
450 var_on_reject.Bind(default_reject_handler_symbol);
451 Goto(&append_callbacks);
452 }
453 }
454
455 Bind(&append_callbacks);
456 {
457 Label fulfilled_check(this);
458 Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset);
459 GotoIfNot(SmiEqual(status, SmiConstant(v8::Promise::kPending)),
460 &fulfilled_check);
461
462 Node* const existing_deferred_promise =
463 LoadObjectField(promise, JSPromise::kDeferredPromiseOffset);
464
465 Label if_noexistingcallbacks(this), if_existingcallbacks(this);
466 Branch(IsUndefined(existing_deferred_promise), &if_noexistingcallbacks,
467 &if_existingcallbacks);
468
469 Bind(&if_noexistingcallbacks);
470 {
471 // Store callbacks directly in the slots.
472 StoreObjectField(promise, JSPromise::kDeferredPromiseOffset,
473 deferred_promise);
474 StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset,
475 deferred_on_resolve);
476 StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset,
477 deferred_on_reject);
478 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset,
479 var_on_resolve.value());
480 StoreObjectField(promise, JSPromise::kRejectReactionsOffset,
481 var_on_reject.value());
482 Goto(&out);
483 }
484
485 Bind(&if_existingcallbacks);
486 {
487 Label if_singlecallback(this), if_multiplecallbacks(this);
488 BranchIfJSObject(existing_deferred_promise, &if_singlecallback,
489 &if_multiplecallbacks);
490
491 Bind(&if_singlecallback);
492 {
493 // Create new FixedArrays to store callbacks, and migrate
494 // existing callbacks.
495 Node* const deferred_promise_arr =
496 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
497 StoreFixedArrayElement(deferred_promise_arr, 0,
498 existing_deferred_promise);
499 StoreFixedArrayElement(deferred_promise_arr, 1, deferred_promise);
500
501 Node* const deferred_on_resolve_arr =
502 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
503 StoreFixedArrayElement(
504 deferred_on_resolve_arr, 0,
505 LoadObjectField(promise, JSPromise::kDeferredOnResolveOffset));
506 StoreFixedArrayElement(deferred_on_resolve_arr, 1, deferred_on_resolve);
507
508 Node* const deferred_on_reject_arr =
509 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
510 StoreFixedArrayElement(
511 deferred_on_reject_arr, 0,
512 LoadObjectField(promise, JSPromise::kDeferredOnRejectOffset));
513 StoreFixedArrayElement(deferred_on_reject_arr, 1, deferred_on_reject);
514
515 Node* const fulfill_reactions =
516 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
517 StoreFixedArrayElement(
518 fulfill_reactions, 0,
519 LoadObjectField(promise, JSPromise::kFulfillReactionsOffset));
520 StoreFixedArrayElement(fulfill_reactions, 1, var_on_resolve.value());
521
522 Node* const reject_reactions =
523 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
524 StoreFixedArrayElement(
525 reject_reactions, 0,
526 LoadObjectField(promise, JSPromise::kRejectReactionsOffset));
527 StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value());
528
529 // Store new FixedArrays in promise.
530 StoreObjectField(promise, JSPromise::kDeferredPromiseOffset,
531 deferred_promise_arr);
532 StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset,
533 deferred_on_resolve_arr);
534 StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset,
535 deferred_on_reject_arr);
536 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset,
537 fulfill_reactions);
538 StoreObjectField(promise, JSPromise::kRejectReactionsOffset,
539 reject_reactions);
540 Goto(&out);
541 }
542
543 Bind(&if_multiplecallbacks);
544 {
545 AppendPromiseCallback(JSPromise::kDeferredPromiseOffset, promise,
546 deferred_promise);
547 AppendPromiseCallback(JSPromise::kDeferredOnResolveOffset, promise,
548 deferred_on_resolve);
549 AppendPromiseCallback(JSPromise::kDeferredOnRejectOffset, promise,
550 deferred_on_reject);
551 AppendPromiseCallback(JSPromise::kFulfillReactionsOffset, promise,
552 var_on_resolve.value());
553 AppendPromiseCallback(JSPromise::kRejectReactionsOffset, promise,
554 var_on_reject.value());
555 Goto(&out);
556 }
557 }
558
559 Bind(&fulfilled_check);
560 {
561 Label reject(this);
562 Node* const result = LoadObjectField(promise, JSPromise::kResultOffset);
563 GotoIfNot(WordEqual(status, SmiConstant(v8::Promise::kFulfilled)),
564 &reject);
565
566 Node* info = AllocatePromiseReactionJobInfo(
567 result, var_on_resolve.value(), deferred_promise, deferred_on_resolve,
568 deferred_on_reject, context);
569 // TODO(gsathya): Move this to TF
570 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info);
571 Goto(&out);
572
573 Bind(&reject);
574 {
575 Node* const has_handler = PromiseHasHandler(promise);
576 Label enqueue(this);
577
578 // TODO(gsathya): Fold these runtime calls and move to TF.
579 GotoIf(has_handler, &enqueue);
580 CallRuntime(Runtime::kPromiseRevokeReject, context, promise);
581 Goto(&enqueue);
582
583 Bind(&enqueue);
584 {
585 Node* info = AllocatePromiseReactionJobInfo(
586 result, var_on_reject.value(), deferred_promise,
587 deferred_on_resolve, deferred_on_reject, context);
588 // TODO(gsathya): Move this to TF
589 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info);
590 Goto(&out);
591 }
592 }
593 }
594 }
595
596 Bind(&out);
597 PromiseSetHasHandler(promise);
598 return deferred_promise;
599 }
600
601 // Promise fast path implementations rely on unmodified JSPromise instances.
602 // We use a fairly coarse granularity for this and simply check whether both
603 // the promise itself is unmodified (i.e. its map has not changed) and its
604 // prototype is unmodified.
605 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp
606 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise,
607 Label* if_isunmodified,
608 Label* if_ismodified) {
609 Node* const native_context = LoadNativeContext(context);
610 Node* const promise_fun =
611 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
612 BranchIfFastPath(native_context, promise_fun, promise, if_isunmodified,
613 if_ismodified);
614 }
615
616 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* native_context,
617 Node* promise_fun,
618 Node* promise,
619 Label* if_isunmodified,
620 Label* if_ismodified) {
621 CSA_ASSERT(this, IsNativeContext(native_context));
622 CSA_ASSERT(this,
623 WordEqual(promise_fun,
624 LoadContextElement(native_context,
625 Context::PROMISE_FUNCTION_INDEX)));
626
627 Node* const map = LoadMap(promise);
628 Node* const initial_map =
629 LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
630 Node* const has_initialmap = WordEqual(map, initial_map);
631
632 GotoIfNot(has_initialmap, if_ismodified);
633
634 Node* const initial_proto_initial_map =
635 LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX);
636 Node* const proto_map = LoadMap(LoadMapPrototype(map));
637 Node* const proto_has_initialmap =
638 WordEqual(proto_map, initial_proto_initial_map);
639
640 Branch(proto_has_initialmap, if_isunmodified, if_ismodified);
641 }
642
643 Node* PromiseBuiltinsAssembler::AllocatePromiseResolveThenableJobInfo(
644 Node* thenable, Node* then, Node* resolve, Node* reject, Node* context) {
645 Node* const info = Allocate(PromiseResolveThenableJobInfo::kSize);
646 StoreMapNoWriteBarrier(info,
647 Heap::kPromiseResolveThenableJobInfoMapRootIndex);
648 StoreObjectFieldNoWriteBarrier(
649 info, PromiseResolveThenableJobInfo::kThenableOffset, thenable);
650 StoreObjectFieldNoWriteBarrier(
651 info, PromiseResolveThenableJobInfo::kThenOffset, then);
652 StoreObjectFieldNoWriteBarrier(
653 info, PromiseResolveThenableJobInfo::kResolveOffset, resolve);
654 StoreObjectFieldNoWriteBarrier(
655 info, PromiseResolveThenableJobInfo::kRejectOffset, reject);
656 StoreObjectFieldNoWriteBarrier(
657 info, PromiseResolveThenableJobInfo::kContextOffset, context);
658 return info;
659 }
660
661 void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
662 Node* promise,
663 Node* result) {
664 Isolate* isolate = this->isolate();
665
666 Variable var_reason(this, MachineRepresentation::kTagged),
667 var_then(this, MachineRepresentation::kTagged);
668
669 Label do_enqueue(this), fulfill(this), if_cycle(this, Label::kDeferred),
670 if_rejectpromise(this, Label::kDeferred), out(this);
671
672 Label cycle_check(this);
673 GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &cycle_check);
674 CallRuntime(Runtime::kPromiseHookResolve, context, promise);
675 Goto(&cycle_check);
676
677 Bind(&cycle_check);
678 // 6. If SameValue(resolution, promise) is true, then
679 GotoIf(SameValue(promise, result), &if_cycle);
680
681 // 7. If Type(resolution) is not Object, then
682 GotoIf(TaggedIsSmi(result), &fulfill);
683 GotoIfNot(IsJSReceiver(result), &fulfill);
684
685 Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred);
686 Node* const native_context = LoadNativeContext(context);
687 Node* const promise_fun =
688 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
689 BranchIfFastPath(native_context, promise_fun, result, &if_nativepromise,
690 &if_notnativepromise);
691
692 // Resolution is a native promise and if it's already resolved or
693 // rejected, shortcircuit the resolution procedure by directly
694 // reusing the value from the promise.
695 Bind(&if_nativepromise);
696 {
697 Node* const thenable_status =
698 LoadObjectField(result, JSPromise::kStatusOffset);
699 Node* const thenable_value =
700 LoadObjectField(result, JSPromise::kResultOffset);
701
702 Label if_isnotpending(this);
703 GotoIfNot(SmiEqual(SmiConstant(v8::Promise::kPending), thenable_status),
704 &if_isnotpending);
705
706 // TODO(gsathya): Use a marker here instead of the actual then
707 // callback, and check for the marker in PromiseResolveThenableJob
708 // and perform PromiseThen.
709 Node* const then =
710 LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
711 var_then.Bind(then);
712 Goto(&do_enqueue);
713
714 Bind(&if_isnotpending);
715 {
716 Label if_fulfilled(this), if_rejected(this);
717 Branch(SmiEqual(SmiConstant(v8::Promise::kFulfilled), thenable_status),
718 &if_fulfilled, &if_rejected);
719
720 Bind(&if_fulfilled);
721 {
722 PromiseFulfill(context, promise, thenable_value,
723 v8::Promise::kFulfilled);
724 PromiseSetHasHandler(promise);
725 Goto(&out);
726 }
727
728 Bind(&if_rejected);
729 {
730 Label reject(this);
731 Node* const has_handler = PromiseHasHandler(result);
732
733 // Promise has already been rejected, but had no handler.
734 // Revoke previously triggered reject event.
735 GotoIf(has_handler, &reject);
736 CallRuntime(Runtime::kPromiseRevokeReject, context, result);
737 Goto(&reject);
738
739 Bind(&reject);
740 // Don't cause a debug event as this case is forwarding a rejection.
741 InternalPromiseReject(context, promise, thenable_value, false);
742 PromiseSetHasHandler(result);
743 Goto(&out);
744 }
745 }
746 }
747
748 Bind(&if_notnativepromise);
749 {
750 // 8. Let then be Get(resolution, "then").
751 Node* const then =
752 GetProperty(context, result, isolate->factory()->then_string());
753
754 // 9. If then is an abrupt completion, then
755 GotoIfException(then, &if_rejectpromise, &var_reason);
756
757 // 11. If IsCallable(thenAction) is false, then
758 GotoIf(TaggedIsSmi(then), &fulfill);
759 Node* const then_map = LoadMap(then);
760 GotoIfNot(IsCallableMap(then_map), &fulfill);
761 var_then.Bind(then);
762 Goto(&do_enqueue);
763 }
764
765 Bind(&do_enqueue);
766 {
767 // TODO(gsathya): Add fast path for native promises with unmodified
768 // PromiseThen (which don't need these resolving functions, but
769 // instead can just call resolve/reject directly).
770 Node* resolve = nullptr;
771 Node* reject = nullptr;
772 std::tie(resolve, reject) = CreatePromiseResolvingFunctions(
773 promise, FalseConstant(), native_context);
774
775 Node* const info = AllocatePromiseResolveThenableJobInfo(
776 result, var_then.value(), resolve, reject, context);
777
778 Label enqueue(this);
779 GotoIfNot(IsDebugActive(), &enqueue);
780
781 GotoIf(TaggedIsSmi(result), &enqueue);
782 GotoIfNot(HasInstanceType(result, JS_PROMISE_TYPE), &enqueue);
783
784 // Mark the dependency of the new promise on the resolution
785 Node* const key =
786 HeapConstant(isolate->factory()->promise_handled_by_symbol());
787 CallRuntime(Runtime::kSetProperty, context, result, key, promise,
788 SmiConstant(STRICT));
789 Goto(&enqueue);
790
791 // 12. Perform EnqueueJob("PromiseJobs",
792 // PromiseResolveThenableJob, « promise, resolution, thenAction»).
793 Bind(&enqueue);
794 // TODO(gsathya): Move this to TF
795 CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, info);
796 Goto(&out);
797 }
798
799 // 7.b Return FulfillPromise(promise, resolution).
800 Bind(&fulfill);
801 {
802 PromiseFulfill(context, promise, result, v8::Promise::kFulfilled);
803 Goto(&out);
804 }
805
806 Bind(&if_cycle);
807 {
808 // 6.a Let selfResolutionError be a newly created TypeError object.
809 Node* const message_id = SmiConstant(MessageTemplate::kPromiseCyclic);
810 Node* const error =
811 CallRuntime(Runtime::kNewTypeError, context, message_id, result);
812 var_reason.Bind(error);
813
814 // 6.b Return RejectPromise(promise, selfResolutionError).
815 Goto(&if_rejectpromise);
816 }
817
818 // 9.a Return RejectPromise(promise, then.[[Value]]).
819 Bind(&if_rejectpromise);
820 {
821 // Don't cause a debug event as this case is forwarding a rejection.
822 InternalPromiseReject(context, promise, var_reason.value(), false);
823 Goto(&out);
824 }
825
826 Bind(&out);
827 }
828
829 void PromiseBuiltinsAssembler::PromiseFulfill(
830 Node* context, Node* promise, Node* result,
831 v8::Promise::PromiseState status) {
832 Label do_promisereset(this), debug_async_event_enqueue_recurring(this);
833
834 Node* const status_smi = SmiConstant(static_cast<int>(status));
835 Node* const deferred_promise =
836 LoadObjectField(promise, JSPromise::kDeferredPromiseOffset);
837
838 GotoIf(IsUndefined(deferred_promise), &debug_async_event_enqueue_recurring);
839
840 Node* const tasks =
841 status == v8::Promise::kFulfilled
842 ? LoadObjectField(promise, JSPromise::kFulfillReactionsOffset)
843 : LoadObjectField(promise, JSPromise::kRejectReactionsOffset);
844
845 Node* const deferred_on_resolve =
846 LoadObjectField(promise, JSPromise::kDeferredOnResolveOffset);
847 Node* const deferred_on_reject =
848 LoadObjectField(promise, JSPromise::kDeferredOnRejectOffset);
849
850 Node* const info = AllocatePromiseReactionJobInfo(
851 result, tasks, deferred_promise, deferred_on_resolve, deferred_on_reject,
852 context);
853
854 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info);
855 Goto(&debug_async_event_enqueue_recurring);
856
857 Bind(&debug_async_event_enqueue_recurring);
858 {
859 GotoIfNot(IsDebugActive(), &do_promisereset);
860 CallRuntime(Runtime::kDebugAsyncEventEnqueueRecurring, context, promise,
861 status_smi);
862 Goto(&do_promisereset);
863 }
864
865 Bind(&do_promisereset);
866 {
867 StoreObjectField(promise, JSPromise::kStatusOffset, status_smi);
868 StoreObjectField(promise, JSPromise::kResultOffset, result);
869 StoreObjectFieldRoot(promise, JSPromise::kDeferredPromiseOffset,
870 Heap::kUndefinedValueRootIndex);
871 StoreObjectFieldRoot(promise, JSPromise::kDeferredOnResolveOffset,
872 Heap::kUndefinedValueRootIndex);
873 StoreObjectFieldRoot(promise, JSPromise::kDeferredOnRejectOffset,
874 Heap::kUndefinedValueRootIndex);
875 StoreObjectFieldRoot(promise, JSPromise::kFulfillReactionsOffset,
876 Heap::kUndefinedValueRootIndex);
877 StoreObjectFieldRoot(promise, JSPromise::kRejectReactionsOffset,
878 Heap::kUndefinedValueRootIndex);
879 }
880 }
881
882 void PromiseBuiltinsAssembler::BranchIfAccessCheckFailed(
883 Node* context, Node* native_context, Node* promise_constructor,
884 Node* executor, Label* if_noaccess) {
885 Variable var_executor(this, MachineRepresentation::kTagged);
886 var_executor.Bind(executor);
887 Label has_access(this), call_runtime(this, Label::kDeferred);
888
889 // If executor is a bound function, load the bound function until we've
890 // reached an actual function.
891 Label found_function(this), loop_over_bound_function(this, &var_executor);
892 Goto(&loop_over_bound_function);
893 Bind(&loop_over_bound_function);
894 {
895 Node* executor_type = LoadInstanceType(var_executor.value());
896 GotoIf(InstanceTypeEqual(executor_type, JS_FUNCTION_TYPE), &found_function);
897 GotoIfNot(InstanceTypeEqual(executor_type, JS_BOUND_FUNCTION_TYPE),
898 &call_runtime);
899 var_executor.Bind(LoadObjectField(
900 var_executor.value(), JSBoundFunction::kBoundTargetFunctionOffset));
901 Goto(&loop_over_bound_function);
902 }
903
904 // Load the context from the function and compare it to the Promise
905 // constructor's context. If they match, everything is fine, otherwise, bail
906 // out to the runtime.
907 Bind(&found_function);
908 {
909 Node* function_context =
910 LoadObjectField(var_executor.value(), JSFunction::kContextOffset);
911 Node* native_function_context = LoadNativeContext(function_context);
912 Branch(WordEqual(native_context, native_function_context), &has_access,
913 &call_runtime);
914 }
915
916 Bind(&call_runtime);
917 {
918 Branch(WordEqual(CallRuntime(Runtime::kAllowDynamicFunction, context,
919 promise_constructor),
920 BooleanConstant(true)),
921 &has_access, if_noaccess);
922 }
923
924 Bind(&has_access);
925 }
926
927 void PromiseBuiltinsAssembler::InternalPromiseReject(Node* context,
928 Node* promise, Node* value,
929 Node* debug_event) {
930 Label out(this);
931 GotoIfNot(IsDebugActive(), &out);
932 GotoIfNot(WordEqual(TrueConstant(), debug_event), &out);
933 CallRuntime(Runtime::kDebugPromiseReject, context, promise, value);
934 Goto(&out);
935
936 Bind(&out);
937 InternalPromiseReject(context, promise, value, false);
938 }
939
940 // This duplicates a lot of logic from PromiseRejectEvent in
941 // runtime-promise.cc
942 void PromiseBuiltinsAssembler::InternalPromiseReject(Node* context,
943 Node* promise, Node* value,
944 bool debug_event) {
945 Label fulfill(this), report_unhandledpromise(this), run_promise_hook(this);
946
947 if (debug_event) {
948 GotoIfNot(IsDebugActive(), &run_promise_hook);
949 CallRuntime(Runtime::kDebugPromiseReject, context, promise, value);
950 Goto(&run_promise_hook);
951 } else {
952 Goto(&run_promise_hook);
953 }
954
955 Bind(&run_promise_hook);
956 {
957 GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &report_unhandledpromise);
958 CallRuntime(Runtime::kPromiseHookResolve, context, promise);
959 Goto(&report_unhandledpromise);
960 }
961
962 Bind(&report_unhandledpromise);
963 {
964 GotoIf(PromiseHasHandler(promise), &fulfill);
965 CallRuntime(Runtime::kReportPromiseReject, context, promise, value);
966 Goto(&fulfill);
967 }
968
969 Bind(&fulfill);
970 PromiseFulfill(context, promise, value, v8::Promise::kRejected);
971 }
972
973 // ES#sec-promise-reject-functions
974 // Promise Reject Functions
975 TF_BUILTIN(PromiseRejectClosure, PromiseBuiltinsAssembler) {
976 Node* const value = Parameter(1);
977 Node* const context = Parameter(4);
978
979 Label out(this);
980
981 // 3. Let alreadyResolved be F.[[AlreadyResolved]].
982 int has_already_visited_slot = kAlreadyVisitedSlot;
983
984 Node* const has_already_visited =
985 LoadContextElement(context, has_already_visited_slot);
986
987 // 4. If alreadyResolved.[[Value]] is true, return undefined.
988 GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out);
989
990 // 5.Set alreadyResolved.[[Value]] to true.
991 StoreContextElementNoWriteBarrier(context, has_already_visited_slot,
992 SmiConstant(1));
993
994 // 2. Let promise be F.[[Promise]].
995 Node* const promise =
996 LoadContextElement(context, IntPtrConstant(kPromiseSlot));
997 Node* const debug_event =
998 LoadContextElement(context, IntPtrConstant(kDebugEventSlot));
999
1000 InternalPromiseReject(context, promise, value, debug_event);
1001 Return(UndefinedConstant());
1002
1003 Bind(&out);
1004 Return(UndefinedConstant());
1005 }
1006
1007 TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
1008 Node* const executor = Parameter(1);
1009 Node* const new_target = Parameter(2);
1010 Node* const context = Parameter(4);
1011 Isolate* isolate = this->isolate();
1012
1013 Label if_targetisundefined(this, Label::kDeferred);
1014
1015 GotoIf(IsUndefined(new_target), &if_targetisundefined);
1016
1017 Label if_notcallable(this, Label::kDeferred);
1018
1019 GotoIf(TaggedIsSmi(executor), &if_notcallable);
1020
1021 Node* const executor_map = LoadMap(executor);
1022 GotoIfNot(IsCallableMap(executor_map), &if_notcallable);
1023
1024 Node* const native_context = LoadNativeContext(context);
1025 Node* const promise_fun =
1026 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1027 Node* const is_debug_active = IsDebugActive();
1028 Label if_targetisnotmodified(this),
1029 if_targetismodified(this, Label::kDeferred), run_executor(this),
1030 debug_push(this), if_noaccess(this, Label::kDeferred);
1031
1032 BranchIfAccessCheckFailed(context, native_context, promise_fun, executor,
1033 &if_noaccess);
1034
1035 Branch(WordEqual(promise_fun, new_target), &if_targetisnotmodified,
1036 &if_targetismodified);
1037
1038 Variable var_result(this, MachineRepresentation::kTagged),
1039 var_reject_call(this, MachineRepresentation::kTagged),
1040 var_reason(this, MachineRepresentation::kTagged);
1041
1042 Bind(&if_targetisnotmodified);
1043 {
1044 Node* const instance = AllocateAndInitJSPromise(context);
1045 var_result.Bind(instance);
1046 Goto(&debug_push);
1047 }
1048
1049 Bind(&if_targetismodified);
1050 {
1051 ConstructorBuiltinsAssembler constructor_assembler(this->state());
1052 Node* const instance = constructor_assembler.EmitFastNewObject(
1053 context, promise_fun, new_target);
1054 PromiseInit(instance);
1055 var_result.Bind(instance);
1056
1057 GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &debug_push);
1058 CallRuntime(Runtime::kPromiseHookInit, context, instance,
1059 UndefinedConstant());
1060 Goto(&debug_push);
1061 }
1062
1063 Bind(&debug_push);
1064 {
1065 GotoIfNot(is_debug_active, &run_executor);
1066 CallRuntime(Runtime::kDebugPushPromise, context, var_result.value());
1067 Goto(&run_executor);
1068 }
1069
1070 Bind(&run_executor);
1071 {
1072 Label out(this), if_rejectpromise(this), debug_pop(this, Label::kDeferred);
1073
1074 Node *resolve, *reject;
1075 std::tie(resolve, reject) = CreatePromiseResolvingFunctions(
1076 var_result.value(), TrueConstant(), native_context);
1077 Callable call_callable = CodeFactory::Call(isolate);
1078
1079 Node* const maybe_exception = CallJS(call_callable, context, executor,
1080 UndefinedConstant(), resolve, reject);
1081
1082 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason);
1083 Branch(is_debug_active, &debug_pop, &out);
1084
1085 Bind(&if_rejectpromise);
1086 {
1087 Callable call_callable = CodeFactory::Call(isolate);
1088 CallJS(call_callable, context, reject, UndefinedConstant(),
1089 var_reason.value());
1090 Branch(is_debug_active, &debug_pop, &out);
1091 }
1092
1093 Bind(&debug_pop);
1094 {
1095 CallRuntime(Runtime::kDebugPopPromise, context);
1096 Goto(&out);
1097 }
1098 Bind(&out);
1099 Return(var_result.value());
1100 }
1101
1102 // 1. If NewTarget is undefined, throw a TypeError exception.
1103 Bind(&if_targetisundefined);
1104 {
1105 Node* const message_id = SmiConstant(MessageTemplate::kNotAPromise);
1106 CallRuntime(Runtime::kThrowTypeError, context, message_id, new_target);
1107 Unreachable();
1108 }
1109
1110 // 2. If IsCallable(executor) is false, throw a TypeError exception.
1111 Bind(&if_notcallable);
1112 {
1113 Node* const message_id =
1114 SmiConstant(MessageTemplate::kResolverNotAFunction);
1115 CallRuntime(Runtime::kThrowTypeError, context, message_id, executor);
1116 Unreachable();
1117 }
1118
1119 // Silently fail if the stack looks fishy.
1120 Bind(&if_noaccess);
1121 {
1122 Node* const counter_id =
1123 SmiConstant(v8::Isolate::kPromiseConstructorReturnedUndefined);
1124 CallRuntime(Runtime::kIncrementUseCounter, context, counter_id);
1125 Return(UndefinedConstant());
1126 }
1127 }
1128
1129 TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) {
1130 Node* const parent = Parameter(1);
1131 Node* const context = Parameter(4);
1132 Return(AllocateAndInitJSPromise(context, parent));
1133 }
1134
1135 TF_BUILTIN(IsPromise, PromiseBuiltinsAssembler) {
1136 Node* const maybe_promise = Parameter(1);
1137 Label if_notpromise(this, Label::kDeferred);
1138
1139 GotoIf(TaggedIsSmi(maybe_promise), &if_notpromise);
1140
1141 Node* const result =
1142 SelectBooleanConstant(HasInstanceType(maybe_promise, JS_PROMISE_TYPE));
1143 Return(result);
1144
1145 Bind(&if_notpromise);
1146 Return(FalseConstant());
1147 }
1148
1149 // ES#sec-promise.prototype.then
1150 // Promise.prototype.catch ( onFulfilled, onRejected )
1151 TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) {
1152 // 1. Let promise be the this value.
1153 Node* const promise = Parameter(0);
1154 Node* const on_resolve = Parameter(1);
1155 Node* const on_reject = Parameter(2);
1156 Node* const context = Parameter(5);
1157
1158 Node* const result =
1159 InternalPromiseThen(context, promise, on_resolve, on_reject);
1160 Return(result);
1161 }
1162
1163 // ES#sec-promise-resolve-functions
1164 // Promise Resolve Functions
1165 TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) {
1166 Node* const value = Parameter(1);
1167 Node* const context = Parameter(4);
1168
1169 Label out(this);
1170
1171 // 3. Let alreadyResolved be F.[[AlreadyResolved]].
1172 int has_already_visited_slot = kAlreadyVisitedSlot;
1173
1174 Node* const has_already_visited =
1175 LoadContextElement(context, has_already_visited_slot);
1176
1177 // 4. If alreadyResolved.[[Value]] is true, return undefined.
1178 GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out);
1179
1180 // 5.Set alreadyResolved.[[Value]] to true.
1181 StoreContextElementNoWriteBarrier(context, has_already_visited_slot,
1182 SmiConstant(1));
1183
1184 // 2. Let promise be F.[[Promise]].
1185 Node* const promise =
1186 LoadContextElement(context, IntPtrConstant(kPromiseSlot));
1187
1188 InternalResolvePromise(context, promise, value);
1189 Return(UndefinedConstant());
1190
1191 Bind(&out);
1192 Return(UndefinedConstant());
1193 }
1194
1195 TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
1196 Node* const promise = Parameter(1);
1197 Node* const result = Parameter(2);
1198 Node* const context = Parameter(5);
1199
1200 InternalResolvePromise(context, promise, result);
1201 Return(UndefinedConstant());
1202 }
1203
1204 TF_BUILTIN(PromiseHandleReject, PromiseBuiltinsAssembler) {
1205 typedef PromiseHandleRejectDescriptor Descriptor;
1206
1207 Node* const promise = Parameter(Descriptor::kPromise);
1208 Node* const on_reject = Parameter(Descriptor::kOnReject);
1209 Node* const exception = Parameter(Descriptor::kException);
1210 Node* const context = Parameter(Descriptor::kContext);
1211
1212 Callable call_callable = CodeFactory::Call(isolate());
1213 Variable var_unused(this, MachineRepresentation::kTagged);
1214
1215 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred);
1216 Branch(IsUndefined(on_reject), &if_internalhandler, &if_customhandler);
1217
1218 Bind(&if_internalhandler);
1219 {
1220 InternalPromiseReject(context, promise, exception, false);
1221 Return(UndefinedConstant());
1222 }
1223
1224 Bind(&if_customhandler);
1225 {
1226 CallJS(call_callable, context, on_reject, UndefinedConstant(), exception);
1227 Return(UndefinedConstant());
1228 }
1229 }
1230
1231 TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) {
1232 Node* const value = Parameter(1);
1233 Node* const handler = Parameter(2);
1234 Node* const deferred_promise = Parameter(3);
1235 Node* const deferred_on_resolve = Parameter(4);
1236 Node* const deferred_on_reject = Parameter(5);
1237 Node* const context = Parameter(8);
1238 Isolate* isolate = this->isolate();
1239
1240 Variable var_reason(this, MachineRepresentation::kTagged);
1241
1242 Node* const is_debug_active = IsDebugActive();
1243 Label run_handler(this), if_rejectpromise(this), promisehook_before(this),
1244 promisehook_after(this), debug_pop(this);
1245
1246 GotoIfNot(is_debug_active, &promisehook_before);
1247 CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise);
1248 Goto(&promisehook_before);
1249
1250 Bind(&promisehook_before);
1251 {
1252 GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &run_handler);
1253 CallRuntime(Runtime::kPromiseHookBefore, context, deferred_promise);
1254 Goto(&run_handler);
1255 }
1256
1257 Bind(&run_handler);
1258 {
1259 Label if_defaulthandler(this), if_callablehandler(this),
1260 if_internalhandler(this), if_customhandler(this, Label::kDeferred);
1261 Variable var_result(this, MachineRepresentation::kTagged);
1262
1263 Branch(IsSymbol(handler), &if_defaulthandler, &if_callablehandler);
1264
1265 Bind(&if_defaulthandler);
1266 {
1267 Label if_resolve(this), if_reject(this);
1268 Node* const default_resolve_handler_symbol = HeapConstant(
1269 isolate->factory()->promise_default_resolve_handler_symbol());
1270 Branch(WordEqual(default_resolve_handler_symbol, handler), &if_resolve,
1271 &if_reject);
1272
1273 Bind(&if_resolve);
1274 {
1275 var_result.Bind(value);
1276 Branch(IsUndefined(deferred_on_resolve), &if_internalhandler,
1277 &if_customhandler);
1278 }
1279
1280 Bind(&if_reject);
1281 {
1282 var_reason.Bind(value);
1283 Goto(&if_rejectpromise);
1284 }
1285 }
1286
1287 Bind(&if_callablehandler);
1288 {
1289 Callable call_callable = CodeFactory::Call(isolate);
1290 Node* const result =
1291 CallJS(call_callable, context, handler, UndefinedConstant(), value);
1292 var_result.Bind(result);
1293 GotoIfException(result, &if_rejectpromise, &var_reason);
1294 Branch(IsUndefined(deferred_on_resolve), &if_internalhandler,
1295 &if_customhandler);
1296 }
1297
1298 Bind(&if_internalhandler);
1299 InternalResolvePromise(context, deferred_promise, var_result.value());
1300 Goto(&promisehook_after);
1301
1302 Bind(&if_customhandler);
1303 {
1304 Callable call_callable = CodeFactory::Call(isolate);
1305 Node* const maybe_exception =
1306 CallJS(call_callable, context, deferred_on_resolve,
1307 UndefinedConstant(), var_result.value());
1308 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason);
1309 Goto(&promisehook_after);
1310 }
1311 }
1312
1313 Bind(&if_rejectpromise);
1314 {
1315 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate);
1316 CallStub(promise_handle_reject, context, deferred_promise,
1317 deferred_on_reject, var_reason.value());
1318 Goto(&promisehook_after);
1319 }
1320
1321 Bind(&promisehook_after);
1322 {
1323 GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &debug_pop);
1324 CallRuntime(Runtime::kPromiseHookAfter, context, deferred_promise);
1325 Goto(&debug_pop);
1326 }
1327
1328 Bind(&debug_pop);
1329 {
1330 Label out(this);
1331
1332 GotoIfNot(is_debug_active, &out);
1333 CallRuntime(Runtime::kDebugPopPromise, context);
1334 Goto(&out);
1335
1336 Bind(&out);
1337 Return(UndefinedConstant());
1338 }
1339 }
1340
1341 // ES#sec-promise.prototype.catch
1342 // Promise.prototype.catch ( onRejected )
1343 TF_BUILTIN(PromiseCatch, PromiseBuiltinsAssembler) {
1344 // 1. Let promise be the this value.
1345 Node* const promise = Parameter(0);
1346 Node* const on_resolve = UndefinedConstant();
1347 Node* const on_reject = Parameter(1);
1348 Node* const context = Parameter(4);
1349
1350 Label if_internalthen(this), if_customthen(this, Label::kDeferred);
1351 GotoIf(TaggedIsSmi(promise), &if_customthen);
1352 BranchIfFastPath(context, promise, &if_internalthen, &if_customthen);
1353
1354 Bind(&if_internalthen);
1355 {
1356 Node* const result =
1357 InternalPromiseThen(context, promise, on_resolve, on_reject);
1358 Return(result);
1359 }
1360
1361 Bind(&if_customthen);
1362 {
1363 Node* const then =
1364 GetProperty(context, promise, isolate()->factory()->then_string());
1365 Callable call_callable = CodeFactory::Call(isolate());
1366 Node* const result =
1367 CallJS(call_callable, context, then, promise, on_resolve, on_reject);
1368 Return(result);
1369 }
1370 }
1371
1372 TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
1373 // 1. Let C be the this value.
1374 Node* receiver = Parameter(0);
1375 Node* value = Parameter(1);
1376 Node* context = Parameter(4);
1377 Isolate* isolate = this->isolate();
1378
1379 // 2. If Type(C) is not Object, throw a TypeError exception.
1380 ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1381 "PromiseResolve");
1382
1383 Node* const native_context = LoadNativeContext(context);
1384 Node* const promise_fun =
1385 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1386
1387 Label if_valueisnativepromise(this), if_valueisnotnativepromise(this),
1388 if_valueisnotpromise(this);
1389
1390 // 3.If IsPromise(x) is true, then
1391 GotoIf(TaggedIsSmi(value), &if_valueisnotpromise);
1392
1393 // This shortcircuits the constructor lookups.
1394 GotoIfNot(HasInstanceType(value, JS_PROMISE_TYPE), &if_valueisnotpromise);
1395
1396 // This adds a fast path as non-subclassed native promises don't have
1397 // an observable constructor lookup.
1398 BranchIfFastPath(native_context, promise_fun, value, &if_valueisnativepromise,
1399 &if_valueisnotnativepromise);
1400
1401 Bind(&if_valueisnativepromise);
1402 {
1403 GotoIfNot(WordEqual(promise_fun, receiver), &if_valueisnotnativepromise);
1404 Return(value);
1405 }
1406
1407 // At this point, value or/and receiver are not native promises, but
1408 // they could be of the same subclass.
1409 Bind(&if_valueisnotnativepromise);
1410 {
1411 // 3.a Let xConstructor be ? Get(x, "constructor").
1412 // The constructor lookup is observable.
1413 Node* const constructor =
1414 GetProperty(context, value, isolate->factory()->constructor_string());
1415
1416 // 3.b If SameValue(xConstructor, C) is true, return x.
1417 GotoIfNot(SameValue(constructor, receiver), &if_valueisnotpromise);
1418
1419 Return(value);
1420 }
1421
1422 Bind(&if_valueisnotpromise);
1423 {
1424 Label if_nativepromise(this), if_notnativepromise(this);
1425 Branch(WordEqual(promise_fun, receiver), &if_nativepromise,
1426 &if_notnativepromise);
1427
1428 // This adds a fast path for native promises that don't need to
1429 // create NewPromiseCapability.
1430 Bind(&if_nativepromise);
1431 {
1432 Node* const result = AllocateAndInitJSPromise(context);
1433 InternalResolvePromise(context, result, value);
1434 Return(result);
1435 }
1436
1437 Bind(&if_notnativepromise);
1438 {
1439 // 4. Let promiseCapability be ? NewPromiseCapability(C).
1440 Node* const capability = NewPromiseCapability(context, receiver);
1441
1442 // 5. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
1443 Callable call_callable = CodeFactory::Call(isolate);
1444 Node* const resolve =
1445 LoadObjectField(capability, JSPromiseCapability::kResolveOffset);
1446 CallJS(call_callable, context, resolve, UndefinedConstant(), value);
1447
1448 // 6. Return promiseCapability.[[Promise]].
1449 Node* const result =
1450 LoadObjectField(capability, JSPromiseCapability::kPromiseOffset);
1451 Return(result);
1452 }
1453 }
1454 }
1455
1456 TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
1457 Node* const resolve = Parameter(1);
1458 Node* const reject = Parameter(2);
1459 Node* const context = Parameter(5);
1460
1461 Node* const capability = LoadContextElement(context, kCapabilitySlot);
1462
1463 Label if_alreadyinvoked(this, Label::kDeferred);
1464 GotoIf(WordNotEqual(
1465 LoadObjectField(capability, JSPromiseCapability::kResolveOffset),
1466 UndefinedConstant()),
1467 &if_alreadyinvoked);
1468 GotoIf(WordNotEqual(
1469 LoadObjectField(capability, JSPromiseCapability::kRejectOffset),
1470 UndefinedConstant()),
1471 &if_alreadyinvoked);
1472
1473 StoreObjectField(capability, JSPromiseCapability::kResolveOffset, resolve);
1474 StoreObjectField(capability, JSPromiseCapability::kRejectOffset, reject);
1475
1476 Return(UndefinedConstant());
1477
1478 Bind(&if_alreadyinvoked);
1479 Node* message = SmiConstant(MessageTemplate::kPromiseExecutorAlreadyInvoked);
1480 CallRuntime(Runtime::kThrowTypeError, context, message);
1481 Unreachable();
1482 }
1483
1484 TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
1485 Node* constructor = Parameter(1);
1486 Node* debug_event = Parameter(2);
1487 Node* context = Parameter(5);
1488
1489 CSA_ASSERT_JS_ARGC_EQ(this, 2);
1490
1491 Return(NewPromiseCapability(context, constructor, debug_event));
1492 }
1493
1494 TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) {
1495 // 1. Let C be the this value.
1496 Node* const receiver = Parameter(0);
1497 Node* const reason = Parameter(1);
1498 Node* const context = Parameter(4);
1499
1500 // 2. If Type(C) is not Object, throw a TypeError exception.
1501 ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
1502 "PromiseReject");
1503
1504 Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
1505 Node* const native_context = LoadNativeContext(context);
1506 Node* const promise_fun =
1507 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
1508 Branch(WordEqual(promise_fun, receiver), &if_nativepromise,
1509 &if_custompromise);
1510
1511 Bind(&if_nativepromise);
1512 {
1513 Node* const promise = AllocateAndSetJSPromise(
1514 context, SmiConstant(v8::Promise::kRejected), reason);
1515 CallRuntime(Runtime::kPromiseRejectEventFromStack, context, promise,
1516 reason);
1517 Return(promise);
1518 }
1519
1520 Bind(&if_custompromise);
1521 {
1522 // 3. Let promiseCapability be ? NewPromiseCapability(C).
1523 Node* const capability = NewPromiseCapability(context, receiver);
1524
1525 // 4. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
1526 Node* const reject =
1527 LoadObjectField(capability, JSPromiseCapability::kRejectOffset);
1528 Callable call_callable = CodeFactory::Call(isolate());
1529 CallJS(call_callable, context, reject, UndefinedConstant(), reason);
1530
1531 // 5. Return promiseCapability.[[Promise]].
1532 Node* const promise =
1533 LoadObjectField(capability, JSPromiseCapability::kPromiseOffset);
1534 Return(promise);
1535 }
1536 }
1537
1538 TF_BUILTIN(InternalPromiseReject, PromiseBuiltinsAssembler) {
1539 Node* const promise = Parameter(1);
1540 Node* const reason = Parameter(2);
1541 Node* const debug_event = Parameter(3);
1542 Node* const context = Parameter(6);
1543
1544 InternalPromiseReject(context, promise, reason, debug_event);
1545 Return(UndefinedConstant());
1546 }
1547
1548 Node* PromiseBuiltinsAssembler::CreatePromiseFinallyContext(
1549 Node* on_finally, Node* native_context) {
1550 Node* const context =
1551 CreatePromiseContext(native_context, kOnFinallyContextLength);
1552 StoreContextElementNoWriteBarrier(context, kOnFinallySlot, on_finally);
1553 return context;
1554 }
1555
1556 std::pair<Node*, Node*> PromiseBuiltinsAssembler::CreatePromiseFinallyFunctions(
1557 Node* on_finally, Node* native_context) {
1558 Node* const promise_context =
1559 CreatePromiseFinallyContext(on_finally, native_context);
1560 Node* const map = LoadContextElement(
1561 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1562 Node* const then_finally_info = LoadContextElement(
1563 native_context, Context::PROMISE_THEN_FINALLY_SHARED_FUN);
1564 Node* const then_finally = AllocateFunctionWithMapAndContext(
1565 map, then_finally_info, promise_context);
1566 Node* const catch_finally_info = LoadContextElement(
1567 native_context, Context::PROMISE_CATCH_FINALLY_SHARED_FUN);
1568 Node* const catch_finally = AllocateFunctionWithMapAndContext(
1569 map, catch_finally_info, promise_context);
1570 return std::make_pair(then_finally, catch_finally);
1571 }
1572
1573 TF_BUILTIN(PromiseValueThunkFinally, PromiseBuiltinsAssembler) {
1574 Node* const context = Parameter(3);
1575
1576 Node* const value = LoadContextElement(context, kOnFinallySlot);
1577 Return(value);
1578 }
1579
1580 Node* PromiseBuiltinsAssembler::CreateValueThunkFunctionContext(
1581 Node* value, Node* native_context) {
1582 Node* const context =
1583 CreatePromiseContext(native_context, kOnFinallyContextLength);
1584 StoreContextElementNoWriteBarrier(context, kOnFinallySlot, value);
1585 return context;
1586 }
1587
1588 Node* PromiseBuiltinsAssembler::CreateValueThunkFunction(Node* value,
1589 Node* native_context) {
1590 Node* const value_thunk_context =
1591 CreateValueThunkFunctionContext(value, native_context);
1592 Node* const map = LoadContextElement(
1593 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1594 Node* const value_thunk_info = LoadContextElement(
1595 native_context, Context::PROMISE_VALUE_THUNK_FINALLY_SHARED_FUN);
1596 Node* const value_thunk = AllocateFunctionWithMapAndContext(
1597 map, value_thunk_info, value_thunk_context);
1598 return value_thunk;
1599 }
1600
1601 TF_BUILTIN(PromiseThenFinally, PromiseBuiltinsAssembler) {
1602 CSA_ASSERT_JS_ARGC_EQ(this, 1);
1603
1604 Node* const value = Parameter(1);
1605 Node* const context = Parameter(4);
1606
1607 Node* const on_finally = LoadContextElement(context, kOnFinallySlot);
1608
1609 // 2.a Let result be ? Call(onFinally, undefined).
1610 Callable call_callable = CodeFactory::Call(isolate());
1611 Node* result =
1612 CallJS(call_callable, context, on_finally, UndefinedConstant());
1613
1614 // 2.b Let promise be ! PromiseResolve( %Promise%, result).
1615 Node* const promise = AllocateAndInitJSPromise(context);
1616 InternalResolvePromise(context, promise, result);
1617
1618 // 2.c Let valueThunk be equivalent to a function that returns value.
1619 Node* native_context = LoadNativeContext(context);
1620 Node* const value_thunk = CreateValueThunkFunction(value, native_context);
1621
1622 // 2.d Let promiseCapability be ! NewPromiseCapability( %Promise%).
1623 Node* const promise_capability = AllocateAndInitJSPromise(context, promise);
1624
1625 // 2.e Return PerformPromiseThen(promise, valueThunk, undefined,
1626 // promiseCapability).
1627 InternalPerformPromiseThen(context, promise, value_thunk, UndefinedConstant(),
1628 promise_capability, UndefinedConstant(),
1629 UndefinedConstant());
1630 Return(promise_capability);
1631 }
1632
1633 TF_BUILTIN(PromiseThrowerFinally, PromiseBuiltinsAssembler) {
1634 Node* const context = Parameter(3);
1635
1636 Node* const reason = LoadContextElement(context, kOnFinallySlot);
1637 CallRuntime(Runtime::kThrow, context, reason);
1638 Unreachable();
1639 }
1640
1641 Node* PromiseBuiltinsAssembler::CreateThrowerFunctionContext(
1642 Node* reason, Node* native_context) {
1643 Node* const context =
1644 CreatePromiseContext(native_context, kOnFinallyContextLength);
1645 StoreContextElementNoWriteBarrier(context, kOnFinallySlot, reason);
1646 return context;
1647 }
1648
1649 Node* PromiseBuiltinsAssembler::CreateThrowerFunction(Node* reason,
1650 Node* native_context) {
1651 Node* const thrower_context =
1652 CreateThrowerFunctionContext(reason, native_context);
1653 Node* const map = LoadContextElement(
1654 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1655 Node* const thrower_info = LoadContextElement(
1656 native_context, Context::PROMISE_THROWER_FINALLY_SHARED_FUN);
1657 Node* const thrower =
1658 AllocateFunctionWithMapAndContext(map, thrower_info, thrower_context);
1659 return thrower;
1660 }
1661
1662 TF_BUILTIN(PromiseCatchFinally, PromiseBuiltinsAssembler) {
1663 CSA_ASSERT_JS_ARGC_EQ(this, 1);
1664
1665 Node* const reason = Parameter(1);
1666 Node* const context = Parameter(4);
1667
1668 Node* const on_finally = LoadContextElement(context, kOnFinallySlot);
1669
1670 // 2.a Let result be ? Call(onFinally, undefined).
1671 Callable call_callable = CodeFactory::Call(isolate());
1672 Node* result =
1673 CallJS(call_callable, context, on_finally, UndefinedConstant());
1674
1675 // 2.b Let promise be ! PromiseResolve( %Promise%, result).
1676 Node* const promise = AllocateAndInitJSPromise(context);
1677 InternalResolvePromise(context, promise, result);
1678
1679 // 2.c Let thrower be equivalent to a function that throws reason.
1680 Node* native_context = LoadNativeContext(context);
1681 Node* const thrower = CreateThrowerFunction(reason, native_context);
1682
1683 // 2.d Let promiseCapability be ! NewPromiseCapability( %Promise%).
1684 Node* const promise_capability = AllocateAndInitJSPromise(context, promise);
1685
1686 // 2.e Return PerformPromiseThen(promise, thrower, undefined,
1687 // promiseCapability).
1688 InternalPerformPromiseThen(context, promise, thrower, UndefinedConstant(),
1689 promise_capability, UndefinedConstant(),
1690 UndefinedConstant());
1691 Return(promise_capability);
1692 }
1693
1694 TF_BUILTIN(PromiseFinally, PromiseBuiltinsAssembler) {
1695 CSA_ASSERT_JS_ARGC_EQ(this, 1);
1696
1697 // 1. Let promise be the this value.
1698 Node* const promise = Parameter(0);
1699 Node* const on_finally = Parameter(1);
1700 Node* const context = Parameter(4);
1701
1702 // 2. If IsPromise(promise) is false, throw a TypeError exception.
1703 ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
1704 "Promise.prototype.finally");
1705
1706 Variable var_then_finally(this, MachineRepresentation::kTagged),
1707 var_catch_finally(this, MachineRepresentation::kTagged);
1708
1709 Label if_notcallable(this, Label::kDeferred), perform_finally(this);
1710
1711 // 3. Let thenFinally be ! CreateThenFinally(onFinally).
1712 // 4. Let catchFinally be ! CreateCatchFinally(onFinally).
1713 GotoIf(TaggedIsSmi(on_finally), &if_notcallable);
1714 Node* const on_finally_map = LoadMap(on_finally);
1715 GotoIfNot(IsCallableMap(on_finally_map), &if_notcallable);
1716
1717 Node* const native_context = LoadNativeContext(context);
1718 Node* then_finally = nullptr;
1719 Node* catch_finally = nullptr;
1720 std::tie(then_finally, catch_finally) =
1721 CreatePromiseFinallyFunctions(on_finally, native_context);
1722 var_then_finally.Bind(then_finally);
1723 var_catch_finally.Bind(catch_finally);
1724 Goto(&perform_finally);
1725
1726 Bind(&if_notcallable);
1727 {
1728 var_then_finally.Bind(on_finally);
1729 var_catch_finally.Bind(on_finally);
1730 Goto(&perform_finally);
1731 }
1732
1733 // 5. Return PerformPromiseThen(promise, valueThunk, undefined,
1734 // promiseCapability).
1735 Bind(&perform_finally);
1736 Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
1737 BranchIfFastPath(context, promise, &if_nativepromise, &if_custompromise);
1738
1739 Bind(&if_nativepromise);
1740 {
1741 Node* deferred_promise = AllocateAndInitJSPromise(context, promise);
1742 InternalPerformPromiseThen(context, promise, var_then_finally.value(),
1743 var_catch_finally.value(), deferred_promise,
1744 UndefinedConstant(), UndefinedConstant());
1745 Return(deferred_promise);
1746 }
1747
1748 Bind(&if_custompromise);
1749 {
1750 Node* const then =
1751 GetProperty(context, promise, isolate()->factory()->then_string());
1752 Callable call_callable = CodeFactory::Call(isolate());
1753 // 5. Return ? Invoke(promise, "then", « thenFinally, catchFinally »).
1754 Node* const result =
1755 CallJS(call_callable, context, then, promise, var_then_finally.value(),
1756 var_catch_finally.value());
1757 Return(result);
1758 }
1759 }
1760
1761 } // namespace internal
1762 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins-promise.h ('k') | src/builtins/builtins-promise-gen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698