OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-promise.h" | 5 #include "src/builtins/builtins-promise.h" |
6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
7 #include "src/builtins/builtins.h" | 7 #include "src/builtins/builtins.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/code-stub-assembler.h" | 9 #include "src/code-stub-assembler.h" |
10 #include "src/promise-utils.h" | 10 #include "src/promise-utils.h" |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 Node* new_elements = AllocateFixedArray(kind, new_capacity, mode, flags); | 173 Node* new_elements = AllocateFixedArray(kind, new_capacity, mode, flags); |
174 | 174 |
175 CopyFixedArrayElements(kind, elements, new_elements, length, barrier_mode, | 175 CopyFixedArrayElements(kind, elements, new_elements, length, barrier_mode, |
176 mode); | 176 mode); |
177 StoreFixedArrayElement(new_elements, length, value, barrier_mode, | 177 StoreFixedArrayElement(new_elements, length, value, barrier_mode, |
178 additional_offset, mode); | 178 additional_offset, mode); |
179 | 179 |
180 StoreObjectField(promise, offset, new_elements); | 180 StoreObjectField(promise, offset, new_elements); |
181 } | 181 } |
182 | 182 |
| 183 Node* PromiseBuiltinsAssembler::InternalPromiseThen(Node* context, |
| 184 Node* promise, |
| 185 Node* on_resolve, |
| 186 Node* on_reject) { |
| 187 Isolate* isolate = this->isolate(); |
| 188 |
| 189 // 2. If IsPromise(promise) is false, throw a TypeError exception. |
| 190 ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE, |
| 191 "Promise.prototype.then"); |
| 192 |
| 193 Node* const native_context = LoadNativeContext(context); |
| 194 Node* const promise_fun = |
| 195 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
| 196 |
| 197 // 3. Let C be ? SpeciesConstructor(promise, %Promise%). |
| 198 Node* constructor = SpeciesConstructor(context, promise, promise_fun); |
| 199 |
| 200 // 4. Let resultCapability be ? NewPromiseCapability(C). |
| 201 Callable call_callable = CodeFactory::Call(isolate); |
| 202 Label fast_promise_capability(this), promise_capability(this), |
| 203 perform_promise_then(this); |
| 204 Variable var_deferred(this, MachineRepresentation::kTagged); |
| 205 |
| 206 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, |
| 207 &promise_capability); |
| 208 |
| 209 // TODO(gsathya): Remove deferred object and move |
| 210 // NewPromiseCapabability functions to TF. |
| 211 Bind(&fast_promise_capability); |
| 212 { |
| 213 // TODO(gsathya): Move this to TF. |
| 214 Node* const promise_internal_capability = LoadContextElement( |
| 215 native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX); |
| 216 Node* const capability = |
| 217 CallJS(call_callable, context, promise_internal_capability, |
| 218 UndefinedConstant(), promise); |
| 219 var_deferred.Bind(capability); |
| 220 Goto(&perform_promise_then); |
| 221 } |
| 222 |
| 223 Bind(&promise_capability); |
| 224 { |
| 225 // TODO(gsathya): Move this to TF. |
| 226 Node* const new_promise_capability = LoadContextElement( |
| 227 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); |
| 228 Node* const capability = |
| 229 CallJS(call_callable, context, new_promise_capability, |
| 230 UndefinedConstant(), constructor); |
| 231 var_deferred.Bind(capability); |
| 232 Goto(&perform_promise_then); |
| 233 } |
| 234 |
| 235 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, |
| 236 // resultCapability). |
| 237 Bind(&perform_promise_then); |
| 238 Node* const result = InternalPerformPromiseThen( |
| 239 context, promise, on_resolve, on_reject, var_deferred.value()); |
| 240 return result; |
| 241 } |
| 242 |
183 Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, | 243 Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, |
184 Node* promise, | 244 Node* promise, |
185 Node* on_resolve, | 245 Node* on_resolve, |
186 Node* on_reject, | 246 Node* on_reject, |
187 Node* deferred) { | 247 Node* deferred) { |
188 Node* const native_context = LoadNativeContext(context); | 248 Node* const native_context = LoadNativeContext(context); |
189 | 249 |
190 Variable var_on_resolve(this, MachineRepresentation::kTagged), | 250 Variable var_on_resolve(this, MachineRepresentation::kTagged), |
191 var_on_reject(this, MachineRepresentation::kTagged); | 251 var_on_reject(this, MachineRepresentation::kTagged); |
192 | 252 |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX); | 431 LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX); |
372 Node* const proto_map = LoadMap(LoadMapPrototype(map)); | 432 Node* const proto_map = LoadMap(LoadMapPrototype(map)); |
373 Node* const proto_has_initialmap = | 433 Node* const proto_has_initialmap = |
374 WordEqual(proto_map, initial_proto_initial_map); | 434 WordEqual(proto_map, initial_proto_initial_map); |
375 | 435 |
376 Branch(proto_has_initialmap, if_isunmodified, if_ismodified); | 436 Branch(proto_has_initialmap, if_isunmodified, if_ismodified); |
377 } | 437 } |
378 | 438 |
379 void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context, | 439 void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context, |
380 Node* promise, | 440 Node* promise, |
381 Node* result, | 441 Node* result) { |
382 Label* out) { | |
383 Isolate* isolate = this->isolate(); | 442 Isolate* isolate = this->isolate(); |
384 | 443 |
385 Variable var_reason(this, MachineRepresentation::kTagged), | 444 Variable var_reason(this, MachineRepresentation::kTagged), |
386 var_then(this, MachineRepresentation::kTagged); | 445 var_then(this, MachineRepresentation::kTagged); |
387 | 446 |
388 Label do_enqueue(this), fulfill(this), if_cycle(this, Label::kDeferred), | 447 Label do_enqueue(this), fulfill(this), if_cycle(this, Label::kDeferred), |
389 if_rejectpromise(this, Label::kDeferred); | 448 if_rejectpromise(this, Label::kDeferred), out(this); |
390 | 449 |
391 Label cycle_check(this); | 450 Label cycle_check(this); |
392 GotoUnless(IsPromiseHookEnabled(), &cycle_check); | 451 GotoUnless(IsPromiseHookEnabled(), &cycle_check); |
393 CallRuntime(Runtime::kPromiseHookResolve, context, promise); | 452 CallRuntime(Runtime::kPromiseHookResolve, context, promise); |
394 Goto(&cycle_check); | 453 Goto(&cycle_check); |
395 | 454 |
396 Bind(&cycle_check); | 455 Bind(&cycle_check); |
397 // 6. If SameValue(resolution, promise) is true, then | 456 // 6. If SameValue(resolution, promise) is true, then |
398 GotoIf(SameValue(promise, result, context), &if_cycle); | 457 GotoIf(SameValue(promise, result, context), &if_cycle); |
399 | 458 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
431 { | 490 { |
432 Label if_fulfilled(this), if_rejected(this); | 491 Label if_fulfilled(this), if_rejected(this); |
433 Branch(SmiEqual(SmiConstant(v8::Promise::kFulfilled), thenable_status), | 492 Branch(SmiEqual(SmiConstant(v8::Promise::kFulfilled), thenable_status), |
434 &if_fulfilled, &if_rejected); | 493 &if_fulfilled, &if_rejected); |
435 | 494 |
436 Bind(&if_fulfilled); | 495 Bind(&if_fulfilled); |
437 { | 496 { |
438 CallRuntime(Runtime::kPromiseFulfill, context, promise, | 497 CallRuntime(Runtime::kPromiseFulfill, context, promise, |
439 SmiConstant(v8::Promise::kFulfilled), thenable_value); | 498 SmiConstant(v8::Promise::kFulfilled), thenable_value); |
440 PromiseSetHasHandler(promise); | 499 PromiseSetHasHandler(promise); |
441 Goto(out); | 500 Goto(&out); |
442 } | 501 } |
443 | 502 |
444 Bind(&if_rejected); | 503 Bind(&if_rejected); |
445 { | 504 { |
446 Label reject(this); | 505 Label reject(this); |
447 Node* const has_handler = PromiseHasHandler(result); | 506 Node* const has_handler = PromiseHasHandler(result); |
448 | 507 |
449 // Promise has already been rejected, but had no handler. | 508 // Promise has already been rejected, but had no handler. |
450 // Revoke previously triggered reject event. | 509 // Revoke previously triggered reject event. |
451 GotoIf(has_handler, &reject); | 510 GotoIf(has_handler, &reject); |
452 CallRuntime(Runtime::kPromiseRevokeReject, context, result); | 511 CallRuntime(Runtime::kPromiseRevokeReject, context, result); |
453 Goto(&reject); | 512 Goto(&reject); |
454 | 513 |
455 Bind(&reject); | 514 Bind(&reject); |
456 // Don't cause a debug event as this case is forwarding a rejection | 515 // Don't cause a debug event as this case is forwarding a rejection |
457 CallRuntime(Runtime::kPromiseReject, context, promise, thenable_value, | 516 CallRuntime(Runtime::kPromiseReject, context, promise, thenable_value, |
458 FalseConstant()); | 517 FalseConstant()); |
459 PromiseSetHasHandler(result); | 518 PromiseSetHasHandler(result); |
460 Goto(out); | 519 Goto(&out); |
461 } | 520 } |
462 } | 521 } |
463 } | 522 } |
464 | 523 |
465 Bind(&if_notnativepromise); | 524 Bind(&if_notnativepromise); |
466 { | 525 { |
467 // 8. Let then be Get(resolution, "then"). | 526 // 8. Let then be Get(resolution, "then"). |
468 Node* const then_str = HeapConstant(isolate->factory()->then_string()); | 527 Node* const then_str = HeapConstant(isolate->factory()->then_string()); |
469 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | 528 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
470 Node* const then = | 529 Node* const then = |
(...skipping 22 matching lines...) Expand all Loading... |
493 CallRuntime(Runtime::kSetProperty, context, result, key, promise, | 552 CallRuntime(Runtime::kSetProperty, context, result, key, promise, |
494 SmiConstant(STRICT)); | 553 SmiConstant(STRICT)); |
495 Goto(&enqueue); | 554 Goto(&enqueue); |
496 | 555 |
497 // 12. Perform EnqueueJob("PromiseJobs", | 556 // 12. Perform EnqueueJob("PromiseJobs", |
498 // PromiseResolveThenableJob, « promise, resolution, thenAction | 557 // PromiseResolveThenableJob, « promise, resolution, thenAction |
499 // »). | 558 // »). |
500 Bind(&enqueue); | 559 Bind(&enqueue); |
501 CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, promise, | 560 CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, promise, |
502 result, var_then.value()); | 561 result, var_then.value()); |
503 Goto(out); | 562 Goto(&out); |
504 } | 563 } |
505 | 564 |
506 // 7.b Return FulfillPromise(promise, resolution). | 565 // 7.b Return FulfillPromise(promise, resolution). |
507 Bind(&fulfill); | 566 Bind(&fulfill); |
508 { | 567 { |
509 CallRuntime(Runtime::kPromiseFulfill, context, promise, | 568 CallRuntime(Runtime::kPromiseFulfill, context, promise, |
510 SmiConstant(v8::Promise::kFulfilled), result); | 569 SmiConstant(v8::Promise::kFulfilled), result); |
511 Goto(out); | 570 Goto(&out); |
512 } | 571 } |
513 | 572 |
514 Bind(&if_cycle); | 573 Bind(&if_cycle); |
515 { | 574 { |
516 // 6.a Let selfResolutionError be a newly created TypeError object. | 575 // 6.a Let selfResolutionError be a newly created TypeError object. |
517 Node* const message_id = SmiConstant(MessageTemplate::kPromiseCyclic); | 576 Node* const message_id = SmiConstant(MessageTemplate::kPromiseCyclic); |
518 Node* const error = | 577 Node* const error = |
519 CallRuntime(Runtime::kNewTypeError, context, message_id, result); | 578 CallRuntime(Runtime::kNewTypeError, context, message_id, result); |
520 var_reason.Bind(error); | 579 var_reason.Bind(error); |
521 | 580 |
522 // 6.b Return RejectPromise(promise, selfResolutionError). | 581 // 6.b Return RejectPromise(promise, selfResolutionError). |
523 Goto(&if_rejectpromise); | 582 Goto(&if_rejectpromise); |
524 } | 583 } |
525 | 584 |
526 // 9.a Return RejectPromise(promise, then.[[Value]]). | 585 // 9.a Return RejectPromise(promise, then.[[Value]]). |
527 Bind(&if_rejectpromise); | 586 Bind(&if_rejectpromise); |
528 { | 587 { |
529 CallRuntime(Runtime::kPromiseReject, context, promise, var_reason.value(), | 588 CallRuntime(Runtime::kPromiseReject, context, promise, var_reason.value(), |
530 TrueConstant()); | 589 TrueConstant()); |
531 Goto(out); | 590 Goto(&out); |
532 } | 591 } |
| 592 |
| 593 Bind(&out); |
533 } | 594 } |
534 | 595 |
535 // ES#sec-promise-reject-functions | 596 // ES#sec-promise-reject-functions |
536 // Promise Reject Functions | 597 // Promise Reject Functions |
537 BUILTIN(PromiseRejectClosure) { | 598 BUILTIN(PromiseRejectClosure) { |
538 HandleScope scope(isolate); | 599 HandleScope scope(isolate); |
539 | 600 |
540 Handle<Context> context(isolate->context(), isolate); | 601 Handle<Context> context(isolate->context(), isolate); |
541 | 602 |
542 if (PromiseUtils::HasAlreadyVisited(context)) { | 603 if (PromiseUtils::HasAlreadyVisited(context)) { |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
755 Node* const deferred = Parameter(4); | 816 Node* const deferred = Parameter(4); |
756 Node* const context = Parameter(7); | 817 Node* const context = Parameter(7); |
757 | 818 |
758 Node* const result = InternalPerformPromiseThen(context, promise, on_resolve, | 819 Node* const result = InternalPerformPromiseThen(context, promise, on_resolve, |
759 on_reject, deferred); | 820 on_reject, deferred); |
760 | 821 |
761 // TODO(gsathya): This is unused, but value is returned according to spec. | 822 // TODO(gsathya): This is unused, but value is returned according to spec. |
762 Return(result); | 823 Return(result); |
763 } | 824 } |
764 | 825 |
| 826 // ES#sec-promise.prototype.then |
| 827 // Promise.prototype.catch ( onFulfilled, onRejected ) |
765 TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) { | 828 TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) { |
766 // 1. Let promise be the this value. | 829 // 1. Let promise be the this value. |
767 Node* const promise = Parameter(0); | 830 Node* const promise = Parameter(0); |
768 Node* const on_resolve = Parameter(1); | 831 Node* const on_resolve = Parameter(1); |
769 Node* const on_reject = Parameter(2); | 832 Node* const on_reject = Parameter(2); |
770 Node* const context = Parameter(5); | 833 Node* const context = Parameter(5); |
771 Isolate* isolate = this->isolate(); | |
772 | 834 |
773 // 2. If IsPromise(promise) is false, throw a TypeError exception. | 835 Node* const result = |
774 ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE, | 836 InternalPromiseThen(context, promise, on_resolve, on_reject); |
775 "Promise.prototype.then"); | |
776 | |
777 Node* const native_context = LoadNativeContext(context); | |
778 Node* const promise_fun = | |
779 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); | |
780 | |
781 // 3. Let C be ? SpeciesConstructor(promise, %Promise%). | |
782 Node* constructor = SpeciesConstructor(context, promise, promise_fun); | |
783 | |
784 // 4. Let resultCapability be ? NewPromiseCapability(C). | |
785 Callable call_callable = CodeFactory::Call(isolate); | |
786 Label fast_promise_capability(this), promise_capability(this), | |
787 perform_promise_then(this); | |
788 Variable var_deferred(this, MachineRepresentation::kTagged); | |
789 | |
790 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, | |
791 &promise_capability); | |
792 | |
793 // TODO(gsathya): Remove deferred object and move | |
794 // NewPromiseCapabability functions to TF. | |
795 Bind(&fast_promise_capability); | |
796 { | |
797 // TODO(gsathya): Move this to TF. | |
798 Node* const promise_internal_capability = LoadContextElement( | |
799 native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX); | |
800 Node* const capability = | |
801 CallJS(call_callable, context, promise_internal_capability, | |
802 UndefinedConstant(), promise); | |
803 var_deferred.Bind(capability); | |
804 Goto(&perform_promise_then); | |
805 } | |
806 | |
807 Bind(&promise_capability); | |
808 { | |
809 // TODO(gsathya): Move this to TF. | |
810 Node* const new_promise_capability = LoadContextElement( | |
811 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); | |
812 Node* const capability = | |
813 CallJS(call_callable, context, new_promise_capability, | |
814 UndefinedConstant(), constructor); | |
815 var_deferred.Bind(capability); | |
816 Goto(&perform_promise_then); | |
817 } | |
818 | |
819 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, | |
820 // resultCapability). | |
821 Bind(&perform_promise_then); | |
822 Node* const result = InternalPerformPromiseThen( | |
823 context, promise, on_resolve, on_reject, var_deferred.value()); | |
824 Return(result); | 837 Return(result); |
825 } | 838 } |
826 | 839 |
827 // ES#sec-promise-resolve-functions | 840 // ES#sec-promise-resolve-functions |
828 // Promise Resolve Functions | 841 // Promise Resolve Functions |
829 TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) { | 842 TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) { |
830 Node* const value = Parameter(1); | 843 Node* const value = Parameter(1); |
831 Node* const context = Parameter(4); | 844 Node* const context = Parameter(4); |
832 | 845 |
833 Label out(this); | 846 Label out(this); |
834 | 847 |
835 // 3. Let alreadyResolved be F.[[AlreadyResolved]]. | 848 // 3. Let alreadyResolved be F.[[AlreadyResolved]]. |
836 Node* const has_already_visited_slot = | 849 Node* const has_already_visited_slot = |
837 IntPtrConstant(PromiseUtils::kAlreadyVisitedSlot); | 850 IntPtrConstant(PromiseUtils::kAlreadyVisitedSlot); |
838 | 851 |
839 Node* const has_already_visited = | 852 Node* const has_already_visited = |
840 LoadFixedArrayElement(context, has_already_visited_slot); | 853 LoadFixedArrayElement(context, has_already_visited_slot); |
841 | 854 |
842 // 4. If alreadyResolved.[[Value]] is true, return undefined. | 855 // 4. If alreadyResolved.[[Value]] is true, return undefined. |
843 GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out); | 856 GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out); |
844 | 857 |
845 // 5.Set alreadyResolved.[[Value]] to true. | 858 // 5.Set alreadyResolved.[[Value]] to true. |
846 StoreFixedArrayElement(context, has_already_visited_slot, SmiConstant(1)); | 859 StoreFixedArrayElement(context, has_already_visited_slot, SmiConstant(1)); |
847 | 860 |
848 // 2. Let promise be F.[[Promise]]. | 861 // 2. Let promise be F.[[Promise]]. |
849 Node* const promise = LoadFixedArrayElement( | 862 Node* const promise = LoadFixedArrayElement( |
850 context, IntPtrConstant(PromiseUtils::kPromiseSlot)); | 863 context, IntPtrConstant(PromiseUtils::kPromiseSlot)); |
851 | 864 |
852 InternalResolvePromise(context, promise, value, &out); | 865 InternalResolvePromise(context, promise, value); |
| 866 Return(UndefinedConstant()); |
853 | 867 |
854 Bind(&out); | 868 Bind(&out); |
855 Return(UndefinedConstant()); | 869 Return(UndefinedConstant()); |
856 } | 870 } |
857 | 871 |
858 TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) { | 872 TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) { |
859 Node* const promise = Parameter(1); | 873 Node* const promise = Parameter(1); |
860 Node* const result = Parameter(2); | 874 Node* const result = Parameter(2); |
861 Node* const context = Parameter(5); | 875 Node* const context = Parameter(5); |
862 | 876 |
863 Label out(this); | 877 InternalResolvePromise(context, promise, result); |
864 InternalResolvePromise(context, promise, result, &out); | |
865 | |
866 Bind(&out); | |
867 Return(UndefinedConstant()); | 878 Return(UndefinedConstant()); |
868 } | 879 } |
869 | 880 |
870 TF_BUILTIN(PromiseHandleReject, PromiseBuiltinsAssembler) { | 881 TF_BUILTIN(PromiseHandleReject, PromiseBuiltinsAssembler) { |
871 typedef PromiseHandleRejectDescriptor Descriptor; | 882 typedef PromiseHandleRejectDescriptor Descriptor; |
872 | 883 |
873 Node* const promise = Parameter(Descriptor::kPromise); | 884 Node* const promise = Parameter(Descriptor::kPromise); |
874 Node* const on_reject = Parameter(Descriptor::kOnReject); | 885 Node* const on_reject = Parameter(Descriptor::kOnReject); |
875 Node* const exception = Parameter(Descriptor::kException); | 886 Node* const exception = Parameter(Descriptor::kException); |
876 Node* const context = Parameter(Descriptor::kContext); | 887 Node* const context = Parameter(Descriptor::kContext); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
938 | 949 |
939 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | 950 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. |
940 Node* const key = HeapConstant(isolate->factory()->resolve_string()); | 951 Node* const key = HeapConstant(isolate->factory()->resolve_string()); |
941 Node* const on_resolve = | 952 Node* const on_resolve = |
942 CallStub(getproperty_callable, context, deferred, key); | 953 CallStub(getproperty_callable, context, deferred, key); |
943 | 954 |
944 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); | 955 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); |
945 Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); | 956 Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); |
946 | 957 |
947 Bind(&if_internalhandler); | 958 Bind(&if_internalhandler); |
948 InternalResolvePromise(context, deferred_promise, result, | 959 InternalResolvePromise(context, deferred_promise, result); |
949 &promisehook_after); | 960 Goto(&promisehook_after); |
950 | 961 |
951 Bind(&if_customhandler); | 962 Bind(&if_customhandler); |
952 { | 963 { |
953 Node* const maybe_exception = CallJS(call_callable, context, on_resolve, | 964 Node* const maybe_exception = CallJS(call_callable, context, on_resolve, |
954 UndefinedConstant(), result); | 965 UndefinedConstant(), result); |
955 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); | 966 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); |
956 Goto(&promisehook_after); | 967 Goto(&promisehook_after); |
957 } | 968 } |
958 } | 969 } |
959 | 970 |
(...skipping 23 matching lines...) Expand all Loading... |
983 | 994 |
984 GotoUnless(is_debug_active, &out); | 995 GotoUnless(is_debug_active, &out); |
985 CallRuntime(Runtime::kDebugPopPromise, context); | 996 CallRuntime(Runtime::kDebugPopPromise, context); |
986 Goto(&out); | 997 Goto(&out); |
987 | 998 |
988 Bind(&out); | 999 Bind(&out); |
989 Return(UndefinedConstant()); | 1000 Return(UndefinedConstant()); |
990 } | 1001 } |
991 } | 1002 } |
992 | 1003 |
| 1004 // ES#sec-promise.prototype.catch |
| 1005 // Promise.prototype.catch ( onRejected ) |
| 1006 TF_BUILTIN(PromiseCatch, PromiseBuiltinsAssembler) { |
| 1007 // 1. Let promise be the this value. |
| 1008 Node* const promise = Parameter(0); |
| 1009 Node* const on_resolve = UndefinedConstant(); |
| 1010 Node* const on_reject = Parameter(1); |
| 1011 Node* const context = Parameter(4); |
| 1012 |
| 1013 Label if_internalthen(this), if_customthen(this, Label::kDeferred); |
| 1014 BranchIfFastPath(context, promise, &if_internalthen, &if_customthen); |
| 1015 |
| 1016 Bind(&if_internalthen); |
| 1017 { |
| 1018 Node* const result = |
| 1019 InternalPromiseThen(context, promise, on_resolve, on_reject); |
| 1020 Return(result); |
| 1021 } |
| 1022 |
| 1023 Bind(&if_customthen); |
| 1024 { |
| 1025 Isolate* isolate = this->isolate(); |
| 1026 Node* const then_str = HeapConstant(isolate->factory()->then_string()); |
| 1027 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| 1028 Node* const then = |
| 1029 CallStub(getproperty_callable, context, promise, then_str); |
| 1030 Callable call_callable = CodeFactory::Call(isolate); |
| 1031 Node* const result = |
| 1032 CallJS(call_callable, context, then, promise, on_resolve, on_reject); |
| 1033 Return(result); |
| 1034 } |
| 1035 } |
| 1036 |
993 } // namespace internal | 1037 } // namespace internal |
994 } // namespace v8 | 1038 } // namespace v8 |
OLD | NEW |