Chromium Code Reviews| 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 44 | 44 |
| 45 Label out(this); | 45 Label out(this); |
| 46 GotoUnless(IsPromiseHookEnabled(), &out); | 46 GotoUnless(IsPromiseHookEnabled(), &out); |
| 47 CallRuntime(Runtime::kPromiseHookInit, context, instance, parent); | 47 CallRuntime(Runtime::kPromiseHookInit, context, instance, parent); |
| 48 Goto(&out); | 48 Goto(&out); |
| 49 | 49 |
| 50 Bind(&out); | 50 Bind(&out); |
| 51 return instance; | 51 return instance; |
| 52 } | 52 } |
| 53 | 53 |
| 54 Node* PromiseBuiltinsAssembler::AllocateAndInitInternalJSPromise( | |
| 55 Node* context) { | |
|
caitp
2017/01/10 04:19:33
This seemed more useful earlier today, but after d
gsathya
2017/01/10 17:47:24
The Async-from-Sync iterator methods seems to use
caitp
2017/01/10 17:48:54
sgtm
| |
| 56 Node* const instance = AllocateJSPromise(context); | |
| 57 PromiseInit(instance); | |
| 58 return instance; | |
| 59 } | |
| 60 | |
| 54 Node* PromiseBuiltinsAssembler::AllocateAndSetJSPromise(Node* context, | 61 Node* PromiseBuiltinsAssembler::AllocateAndSetJSPromise(Node* context, |
| 55 Node* status, | 62 Node* status, |
| 56 Node* result) { | 63 Node* result) { |
| 57 CSA_ASSERT(this, TaggedIsSmi(status)); | 64 CSA_ASSERT(this, TaggedIsSmi(status)); |
| 58 | 65 |
| 59 Node* const instance = AllocateJSPromise(context); | 66 Node* const instance = AllocateJSPromise(context); |
| 60 | 67 |
| 61 StoreObjectFieldNoWriteBarrier(instance, JSPromise::kStatusOffset, status); | 68 StoreObjectFieldNoWriteBarrier(instance, JSPromise::kStatusOffset, status); |
| 62 StoreObjectFieldNoWriteBarrier(instance, JSPromise::kResultOffset, result); | 69 StoreObjectFieldNoWriteBarrier(instance, JSPromise::kResultOffset, result); |
| 63 StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset, | 70 StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset, |
| (...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 598 } | 605 } |
| 599 } | 606 } |
| 600 } | 607 } |
| 601 } | 608 } |
| 602 | 609 |
| 603 Bind(&out); | 610 Bind(&out); |
| 604 PromiseSetHasHandler(promise); | 611 PromiseSetHasHandler(promise); |
| 605 return deferred_promise; | 612 return deferred_promise; |
| 606 } | 613 } |
| 607 | 614 |
| 615 void PromiseBuiltinsAssembler::FastPerformPromiseThen(Node* context, | |
| 616 Node* promise, | |
| 617 Node* on_resolve, | |
| 618 Node* on_reject, | |
| 619 Node* result_promise) { | |
| 620 CSA_SLOW_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE)); | |
|
caitp
2017/01/10 04:13:41
Basically just a slightly smaller version of Inter
| |
| 621 if (result_promise != nullptr) { | |
| 622 CSA_SLOW_ASSERT(this, HasInstanceType(result_promise, JS_PROMISE_TYPE)); | |
| 623 } | |
| 624 | |
| 625 if (on_resolve == nullptr) { | |
| 626 on_resolve = LoadContextElement(LoadNativeContext(context), | |
| 627 Context::PROMISE_ID_RESOLVE_HANDLER_INDEX); | |
| 628 } else if (on_reject == nullptr) { | |
| 629 on_reject = LoadContextElement(LoadNativeContext(context), | |
| 630 Context::PROMISE_ID_REJECT_HANDLER_INDEX); | |
| 631 } | |
| 632 CSA_SLOW_ASSERT(this, IsJSFunction(on_resolve)); | |
| 633 CSA_SLOW_ASSERT(this, IsJSFunction(on_reject)); | |
| 634 | |
| 635 Label if_ispending(this), if_isfulfilled(this), merge(this); | |
| 636 | |
| 637 Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset); | |
| 638 Branch(SmiEqual(status, SmiConstant(v8::Promise::kPending)), &if_ispending, | |
| 639 &if_isfulfilled); | |
| 640 | |
| 641 Bind(&if_ispending); | |
| 642 { | |
| 643 // Assert: There are no callbacks attached. | |
| 644 CSA_SLOW_ASSERT(this, IsUndefined(LoadObjectField( | |
| 645 promise, JSPromise::kDeferredPromiseOffset))); | |
| 646 | |
| 647 // Store callbacks directly in the slots. | |
| 648 StoreObjectField(promise, JSPromise::kDeferredPromiseOffset, | |
| 649 result_promise ? result_promise : UndefinedConstant()); | |
| 650 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, on_resolve); | |
| 651 StoreObjectField(promise, JSPromise::kRejectReactionsOffset, on_reject); | |
| 652 Goto(&merge); | |
| 653 } | |
| 654 | |
| 655 Bind(&if_isfulfilled); | |
| 656 { | |
| 657 Node* const handler = | |
| 658 Select(SmiEqual(status, SmiConstant(v8::Promise::kFulfilled)), | |
| 659 [&]() -> Node* { return on_resolve; }, | |
| 660 [&]() -> Node* { | |
| 661 Label done(this); | |
| 662 GotoIf(PromiseHasHandler(promise), &done); | |
| 663 // TODO(gsathya): Fold these runtime calls and move to TF. | |
| 664 CallRuntime(Runtime::kPromiseRevokeReject, context, promise); | |
| 665 Goto(&done); | |
| 666 Bind(&done); | |
| 667 return on_reject; | |
| 668 }, | |
| 669 MachineRepresentation::kTagged); | |
| 670 | |
| 671 Node* const result = LoadObjectField(promise, JSPromise::kResultOffset); | |
| 672 Node* info = AllocatePromiseReactionJobInfo( | |
| 673 promise, result, handler, | |
| 674 result_promise ? result_promise : UndefinedConstant(), | |
| 675 UndefinedConstant(), UndefinedConstant(), context); | |
| 676 // TODO(gsathya): Move this to TF | |
| 677 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info, status); | |
| 678 Goto(&merge); | |
| 679 } | |
| 680 | |
| 681 Bind(&merge); | |
| 682 } | |
| 683 | |
| 608 // Promise fast path implementations rely on unmodified JSPromise instances. | 684 // Promise fast path implementations rely on unmodified JSPromise instances. |
| 609 // We use a fairly coarse granularity for this and simply check whether both | 685 // 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 | 686 // the promise itself is unmodified (i.e. its map has not changed) and its |
| 611 // prototype is unmodified. | 687 // prototype is unmodified. |
| 612 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp | 688 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp |
| 613 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, | 689 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, |
| 614 Label* if_isunmodified, | 690 Label* if_isunmodified, |
| 615 Label* if_ismodified) { | 691 Label* if_ismodified) { |
| 616 Node* const native_context = LoadNativeContext(context); | 692 Node* const native_context = LoadNativeContext(context); |
| 617 Node* const promise_fun = | 693 Node* const promise_fun = |
| (...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1061 } | 1137 } |
| 1062 | 1138 |
| 1063 TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) { | 1139 TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) { |
| 1064 Node* const promise = Parameter(1); | 1140 Node* const promise = Parameter(1); |
| 1065 Node* const on_resolve = Parameter(2); | 1141 Node* const on_resolve = Parameter(2); |
| 1066 Node* const on_reject = Parameter(3); | 1142 Node* const on_reject = Parameter(3); |
| 1067 Node* const deferred_promise = Parameter(4); | 1143 Node* const deferred_promise = Parameter(4); |
| 1068 Node* const context = Parameter(7); | 1144 Node* const context = Parameter(7); |
| 1069 | 1145 |
| 1070 // No deferred_on_resolve/deferred_on_reject because this is just an | 1146 // No deferred_on_resolve/deferred_on_reject because this is just an |
| 1071 // internal promise created by async-await. | 1147 // internal promise created by async-await / async-iteration. |
| 1072 Node* const result = InternalPerformPromiseThen( | 1148 Node* const result = InternalPerformPromiseThen( |
| 1073 context, promise, on_resolve, on_reject, deferred_promise, | 1149 context, promise, on_resolve, on_reject, deferred_promise, |
| 1074 UndefinedConstant(), UndefinedConstant()); | 1150 UndefinedConstant(), UndefinedConstant()); |
| 1075 | 1151 |
| 1076 // TODO(gsathya): This is unused, but value is returned according to spec. | 1152 // TODO(gsathya): This is unused, but value is returned according to spec. |
| 1077 Return(result); | 1153 Return(result); |
| 1078 } | 1154 } |
| 1079 | 1155 |
| 1080 // ES#sec-promise.prototype.then | 1156 // ES#sec-promise.prototype.then |
| 1081 // Promise.prototype.catch ( onFulfilled, onRejected ) | 1157 // Promise.prototype.catch ( onFulfilled, onRejected ) |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1441 | 1517 |
| 1442 // 5. Return promiseCapability.[[Promise]]. | 1518 // 5. Return promiseCapability.[[Promise]]. |
| 1443 Node* const promise = | 1519 Node* const promise = |
| 1444 LoadObjectField(capability, JSPromiseCapability::kPromiseOffset); | 1520 LoadObjectField(capability, JSPromiseCapability::kPromiseOffset); |
| 1445 Return(promise); | 1521 Return(promise); |
| 1446 } | 1522 } |
| 1447 } | 1523 } |
| 1448 | 1524 |
| 1449 } // namespace internal | 1525 } // namespace internal |
| 1450 } // namespace v8 | 1526 } // namespace v8 |
| OLD | NEW |