Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 7 | #include "src/code-factory.h" |
| 8 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 9 | namespace v8 { |
| 10 | namespace internal { |
| 11 | namespace interpreter { |
| 12 | |
| 13 | using compiler::Node; |
| 14 | |
| 15 | #define __ assembler_-> |
| 16 | |
| 17 | IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler) |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 18 | : isolate_(assembler->isolate()), |
| 19 | zone_(assembler->zone()), |
| 20 | assembler_(assembler) {} |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 21 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 22 | // static |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 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) \ |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 80 | static_cast<int32_t>(IntrinsicId::k##name), |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 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); \ |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 87 | if (FLAG_debug_code && expected_arg_count >= 0) { \ |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 88 | AbortIfArgCountMismatch(expected_arg_count, arg_count); \ |
| 89 | } \ |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 90 | result.Bind(name(first_arg_reg, arg_count, context)); \ |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 91 | __ Goto(&end); |
| 92 | INTRINSICS_LIST(HANDLE_CASE) |
| 93 | #undef HANDLE_CASE |
| 94 | |
| 95 | __ Bind(&abort); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 96 | { |
| 97 | __ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic); |
| 98 | result.Bind(__ UndefinedConstant()); |
| 99 | __ Goto(&end); |
| 100 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 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_); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 114 | if (mode == kInstanceTypeEqual) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 115 | return __ Word32Equal(instance_type, __ Int32Constant(type)); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 116 | } else { |
| 117 | DCHECK(mode == kInstanceTypeGreaterThanOrEqual); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 118 | return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type)); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 119 | } |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 120 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 121 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 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); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 129 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 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 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 144 | |
| 145 | __ Bind(&end); |
| 146 | return return_value.value(); |
| 147 | } |
| 148 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 149 | Node* IntrinsicsHelper::IsJSReceiver(Node* input, Node* arg_count, |
| 150 | Node* context) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 151 | InterpreterAssembler::Variable return_value(assembler_, |
| 152 | MachineRepresentation::kTagged); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 153 | InterpreterAssembler::Label return_true(assembler_), return_false(assembler_), |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 154 | end(assembler_); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 155 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 156 | Node* arg = __ LoadRegister(input); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 157 | __ GotoIf(__ WordIsSmi(arg), &return_false); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 158 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 159 | STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 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 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 175 | |
| 176 | __ Bind(&end); |
| 177 | return return_value.value(); |
| 178 | } |
| 179 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 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) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 198 | InterpreterAssembler::Variable return_value(assembler_, |
| 199 | MachineRepresentation::kTagged); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 200 | InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_), |
| 201 | end(assembler_); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 202 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 203 | Node* arg = __ LoadRegister(input); |
| 204 | |
| 205 | __ Branch(__ WordIsSmi(arg), &if_smi, &if_not_smi); |
| 206 | __ Bind(&if_smi); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 207 | { |
| 208 | return_value.Bind(__ BooleanConstant(true)); |
| 209 | __ Goto(&end); |
| 210 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 211 | |
| 212 | __ Bind(&if_not_smi); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 213 | { |
| 214 | return_value.Bind(__ BooleanConstant(false)); |
| 215 | __ Goto(&end); |
| 216 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 217 | |
| 218 | __ Bind(&end); |
| 219 | return return_value.value(); |
| 220 | } |
| 221 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 347 | void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 348 | InterpreterAssembler::Label match(assembler_); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 349 | Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected)); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 350 | __ GotoIf(comparison, &match); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 351 | __ Abort(kWrongArgumentCountForInvokeIntrinsic); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 352 | __ Goto(&match); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 353 | __ Bind(&match); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 354 | } |
| 355 | |
| 356 | } // namespace interpreter |
| 357 | } // namespace internal |
| 358 | } // namespace v8 |