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 "test/unittests/interpreter/interpreter-assembler-unittest.h" 6 7#include "src/code-factory.h" 8#include "src/compiler/graph.h" 9#include "src/compiler/node.h" 10#include "src/interface-descriptors.h" 11#include "src/isolate.h" 12#include "test/unittests/compiler/compiler-test-utils.h" 13#include "test/unittests/compiler/node-test-utils.h" 14 15using ::testing::_; 16 17namespace v8 { 18namespace internal { 19 20using namespace compiler; 21 22namespace interpreter { 23 24const interpreter::Bytecode kBytecodes[] = { 25#define DEFINE_BYTECODE(Name, ...) interpreter::Bytecode::k##Name, 26 BYTECODE_LIST(DEFINE_BYTECODE) 27#undef DEFINE_BYTECODE 28}; 29 30Matcher<Node*> IsIntPtrConstant(const intptr_t value) { 31 return kPointerSize == 8 ? IsInt64Constant(static_cast<int64_t>(value)) 32 : IsInt32Constant(static_cast<int32_t>(value)); 33} 34 35Matcher<Node*> IsIntPtrAdd(const Matcher<Node*>& lhs_matcher, 36 const Matcher<Node*>& rhs_matcher) { 37 return kPointerSize == 8 ? IsInt64Add(lhs_matcher, rhs_matcher) 38 : IsInt32Add(lhs_matcher, rhs_matcher); 39} 40 41Matcher<Node*> IsIntPtrSub(const Matcher<Node*>& lhs_matcher, 42 const Matcher<Node*>& rhs_matcher) { 43 return kPointerSize == 8 ? IsInt64Sub(lhs_matcher, rhs_matcher) 44 : IsInt32Sub(lhs_matcher, rhs_matcher); 45} 46 47Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher, 48 const Matcher<Node*>& rhs_matcher) { 49 return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher) 50 : IsWord32Shl(lhs_matcher, rhs_matcher); 51} 52 53Matcher<Node*> IsWordSar(const Matcher<Node*>& lhs_matcher, 54 const Matcher<Node*>& rhs_matcher) { 55 return kPointerSize == 8 ? IsWord64Sar(lhs_matcher, rhs_matcher) 56 : IsWord32Sar(lhs_matcher, rhs_matcher); 57} 58 59Matcher<Node*> IsWordOr(const Matcher<Node*>& lhs_matcher, 60 const Matcher<Node*>& rhs_matcher) { 61 return kPointerSize == 8 ? IsWord64Or(lhs_matcher, rhs_matcher) 62 : IsWord32Or(lhs_matcher, rhs_matcher); 63} 64 65InterpreterAssemblerTest::InterpreterAssemblerForTest:: 66 ~InterpreterAssemblerForTest() { 67 // Tests don't necessarily read and write accumulator but 68 // InterpreterAssembler checks accumulator uses. 69 if (Bytecodes::ReadsAccumulator(bytecode())) { 70 GetAccumulator(); 71 } 72 if (Bytecodes::WritesAccumulator(bytecode())) { 73 SetAccumulator(nullptr); 74 } 75} 76 77Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoad( 78 const Matcher<LoadRepresentation>& rep_matcher, 79 const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher) { 80 return ::i::compiler::IsLoad(rep_matcher, base_matcher, index_matcher, _, _); 81} 82 83Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore( 84 const Matcher<StoreRepresentation>& rep_matcher, 85 const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher, 86 const Matcher<Node*>& value_matcher) { 87 return ::i::compiler::IsStore(rep_matcher, base_matcher, index_matcher, 88 value_matcher, _, _); 89} 90 91Matcher<Node*> 92InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedByteOperand( 93 int offset) { 94 return IsLoad( 95 MachineType::Uint8(), 96 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 97 IsIntPtrAdd( 98 IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 99 IsIntPtrConstant(offset))); 100} 101 102Matcher<Node*> 103InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedByteOperand( 104 int offset) { 105 Matcher<Node*> load_matcher = IsLoad( 106 MachineType::Int8(), 107 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 108 IsIntPtrAdd( 109 IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 110 IsIntPtrConstant(offset))); 111 if (kPointerSize == 8) { 112 load_matcher = IsChangeInt32ToInt64(load_matcher); 113 } 114 return load_matcher; 115} 116 117Matcher<Node*> 118InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedShortOperand( 119 int offset) { 120 if (TargetSupportsUnalignedAccess()) { 121 return IsLoad( 122 MachineType::Uint16(), 123 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 124 IsIntPtrAdd( 125 IsParameter( 126 InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 127 IsIntPtrConstant(offset))); 128 } else { 129#if V8_TARGET_LITTLE_ENDIAN 130 const int kStep = -1; 131 const int kMsbOffset = 1; 132#elif V8_TARGET_BIG_ENDIAN 133 const int kStep = 1; 134 const int kMsbOffset = 0; 135#else 136#error "Unknown Architecture" 137#endif 138 Matcher<Node*> bytes[2]; 139 for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) { 140 bytes[i] = IsLoad( 141 MachineType::Uint8(), 142 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 143 IsIntPtrAdd( 144 IsParameter( 145 InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 146 IsIntPtrConstant(offset + kMsbOffset + kStep * i))); 147 } 148 return IsWord32Or(IsWord32Shl(bytes[0], IsInt32Constant(kBitsPerByte)), 149 bytes[1]); 150 } 151} 152 153Matcher<Node*> 154InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedShortOperand( 155 int offset) { 156 Matcher<Node*> load_matcher; 157 if (TargetSupportsUnalignedAccess()) { 158 load_matcher = IsLoad( 159 MachineType::Int16(), 160 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 161 IsIntPtrAdd( 162 IsParameter( 163 InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 164 IsIntPtrConstant(offset))); 165 } else { 166#if V8_TARGET_LITTLE_ENDIAN 167 const int kStep = -1; 168 const int kMsbOffset = 1; 169#elif V8_TARGET_BIG_ENDIAN 170 const int kStep = 1; 171 const int kMsbOffset = 0; 172#else 173#error "Unknown Architecture" 174#endif 175 Matcher<Node*> bytes[2]; 176 for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) { 177 bytes[i] = IsLoad( 178 (i == 0) ? MachineType::Int8() : MachineType::Uint8(), 179 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 180 IsIntPtrAdd( 181 IsParameter( 182 InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 183 IsIntPtrConstant(offset + kMsbOffset + kStep * i))); 184 } 185 load_matcher = IsWord32Or( 186 IsWord32Shl(bytes[0], IsInt32Constant(kBitsPerByte)), bytes[1]); 187 } 188 189 if (kPointerSize == 8) { 190 load_matcher = IsChangeInt32ToInt64(load_matcher); 191 } 192 return load_matcher; 193} 194 195Matcher<Node*> 196InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedQuadOperand( 197 int offset) { 198 if (TargetSupportsUnalignedAccess()) { 199 return IsLoad( 200 MachineType::Uint32(), 201 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 202 IsIntPtrAdd( 203 IsParameter( 204 InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 205 IsIntPtrConstant(offset))); 206 } else { 207#if V8_TARGET_LITTLE_ENDIAN 208 const int kStep = -1; 209 const int kMsbOffset = 3; 210#elif V8_TARGET_BIG_ENDIAN 211 const int kStep = 1; 212 const int kMsbOffset = 0; 213#else 214#error "Unknown Architecture" 215#endif 216 Matcher<Node*> bytes[4]; 217 for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) { 218 bytes[i] = IsLoad( 219 MachineType::Uint8(), 220 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 221 IsIntPtrAdd( 222 IsParameter( 223 InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 224 IsIntPtrConstant(offset + kMsbOffset + kStep * i))); 225 } 226 return IsWord32Or( 227 IsWord32Shl(bytes[0], IsInt32Constant(3 * kBitsPerByte)), 228 IsWord32Or( 229 IsWord32Shl(bytes[1], IsInt32Constant(2 * kBitsPerByte)), 230 IsWord32Or(IsWord32Shl(bytes[2], IsInt32Constant(1 * kBitsPerByte)), 231 bytes[3]))); 232 } 233} 234 235Matcher<Node*> 236InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedQuadOperand( 237 int offset) { 238 Matcher<Node*> load_matcher; 239 if (TargetSupportsUnalignedAccess()) { 240 load_matcher = IsLoad( 241 MachineType::Int32(), 242 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 243 IsIntPtrAdd( 244 IsParameter( 245 InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 246 IsIntPtrConstant(offset))); 247 } else { 248#if V8_TARGET_LITTLE_ENDIAN 249 const int kStep = -1; 250 int kMsbOffset = 3; 251#elif V8_TARGET_BIG_ENDIAN 252 const int kStep = 1; 253 int kMsbOffset = 0; 254#else 255#error "Unknown Architecture" 256#endif 257 Matcher<Node*> bytes[4]; 258 for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) { 259 bytes[i] = IsLoad( 260 (i == 0) ? MachineType::Int8() : MachineType::Uint8(), 261 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 262 IsIntPtrAdd( 263 IsParameter( 264 InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 265 IsIntPtrConstant(offset + kMsbOffset + kStep * i))); 266 } 267 load_matcher = IsWord32Or( 268 IsWord32Shl(bytes[0], IsInt32Constant(3 * kBitsPerByte)), 269 IsWord32Or( 270 IsWord32Shl(bytes[1], IsInt32Constant(2 * kBitsPerByte)), 271 IsWord32Or(IsWord32Shl(bytes[2], IsInt32Constant(1 * kBitsPerByte)), 272 bytes[3]))); 273 } 274 275 if (kPointerSize == 8) { 276 load_matcher = IsChangeInt32ToInt64(load_matcher); 277 } 278 return load_matcher; 279} 280 281Matcher<Node*> 282InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedOperand( 283 int offset, OperandSize operand_size) { 284 switch (operand_size) { 285 case OperandSize::kByte: 286 return IsSignedByteOperand(offset); 287 case OperandSize::kShort: 288 return IsSignedShortOperand(offset); 289 case OperandSize::kQuad: 290 return IsSignedQuadOperand(offset); 291 case OperandSize::kNone: 292 UNREACHABLE(); 293 } 294 return nullptr; 295} 296 297Matcher<Node*> 298InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedOperand( 299 int offset, OperandSize operand_size) { 300 switch (operand_size) { 301 case OperandSize::kByte: 302 return IsUnsignedByteOperand(offset); 303 case OperandSize::kShort: 304 return IsUnsignedShortOperand(offset); 305 case OperandSize::kQuad: 306 return IsUnsignedQuadOperand(offset); 307 case OperandSize::kNone: 308 UNREACHABLE(); 309 } 310 return nullptr; 311} 312 313TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) { 314 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 315 InterpreterAssemblerForTest m(this, bytecode); 316 Node* tail_call_node = m.Dispatch(); 317 318 OperandScale operand_scale = OperandScale::kSingle; 319 Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd( 320 IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 321 IsIntPtrConstant( 322 interpreter::Bytecodes::Size(bytecode, operand_scale))); 323 Matcher<Node*> target_bytecode_matcher = m.IsLoad( 324 MachineType::Uint8(), 325 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 326 next_bytecode_offset_matcher); 327 if (kPointerSize == 8) { 328 target_bytecode_matcher = IsChangeUint32ToUint64(target_bytecode_matcher); 329 } 330 Matcher<Node*> code_target_matcher = m.IsLoad( 331 MachineType::Pointer(), 332 IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), 333 IsWordShl(target_bytecode_matcher, IsIntPtrConstant(kPointerSizeLog2))); 334 335 EXPECT_THAT( 336 tail_call_node, 337 IsTailCall( 338 _, code_target_matcher, 339 IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter), 340 next_bytecode_offset_matcher, 341 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 342 IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), 343 _, _)); 344 } 345} 346 347TARGET_TEST_F(InterpreterAssemblerTest, Jump) { 348 // If debug code is enabled we emit extra code in Jump. 349 if (FLAG_debug_code) return; 350 351 int jump_offsets[] = {-9710, -77, 0, +3, +97109}; 352 TRACED_FOREACH(int, jump_offset, jump_offsets) { 353 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 354 InterpreterAssemblerForTest m(this, bytecode); 355 Node* tail_call_node = m.Jump(m.IntPtrConstant(jump_offset)); 356 357 Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd( 358 IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), 359 IsIntPtrConstant(jump_offset)); 360 Matcher<Node*> target_bytecode_matcher = 361 m.IsLoad(MachineType::Uint8(), _, next_bytecode_offset_matcher); 362 if (kPointerSize == 8) { 363 target_bytecode_matcher = 364 IsChangeUint32ToUint64(target_bytecode_matcher); 365 } 366 Matcher<Node*> code_target_matcher = m.IsLoad( 367 MachineType::Pointer(), 368 IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), 369 IsWordShl(target_bytecode_matcher, 370 IsIntPtrConstant(kPointerSizeLog2))); 371 372 EXPECT_THAT( 373 tail_call_node, 374 IsTailCall( 375 _, code_target_matcher, 376 IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter), 377 next_bytecode_offset_matcher, _, 378 IsParameter( 379 InterpreterDispatchDescriptor::kDispatchTableParameter), 380 _, _)); 381 } 382 } 383} 384 385TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { 386 static const OperandScale kOperandScales[] = { 387 OperandScale::kSingle, OperandScale::kDouble, OperandScale::kQuadruple}; 388 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 389 TRACED_FOREACH(interpreter::OperandScale, operand_scale, kOperandScales) { 390 InterpreterAssemblerForTest m(this, bytecode, operand_scale); 391 int number_of_operands = 392 interpreter::Bytecodes::NumberOfOperands(bytecode); 393 for (int i = 0; i < number_of_operands; i++) { 394 int offset = interpreter::Bytecodes::GetOperandOffset(bytecode, i, 395 operand_scale); 396 OperandType operand_type = 397 interpreter::Bytecodes::GetOperandType(bytecode, i); 398 OperandSize operand_size = 399 Bytecodes::SizeOfOperand(operand_type, operand_scale); 400 switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) { 401 case interpreter::OperandType::kRegCount: 402 EXPECT_THAT(m.BytecodeOperandCount(i), 403 m.IsUnsignedOperand(offset, operand_size)); 404 break; 405 case interpreter::OperandType::kFlag8: 406 EXPECT_THAT(m.BytecodeOperandFlag(i), 407 m.IsUnsignedOperand(offset, operand_size)); 408 break; 409 case interpreter::OperandType::kIdx: 410 EXPECT_THAT(m.BytecodeOperandIdx(i), 411 m.IsUnsignedOperand(offset, operand_size)); 412 break; 413 case interpreter::OperandType::kImm: { 414 EXPECT_THAT(m.BytecodeOperandImm(i), 415 m.IsSignedOperand(offset, operand_size)); 416 break; 417 } 418 case interpreter::OperandType::kMaybeReg: 419 case interpreter::OperandType::kReg: 420 case interpreter::OperandType::kRegOut: 421 case interpreter::OperandType::kRegOutPair: 422 case interpreter::OperandType::kRegOutTriple: 423 case interpreter::OperandType::kRegPair: 424 EXPECT_THAT(m.BytecodeOperandReg(i), 425 m.IsSignedOperand(offset, operand_size)); 426 break; 427 case interpreter::OperandType::kRuntimeId: 428 EXPECT_THAT(m.BytecodeOperandRuntimeId(i), 429 m.IsUnsignedOperand(offset, operand_size)); 430 break; 431 case interpreter::OperandType::kIntrinsicId: 432 EXPECT_THAT(m.BytecodeOperandIntrinsicId(i), 433 m.IsUnsignedOperand(offset, operand_size)); 434 break; 435 case interpreter::OperandType::kNone: 436 UNREACHABLE(); 437 break; 438 } 439 } 440 } 441 } 442} 443 444TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) { 445 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 446 if (!interpreter::Bytecodes::ReadsAccumulator(bytecode) || 447 !interpreter::Bytecodes::WritesAccumulator(bytecode)) { 448 continue; 449 } 450 451 InterpreterAssemblerForTest m(this, bytecode); 452 // Should be incoming accumulator if not set. 453 EXPECT_THAT( 454 m.GetAccumulator(), 455 IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter)); 456 // Should be set by SetAccumulator. 457 Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef); 458 m.SetAccumulator(accumulator_value_1); 459 EXPECT_THAT(m.GetAccumulator(), accumulator_value_1); 460 Node* accumulator_value_2 = m.Int32Constant(42); 461 m.SetAccumulator(accumulator_value_2); 462 EXPECT_THAT(m.GetAccumulator(), accumulator_value_2); 463 464 // Should be passed to next bytecode handler on dispatch. 465 Node* tail_call_node = m.Dispatch(); 466 467 EXPECT_THAT(tail_call_node, 468 IsTailCall(_, _, accumulator_value_2, _, _, _, _)); 469 } 470} 471 472TARGET_TEST_F(InterpreterAssemblerTest, GetContext) { 473 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 474 InterpreterAssemblerForTest m(this, bytecode); 475 EXPECT_THAT( 476 m.GetContext(), 477 m.IsLoad(MachineType::AnyTagged(), IsLoadParentFramePointer(), 478 IsIntPtrConstant(Register::current_context().ToOperand() 479 << kPointerSizeLog2))); 480 } 481} 482 483TARGET_TEST_F(InterpreterAssemblerTest, RegisterLocation) { 484 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 485 InterpreterAssemblerForTest m(this, bytecode); 486 Node* reg_index_node = m.IntPtrConstant(44); 487 Node* reg_location_node = m.RegisterLocation(reg_index_node); 488 EXPECT_THAT(reg_location_node, 489 IsIntPtrAdd(IsLoadParentFramePointer(), 490 IsWordShl(reg_index_node, 491 IsIntPtrConstant(kPointerSizeLog2)))); 492 } 493} 494 495TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) { 496 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 497 InterpreterAssemblerForTest m(this, bytecode); 498 Node* reg_index_node = m.IntPtrConstant(44); 499 Node* load_reg_node = m.LoadRegister(reg_index_node); 500 EXPECT_THAT(load_reg_node, 501 m.IsLoad(MachineType::AnyTagged(), IsLoadParentFramePointer(), 502 IsWordShl(reg_index_node, 503 IsIntPtrConstant(kPointerSizeLog2)))); 504 } 505} 506 507TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) { 508 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 509 InterpreterAssemblerForTest m(this, bytecode); 510 Node* store_value = m.Int32Constant(0xdeadbeef); 511 Node* reg_index_node = m.IntPtrConstant(44); 512 Node* store_reg_node = m.StoreRegister(store_value, reg_index_node); 513 EXPECT_THAT( 514 store_reg_node, 515 m.IsStore(StoreRepresentation(MachineRepresentation::kTagged, 516 kNoWriteBarrier), 517 IsLoadParentFramePointer(), 518 IsWordShl(reg_index_node, IsIntPtrConstant(kPointerSizeLog2)), 519 store_value)); 520 } 521} 522 523TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) { 524 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 525 InterpreterAssemblerForTest m(this, bytecode); 526 Node* value = m.Int32Constant(44); 527 EXPECT_THAT(m.SmiTag(value), 528 IsIntPtrConstant(static_cast<intptr_t>(44) 529 << (kSmiShiftSize + kSmiTagSize))); 530 EXPECT_THAT( 531 m.SmiUntag(value), 532 IsWordSar(value, IsIntPtrConstant(kSmiShiftSize + kSmiTagSize))); 533 } 534} 535 536TARGET_TEST_F(InterpreterAssemblerTest, IntPtrAdd) { 537 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 538 InterpreterAssemblerForTest m(this, bytecode); 539 Node* a = m.Int32Constant(0); 540 Node* b = m.Int32Constant(1); 541 Node* add = m.IntPtrAdd(a, b); 542 EXPECT_THAT(add, IsIntPtrAdd(a, b)); 543 } 544} 545 546TARGET_TEST_F(InterpreterAssemblerTest, IntPtrSub) { 547 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 548 InterpreterAssemblerForTest m(this, bytecode); 549 Node* a = m.Int32Constant(0); 550 Node* b = m.Int32Constant(1); 551 Node* add = m.IntPtrSub(a, b); 552 EXPECT_THAT(add, IsIntPtrSub(a, b)); 553 } 554} 555 556TARGET_TEST_F(InterpreterAssemblerTest, WordShl) { 557 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 558 InterpreterAssemblerForTest m(this, bytecode); 559 Node* a = m.IntPtrConstant(0); 560 Node* add = m.WordShl(a, 10); 561 EXPECT_THAT(add, IsWordShl(a, IsIntPtrConstant(10))); 562 } 563} 564 565TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) { 566 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 567 InterpreterAssemblerForTest m(this, bytecode); 568 Node* index = m.IntPtrConstant(2); 569 Node* load_constant = m.LoadConstantPoolEntry(index); 570 Matcher<Node*> constant_pool_matcher = m.IsLoad( 571 MachineType::AnyTagged(), 572 IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), 573 IsIntPtrConstant(BytecodeArray::kConstantPoolOffset - kHeapObjectTag)); 574 EXPECT_THAT( 575 load_constant, 576 m.IsLoad(MachineType::AnyTagged(), constant_pool_matcher, 577 IsIntPtrAdd( 578 IsIntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag), 579 IsWordShl(index, IsIntPtrConstant(kPointerSizeLog2))))); 580 } 581} 582 583TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) { 584 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 585 InterpreterAssemblerForTest m(this, bytecode); 586 Node* object = m.IntPtrConstant(0xdeadbeef); 587 int offset = 16; 588 Node* load_field = m.LoadObjectField(object, offset); 589 EXPECT_THAT(load_field, 590 m.IsLoad(MachineType::AnyTagged(), object, 591 IsIntPtrConstant(offset - kHeapObjectTag))); 592 } 593} 594 595TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) { 596 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 597 InterpreterAssemblerForTest m(this, bytecode); 598 Node* context = m.IntPtrConstant(1); 599 Node* slot_index = m.IntPtrConstant(22); 600 Node* load_context_slot = m.LoadContextSlot(context, slot_index); 601 602 Matcher<Node*> offset = 603 IsIntPtrAdd(IsWordShl(slot_index, IsIntPtrConstant(kPointerSizeLog2)), 604 IsIntPtrConstant(Context::kHeaderSize - kHeapObjectTag)); 605 EXPECT_THAT(load_context_slot, 606 m.IsLoad(MachineType::AnyTagged(), context, offset)); 607 } 608} 609 610TARGET_TEST_F(InterpreterAssemblerTest, StoreContextSlot) { 611 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 612 InterpreterAssemblerForTest m(this, bytecode); 613 Node* context = m.IntPtrConstant(1); 614 Node* slot_index = m.IntPtrConstant(22); 615 Node* value = m.SmiConstant(Smi::FromInt(100)); 616 Node* store_context_slot = m.StoreContextSlot(context, slot_index, value); 617 618 Matcher<Node*> offset = 619 IsIntPtrAdd(IsWordShl(slot_index, IsIntPtrConstant(kPointerSizeLog2)), 620 IsIntPtrConstant(Context::kHeaderSize - kHeapObjectTag)); 621 EXPECT_THAT(store_context_slot, 622 m.IsStore(StoreRepresentation(MachineRepresentation::kTagged, 623 kFullWriteBarrier), 624 context, offset, value)); 625 } 626} 627 628TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime2) { 629 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 630 InterpreterAssemblerForTest m(this, bytecode); 631 Node* arg1 = m.Int32Constant(2); 632 Node* arg2 = m.Int32Constant(3); 633 Node* context = m.Int32Constant(4); 634 Node* call_runtime = m.CallRuntime(Runtime::kAdd, context, arg1, arg2); 635 EXPECT_THAT(call_runtime, 636 IsCall(_, _, arg1, arg2, _, IsInt32Constant(2), context, _, _)); 637 } 638} 639 640TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) { 641 const int kResultSizes[] = {1, 2}; 642 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 643 TRACED_FOREACH(int, result_size, kResultSizes) { 644 InterpreterAssemblerForTest m(this, bytecode); 645 Callable builtin = CodeFactory::InterpreterCEntry(isolate(), result_size); 646 647 Node* function_id = m.Int32Constant(0); 648 Node* first_arg = m.Int32Constant(1); 649 Node* arg_count = m.Int32Constant(2); 650 Node* context = m.Int32Constant(4); 651 652 Matcher<Node*> function_table = IsExternalConstant( 653 ExternalReference::runtime_function_table_address(isolate())); 654 Matcher<Node*> function = IsIntPtrAdd( 655 function_table, 656 IsInt32Mul(function_id, IsInt32Constant(sizeof(Runtime::Function)))); 657 Matcher<Node*> function_entry = 658 m.IsLoad(MachineType::Pointer(), function, 659 IsIntPtrConstant(offsetof(Runtime::Function, entry))); 660 661 Node* call_runtime = m.CallRuntimeN(function_id, context, first_arg, 662 arg_count, result_size); 663 EXPECT_THAT(call_runtime, 664 IsCall(_, IsHeapConstant(builtin.code()), arg_count, 665 first_arg, function_entry, context, _, _)); 666 } 667 } 668} 669 670TARGET_TEST_F(InterpreterAssemblerTest, CallJS) { 671 TailCallMode tail_call_modes[] = {TailCallMode::kDisallow, 672 TailCallMode::kAllow}; 673 TRACED_FOREACH(TailCallMode, tail_call_mode, tail_call_modes) { 674 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 675 InterpreterAssemblerForTest m(this, bytecode); 676 Callable builtin = 677 CodeFactory::InterpreterPushArgsAndCall(isolate(), tail_call_mode); 678 Node* function = m.Int32Constant(0); 679 Node* first_arg = m.Int32Constant(1); 680 Node* arg_count = m.Int32Constant(2); 681 Node* context = m.Int32Constant(3); 682 Node* call_js = 683 m.CallJS(function, context, first_arg, arg_count, tail_call_mode); 684 EXPECT_THAT(call_js, IsCall(_, IsHeapConstant(builtin.code()), arg_count, 685 first_arg, function, context, _, _)); 686 } 687 } 688} 689 690TARGET_TEST_F(InterpreterAssemblerTest, LoadTypeFeedbackVector) { 691 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { 692 InterpreterAssemblerForTest m(this, bytecode); 693 Node* feedback_vector = m.LoadTypeFeedbackVector(); 694 695 Matcher<Node*> load_function_matcher = 696 m.IsLoad(MachineType::AnyTagged(), IsLoadParentFramePointer(), 697 IsIntPtrConstant(Register::function_closure().ToOperand() 698 << kPointerSizeLog2)); 699 Matcher<Node*> load_literals_matcher = m.IsLoad( 700 MachineType::AnyTagged(), load_function_matcher, 701 IsIntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag)); 702 703 EXPECT_THAT(feedback_vector, 704 m.IsLoad(MachineType::AnyTagged(), load_literals_matcher, 705 IsIntPtrConstant(LiteralsArray::kFeedbackVectorOffset - 706 kHeapObjectTag))); 707 } 708} 709 710} // namespace interpreter 711} // namespace internal 712} // namespace v8 713