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 3 // found in the LICENSE file. 4 5 #include "src/interpreter/interpreter-intrinsics.h" 6 7 #include "src/code-factory.h" 8 9 namespace v8 { 10 namespace internal { 11 namespace interpreter { 12 13 using compiler::Node; 14 15 #define __ assembler_-> 16 17 IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler) 18 : isolate_(assembler->isolate()), 19 zone_(assembler->zone()), 20 assembler_(assembler) {} 21 22 // static 23 bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) { 24 switch (function_id) { 25 #define SUPPORTED(name, lower_case, count) case Runtime::kInline##name: 26 INTRINSICS_LIST(SUPPORTED) 27 return true; 28 #undef SUPPORTED 29 default: 30 return false; 31 } 32 } 33 34 // static 35 IntrinsicsHelper::IntrinsicId IntrinsicsHelper::FromRuntimeId( 36 Runtime::FunctionId function_id) { 37 switch (function_id) { 38 #define TO_RUNTIME_ID(name, lower_case, count) \ 39 case Runtime::kInline##name: \ 40 return IntrinsicId::k##name; 41 INTRINSICS_LIST(TO_RUNTIME_ID) 42 #undef TO_RUNTIME_ID 43 default: 44 UNREACHABLE(); 45 return static_cast<IntrinsicsHelper::IntrinsicId>(-1); 46 } 47 } 48 49 // static 50 Runtime::FunctionId IntrinsicsHelper::ToRuntimeId( 51 IntrinsicsHelper::IntrinsicId intrinsic_id) { 52 switch (intrinsic_id) { 53 #define TO_INTRINSIC_ID(name, lower_case, count) \ 54 case IntrinsicId::k##name: \ 55 return Runtime::kInline##name; 56 INTRINSICS_LIST(TO_INTRINSIC_ID) 57 #undef TO_INTRINSIC_ID 58 default: 59 UNREACHABLE(); 60 return static_cast<Runtime::FunctionId>(-1); 61 } 62 } 63 64 Node* IntrinsicsHelper::InvokeIntrinsic(Node* function_id, Node* context, 65 Node* first_arg_reg, Node* arg_count) { 66 InterpreterAssembler::Label abort(assembler_), end(assembler_); 67 InterpreterAssembler::Variable result(assembler_, 68 MachineRepresentation::kTagged); 69 70 #define MAKE_LABEL(name, lower_case, count) \ 71 InterpreterAssembler::Label lower_case(assembler_); 72 INTRINSICS_LIST(MAKE_LABEL) 73 #undef MAKE_LABEL 74 75 #define LABEL_POINTER(name, lower_case, count) &lower_case, 76 InterpreterAssembler::Label* labels[] = {INTRINSICS_LIST(LABEL_POINTER)}; 77 #undef LABEL_POINTER 78 79 #define CASE(name, lower_case, count) \ 80 static_cast<int32_t>(IntrinsicId::k##name), 81 int32_t cases[] = {INTRINSICS_LIST(CASE)}; 82 #undef CASE 83 84 __ Switch(function_id, &abort, cases, labels, arraysize(cases)); 85 #define HANDLE_CASE(name, lower_case, expected_arg_count) \ 86 __ Bind(&lower_case); \ 87 if (FLAG_debug_code && expected_arg_count >= 0) { \ 88 AbortIfArgCountMismatch(expected_arg_count, arg_count); \ 89 } \ 90 result.Bind(name(first_arg_reg, arg_count, context)); \ 91 __ Goto(&end); 92 INTRINSICS_LIST(HANDLE_CASE) 93 #undef HANDLE_CASE 94 95 __ Bind(&abort); 96 { 97 __ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic); 98 result.Bind(__ UndefinedConstant()); 99 __ Goto(&end); 100 } 101 102 __ Bind(&end); 103 return result.value(); 104 } 105 106 Node* IntrinsicsHelper::CompareInstanceType(Node* map, int type, 107 InstanceTypeCompareMode mode) { 108 InterpreterAssembler::Variable return_value(assembler_, 109 MachineRepresentation::kTagged); 110 Node* instance_type = __ LoadInstanceType(map); 111 112 InterpreterAssembler::Label if_true(assembler_), if_false(assembler_), 113 end(assembler_); 114 if (mode == kInstanceTypeEqual) { 115 return __ Word32Equal(instance_type, __ Int32Constant(type)); 116 } else { 117 DCHECK(mode == kInstanceTypeGreaterThanOrEqual); 118 return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type)); 119 } 120 } 121 122 Node* IntrinsicsHelper::IsInstanceType(Node* input, int type) { 123 InterpreterAssembler::Variable return_value(assembler_, 124 MachineRepresentation::kTagged); 125 InterpreterAssembler::Label if_not_smi(assembler_), return_true(assembler_), 126 return_false(assembler_), end(assembler_); 127 Node* arg = __ LoadRegister(input); 128 __ GotoIf(__ WordIsSmi(arg), &return_false); 129 130 Node* condition = CompareInstanceType(arg, type, kInstanceTypeEqual); 131 __ Branch(condition, &return_true, &return_false); 132 133 __ Bind(&return_true); 134 { 135 return_value.Bind(__ BooleanConstant(true)); 136 __ Goto(&end); 137 } 138 139 __ Bind(&return_false); 140 { 141 return_value.Bind(__ BooleanConstant(false)); 142 __ Goto(&end); 143 } 144 145 __ Bind(&end); 146 return return_value.value(); 147 } 148 149 Node* IntrinsicsHelper::IsJSReceiver(Node* input, Node* arg_count, 150 Node* context) { 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(__ WordIsSmi(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::IsRegExp(Node* input, Node* arg_count, Node* context) { 189 return IsInstanceType(input, JS_REGEXP_TYPE); 190 } 191 192 Node* IntrinsicsHelper::IsTypedArray(Node* input, Node* arg_count, 193 Node* context) { 194 return IsInstanceType(input, JS_TYPED_ARRAY_TYPE); 195 } 196 197 Node* IntrinsicsHelper::IsSmi(Node* input, Node* arg_count, Node* context) { 198 InterpreterAssembler::Variable return_value(assembler_, 199 MachineRepresentation::kTagged); 200 InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_), 201 end(assembler_); 202 203 Node* arg = __ LoadRegister(input); 204 205 __ Branch(__ WordIsSmi(arg), &if_smi, &if_not_smi); 206 __ Bind(&if_smi); 207 { 208 return_value.Bind(__ BooleanConstant(true)); 209 __ Goto(&end); 210 } 211 212 __ Bind(&if_not_smi); 213 { 214 return_value.Bind(__ BooleanConstant(false)); 215 __ Goto(&end); 216 } 217 218 __ Bind(&end); 219 return return_value.value(); 220 } 221 222 Node* IntrinsicsHelper::IntrinsicAsStubCall(Node* args_reg, Node* context, 223 Callable const& callable) { 224 int param_count = callable.descriptor().GetParameterCount(); 225 Node** args = zone()->NewArray<Node*>(param_count + 1); // 1 for context 226 for (int i = 0; i < param_count; i++) { 227 args[i] = __ LoadRegister(args_reg); 228 args_reg = __ NextRegister(args_reg); 229 } 230 args[param_count] = context; 231 232 return __ CallStubN(callable, args); 233 } 234 235 Node* IntrinsicsHelper::HasProperty(Node* input, Node* arg_count, 236 Node* context) { 237 return IntrinsicAsStubCall(input, context, 238 CodeFactory::HasProperty(isolate())); 239 } 240 241 Node* IntrinsicsHelper::MathPow(Node* input, Node* arg_count, Node* context) { 242 return IntrinsicAsStubCall(input, context, CodeFactory::MathPow(isolate())); 243 } 244 245 Node* IntrinsicsHelper::NewObject(Node* input, Node* arg_count, Node* context) { 246 return IntrinsicAsStubCall(input, context, 247 CodeFactory::FastNewObject(isolate())); 248 } 249 250 Node* IntrinsicsHelper::NumberToString(Node* input, Node* arg_count, 251 Node* context) { 252 return IntrinsicAsStubCall(input, context, 253 CodeFactory::NumberToString(isolate())); 254 } 255 256 Node* IntrinsicsHelper::RegExpConstructResult(Node* input, Node* arg_count, 257 Node* context) { 258 return IntrinsicAsStubCall(input, context, 259 CodeFactory::RegExpConstructResult(isolate())); 260 } 261 262 Node* IntrinsicsHelper::RegExpExec(Node* input, Node* arg_count, 263 Node* context) { 264 return IntrinsicAsStubCall(input, context, 265 CodeFactory::RegExpExec(isolate())); 266 } 267 268 Node* IntrinsicsHelper::SubString(Node* input, Node* arg_count, Node* context) { 269 return IntrinsicAsStubCall(input, context, CodeFactory::SubString(isolate())); 270 } 271 272 Node* IntrinsicsHelper::ToString(Node* input, Node* arg_count, Node* context) { 273 return IntrinsicAsStubCall(input, context, CodeFactory::ToString(isolate())); 274 } 275 276 Node* IntrinsicsHelper::ToName(Node* input, Node* arg_count, Node* context) { 277 return IntrinsicAsStubCall(input, context, CodeFactory::ToName(isolate())); 278 } 279 280 Node* IntrinsicsHelper::ToLength(Node* input, Node* arg_count, Node* context) { 281 return IntrinsicAsStubCall(input, context, CodeFactory::ToLength(isolate())); 282 } 283 284 Node* IntrinsicsHelper::ToInteger(Node* input, Node* arg_count, Node* context) { 285 return IntrinsicAsStubCall(input, context, CodeFactory::ToInteger(isolate())); 286 } 287 288 Node* IntrinsicsHelper::ToNumber(Node* input, Node* arg_count, Node* context) { 289 return IntrinsicAsStubCall(input, context, CodeFactory::ToNumber(isolate())); 290 } 291 292 Node* IntrinsicsHelper::ToObject(Node* input, Node* arg_count, Node* context) { 293 return IntrinsicAsStubCall(input, context, CodeFactory::ToObject(isolate())); 294 } 295 296 Node* IntrinsicsHelper::Call(Node* args_reg, Node* arg_count, Node* context) { 297 // First argument register contains the function target. 298 Node* function = __ LoadRegister(args_reg); 299 300 // Receiver is the second runtime call argument. 301 Node* receiver_reg = __ NextRegister(args_reg); 302 Node* receiver_arg = __ RegisterLocation(receiver_reg); 303 304 // Subtract function and receiver from arg count. 305 Node* function_and_receiver_count = __ Int32Constant(2); 306 Node* target_args_count = __ Int32Sub(arg_count, function_and_receiver_count); 307 308 if (FLAG_debug_code) { 309 InterpreterAssembler::Label arg_count_positive(assembler_); 310 Node* comparison = __ Int32LessThan(target_args_count, __ Int32Constant(0)); 311 __ GotoUnless(comparison, &arg_count_positive); 312 __ Abort(kWrongArgumentCountForInvokeIntrinsic); 313 __ Goto(&arg_count_positive); 314 __ Bind(&arg_count_positive); 315 } 316 317 Node* result = __ CallJS(function, context, receiver_arg, target_args_count, 318 TailCallMode::kDisallow); 319 return result; 320 } 321 322 Node* IntrinsicsHelper::ValueOf(Node* args_reg, Node* arg_count, 323 Node* context) { 324 InterpreterAssembler::Variable return_value(assembler_, 325 MachineRepresentation::kTagged); 326 InterpreterAssembler::Label done(assembler_); 327 328 Node* object = __ LoadRegister(args_reg); 329 return_value.Bind(object); 330 331 // If the object is a smi return the object. 332 __ GotoIf(__ WordIsSmi(object), &done); 333 334 // If the object is not a value type, return the object. 335 Node* condition = 336 CompareInstanceType(object, JS_VALUE_TYPE, kInstanceTypeEqual); 337 __ GotoUnless(condition, &done); 338 339 // If the object is a value type, return the value field. 340 return_value.Bind(__ LoadObjectField(object, JSValue::kValueOffset)); 341 __ Goto(&done); 342 343 __ Bind(&done); 344 return return_value.value(); 345 } 346 347 void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) { 348 InterpreterAssembler::Label match(assembler_); 349 Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected)); 350 __ GotoIf(comparison, &match); 351 __ Abort(kWrongArgumentCountForInvokeIntrinsic); 352 __ Goto(&match); 353 __ Bind(&match); 354 } 355 356 } // namespace interpreter 357 } // namespace internal 358 } // namespace v8 359