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

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

Issue 2567333002: [promises] port NewPromiseCapability to TF (Closed)
Patch Set: fix cctests and stuff 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-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"
11 11
12 namespace v8 { 12 namespace v8 {
13 namespace internal { 13 namespace internal {
14 14
15 typedef compiler::Node Node; 15 typedef compiler::Node Node;
16 typedef CodeStubAssembler::ParameterMode ParameterMode; 16 typedef CodeStubAssembler::ParameterMode ParameterMode;
17 typedef compiler::CodeAssemblerState CodeAssemblerState; 17 typedef compiler::CodeAssemblerState CodeAssemblerState;
18 18
19 Node* PromiseBuiltinsAssembler::CreatePromiseGetCapabilitiesExecutorContext(
20 Node* promise_capability, Node* native_context) {
21 Node* context = Allocate(
22 FixedArray::SizeFor(GetPromiseCapabilityExecutor::kContextLength));
23 Node* map = HeapConstant(isolate()->factory()->function_context_map());
24 StoreMapNoWriteBarrier(context, map);
25 StoreObjectFieldNoWriteBarrier(
26 context, FixedArray::kLengthOffset,
27 SmiConstant(GetPromiseCapabilityExecutor::kContextLength));
28
29 Node* script = LoadContextElement(native_context, Context::CLOSURE_INDEX);
30 StoreContextElement(context, Context::CLOSURE_INDEX, script);
31 StoreContextElement(context, Context::PREVIOUS_INDEX, UndefinedConstant());
32 StoreContextElement(context, Context::EXTENSION_INDEX, TheHoleConstant());
33 StoreContextElement(context, Context::NATIVE_CONTEXT_INDEX, native_context);
gsathya 2016/12/21 01:02:33 You refactor this to reuse CreatePromiseResolvingF
34 StoreContextElement(context, GetPromiseCapabilityExecutor::kCapabilitySlot,
gsathya 2016/12/21 01:02:33 StoreContextElementNoWriteBarrier
Igor Sheludko 2016/12/21 12:00:45 We can use it for all the stores because the objec
35 promise_capability);
36 return context;
37 }
38
39 Node* PromiseBuiltinsAssembler::NewPromiseCapability(Node* context,
40 Node* constructor,
41 Node* debug_event) {
42 if (debug_event == nullptr) {
43 debug_event = TrueConstant();
44 }
45
46 Node* native_context = LoadNativeContext(context);
47
48 Node* capability = Allocate(JSPromiseCapability::kSize);
49 StoreMapNoWriteBarrier(capability, Heap::kJSPromiseCapabilityMapRootIndex);
gsathya 2016/12/21 01:02:33 Why not use AllocateJSObjectFromMap here?
caitp 2016/12/21 21:01:13 Done.
50 StoreObjectFieldNoWriteBarrier(capability, JSObject::kPropertiesOffset,
51 EmptyFixedArrayConstant());
52 StoreObjectFieldNoWriteBarrier(capability, JSObject::kElementsOffset,
53 EmptyFixedArrayConstant());
54 StoreObjectFieldNoWriteBarrier(
55 capability, JSPromiseCapability::kPromiseOffset, UndefinedConstant());
56 StoreObjectFieldNoWriteBarrier(
57 capability, JSPromiseCapability::kResolveOffset, UndefinedConstant());
58 StoreObjectFieldNoWriteBarrier(capability, JSPromiseCapability::kRejectOffset,
59 UndefinedConstant());
60
61 Variable var_result(this, MachineRepresentation::kTagged);
62 var_result.Bind(capability);
63
64 Label if_builtin_promise(this), if_custom_promise(this), out(this);
65 Branch(WordEqual(constructor,
66 LoadContextElement(native_context,
67 Context::PROMISE_FUNCTION_INDEX)),
68 &if_builtin_promise, &if_custom_promise);
69
70 Bind(&if_builtin_promise);
71 {
72 Node* promise = AllocateJSPromise(context);
73 PromiseInit(promise);
74 StoreObjectFieldNoWriteBarrier(
75 capability, JSPromiseCapability::kPromiseOffset, promise);
76
77 Node* resolve = nullptr;
78 Node* reject = nullptr;
79
80 std::tie(resolve, reject) =
81 CreatePromiseResolvingFunctions(promise, debug_event, native_context);
82 StoreObjectField(capability, JSPromiseCapability::kResolveOffset, resolve);
83 StoreObjectField(capability, JSPromiseCapability::kRejectOffset, reject);
84
85 GotoUnless(IsPromiseHookEnabled(), &out);
86 CallRuntime(Runtime::kPromiseHookInit, context, promise,
87 UndefinedConstant());
88 Goto(&out);
89 }
90
91 Bind(&if_custom_promise);
92 {
93 Label if_notcallable(this, Label::kDeferred);
94 Node* executor_context =
95 CreatePromiseGetCapabilitiesExecutorContext(capability, native_context);
96 Node* executor_info = LoadContextElement(
97 native_context, Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN);
98 Node* function_map = LoadContextElement(
99 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
100 Node* executor = AllocateFunctionWithMapAndContext(
101 function_map, executor_info, executor_context);
102
103 Node* promise = ConstructJS(CodeFactory::Construct(isolate()), context,
104 constructor, executor);
105
106 Node* resolve =
107 LoadObjectField(capability, JSPromiseCapability::kResolveOffset);
108 GotoIf(TaggedIsSmi(resolve), &if_notcallable);
109 GotoUnless(IsCallableMap(LoadMap(resolve)), &if_notcallable);
110
111 Node* reject =
112 LoadObjectField(capability, JSPromiseCapability::kRejectOffset);
113 GotoIf(TaggedIsSmi(reject), &if_notcallable);
114 GotoUnless(IsCallableMap(LoadMap(reject)), &if_notcallable);
115
116 StoreObjectField(capability, JSPromiseCapability::kPromiseOffset, promise);
117
118 Goto(&out);
119
120 Bind(&if_notcallable);
121 Node* message = SmiConstant(MessageTemplate::kPromiseNonCallable);
122 StoreObjectField(capability, JSPromiseCapability::kPromiseOffset,
123 UndefinedConstant());
124 StoreObjectField(capability, JSPromiseCapability::kResolveOffset,
125 UndefinedConstant());
126 StoreObjectField(capability, JSPromiseCapability::kRejectOffset,
127 UndefinedConstant());
128 CallRuntime(Runtime::kThrowTypeError, context, message);
129 var_result.Bind(UndefinedConstant());
130 Goto(&out);
131 }
132
133 Bind(&out);
134 return var_result.value();
135 }
136
137 Node* PromiseBuiltinsAssembler::NewInternalPromiseCapability(Node* context,
138 Node* parent) {
139 Node* promise = AllocateJSPromise(context);
140 PromiseInit(promise);
141
142 Label out(this);
143
144 Node* capability = Allocate(JSPromiseCapability::kSize);
145 StoreMapNoWriteBarrier(capability, Heap::kJSPromiseCapabilityMapRootIndex);
146 StoreObjectFieldNoWriteBarrier(capability, JSObject::kPropertiesOffset,
147 EmptyFixedArrayConstant());
148 StoreObjectFieldNoWriteBarrier(capability, JSObject::kElementsOffset,
149 EmptyFixedArrayConstant());
150 StoreObjectFieldNoWriteBarrier(capability,
151 JSPromiseCapability::kPromiseOffset, promise);
152 StoreObjectFieldNoWriteBarrier(
153 capability, JSPromiseCapability::kResolveOffset, UndefinedConstant());
154 StoreObjectFieldNoWriteBarrier(capability, JSPromiseCapability::kRejectOffset,
155 UndefinedConstant());
156
157 GotoUnless(IsPromiseHookEnabled(), &out);
158 CallRuntime(Runtime::kPromiseHookInit, context, promise, parent);
159 Goto(&out);
160
161 Bind(&out);
162 return capability;
163 }
164
19 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext( 165 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
20 Node* promise, Node* debug_event, Node* native_context) { 166 Node* promise, Node* debug_event, Node* native_context) {
21 Node* const context = 167 Node* const context =
22 Allocate(FixedArray::SizeFor(PromiseUtils::kPromiseContextLength)); 168 Allocate(FixedArray::SizeFor(PromiseUtils::kPromiseContextLength));
23 StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex); 169 StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex);
24 StoreObjectFieldNoWriteBarrier( 170 StoreObjectFieldNoWriteBarrier(
25 context, FixedArray::kLengthOffset, 171 context, FixedArray::kLengthOffset,
26 SmiConstant(PromiseUtils::kPromiseContextLength)); 172 SmiConstant(PromiseUtils::kPromiseContextLength));
27 173
28 Node* const empty_fn = 174 Node* const empty_fn =
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 477
332 Goto(&out); 478 Goto(&out);
333 } 479 }
334 } 480 }
335 } 481 }
336 } 482 }
337 483
338 Bind(&out); 484 Bind(&out);
339 PromiseSetHasHandler(promise); 485 PromiseSetHasHandler(promise);
340 486
341 // TODO(gsathya): This call will be removed once we don't have to 487 CSA_ASSERT(this, HasInstanceType(deferred, JS_PROMISE_CAPABILITY_TYPE));
342 // deal with deferred objects. 488 Node* then_promise =
343 Isolate* isolate = this->isolate(); 489 LoadObjectField(deferred, JSPromiseCapability::kPromiseOffset);
344 Callable getproperty_callable = CodeFactory::GetProperty(isolate); 490 return then_promise;
345 Node* const key =
346 HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise"));
347 Node* const result = CallStub(getproperty_callable, context, deferred, key);
348
349 return result;
350 } 491 }
351 492
352 // Promise fast path implementations rely on unmodified JSPromise instances. 493 // Promise fast path implementations rely on unmodified JSPromise instances.
353 // We use a fairly coarse granularity for this and simply check whether both 494 // We use a fairly coarse granularity for this and simply check whether both
354 // the promise itself is unmodified (i.e. its map has not changed) and its 495 // the promise itself is unmodified (i.e. its map has not changed) and its
355 // prototype is unmodified. 496 // prototype is unmodified.
356 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp 497 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp
357 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, 498 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise,
358 Label* if_isunmodified, 499 Label* if_isunmodified,
359 Label* if_ismodified) { 500 Label* if_ismodified) {
(...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after
788 perform_promise_then(this); 929 perform_promise_then(this);
789 Variable var_deferred(this, MachineRepresentation::kTagged); 930 Variable var_deferred(this, MachineRepresentation::kTagged);
790 931
791 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, 932 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability,
792 &promise_capability); 933 &promise_capability);
793 934
794 // TODO(gsathya): Remove deferred object and move 935 // TODO(gsathya): Remove deferred object and move
795 // NewPromiseCapabability functions to TF. 936 // NewPromiseCapabability functions to TF.
796 Bind(&fast_promise_capability); 937 Bind(&fast_promise_capability);
797 { 938 {
798 // TODO(gsathya): Move this to TF. 939 Node* const capability = NewInternalPromiseCapability(context, promise);
799 Node* const promise_internal_capability = LoadContextElement(
800 native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX);
801 Node* const capability =
802 CallJS(call_callable, context, promise_internal_capability,
803 UndefinedConstant(), promise);
804 var_deferred.Bind(capability); 940 var_deferred.Bind(capability);
805 Goto(&perform_promise_then); 941 Goto(&perform_promise_then);
806 } 942 }
807 943
808 Bind(&promise_capability); 944 Bind(&promise_capability);
809 { 945 {
810 // TODO(gsathya): Move this to TF. 946 Node* const capability = NewPromiseCapability(context, constructor);
811 Node* const new_promise_capability = LoadContextElement(
812 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX);
813 Node* const capability =
814 CallJS(call_callable, context, new_promise_capability,
815 UndefinedConstant(), constructor);
816 var_deferred.Bind(capability); 947 var_deferred.Bind(capability);
817 Goto(&perform_promise_then); 948 Goto(&perform_promise_then);
818 } 949 }
819 950
820 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, 951 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
821 // resultCapability). 952 // resultCapability).
822 Bind(&perform_promise_then); 953 Bind(&perform_promise_then);
823 Node* const result = InternalPerformPromiseThen( 954 Node* const result = InternalPerformPromiseThen(
824 context, promise, on_resolve, on_reject, var_deferred.value()); 955 context, promise, on_resolve, on_reject, var_deferred.value());
825 Return(result); 956 Return(result);
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
898 1029
899 TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { 1030 TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) {
900 Node* const promise = Parameter(1); 1031 Node* const promise = Parameter(1);
901 Node* const value = Parameter(2); 1032 Node* const value = Parameter(2);
902 Node* const handler = Parameter(3); 1033 Node* const handler = Parameter(3);
903 Node* const deferred = Parameter(4); 1034 Node* const deferred = Parameter(4);
904 Node* const context = Parameter(7); 1035 Node* const context = Parameter(7);
905 Isolate* isolate = this->isolate(); 1036 Isolate* isolate = this->isolate();
906 1037
907 // Get promise from deferred 1038 // Get promise from deferred
908 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. 1039 CSA_ASSERT(this, HasInstanceType(deferred, JS_PROMISE_CAPABILITY_TYPE));
909 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
910 Node* const key = HeapConstant(isolate->factory()->promise_string());
911 Node* const deferred_promise = 1040 Node* const deferred_promise =
912 CallStub(getproperty_callable, context, deferred, key); 1041 LoadObjectField(deferred, JSPromiseCapability::kPromiseOffset);
913 1042
914 Variable var_reason(this, MachineRepresentation::kTagged); 1043 Variable var_reason(this, MachineRepresentation::kTagged);
915 1044
916 Node* const is_debug_active = IsDebugActive(); 1045 Node* const is_debug_active = IsDebugActive();
917 Label run_handler(this), if_rejectpromise(this), promisehook_before(this), 1046 Label run_handler(this), if_rejectpromise(this), promisehook_before(this),
918 promisehook_after(this), debug_pop(this); 1047 promisehook_after(this), debug_pop(this);
919 1048
920 GotoUnless(is_debug_active, &promisehook_before); 1049 GotoUnless(is_debug_active, &promisehook_before);
921 CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); 1050 CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise);
922 Goto(&promisehook_before); 1051 Goto(&promisehook_before);
923 1052
924 Bind(&promisehook_before); 1053 Bind(&promisehook_before);
925 { 1054 {
926 GotoUnless(IsPromiseHookEnabled(), &run_handler); 1055 GotoUnless(IsPromiseHookEnabled(), &run_handler);
927 CallRuntime(Runtime::kPromiseHookBefore, context, promise); 1056 CallRuntime(Runtime::kPromiseHookBefore, context, promise);
928 Goto(&run_handler); 1057 Goto(&run_handler);
929 } 1058 }
930 1059
931 Bind(&run_handler); 1060 Bind(&run_handler);
932 { 1061 {
933 Callable call_callable = CodeFactory::Call(isolate); 1062 Callable call_callable = CodeFactory::Call(isolate);
934 1063
935 Node* const result = 1064 Node* const result =
936 CallJS(call_callable, context, handler, UndefinedConstant(), value); 1065 CallJS(call_callable, context, handler, UndefinedConstant(), value);
937 1066
938 GotoIfException(result, &if_rejectpromise, &var_reason); 1067 GotoIfException(result, &if_rejectpromise, &var_reason);
939 1068
940 // TODO(gsathya): Remove this lookup by getting rid of the deferred object.
941 Node* const key = HeapConstant(isolate->factory()->resolve_string());
942 Node* const on_resolve = 1069 Node* const on_resolve =
943 CallStub(getproperty_callable, context, deferred, key); 1070 LoadObjectField(deferred, JSPromiseCapability::kResolveOffset);
944 1071
945 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); 1072 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred);
946 Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); 1073 Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler);
947 1074
948 Bind(&if_internalhandler); 1075 Bind(&if_internalhandler);
949 InternalResolvePromise(context, deferred_promise, result, 1076 InternalResolvePromise(context, deferred_promise, result,
950 &promisehook_after); 1077 &promisehook_after);
951 1078
952 Bind(&if_customhandler); 1079 Bind(&if_customhandler);
953 { 1080 {
954 Node* const maybe_exception = CallJS(call_callable, context, on_resolve, 1081 Node* const maybe_exception = CallJS(call_callable, context, on_resolve,
955 UndefinedConstant(), result); 1082 UndefinedConstant(), result);
956 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); 1083 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason);
957 Goto(&promisehook_after); 1084 Goto(&promisehook_after);
958 } 1085 }
959 } 1086 }
960 1087
961 Bind(&if_rejectpromise); 1088 Bind(&if_rejectpromise);
962 { 1089 {
963 // TODO(gsathya): Remove this lookup by getting rid of the deferred object.
964 Node* const key = HeapConstant(isolate->factory()->reject_string());
965 Node* const on_reject = 1090 Node* const on_reject =
966 CallStub(getproperty_callable, context, deferred, key); 1091 LoadObjectField(deferred, JSPromiseCapability::kRejectOffset);
967 1092
968 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); 1093 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate);
969 CallStub(promise_handle_reject, context, deferred_promise, on_reject, 1094 CallStub(promise_handle_reject, context, deferred_promise, on_reject,
970 var_reason.value()); 1095 var_reason.value());
971 Goto(&promisehook_after); 1096 Goto(&promisehook_after);
972 } 1097 }
973 1098
974 Bind(&promisehook_after); 1099 Bind(&promisehook_after);
975 { 1100 {
976 GotoUnless(IsPromiseHookEnabled(), &debug_pop); 1101 GotoUnless(IsPromiseHookEnabled(), &debug_pop);
977 CallRuntime(Runtime::kPromiseHookAfter, context, promise); 1102 CallRuntime(Runtime::kPromiseHookAfter, context, promise);
978 Goto(&debug_pop); 1103 Goto(&debug_pop);
979 } 1104 }
980 1105
981 Bind(&debug_pop); 1106 Bind(&debug_pop);
982 { 1107 {
983 Label out(this); 1108 Label out(this);
984 1109
985 GotoUnless(is_debug_active, &out); 1110 GotoUnless(is_debug_active, &out);
986 CallRuntime(Runtime::kDebugPopPromise, context); 1111 CallRuntime(Runtime::kDebugPopPromise, context);
987 Goto(&out); 1112 Goto(&out);
988 1113
989 Bind(&out); 1114 Bind(&out);
990 Return(UndefinedConstant()); 1115 Return(UndefinedConstant());
991 } 1116 }
992 } 1117 }
993 1118
1119 TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
1120 Node* const resolve = Parameter(1);
1121 Node* const reject = Parameter(2);
1122 Node* const context = Parameter(5);
1123
1124 Node* const capability = LoadContextElement(
1125 context, GetPromiseCapabilityExecutor::kCapabilitySlot);
1126
1127 Label if_alreadyinvoked(this, Label::kDeferred);
1128 GotoIf(WordNotEqual(
1129 LoadObjectField(capability, JSPromiseCapability::kResolveOffset),
1130 UndefinedConstant()),
1131 &if_alreadyinvoked);
1132 GotoIf(WordNotEqual(
1133 LoadObjectField(capability, JSPromiseCapability::kRejectOffset),
1134 UndefinedConstant()),
1135 &if_alreadyinvoked);
1136
1137 StoreObjectField(capability, JSPromiseCapability::kResolveOffset, resolve);
1138 StoreObjectField(capability, JSPromiseCapability::kRejectOffset, reject);
1139
1140 Return(UndefinedConstant());
1141
1142 Bind(&if_alreadyinvoked);
1143 Node* message = SmiConstant(MessageTemplate::kPromiseExecutorAlreadyInvoked);
1144 Return(CallRuntime(Runtime::kThrowTypeError, context, message));
1145 }
1146
1147 TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
1148 Node* constructor = Parameter(1);
1149 Node* debug_event = Parameter(2);
1150 Node* context = Parameter(5);
1151
1152 CSA_ASSERT_JS_ARGC_EQ(this, 2);
1153
1154 Return(NewPromiseCapability(context, constructor, debug_event));
1155 }
1156
1157 TF_BUILTIN(NewInternalPromiseCapability, PromiseBuiltinsAssembler) {
1158 Node* parent = Parameter(1);
1159 Node* context = Parameter(4);
1160 CSA_ASSERT_JS_ARGC_EQ(this, 1);
1161
1162 Return(NewInternalPromiseCapability(context, parent));
1163 }
1164
994 } // namespace internal 1165 } // namespace internal
995 } // namespace v8 1166 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698