Home | History | Annotate | Download | only in interpreter
      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 
     15 using ::testing::_;
     16 
     17 namespace v8 {
     18 namespace internal {
     19 
     20 using namespace compiler;
     21 
     22 namespace interpreter {
     23 
     24 const interpreter::Bytecode kBytecodes[] = {
     25 #define DEFINE_BYTECODE(Name, ...) interpreter::Bytecode::k##Name,
     26     BYTECODE_LIST(DEFINE_BYTECODE)
     27 #undef DEFINE_BYTECODE
     28 };
     29 
     30 Matcher<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 
     35 Matcher<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 
     41 Matcher<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 
     47 Matcher<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 
     53 Matcher<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 
     59 Matcher<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 
     65 InterpreterAssemblerTest::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 
     77 Matcher<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 
     83 Matcher<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 
     91 Matcher<Node*>
     92 InterpreterAssemblerTest::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 
    102 Matcher<Node*>
    103 InterpreterAssemblerTest::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 
    117 Matcher<Node*>
    118 InterpreterAssemblerTest::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 
    153 Matcher<Node*>
    154 InterpreterAssemblerTest::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 
    195 Matcher<Node*>
    196 InterpreterAssemblerTest::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 
    235 Matcher<Node*>
    236 InterpreterAssemblerTest::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 
    281 Matcher<Node*>
    282 InterpreterAssemblerTest::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 
    297 Matcher<Node*>
    298 InterpreterAssemblerTest::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 
    313 TARGET_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 
    347 TARGET_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 
    385 TARGET_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 
    444 TARGET_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 
    472 TARGET_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 
    483 TARGET_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 
    495 TARGET_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 
    507 TARGET_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 
    523 TARGET_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 
    536 TARGET_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 
    546 TARGET_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 
    556 TARGET_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 
    565 TARGET_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 
    583 TARGET_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 
    595 TARGET_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 
    610 TARGET_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 
    628 TARGET_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 
    640 TARGET_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 
    670 TARGET_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 
    690 TARGET_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