| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/interpreter/interpreter-intrinsics.h" | 5 #include "src/interpreter/interpreter-intrinsics.h" |
| 6 | 6 |
| 7 #include "src/code-factory.h" | 7 #include "src/base/logging.h" |
| 8 #include "src/objects-inl.h" | |
| 9 | 8 |
| 10 namespace v8 { | 9 namespace v8 { |
| 11 namespace internal { | 10 namespace internal { |
| 12 namespace interpreter { | 11 namespace interpreter { |
| 13 | 12 |
| 14 using compiler::Node; | |
| 15 | |
| 16 #define __ assembler_-> | |
| 17 | |
| 18 IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler) | |
| 19 : isolate_(assembler->isolate()), | |
| 20 zone_(assembler->zone()), | |
| 21 assembler_(assembler) {} | |
| 22 | |
| 23 // static | 13 // static |
| 24 bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) { | 14 bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) { |
| 25 switch (function_id) { | 15 switch (function_id) { |
| 26 #define SUPPORTED(name, lower_case, count) case Runtime::kInline##name: | 16 #define SUPPORTED(name, lower_case, count) case Runtime::kInline##name: |
| 27 INTRINSICS_LIST(SUPPORTED) | 17 INTRINSICS_LIST(SUPPORTED) |
| 28 return true; | 18 return true; |
| 29 #undef SUPPORTED | 19 #undef SUPPORTED |
| 30 default: | 20 default: |
| 31 return false; | 21 return false; |
| 32 } | 22 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 55 case IntrinsicId::k##name: \ | 45 case IntrinsicId::k##name: \ |
| 56 return Runtime::kInline##name; | 46 return Runtime::kInline##name; |
| 57 INTRINSICS_LIST(TO_INTRINSIC_ID) | 47 INTRINSICS_LIST(TO_INTRINSIC_ID) |
| 58 #undef TO_INTRINSIC_ID | 48 #undef TO_INTRINSIC_ID |
| 59 default: | 49 default: |
| 60 UNREACHABLE(); | 50 UNREACHABLE(); |
| 61 return static_cast<Runtime::FunctionId>(-1); | 51 return static_cast<Runtime::FunctionId>(-1); |
| 62 } | 52 } |
| 63 } | 53 } |
| 64 | 54 |
| 65 Node* IntrinsicsHelper::InvokeIntrinsic(Node* function_id, Node* context, | |
| 66 Node* first_arg_reg, Node* arg_count) { | |
| 67 InterpreterAssembler::Label abort(assembler_), end(assembler_); | |
| 68 InterpreterAssembler::Variable result(assembler_, | |
| 69 MachineRepresentation::kTagged); | |
| 70 | |
| 71 #define MAKE_LABEL(name, lower_case, count) \ | |
| 72 InterpreterAssembler::Label lower_case(assembler_); | |
| 73 INTRINSICS_LIST(MAKE_LABEL) | |
| 74 #undef MAKE_LABEL | |
| 75 | |
| 76 #define LABEL_POINTER(name, lower_case, count) &lower_case, | |
| 77 InterpreterAssembler::Label* labels[] = {INTRINSICS_LIST(LABEL_POINTER)}; | |
| 78 #undef LABEL_POINTER | |
| 79 | |
| 80 #define CASE(name, lower_case, count) \ | |
| 81 static_cast<int32_t>(IntrinsicId::k##name), | |
| 82 int32_t cases[] = {INTRINSICS_LIST(CASE)}; | |
| 83 #undef CASE | |
| 84 | |
| 85 __ Switch(function_id, &abort, cases, labels, arraysize(cases)); | |
| 86 #define HANDLE_CASE(name, lower_case, expected_arg_count) \ | |
| 87 __ Bind(&lower_case); \ | |
| 88 if (FLAG_debug_code && expected_arg_count >= 0) { \ | |
| 89 AbortIfArgCountMismatch(expected_arg_count, arg_count); \ | |
| 90 } \ | |
| 91 result.Bind(name(first_arg_reg, arg_count, context)); \ | |
| 92 __ Goto(&end); | |
| 93 INTRINSICS_LIST(HANDLE_CASE) | |
| 94 #undef HANDLE_CASE | |
| 95 | |
| 96 __ Bind(&abort); | |
| 97 { | |
| 98 __ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic); | |
| 99 result.Bind(__ UndefinedConstant()); | |
| 100 __ Goto(&end); | |
| 101 } | |
| 102 | |
| 103 __ Bind(&end); | |
| 104 return result.value(); | |
| 105 } | |
| 106 | |
| 107 Node* IntrinsicsHelper::CompareInstanceType(Node* object, int type, | |
| 108 InstanceTypeCompareMode mode) { | |
| 109 Node* instance_type = __ LoadInstanceType(object); | |
| 110 | |
| 111 if (mode == kInstanceTypeEqual) { | |
| 112 return __ Word32Equal(instance_type, __ Int32Constant(type)); | |
| 113 } else { | |
| 114 DCHECK(mode == kInstanceTypeGreaterThanOrEqual); | |
| 115 return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type)); | |
| 116 } | |
| 117 } | |
| 118 | |
| 119 Node* IntrinsicsHelper::IsInstanceType(Node* input, int type) { | |
| 120 InterpreterAssembler::Variable return_value(assembler_, | |
| 121 MachineRepresentation::kTagged); | |
| 122 // TODO(ishell): Use Select here. | |
| 123 InterpreterAssembler::Label if_not_smi(assembler_), return_true(assembler_), | |
| 124 return_false(assembler_), end(assembler_); | |
| 125 Node* arg = __ LoadRegister(input); | |
| 126 __ GotoIf(__ TaggedIsSmi(arg), &return_false); | |
| 127 | |
| 128 Node* condition = CompareInstanceType(arg, type, kInstanceTypeEqual); | |
| 129 __ Branch(condition, &return_true, &return_false); | |
| 130 | |
| 131 __ Bind(&return_true); | |
| 132 { | |
| 133 return_value.Bind(__ BooleanConstant(true)); | |
| 134 __ Goto(&end); | |
| 135 } | |
| 136 | |
| 137 __ Bind(&return_false); | |
| 138 { | |
| 139 return_value.Bind(__ BooleanConstant(false)); | |
| 140 __ Goto(&end); | |
| 141 } | |
| 142 | |
| 143 __ Bind(&end); | |
| 144 return return_value.value(); | |
| 145 } | |
| 146 | |
| 147 Node* IntrinsicsHelper::IsJSReceiver(Node* input, Node* arg_count, | |
| 148 Node* context) { | |
| 149 // TODO(ishell): Use Select here. | |
| 150 // TODO(ishell): Use CSA::IsJSReceiverInstanceType here. | |
| 151 InterpreterAssembler::Variable return_value(assembler_, | |
| 152 MachineRepresentation::kTagged); | |
| 153 InterpreterAssembler::Label return_true(assembler_), return_false(assembler_), | |
| 154 end(assembler_); | |
| 155 | |
| 156 Node* arg = __ LoadRegister(input); | |
| 157 __ GotoIf(__ TaggedIsSmi(arg), &return_false); | |
| 158 | |
| 159 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | |
| 160 Node* condition = CompareInstanceType(arg, FIRST_JS_RECEIVER_TYPE, | |
| 161 kInstanceTypeGreaterThanOrEqual); | |
| 162 __ Branch(condition, &return_true, &return_false); | |
| 163 | |
| 164 __ Bind(&return_true); | |
| 165 { | |
| 166 return_value.Bind(__ BooleanConstant(true)); | |
| 167 __ Goto(&end); | |
| 168 } | |
| 169 | |
| 170 __ Bind(&return_false); | |
| 171 { | |
| 172 return_value.Bind(__ BooleanConstant(false)); | |
| 173 __ Goto(&end); | |
| 174 } | |
| 175 | |
| 176 __ Bind(&end); | |
| 177 return return_value.value(); | |
| 178 } | |
| 179 | |
| 180 Node* IntrinsicsHelper::IsArray(Node* input, Node* arg_count, Node* context) { | |
| 181 return IsInstanceType(input, JS_ARRAY_TYPE); | |
| 182 } | |
| 183 | |
| 184 Node* IntrinsicsHelper::IsJSProxy(Node* input, Node* arg_count, Node* context) { | |
| 185 return IsInstanceType(input, JS_PROXY_TYPE); | |
| 186 } | |
| 187 | |
| 188 Node* IntrinsicsHelper::IsTypedArray(Node* input, Node* arg_count, | |
| 189 Node* context) { | |
| 190 return IsInstanceType(input, JS_TYPED_ARRAY_TYPE); | |
| 191 } | |
| 192 | |
| 193 Node* IntrinsicsHelper::IsSmi(Node* input, Node* arg_count, Node* context) { | |
| 194 // TODO(ishell): Use SelectBooleanConstant here. | |
| 195 InterpreterAssembler::Variable return_value(assembler_, | |
| 196 MachineRepresentation::kTagged); | |
| 197 InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_), | |
| 198 end(assembler_); | |
| 199 | |
| 200 Node* arg = __ LoadRegister(input); | |
| 201 | |
| 202 __ Branch(__ TaggedIsSmi(arg), &if_smi, &if_not_smi); | |
| 203 __ Bind(&if_smi); | |
| 204 { | |
| 205 return_value.Bind(__ BooleanConstant(true)); | |
| 206 __ Goto(&end); | |
| 207 } | |
| 208 | |
| 209 __ Bind(&if_not_smi); | |
| 210 { | |
| 211 return_value.Bind(__ BooleanConstant(false)); | |
| 212 __ Goto(&end); | |
| 213 } | |
| 214 | |
| 215 __ Bind(&end); | |
| 216 return return_value.value(); | |
| 217 } | |
| 218 | |
| 219 Node* IntrinsicsHelper::IntrinsicAsStubCall(Node* args_reg, Node* context, | |
| 220 Callable const& callable) { | |
| 221 int param_count = callable.descriptor().GetParameterCount(); | |
| 222 int input_count = param_count + 2; // +2 for target and context | |
| 223 Node** args = zone()->NewArray<Node*>(input_count); | |
| 224 int index = 0; | |
| 225 args[index++] = __ HeapConstant(callable.code()); | |
| 226 for (int i = 0; i < param_count; i++) { | |
| 227 args[index++] = __ LoadRegister(args_reg); | |
| 228 args_reg = __ NextRegister(args_reg); | |
| 229 } | |
| 230 args[index++] = context; | |
| 231 return __ CallStubN(callable.descriptor(), 1, input_count, args); | |
| 232 } | |
| 233 | |
| 234 Node* IntrinsicsHelper::CreateIterResultObject(Node* input, Node* arg_count, | |
| 235 Node* context) { | |
| 236 return IntrinsicAsStubCall(input, context, | |
| 237 CodeFactory::CreateIterResultObject(isolate())); | |
| 238 } | |
| 239 | |
| 240 Node* IntrinsicsHelper::HasProperty(Node* input, Node* arg_count, | |
| 241 Node* context) { | |
| 242 return IntrinsicAsStubCall(input, context, | |
| 243 CodeFactory::HasProperty(isolate())); | |
| 244 } | |
| 245 | |
| 246 Node* IntrinsicsHelper::SubString(Node* input, Node* arg_count, Node* context) { | |
| 247 return IntrinsicAsStubCall(input, context, CodeFactory::SubString(isolate())); | |
| 248 } | |
| 249 | |
| 250 Node* IntrinsicsHelper::ToString(Node* input, Node* arg_count, Node* context) { | |
| 251 return IntrinsicAsStubCall(input, context, CodeFactory::ToString(isolate())); | |
| 252 } | |
| 253 | |
| 254 Node* IntrinsicsHelper::ToLength(Node* input, Node* arg_count, Node* context) { | |
| 255 return IntrinsicAsStubCall(input, context, CodeFactory::ToLength(isolate())); | |
| 256 } | |
| 257 | |
| 258 Node* IntrinsicsHelper::ToInteger(Node* input, Node* arg_count, Node* context) { | |
| 259 return IntrinsicAsStubCall(input, context, CodeFactory::ToInteger(isolate())); | |
| 260 } | |
| 261 | |
| 262 Node* IntrinsicsHelper::ToNumber(Node* input, Node* arg_count, Node* context) { | |
| 263 return IntrinsicAsStubCall(input, context, CodeFactory::ToNumber(isolate())); | |
| 264 } | |
| 265 | |
| 266 Node* IntrinsicsHelper::ToObject(Node* input, Node* arg_count, Node* context) { | |
| 267 return IntrinsicAsStubCall(input, context, CodeFactory::ToObject(isolate())); | |
| 268 } | |
| 269 | |
| 270 Node* IntrinsicsHelper::Call(Node* args_reg, Node* arg_count, Node* context) { | |
| 271 // First argument register contains the function target. | |
| 272 Node* function = __ LoadRegister(args_reg); | |
| 273 | |
| 274 // Receiver is the second runtime call argument. | |
| 275 Node* receiver_reg = __ NextRegister(args_reg); | |
| 276 Node* receiver_arg = __ RegisterLocation(receiver_reg); | |
| 277 | |
| 278 // Subtract function and receiver from arg count. | |
| 279 Node* function_and_receiver_count = __ Int32Constant(2); | |
| 280 Node* target_args_count = __ Int32Sub(arg_count, function_and_receiver_count); | |
| 281 | |
| 282 if (FLAG_debug_code) { | |
| 283 InterpreterAssembler::Label arg_count_positive(assembler_); | |
| 284 Node* comparison = __ Int32LessThan(target_args_count, __ Int32Constant(0)); | |
| 285 __ GotoIfNot(comparison, &arg_count_positive); | |
| 286 __ Abort(kWrongArgumentCountForInvokeIntrinsic); | |
| 287 __ Goto(&arg_count_positive); | |
| 288 __ Bind(&arg_count_positive); | |
| 289 } | |
| 290 | |
| 291 Node* result = __ CallJS(function, context, receiver_arg, target_args_count, | |
| 292 TailCallMode::kDisallow); | |
| 293 return result; | |
| 294 } | |
| 295 | |
| 296 Node* IntrinsicsHelper::ClassOf(Node* args_reg, Node* arg_count, | |
| 297 Node* context) { | |
| 298 Node* value = __ LoadRegister(args_reg); | |
| 299 return __ ClassOf(value); | |
| 300 } | |
| 301 | |
| 302 Node* IntrinsicsHelper::CreateAsyncFromSyncIterator(Node* args_reg, | |
| 303 Node* arg_count, | |
| 304 Node* context) { | |
| 305 InterpreterAssembler::Label not_receiver( | |
| 306 assembler_, InterpreterAssembler::Label::kDeferred); | |
| 307 InterpreterAssembler::Label done(assembler_); | |
| 308 InterpreterAssembler::Variable return_value(assembler_, | |
| 309 MachineRepresentation::kTagged); | |
| 310 | |
| 311 Node* sync_iterator = __ LoadRegister(args_reg); | |
| 312 | |
| 313 __ GotoIf(__ TaggedIsSmi(sync_iterator), ¬_receiver); | |
| 314 __ GotoIfNot(__ IsJSReceiver(sync_iterator), ¬_receiver); | |
| 315 | |
| 316 Node* const native_context = __ LoadNativeContext(context); | |
| 317 Node* const map = __ LoadContextElement( | |
| 318 native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX); | |
| 319 Node* const iterator = __ AllocateJSObjectFromMap(map); | |
| 320 | |
| 321 __ StoreObjectFieldNoWriteBarrier( | |
| 322 iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator); | |
| 323 | |
| 324 return_value.Bind(iterator); | |
| 325 __ Goto(&done); | |
| 326 | |
| 327 __ Bind(¬_receiver); | |
| 328 { | |
| 329 return_value.Bind( | |
| 330 __ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context)); | |
| 331 | |
| 332 // Unreachable due to the Throw in runtime call. | |
| 333 __ Goto(&done); | |
| 334 } | |
| 335 | |
| 336 __ Bind(&done); | |
| 337 return return_value.value(); | |
| 338 } | |
| 339 | |
| 340 void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) { | |
| 341 InterpreterAssembler::Label match(assembler_); | |
| 342 Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected)); | |
| 343 __ GotoIf(comparison, &match); | |
| 344 __ Abort(kWrongArgumentCountForInvokeIntrinsic); | |
| 345 __ Goto(&match); | |
| 346 __ Bind(&match); | |
| 347 } | |
| 348 | |
| 349 } // namespace interpreter | 55 } // namespace interpreter |
| 350 } // namespace internal | 56 } // namespace internal |
| 351 } // namespace v8 | 57 } // namespace v8 |
| OLD | NEW |