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