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-constructor.h" | 6 #include "src/builtins/builtins-constructor.h" |
7 #include "src/builtins/builtins-utils.h" | 7 #include "src/builtins/builtins-utils.h" |
8 #include "src/builtins/builtins.h" | 8 #include "src/builtins/builtins.h" |
9 #include "src/code-factory.h" | 9 #include "src/code-factory.h" |
10 #include "src/code-stub-assembler.h" | 10 #include "src/code-stub-assembler.h" |
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 } | 598 } |
599 } | 599 } |
600 } | 600 } |
601 } | 601 } |
602 | 602 |
603 Bind(&out); | 603 Bind(&out); |
604 PromiseSetHasHandler(promise); | 604 PromiseSetHasHandler(promise); |
605 return deferred_promise; | 605 return deferred_promise; |
606 } | 606 } |
607 | 607 |
| 608 void PromiseBuiltinsAssembler::FastPerformPromiseThen(Node* context, |
| 609 Node* promise, |
| 610 Node* on_resolve, |
| 611 Node* on_reject, |
| 612 Node* result_promise) { |
| 613 CSA_SLOW_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE)); |
| 614 if (result_promise != nullptr) { |
| 615 CSA_SLOW_ASSERT(this, HasInstanceType(result_promise, JS_PROMISE_TYPE)); |
| 616 } |
| 617 |
| 618 if (on_resolve == nullptr) { |
| 619 on_resolve = LoadContextElement(LoadNativeContext(context), |
| 620 Context::PROMISE_ID_RESOLVE_HANDLER_INDEX); |
| 621 } else if (on_reject == nullptr) { |
| 622 on_reject = LoadContextElement(LoadNativeContext(context), |
| 623 Context::PROMISE_ID_REJECT_HANDLER_INDEX); |
| 624 } |
| 625 CSA_SLOW_ASSERT(this, IsJSFunction(on_resolve)); |
| 626 CSA_SLOW_ASSERT(this, IsJSFunction(on_reject)); |
| 627 |
| 628 Label if_ispending(this), if_isfulfilled(this), merge(this); |
| 629 |
| 630 Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset); |
| 631 Branch(SmiEqual(status, SmiConstant(v8::Promise::kPending)), &if_ispending, |
| 632 &if_isfulfilled); |
| 633 |
| 634 Bind(&if_ispending); |
| 635 { |
| 636 // Assert: There are no callbacks attached. |
| 637 CSA_SLOW_ASSERT(this, IsUndefined(LoadObjectField( |
| 638 promise, JSPromise::kDeferredPromiseOffset))); |
| 639 |
| 640 // Store callbacks directly in the slots. |
| 641 StoreObjectField(promise, JSPromise::kDeferredPromiseOffset, |
| 642 result_promise ? result_promise : UndefinedConstant()); |
| 643 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, on_resolve); |
| 644 StoreObjectField(promise, JSPromise::kRejectReactionsOffset, on_reject); |
| 645 Goto(&merge); |
| 646 } |
| 647 |
| 648 Bind(&if_isfulfilled); |
| 649 { |
| 650 Node* const handler = |
| 651 Select(SmiEqual(status, SmiConstant(v8::Promise::kFulfilled)), |
| 652 [&]() -> Node* { return on_resolve; }, |
| 653 [&]() -> Node* { |
| 654 Label done(this); |
| 655 GotoIf(PromiseHasHandler(promise), &done); |
| 656 // TODO(gsathya): Fold these runtime calls and move to TF. |
| 657 CallRuntime(Runtime::kPromiseRevokeReject, context, promise); |
| 658 Goto(&done); |
| 659 Bind(&done); |
| 660 return on_reject; |
| 661 }, |
| 662 MachineRepresentation::kTagged); |
| 663 |
| 664 Node* const result = LoadObjectField(promise, JSPromise::kResultOffset); |
| 665 Node* info = AllocatePromiseReactionJobInfo( |
| 666 promise, result, handler, |
| 667 result_promise ? result_promise : UndefinedConstant(), |
| 668 UndefinedConstant(), UndefinedConstant(), context); |
| 669 // TODO(gsathya): Move this to TF |
| 670 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info, status); |
| 671 Goto(&merge); |
| 672 } |
| 673 |
| 674 Bind(&merge); |
| 675 } |
| 676 |
608 // Promise fast path implementations rely on unmodified JSPromise instances. | 677 // Promise fast path implementations rely on unmodified JSPromise instances. |
609 // We use a fairly coarse granularity for this and simply check whether both | 678 // We use a fairly coarse granularity for this and simply check whether both |
610 // the promise itself is unmodified (i.e. its map has not changed) and its | 679 // the promise itself is unmodified (i.e. its map has not changed) and its |
611 // prototype is unmodified. | 680 // prototype is unmodified. |
612 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp | 681 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp |
613 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, | 682 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, |
614 Label* if_isunmodified, | 683 Label* if_isunmodified, |
615 Label* if_ismodified) { | 684 Label* if_ismodified) { |
616 Node* const native_context = LoadNativeContext(context); | 685 Node* const native_context = LoadNativeContext(context); |
617 Node* const promise_fun = | 686 Node* const promise_fun = |
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1069 } | 1138 } |
1070 | 1139 |
1071 TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) { | 1140 TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) { |
1072 Node* const promise = Parameter(1); | 1141 Node* const promise = Parameter(1); |
1073 Node* const on_resolve = Parameter(2); | 1142 Node* const on_resolve = Parameter(2); |
1074 Node* const on_reject = Parameter(3); | 1143 Node* const on_reject = Parameter(3); |
1075 Node* const deferred_promise = Parameter(4); | 1144 Node* const deferred_promise = Parameter(4); |
1076 Node* const context = Parameter(7); | 1145 Node* const context = Parameter(7); |
1077 | 1146 |
1078 // No deferred_on_resolve/deferred_on_reject because this is just an | 1147 // No deferred_on_resolve/deferred_on_reject because this is just an |
1079 // internal promise created by async-await. | 1148 // internal promise created by async-await / async-iteration. |
1080 Node* const result = InternalPerformPromiseThen( | 1149 Node* const result = InternalPerformPromiseThen( |
1081 context, promise, on_resolve, on_reject, deferred_promise, | 1150 context, promise, on_resolve, on_reject, deferred_promise, |
1082 UndefinedConstant(), UndefinedConstant()); | 1151 UndefinedConstant(), UndefinedConstant()); |
1083 | 1152 |
1084 // TODO(gsathya): This is unused, but value is returned according to spec. | 1153 // TODO(gsathya): This is unused, but value is returned according to spec. |
1085 Return(result); | 1154 Return(result); |
1086 } | 1155 } |
1087 | 1156 |
1088 // ES#sec-promise.prototype.then | 1157 // ES#sec-promise.prototype.then |
1089 // Promise.prototype.catch ( onFulfilled, onRejected ) | 1158 // Promise.prototype.catch ( onFulfilled, onRejected ) |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1449 | 1518 |
1450 // 5. Return promiseCapability.[[Promise]]. | 1519 // 5. Return promiseCapability.[[Promise]]. |
1451 Node* const promise = | 1520 Node* const promise = |
1452 LoadObjectField(capability, JSPromiseCapability::kPromiseOffset); | 1521 LoadObjectField(capability, JSPromiseCapability::kPromiseOffset); |
1453 Return(promise); | 1522 Return(promise); |
1454 } | 1523 } |
1455 } | 1524 } |
1456 | 1525 |
1457 } // namespace internal | 1526 } // namespace internal |
1458 } // namespace v8 | 1527 } // namespace v8 |
OLD | NEW |