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-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" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
56 AllocateFunctionWithMapAndContext(map, resolve_info, promise_context); | 56 AllocateFunctionWithMapAndContext(map, resolve_info, promise_context); |
57 Node* const reject_info = | 57 Node* const reject_info = |
58 LoadContextElement(native_context, Context::PROMISE_REJECT_SHARED_FUN); | 58 LoadContextElement(native_context, Context::PROMISE_REJECT_SHARED_FUN); |
59 Node* const reject = | 59 Node* const reject = |
60 AllocateFunctionWithMapAndContext(map, reject_info, promise_context); | 60 AllocateFunctionWithMapAndContext(map, reject_info, promise_context); |
61 | 61 |
62 return std::make_pair(resolve, reject); | 62 return std::make_pair(resolve, reject); |
63 } | 63 } |
64 | 64 |
65 Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver( | 65 Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver( |
66 Node* context, Node* value, MessageTemplate::Template msg_template) { | 66 Node* context, Node* value, MessageTemplate::Template msg_template, |
67 const char* method_name) { | |
67 Label out(this), throw_exception(this, Label::kDeferred); | 68 Label out(this), throw_exception(this, Label::kDeferred); |
68 Variable var_value_map(this, MachineRepresentation::kTagged); | 69 Variable var_value_map(this, MachineRepresentation::kTagged); |
69 | 70 |
70 GotoIf(TaggedIsSmi(value), &throw_exception); | 71 GotoIf(TaggedIsSmi(value), &throw_exception); |
71 | 72 |
72 // Load the instance type of the {value}. | 73 // Load the instance type of the {value}. |
73 var_value_map.Bind(LoadMap(value)); | 74 var_value_map.Bind(LoadMap(value)); |
74 Node* const value_instance_type = LoadMapInstanceType(var_value_map.value()); | 75 Node* const value_instance_type = LoadMapInstanceType(var_value_map.value()); |
75 | 76 |
76 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception); | 77 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception); |
77 | 78 |
78 // The {value} is not a compatible receiver for this method. | 79 // The {value} is not a compatible receiver for this method. |
79 Bind(&throw_exception); | 80 Bind(&throw_exception); |
80 { | 81 { |
82 Isolate* isolate = this->isolate(); | |
83 Node* method; | |
84 method = method_name == NULL | |
85 ? UndefinedConstant() | |
86 : HeapConstant(isolate->factory()->NewStringFromAsciiChecked( | |
87 method_name)); | |
88 | |
81 Node* const message_id = SmiConstant(msg_template); | 89 Node* const message_id = SmiConstant(msg_template); |
82 CallRuntime(Runtime::kThrowTypeError, context, message_id); | 90 CallRuntime(Runtime::kThrowTypeError, context, message_id, method); |
83 var_value_map.Bind(UndefinedConstant()); | 91 var_value_map.Bind(UndefinedConstant()); |
84 Goto(&out); // Never reached. | 92 Goto(&out); // Never reached. |
85 } | 93 } |
86 | 94 |
87 Bind(&out); | 95 Bind(&out); |
88 return var_value_map.value(); | 96 return var_value_map.value(); |
89 } | 97 } |
90 | 98 |
91 Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) { | 99 Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) { |
92 Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset); | 100 Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset); |
(...skipping 934 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1027 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | 1035 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
1028 Node* const then = | 1036 Node* const then = |
1029 CallStub(getproperty_callable, context, promise, then_str); | 1037 CallStub(getproperty_callable, context, promise, then_str); |
1030 Callable call_callable = CodeFactory::Call(isolate); | 1038 Callable call_callable = CodeFactory::Call(isolate); |
1031 Node* const result = | 1039 Node* const result = |
1032 CallJS(call_callable, context, then, promise, on_resolve, on_reject); | 1040 CallJS(call_callable, context, then, promise, on_resolve, on_reject); |
1033 Return(result); | 1041 Return(result); |
1034 } | 1042 } |
1035 } | 1043 } |
1036 | 1044 |
1045 TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) { | |
1046 // 1. Let C be the this value. | |
1047 Node* receiver = Parameter(0); | |
1048 Node* value = Parameter(1); | |
1049 Node* context = Parameter(4); | |
1050 Isolate* isolate = this->isolate(); | |
1051 | |
1052 // 2. If Type(C) is not Object, throw a TypeError exception. | |
1053 ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject, | |
1054 "PromiseResolve"); | |
1055 | |
1056 Label if_valueisnativepromise(this), if_valueisnotnativepromise(this), | |
1057 if_valueisnotpromise(this); | |
1058 | |
1059 // 3.If IsPromise(x) is true, then | |
1060 GotoIf(TaggedIsSmi(value), &if_valueisnotpromise); | |
1061 | |
1062 // This shortcircuits the constructor lookups. | |
1063 GotoUnless(HasInstanceType(value, JS_PROMISE_TYPE), &if_valueisnotpromise); | |
1064 | |
1065 // This adds a fast path as non-subclassed native promises don't have | |
1066 // an observable constructor lookup. | |
1067 BranchIfFastPath(context, value, &if_valueisnativepromise, | |
1068 &if_valueisnotnativepromise); | |
1069 | |
1070 Bind(&if_valueisnativepromise); | |
1071 { | |
1072 Node* const native_context = LoadNativeContext(context); | |
adamk
2016/12/22 19:39:35
Newbie question: Doesn't this duplicate the contex
Igor Sheludko
2016/12/27 14:30:28
Good point. Maybe BranchIfFastPath() should return
gsathya
2017/01/03 17:35:26
Added a BranchIfFastPath that accepts a native con
| |
1073 Node* const promise_fun = | |
1074 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); | |
1075 GotoUnless(WordEqual(promise_fun, receiver), &if_valueisnotnativepromise); | |
1076 Return(value); | |
1077 } | |
1078 | |
1079 // At this point, value or/and receiver are not native promises, but | |
1080 // they could be of the same subclass. | |
1081 Bind(&if_valueisnotnativepromise); | |
1082 { | |
1083 // 3.a Let xConstructor be ? Get(x, "constructor"). | |
1084 // The constructor lookup is observable. | |
1085 Node* const constructor_str = | |
1086 HeapConstant(isolate->factory()->constructor_string()); | |
1087 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
1088 Node* const constructor = | |
1089 CallStub(getproperty_callable, context, value, constructor_str); | |
1090 | |
1091 // 3.b If SameValue(xConstructor, C) is true, return x. | |
1092 GotoUnless(SameValue(constructor, receiver, context), | |
1093 &if_valueisnotpromise); | |
1094 | |
1095 Return(value); | |
1096 } | |
1097 | |
1098 Bind(&if_valueisnotpromise); | |
1099 { | |
1100 Label if_nativepromise(this), if_notnativepromise(this); | |
1101 BranchIfFastPath(context, receiver, &if_nativepromise, | |
1102 &if_notnativepromise); | |
1103 | |
1104 // This adds a fast path for native promises that don't need to | |
1105 // create NewPromiseCapability. | |
1106 Bind(&if_nativepromise); | |
1107 { | |
1108 Label do_resolve(this); | |
1109 | |
1110 Node* const result = AllocateJSPromise(context); | |
1111 PromiseInit(result); | |
1112 | |
1113 GotoUnless(IsPromiseHookEnabled(), &do_resolve); | |
1114 CallRuntime(Runtime::kPromiseHookInit, context, result, | |
1115 UndefinedConstant()); | |
1116 Goto(&do_resolve); | |
1117 | |
1118 Bind(&do_resolve); | |
1119 InternalResolvePromise(context, result, value); | |
1120 Return(result); | |
1121 } | |
1122 | |
1123 Bind(&if_notnativepromise); | |
1124 { | |
1125 Isolate* isolate = this->isolate(); | |
1126 Node* const native_context = LoadNativeContext(context); | |
adamk
2016/12/22 19:39:35
Possibly another newbie question: seems like this
gsathya
2017/01/03 17:35:25
Only certain code paths use the native_context so
| |
1127 | |
1128 // 4. Let promiseCapability be ? NewPromiseCapability(C). | |
1129 // TODO(gsathya): Move this to TF. | |
1130 Callable call_callable = CodeFactory::Call(isolate); | |
1131 Node* const new_promise_capability = LoadContextElement( | |
1132 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); | |
1133 // Should debug event be false? | |
1134 Node* const capability = | |
1135 CallJS(call_callable, context, new_promise_capability, | |
1136 UndefinedConstant(), receiver, TrueConstant()); | |
1137 | |
1138 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
1139 // 5. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »). | |
1140 Node* const resolve_str = | |
1141 HeapConstant(isolate->factory()->resolve_string()); | |
1142 Node* const resolve = | |
1143 CallStub(getproperty_callable, context, capability, resolve_str); | |
1144 CallJS(call_callable, context, resolve, UndefinedConstant(), value); | |
1145 | |
1146 // 6. Return promiseCapability.[[Promise]]. | |
1147 Node* const promise_str = | |
1148 HeapConstant(isolate->factory()->promise_string()); | |
1149 Node* const result = | |
1150 CallStub(getproperty_callable, context, capability, promise_str); | |
1151 Return(result); | |
1152 } | |
1153 } | |
1154 } | |
1155 | |
1037 } // namespace internal | 1156 } // namespace internal |
1038 } // namespace v8 | 1157 } // namespace v8 |
OLD | NEW |