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-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.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-reject-functions | 14 // ES#sec-promise-reject-functions |
15 // Promise Reject Functions | 15 // Promise Reject Functions |
16 BUILTIN(PromiseRejectClosure) { | 16 BUILTIN(PromiseRejectClosure) { |
17 HandleScope scope(isolate); | 17 HandleScope scope(isolate); |
18 | 18 |
19 Handle<Context> context(isolate->context(), isolate); | 19 Handle<Context> context(isolate->context(), isolate); |
20 | 20 |
21 if (PromiseUtils::HasAlreadyVisited(context)) { | 21 if (PromiseUtils::HasAlreadyVisited(context)) { |
22 return isolate->heap()->undefined_value(); | 22 return isolate->heap()->undefined_value(); |
23 } | 23 } |
24 | 24 |
25 PromiseUtils::SetAlreadyVisited(context); | 25 PromiseUtils::SetAlreadyVisited(context); |
26 Handle<Object> value = args.atOrUndefined(isolate, 1); | 26 Handle<Object> value = args.atOrUndefined(isolate, 1); |
27 Handle<JSObject> promise = handle(PromiseUtils::GetPromise(context), isolate); | 27 Handle<JSPromise> promise = |
| 28 handle(PromiseUtils::GetPromise(context), isolate); |
28 Handle<Object> debug_event = | 29 Handle<Object> debug_event = |
29 handle(PromiseUtils::GetDebugEvent(context), isolate); | 30 handle(PromiseUtils::GetDebugEvent(context), isolate); |
30 MaybeHandle<Object> maybe_result; | 31 MaybeHandle<Object> maybe_result; |
31 Handle<Object> argv[] = {promise, value, debug_event}; | 32 Handle<Object> argv[] = {promise, value, debug_event}; |
| 33 |
| 34 isolate->RunPromiseHook(PromiseHookType::kResolve, promise, |
| 35 isolate->factory()->undefined_value()); |
| 36 |
32 RETURN_FAILURE_ON_EXCEPTION( | 37 RETURN_FAILURE_ON_EXCEPTION( |
33 isolate, Execution::Call(isolate, isolate->promise_internal_reject(), | 38 isolate, Execution::Call(isolate, isolate->promise_internal_reject(), |
34 isolate->factory()->undefined_value(), | 39 isolate->factory()->undefined_value(), |
35 arraysize(argv), argv)); | 40 arraysize(argv), argv)); |
36 return isolate->heap()->undefined_value(); | 41 return isolate->heap()->undefined_value(); |
37 } | 42 } |
38 | 43 |
39 // ES#sec-createresolvingfunctions | 44 // ES#sec-createresolvingfunctions |
40 // CreateResolvingFunctions ( promise ) | 45 // CreateResolvingFunctions ( promise ) |
41 BUILTIN(CreateResolvingFunctions) { | 46 BUILTIN(CreateResolvingFunctions) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 &if_targetismodified); | 96 &if_targetismodified); |
92 | 97 |
93 Variable var_result(&a, MachineRepresentation::kTagged), | 98 Variable var_result(&a, MachineRepresentation::kTagged), |
94 var_reject_call(&a, MachineRepresentation::kTagged), | 99 var_reject_call(&a, MachineRepresentation::kTagged), |
95 var_reason(&a, MachineRepresentation::kTagged); | 100 var_reason(&a, MachineRepresentation::kTagged); |
96 | 101 |
97 a.Bind(&if_targetisnotmodified); | 102 a.Bind(&if_targetisnotmodified); |
98 { | 103 { |
99 Node* const instance = a.AllocateJSPromise(context); | 104 Node* const instance = a.AllocateJSPromise(context); |
100 var_result.Bind(instance); | 105 var_result.Bind(instance); |
| 106 a.GotoUnless(a.IsPromiseHookEnabled(), &init); |
| 107 a.CallRuntime(Runtime::kPromiseHookInit, context, instance, |
| 108 a.UndefinedConstant()); |
101 a.Goto(&init); | 109 a.Goto(&init); |
102 } | 110 } |
103 | 111 |
104 a.Bind(&if_targetismodified); | 112 a.Bind(&if_targetismodified); |
105 { | 113 { |
106 Callable fast_new_object_stub = CodeFactory::FastNewObject(isolate); | 114 Callable fast_new_object_stub = CodeFactory::FastNewObject(isolate); |
107 Node* const instance = | 115 Node* const instance = |
108 a.CallStub(fast_new_object_stub, context, promise_fun, new_target); | 116 a.CallStub(fast_new_object_stub, context, promise_fun, new_target); |
109 | 117 |
110 var_result.Bind(instance); | 118 var_result.Bind(instance); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 Node* const message_id = | 182 Node* const message_id = |
175 a.SmiConstant(MessageTemplate::kResolverNotAFunction); | 183 a.SmiConstant(MessageTemplate::kResolverNotAFunction); |
176 a.CallRuntime(Runtime::kThrowTypeError, context, message_id, executor); | 184 a.CallRuntime(Runtime::kThrowTypeError, context, message_id, executor); |
177 a.Return(a.UndefinedConstant()); // Never reached. | 185 a.Return(a.UndefinedConstant()); // Never reached. |
178 } | 186 } |
179 } | 187 } |
180 | 188 |
181 void Builtins::Generate_PromiseInternalConstructor( | 189 void Builtins::Generate_PromiseInternalConstructor( |
182 compiler::CodeAssemblerState* state) { | 190 compiler::CodeAssemblerState* state) { |
183 typedef compiler::Node Node; | 191 typedef compiler::Node Node; |
| 192 typedef CodeStubAssembler::Label Label; |
184 CodeStubAssembler a(state); | 193 CodeStubAssembler a(state); |
185 | 194 |
186 Node* const context = a.Parameter(3); | 195 Node* const parent = a.Parameter(1); |
| 196 Node* const context = a.Parameter(4); |
187 Node* const instance = a.AllocateJSPromise(context); | 197 Node* const instance = a.AllocateJSPromise(context); |
188 a.PromiseInit(instance); | 198 a.PromiseInit(instance); |
| 199 |
| 200 Label out(&a); |
| 201 a.GotoUnless(a.IsPromiseHookEnabled(), &out); |
| 202 a.CallRuntime(Runtime::kPromiseHookInit, context, instance, parent); |
| 203 a.Goto(&out); |
| 204 a.Bind(&out); |
189 a.Return(instance); | 205 a.Return(instance); |
190 } | 206 } |
191 | 207 |
192 void Builtins::Generate_PromiseCreateAndSet( | 208 void Builtins::Generate_PromiseCreateAndSet( |
193 compiler::CodeAssemblerState* state) { | 209 compiler::CodeAssemblerState* state) { |
194 typedef compiler::Node Node; | 210 typedef compiler::Node Node; |
| 211 typedef CodeStubAssembler::Label Label; |
195 CodeStubAssembler a(state); | 212 CodeStubAssembler a(state); |
196 | 213 |
197 Node* const status = a.Parameter(1); | 214 Node* const status = a.Parameter(1); |
198 Node* const result = a.Parameter(2); | 215 Node* const result = a.Parameter(2); |
199 Node* const context = a.Parameter(5); | 216 Node* const context = a.Parameter(5); |
200 | 217 |
201 Node* const instance = a.AllocateJSPromise(context); | 218 Node* const instance = a.AllocateJSPromise(context); |
202 a.PromiseSet(instance, status, result); | 219 a.PromiseSet(instance, status, result); |
| 220 |
| 221 Label out(&a); |
| 222 a.GotoUnless(a.IsPromiseHookEnabled(), &out); |
| 223 a.CallRuntime(Runtime::kPromiseHookInit, context, instance, |
| 224 a.UndefinedConstant()); |
| 225 a.Goto(&out); |
| 226 a.Bind(&out); |
203 a.Return(instance); | 227 a.Return(instance); |
204 } | 228 } |
205 | 229 |
206 namespace { | 230 namespace { |
207 | 231 |
208 compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, | 232 compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
209 compiler::Node* context, | 233 compiler::Node* context, |
210 compiler::Node* value, | 234 compiler::Node* value, |
211 MessageTemplate::Template msg_template) { | 235 MessageTemplate::Template msg_template) { |
212 typedef compiler::Node Node; | 236 typedef compiler::Node Node; |
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
597 | 621 |
598 // TODO(gsathya): Remove deferred object and move | 622 // TODO(gsathya): Remove deferred object and move |
599 // NewPromiseCapbability functions to TF. | 623 // NewPromiseCapbability functions to TF. |
600 a.Bind(&fast_promise_capability); | 624 a.Bind(&fast_promise_capability); |
601 { | 625 { |
602 // TODO(gsathya): Move this to TF. | 626 // TODO(gsathya): Move this to TF. |
603 Node* const promise_internal_capability = a.LoadContextElement( | 627 Node* const promise_internal_capability = a.LoadContextElement( |
604 native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX); | 628 native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX); |
605 Node* const capability = | 629 Node* const capability = |
606 a.CallJS(call_callable, context, promise_internal_capability, | 630 a.CallJS(call_callable, context, promise_internal_capability, |
607 a.UndefinedConstant()); | 631 a.UndefinedConstant(), promise); |
608 var_deferred.Bind(capability); | 632 var_deferred.Bind(capability); |
609 a.Goto(&perform_promise_then); | 633 a.Goto(&perform_promise_then); |
610 } | 634 } |
611 | 635 |
612 a.Bind(&promise_capability); | 636 a.Bind(&promise_capability); |
613 { | 637 { |
614 // TODO(gsathya): Move this to TF. | 638 // TODO(gsathya): Move this to TF. |
615 Node* const new_promise_capability = a.LoadContextElement( | 639 Node* const new_promise_capability = a.LoadContextElement( |
616 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); | 640 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); |
617 Node* const capability = | 641 Node* const capability = |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
839 // 4. If alreadyResolved.[[Value]] is true, return undefined. | 863 // 4. If alreadyResolved.[[Value]] is true, return undefined. |
840 a.GotoIf(a.SmiEqual(has_already_visited, a.SmiConstant(1)), &out); | 864 a.GotoIf(a.SmiEqual(has_already_visited, a.SmiConstant(1)), &out); |
841 | 865 |
842 // 5.Set alreadyResolved.[[Value]] to true. | 866 // 5.Set alreadyResolved.[[Value]] to true. |
843 a.StoreFixedArrayElement(context, has_already_visited_slot, a.SmiConstant(1)); | 867 a.StoreFixedArrayElement(context, has_already_visited_slot, a.SmiConstant(1)); |
844 | 868 |
845 // 2. Let promise be F.[[Promise]]. | 869 // 2. Let promise be F.[[Promise]]. |
846 Node* const promise = a.LoadFixedArrayElement( | 870 Node* const promise = a.LoadFixedArrayElement( |
847 context, a.IntPtrConstant(PromiseUtils::kPromiseSlot)); | 871 context, a.IntPtrConstant(PromiseUtils::kPromiseSlot)); |
848 | 872 |
| 873 Label run_resolve(&a); |
| 874 a.GotoUnless(a.IsPromiseHookEnabled(), &run_resolve); |
| 875 a.CallRuntime(Runtime::kPromiseHookResolve, context, promise); |
| 876 a.Goto(&run_resolve); |
| 877 |
| 878 a.Bind(&run_resolve); |
849 InternalResolvePromise(&a, context, promise, value, &out); | 879 InternalResolvePromise(&a, context, promise, value, &out); |
850 | 880 |
851 a.Bind(&out); | 881 a.Bind(&out); |
852 a.Return(a.UndefinedConstant()); | 882 a.Return(a.UndefinedConstant()); |
853 } | 883 } |
854 | 884 |
855 void Builtins::Generate_ResolvePromise(compiler::CodeAssemblerState* state) { | 885 void Builtins::Generate_ResolvePromise(compiler::CodeAssemblerState* state) { |
856 CodeStubAssembler a(state); | 886 CodeStubAssembler a(state); |
857 typedef compiler::Node Node; | 887 typedef compiler::Node Node; |
858 typedef CodeStubAssembler::Label Label; | 888 typedef CodeStubAssembler::Label Label; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
902 a.Return(a.UndefinedConstant()); | 932 a.Return(a.UndefinedConstant()); |
903 } | 933 } |
904 } | 934 } |
905 | 935 |
906 void Builtins::Generate_PromiseHandle(compiler::CodeAssemblerState* state) { | 936 void Builtins::Generate_PromiseHandle(compiler::CodeAssemblerState* state) { |
907 CodeStubAssembler a(state); | 937 CodeStubAssembler a(state); |
908 typedef compiler::Node Node; | 938 typedef compiler::Node Node; |
909 typedef CodeStubAssembler::Label Label; | 939 typedef CodeStubAssembler::Label Label; |
910 typedef CodeStubAssembler::Variable Variable; | 940 typedef CodeStubAssembler::Variable Variable; |
911 | 941 |
| 942 Node* const promise = a.Parameter(1); |
912 Node* const value = a.Parameter(2); | 943 Node* const value = a.Parameter(2); |
913 Node* const handler = a.Parameter(3); | 944 Node* const handler = a.Parameter(3); |
914 Node* const deferred = a.Parameter(4); | 945 Node* const deferred = a.Parameter(4); |
915 Node* const context = a.Parameter(7); | 946 Node* const context = a.Parameter(7); |
916 Isolate* isolate = a.isolate(); | 947 Isolate* isolate = a.isolate(); |
917 | 948 |
918 // Get promise from deferred | 949 // Get promise from deferred |
919 // 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. |
920 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | 951 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
921 Node* const key = a.HeapConstant(isolate->factory()->promise_string()); | 952 Node* const key = a.HeapConstant(isolate->factory()->promise_string()); |
922 Node* const deferred_promise = | 953 Node* const deferred_promise = |
923 a.CallStub(getproperty_callable, context, deferred, key); | 954 a.CallStub(getproperty_callable, context, deferred, key); |
924 | 955 |
925 Variable var_reason(&a, MachineRepresentation::kTagged); | 956 Variable var_reason(&a, MachineRepresentation::kTagged); |
926 | 957 |
927 Node* const is_debug_active = a.IsDebugActive(); | 958 Node* const is_debug_active = a.IsDebugActive(); |
928 Label run_handler(&a), if_rejectpromise(&a), debug_push(&a, Label::kDeferred), | 959 Label run_handler(&a), if_rejectpromise(&a), debug_push(&a, Label::kDeferred), |
929 debug_pop(&a, Label::kDeferred); | 960 debug_pop(&a), promisehook_after(&a); |
930 a.Branch(is_debug_active, &debug_push, &run_handler); | 961 |
| 962 a.GotoUnless(a.IsPromiseHookEnabled(), &debug_push); |
| 963 a.CallRuntime(Runtime::kPromiseHookBefore, context, promise); |
| 964 a.Goto(&debug_push); |
931 | 965 |
932 a.Bind(&debug_push); | 966 a.Bind(&debug_push); |
933 { | 967 { |
| 968 a.GotoUnless(is_debug_active, &run_handler); |
934 a.CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); | 969 a.CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); |
935 a.Goto(&run_handler); | 970 a.Goto(&run_handler); |
936 } | 971 } |
937 | 972 |
938 a.Bind(&run_handler); | 973 a.Bind(&run_handler); |
939 { | 974 { |
940 Callable call_callable = CodeFactory::Call(isolate); | 975 Callable call_callable = CodeFactory::Call(isolate); |
941 | 976 |
942 Node* const result = | 977 Node* const result = |
943 a.CallJS(call_callable, context, handler, a.UndefinedConstant(), value); | 978 a.CallJS(call_callable, context, handler, a.UndefinedConstant(), value); |
944 | 979 |
945 a.GotoIfException(result, &if_rejectpromise, &var_reason); | 980 a.GotoIfException(result, &if_rejectpromise, &var_reason); |
946 | 981 |
947 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | 982 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. |
948 Node* const key = a.HeapConstant(isolate->factory()->resolve_string()); | 983 Node* const key = a.HeapConstant(isolate->factory()->resolve_string()); |
949 Node* const on_resolve = | 984 Node* const on_resolve = |
950 a.CallStub(getproperty_callable, context, deferred, key); | 985 a.CallStub(getproperty_callable, context, deferred, key); |
951 | 986 |
952 Label if_internalhandler(&a), if_customhandler(&a, Label::kDeferred); | 987 Label if_internalhandler(&a), if_customhandler(&a, Label::kDeferred); |
953 a.Branch(a.IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); | 988 a.Branch(a.IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); |
954 | 989 |
955 a.Bind(&if_internalhandler); | 990 a.Bind(&if_internalhandler); |
956 InternalResolvePromise(&a, context, deferred_promise, result, &debug_pop); | 991 InternalResolvePromise(&a, context, deferred_promise, result, |
| 992 &promisehook_after); |
957 | 993 |
958 a.Bind(&if_customhandler); | 994 a.Bind(&if_customhandler); |
959 { | 995 { |
960 Node* const maybe_exception = a.CallJS(call_callable, context, on_resolve, | 996 Node* const maybe_exception = a.CallJS(call_callable, context, on_resolve, |
961 a.UndefinedConstant(), result); | 997 a.UndefinedConstant(), result); |
962 a.GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); | 998 a.GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); |
963 a.Goto(&debug_pop); | 999 a.Goto(&promisehook_after); |
964 } | 1000 } |
965 } | 1001 } |
966 | 1002 |
967 a.Bind(&if_rejectpromise); | 1003 a.Bind(&if_rejectpromise); |
968 { | 1004 { |
969 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | 1005 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. |
970 Node* const key = a.HeapConstant(isolate->factory()->reject_string()); | 1006 Node* const key = a.HeapConstant(isolate->factory()->reject_string()); |
971 Node* const on_reject = | 1007 Node* const on_reject = |
972 a.CallStub(getproperty_callable, context, deferred, key); | 1008 a.CallStub(getproperty_callable, context, deferred, key); |
973 | 1009 |
974 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); | 1010 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); |
975 a.CallStub(promise_handle_reject, context, deferred_promise, on_reject, | 1011 a.CallStub(promise_handle_reject, context, deferred_promise, on_reject, |
976 var_reason.value()); | 1012 var_reason.value()); |
| 1013 a.Goto(&promisehook_after); |
| 1014 } |
| 1015 |
| 1016 a.Bind(&promisehook_after); |
| 1017 { |
| 1018 a.GotoUnless(a.IsPromiseHookEnabled(), &debug_pop); |
| 1019 a.CallRuntime(Runtime::kPromiseHookAfter, context, promise); |
977 a.Goto(&debug_pop); | 1020 a.Goto(&debug_pop); |
978 } | 1021 } |
979 | 1022 |
980 a.Bind(&debug_pop); | 1023 a.Bind(&debug_pop); |
981 { | 1024 { |
982 Label out(&a); | 1025 Label out(&a); |
983 | |
984 a.GotoUnless(is_debug_active, &out); | 1026 a.GotoUnless(is_debug_active, &out); |
985 a.CallRuntime(Runtime::kDebugPopPromise, context); | 1027 a.CallRuntime(Runtime::kDebugPopPromise, context); |
986 a.Goto(&out); | 1028 a.Goto(&out); |
987 | 1029 |
988 a.Bind(&out); | 1030 a.Bind(&out); |
989 a.Return(a.UndefinedConstant()); | 1031 a.Return(a.UndefinedConstant()); |
990 } | 1032 } |
991 } | 1033 } |
992 | 1034 |
993 } // namespace internal | 1035 } // namespace internal |
994 } // namespace v8 | 1036 } // namespace v8 |
OLD | NEW |