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-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 |