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

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

Issue 2541283002: [promises] Port ResolvePromise to TF (Closed)
Patch Set: add comments Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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-utils.h" 5 #include "src/builtins/builtins-utils.h"
6 #include "src/builtins/builtins.h" 6 #include "src/builtins/builtins.h"
7 7
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/promise-utils.h" 9 #include "src/promise-utils.h"
10 10
11 namespace v8 { 11 namespace v8 {
12 namespace internal { 12 namespace internal {
13 13
14 // ES#sec-promise-resolve-functions
15 // Promise Resolve Functions
16 BUILTIN(PromiseResolveClosure) {
17 HandleScope scope(isolate);
18
19 Handle<Context> context(isolate->context(), isolate);
20
21 if (PromiseUtils::HasAlreadyVisited(context)) {
22 return isolate->heap()->undefined_value();
23 }
24
25 PromiseUtils::SetAlreadyVisited(context);
26 Handle<JSObject> promise = handle(PromiseUtils::GetPromise(context), isolate);
27 Handle<Object> value = args.atOrUndefined(isolate, 1);
28
29 MaybeHandle<Object> maybe_result;
30 Handle<Object> argv[] = {promise, value};
31 RETURN_FAILURE_ON_EXCEPTION(
32 isolate, Execution::Call(isolate, isolate->promise_resolve(),
33 isolate->factory()->undefined_value(),
34 arraysize(argv), argv));
35 return isolate->heap()->undefined_value();
36 }
37
38 // ES#sec-promise-reject-functions 14 // ES#sec-promise-reject-functions
39 // Promise Reject Functions 15 // Promise Reject Functions
40 BUILTIN(PromiseRejectClosure) { 16 BUILTIN(PromiseRejectClosure) {
41 HandleScope scope(isolate); 17 HandleScope scope(isolate);
42 18
43 Handle<Context> context(isolate->context(), isolate); 19 Handle<Context> context(isolate->context(), isolate);
44 20
45 if (PromiseUtils::HasAlreadyVisited(context)) { 21 if (PromiseUtils::HasAlreadyVisited(context)) {
46 return isolate->heap()->undefined_value(); 22 return isolate->heap()->undefined_value();
47 } 23 }
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 // deal with deferred objects. 634 // deal with deferred objects.
659 Callable getproperty_callable = CodeFactory::GetProperty(isolate); 635 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
660 Node* const key = 636 Node* const key =
661 a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); 637 a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise"));
662 Node* const result = 638 Node* const result =
663 a.CallStub(getproperty_callable, context, var_deferred.value(), key); 639 a.CallStub(getproperty_callable, context, var_deferred.value(), key);
664 640
665 a.Return(result); 641 a.Return(result);
666 } 642 }
667 643
644 namespace {
645 // RegExp fast path implementations rely on unmodified JSPromise instances.
jgruber 2016/12/05 09:25:17 Promise
gsathya 2016/12/05 16:03:05 Done.
646 // We use a fairly coarse granularity for this and simply check whether both
647 // the promise itself is unmodified (i.e. its map has not changed) and its
648 // prototype is unmodified.
649 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp
650 void BranchIfFastPath(CodeStubAssembler* a, compiler::Node* context,
651 compiler::Node* promise,
652 CodeStubAssembler::Label* if_isunmodified,
653 CodeStubAssembler::Label* if_ismodified) {
654 typedef compiler::Node Node;
655
656 // TODO(gsathya): Assert if promise is receiver
657 Node* const map = a->LoadMap(promise);
658 Node* const native_context = a->LoadNativeContext(context);
659 Node* const promise_fun =
660 a->LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
661 Node* const initial_map =
662 a->LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
663 Node* const has_initialmap = a->WordEqual(map, initial_map);
664
665 a->GotoUnless(has_initialmap, if_ismodified);
666
667 Node* const initial_proto_initial_map = a->LoadContextElement(
668 native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX);
669 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map));
670 Node* const proto_has_initialmap =
671 a->WordEqual(proto_map, initial_proto_initial_map);
672
673 // TODO(ishell): Update this check once map changes for constant field
jgruber 2016/12/05 09:25:17 We can remove this TODO since the mentioned change
gsathya 2016/12/05 16:03:05 Done.
674 // tracking are landing.
675 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified);
676 }
677 } // namespace
678
679 void InternalResolvePromise(CodeStubAssembler* a, compiler::Node* context,
680 compiler::Node* promise, compiler::Node* result) {
681 typedef CodeStubAssembler::Variable Variable;
jgruber 2016/12/05 09:25:17 As mentioned offline, you might consider switching
gsathya 2016/12/05 16:03:05 I'm going to wait until I finish the rest of the b
jgruber 2016/12/07 12:59:38 Acknowledged, sgtm.
682 typedef CodeStubAssembler::Label Label;
683 typedef compiler::Node Node;
684
685 Isolate* isolate = a->isolate();
686
687 Variable var_reason(a, MachineRepresentation::kTagged);
688
689 Label out(a), fulfill(a), if_cycle(a, Label::kDeferred),
690 if_rejectpromise(a, Label::kDeferred);
691
692 // 6. If SameValue(resolution, promise) is true, then
693 a->GotoIf(a->WordEqual(promise, result), &if_cycle);
jgruber 2016/12/05 09:25:17 SameValue is more involved than WordEqual. You can
gsathya 2016/12/05 16:03:05 Done.
694
695 // 7. If Type(resolution) is not Object, then
696 a->GotoIf(a->TaggedIsSmi(result), &fulfill);
697 Node* const result_instance_type = a->LoadMapInstanceType(a->LoadMap(result));
698 a->GotoUnless(a->IsJSReceiverInstanceType(result_instance_type), &fulfill);
jgruber 2016/12/05 09:25:17 IsJSReceiver()
gsathya 2016/12/05 16:03:05 Done.
699
700 Label if_nativepromise(a), if_notnativepromise(a, Label::kDeferred);
701 BranchIfFastPath(a, context, result, &if_nativepromise, &if_notnativepromise);
702
703 a->Bind(&if_nativepromise);
704 {
705 Node* const thenable_status =
706 a->LoadObjectField(result, JSPromise::kStatusOffset);
707 Node* const thenable_value =
708 a->LoadObjectField(result, JSPromise::kResultOffset);
709
710 Label if_isnotpending(a);
711 a->GotoUnless(a->SmiEqual(a->SmiConstant(kPromisePending), thenable_status),
712 &if_isnotpending);
713
714 Node* const native_context = a->LoadNativeContext(context);
715 Node* const then =
716 a->LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
717
718 a->CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, promise,
719 result, then);
720 a->Goto(&out);
721
722 a->Bind(&if_isnotpending);
723 {
724 Label if_fulfilled(a), if_rejected(a);
725 a->Branch(a->SmiEqual(a->SmiConstant(kPromiseFulfilled), thenable_status),
726 &if_fulfilled, &if_rejected);
727
728 a->Bind(&if_fulfilled);
729 {
730 a->CallRuntime(Runtime::kPromiseFulfill, context, promise,
731 a->SmiConstant(kPromiseFulfilled), thenable_value);
732 a->Goto(&out);
733 }
734
735 a->Bind(&if_rejected);
736 {
737 a->CallRuntime(Runtime::kPromiseReject, context, promise,
738 thenable_value, a->FalseConstant());
739 a->Goto(&out);
740 }
741 }
742 }
743
744 a->Bind(&if_notnativepromise);
745 {
746 // 8. Let then be Get(resolution, "then").
747 Node* const then_str = a->HeapConstant(isolate->factory()->then_string());
748 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
749 Node* const then =
750 a->CallStub(getproperty_callable, context, result, then_str);
751
752 // 9. If then is an abrupt completion, then
753 a->GotoIfException(then, &if_rejectpromise, &var_reason);
754
755 // 11. If IsCallable(thenAction) is false, then
756 a->GotoIf(a->TaggedIsSmi(then), &fulfill);
757 Node* const then_map = a->LoadMap(then);
758 a->GotoUnless(a->IsCallableMap(then_map), &fulfill);
759
760 // 12. Perform EnqueueJob("PromiseJobs",
761 // PromiseResolveThenableJob, « promise, resolution, thenAction
762 // »).
763 a->CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, promise,
764 result, then);
765 a->Goto(&out);
766 }
767
768 // 7.b Return FulfillPromise(promise, resolution).
769 a->Bind(&fulfill);
770 {
771 a->CallRuntime(Runtime::kPromiseFulfill, context, promise,
772 a->SmiConstant(kPromiseFulfilled), result);
773 a->Goto(&out);
774 }
775
776 a->Bind(&if_cycle);
777 {
778 // 6.a Let selfResolutionError be a newly created TypeError object.
779 Node* const message_id = a->SmiConstant(MessageTemplate::kPromiseCyclic);
780 Node* const error =
781 a->CallRuntime(Runtime::kNewTypeError, context, message_id, result);
782 var_reason.Bind(error);
783
784 // 6.b Return RejectPromise(promise, selfResolutionError).
785 a->Goto(&if_rejectpromise);
786 }
787
788 // 9.a Return RejectPromise(promise, then.[[Value]]).
789 a->Bind(&if_rejectpromise);
790 {
791 a->CallRuntime(Runtime::kPromiseReject, context, promise,
792 var_reason.value(), a->TrueConstant());
793 a->Goto(&out);
794 }
795
796 a->Bind(&out);
797 a->Return(a->UndefinedConstant());
798 }
799
800 // ES#sec-promise-resolve-functions
801 // Promise Resolve Functions
802 void Builtins::Generate_PromiseResolveClosure(
803 compiler::CodeAssemblerState* state) {
804 CodeStubAssembler a(state);
805 typedef compiler::Node Node;
806 typedef CodeStubAssembler::Label Label;
807
808 Node* const value = a.Parameter(1);
809 Node* const context = a.Parameter(4);
810 Isolate* isolate = a.isolate();
811
812 Label out(&a);
813
814 // 3. Let alreadyResolved be F.[[AlreadyResolved]].
815 Node* const has_already_visited_slot =
816 a.IntPtrConstant(PromiseUtils::kAlreadyVisitedSlot);
817
818 Node* const has_already_visited =
819 a.LoadFixedArrayElement(context, has_already_visited_slot);
820
821 // 4. If alreadyResolved.[[Value]] is true, return undefined.
822 a.GotoIf(a.SmiEqual(has_already_visited, a.SmiConstant(1)), &out);
jgruber 2016/12/05 09:25:17 Is line 825 below the only place where we write in
gsathya 2016/12/05 16:03:05 PromiseUtils::CreateResolvingFunctions and Promise
jgruber 2016/12/07 12:59:38 Ok. IMHO the fact that we use a Smi 0/1 encoding i
823
824 // 5.Set alreadyResolved.[[Value]] to true.
825 a.StoreFixedArrayElement(context, has_already_visited_slot, a.SmiConstant(1));
826
827 // 2. Let promise be F.[[Promise]].
828 Node* const promise = a.LoadFixedArrayElement(
829 context, a.IntPtrConstant(PromiseUtils::kPromiseSlot));
830
831 InternalResolvePromise(&a, context, promise, value);
832
833 a.Bind(&out);
834 a.Return(a.UndefinedConstant());
835 }
836
837 void Builtins::Generate_ResolvePromise(compiler::CodeAssemblerState* state) {
838 CodeStubAssembler a(state);
839 typedef compiler::Node Node;
840
841 Node* const promise = a.Parameter(1);
842 Node* const result = a.Parameter(2);
843 Node* const context = a.Parameter(5);
844
845 InternalResolvePromise(&a, context, promise, result);
846 }
847
668 } // namespace internal 848 } // namespace internal
669 } // namespace v8 849 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/contexts.h » ('j') | src/js/promise.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698