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/codegen/code-factory.h"
8 #include "src/codegen/interface-descriptors.h"
9 #include "src/compiler/node-properties.h"
10 #include "src/compiler/node.h"
11 #include "src/execution/isolate.h"
12 #include "src/objects/objects-inl.h"
13 #include "test/unittests/compiler/compiler-test-utils.h"
14 #include "test/unittests/compiler/node-test-utils.h"
15 
16 using ::testing::_;
17 using ::testing::Eq;
18 
19 namespace c = v8::internal::compiler;
20 
21 namespace v8 {
22 namespace internal {
23 namespace interpreter {
24 namespace interpreter_assembler_unittest {
25 
InterpreterAssemblerTestState(InterpreterAssemblerTest * test,Bytecode bytecode)26 InterpreterAssemblerTestState::InterpreterAssemblerTestState(
27     InterpreterAssemblerTest* test, Bytecode bytecode)
28     : compiler::CodeAssemblerState(
29           test->isolate(), test->zone(), InterpreterDispatchDescriptor{},
30           CodeKind::BYTECODE_HANDLER, Bytecodes::ToString(bytecode)) {}
31 
32 const interpreter::Bytecode kBytecodes[] = {
33 #define DEFINE_BYTECODE(Name, ...) interpreter::Bytecode::k##Name,
34     BYTECODE_LIST(DEFINE_BYTECODE)
35 #undef DEFINE_BYTECODE
36 };
37 
38 
39 InterpreterAssemblerTest::InterpreterAssemblerForTest::
~InterpreterAssemblerForTest()40     ~InterpreterAssemblerForTest() {
41   // Tests don't necessarily read and write accumulator but
42   // InterpreterAssembler checks accumulator uses.
43   if (Bytecodes::ReadsAccumulator(bytecode())) {
44     GetAccumulator();
45   }
46   if (Bytecodes::WritesAccumulator(bytecode())) {
47     SetAccumulator(NullConstant());
48   }
49   if (Bytecodes::WritesImplicitRegister(bytecode())) {
50     StoreRegisterForShortStar(NullConstant(), IntPtrConstant(2));
51   }
52 }
53 
IsLoad(const Matcher<c::LoadRepresentation> & rep_matcher,const Matcher<c::Node * > & base_matcher,const Matcher<c::Node * > & index_matcher)54 Matcher<c::Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoad(
55     const Matcher<c::LoadRepresentation>& rep_matcher,
56     const Matcher<c::Node*>& base_matcher,
57     const Matcher<c::Node*>& index_matcher) {
58   return ::i::compiler::IsLoad(rep_matcher, base_matcher, index_matcher, _, _);
59 }
60 
61 Matcher<c::Node*>
IsLoadFromObject(const Matcher<c::LoadRepresentation> & rep_matcher,const Matcher<c::Node * > & base_matcher,const Matcher<c::Node * > & index_matcher)62 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoadFromObject(
63     const Matcher<c::LoadRepresentation>& rep_matcher,
64     const Matcher<c::Node*>& base_matcher,
65     const Matcher<c::Node*>& index_matcher) {
66   return ::i::compiler::IsLoadFromObject(rep_matcher, base_matcher,
67                                          index_matcher, _, _);
68 }
69 
70 Matcher<c::Node*>
IsStore(const Matcher<c::StoreRepresentation> & rep_matcher,const Matcher<c::Node * > & base_matcher,const Matcher<c::Node * > & index_matcher,const Matcher<c::Node * > & value_matcher)71 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore(
72     const Matcher<c::StoreRepresentation>& rep_matcher,
73     const Matcher<c::Node*>& base_matcher,
74     const Matcher<c::Node*>& index_matcher,
75     const Matcher<c::Node*>& value_matcher) {
76   return ::i::compiler::IsStore(rep_matcher, base_matcher, index_matcher,
77                                 value_matcher, _, _);
78 }
79 
80 Matcher<c::Node*>
IsWordNot(const Matcher<c::Node * > & value_matcher)81 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsWordNot(
82     const Matcher<c::Node*>& value_matcher) {
83   return kSystemPointerSize == 8
84              ? IsWord64Xor(value_matcher, c::IsInt64Constant(-1))
85              : IsWord32Xor(value_matcher, c::IsInt32Constant(-1));
86 }
87 
88 Matcher<c::Node*>
IsUnsignedByteOperand(int offset)89 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedByteOperand(
90     int offset) {
91   return IsLoad(
92       MachineType::Uint8(),
93       c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
94       c::IsIntPtrAdd(
95           c::IsParameter(InterpreterDispatchDescriptor::kBytecodeOffset),
96           c::IsIntPtrConstant(offset)));
97 }
98 
99 Matcher<c::Node*>
IsSignedByteOperand(int offset)100 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedByteOperand(
101     int offset) {
102   return IsLoad(
103       MachineType::Int8(),
104       c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
105       c::IsIntPtrAdd(
106           c::IsParameter(InterpreterDispatchDescriptor::kBytecodeOffset),
107           c::IsIntPtrConstant(offset)));
108 }
109 
110 Matcher<c::Node*>
IsUnsignedShortOperand(int offset)111 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedShortOperand(
112     int offset) {
113   if (TargetSupportsUnalignedAccess()) {
114     return IsLoad(
115         MachineType::Uint16(),
116         c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
117         c::IsIntPtrAdd(
118             c::IsParameter(InterpreterDispatchDescriptor::kBytecodeOffset),
119             c::IsIntPtrConstant(offset)));
120   } else {
121 #if V8_TARGET_LITTLE_ENDIAN
122     const int kStep = -1;
123     const int kMsbOffset = 1;
124 #elif V8_TARGET_BIG_ENDIAN
125     const int kStep = 1;
126     const int kMsbOffset = 0;
127 #else
128 #error "Unknown Architecture"
129 #endif
130     Matcher<c::Node*> bytes[2];
131     for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) {
132       bytes[i] = IsLoad(
133           MachineType::Uint8(),
134           c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
135           c::IsIntPtrAdd(
136               c::IsParameter(InterpreterDispatchDescriptor::kBytecodeOffset),
137               c::IsIntPtrConstant(offset + kMsbOffset + kStep * i)));
138     }
139     return c::IsWord32Or(
140         c::IsWord32Shl(bytes[0], c::IsInt32Constant(kBitsPerByte)), bytes[1]);
141   }
142 }
143 
144 Matcher<c::Node*>
IsSignedShortOperand(int offset)145 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedShortOperand(
146     int offset) {
147   if (TargetSupportsUnalignedAccess()) {
148     return IsLoad(
149         MachineType::Int16(),
150         c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
151         c::IsIntPtrAdd(
152             c::IsParameter(InterpreterDispatchDescriptor::kBytecodeOffset),
153             c::IsIntPtrConstant(offset)));
154   } else {
155 #if V8_TARGET_LITTLE_ENDIAN
156     const int kStep = -1;
157     const int kMsbOffset = 1;
158 #elif V8_TARGET_BIG_ENDIAN
159     const int kStep = 1;
160     const int kMsbOffset = 0;
161 #else
162 #error "Unknown Architecture"
163 #endif
164     Matcher<c::Node*> bytes[2];
165     for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) {
166       bytes[i] = IsLoad(
167           (i == 0) ? MachineType::Int8() : MachineType::Uint8(),
168           c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
169           c::IsIntPtrAdd(
170               c::IsParameter(InterpreterDispatchDescriptor::kBytecodeOffset),
171               c::IsIntPtrConstant(offset + kMsbOffset + kStep * i)));
172     }
173     return c::IsWord32Or(
174         c::IsWord32Shl(bytes[0], c::IsInt32Constant(kBitsPerByte)), bytes[1]);
175   }
176 }
177 
178 Matcher<c::Node*>
IsUnsignedQuadOperand(int offset)179 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedQuadOperand(
180     int offset) {
181   if (TargetSupportsUnalignedAccess()) {
182     return IsLoad(
183         MachineType::Uint32(),
184         c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
185         c::IsIntPtrAdd(
186             c::IsParameter(InterpreterDispatchDescriptor::kBytecodeOffset),
187             c::IsIntPtrConstant(offset)));
188   } else {
189 #if V8_TARGET_LITTLE_ENDIAN
190     const int kStep = -1;
191     const int kMsbOffset = 3;
192 #elif V8_TARGET_BIG_ENDIAN
193     const int kStep = 1;
194     const int kMsbOffset = 0;
195 #else
196 #error "Unknown Architecture"
197 #endif
198     Matcher<c::Node*> bytes[4];
199     for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) {
200       bytes[i] = IsLoad(
201           MachineType::Uint8(),
202           c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
203           c::IsIntPtrAdd(
204               c::IsParameter(InterpreterDispatchDescriptor::kBytecodeOffset),
205               c::IsIntPtrConstant(offset + kMsbOffset + kStep * i)));
206     }
207     return c::IsWord32Or(
208         c::IsWord32Shl(bytes[0], c::IsInt32Constant(3 * kBitsPerByte)),
209         c::IsWord32Or(
210             c::IsWord32Shl(bytes[1], c::IsInt32Constant(2 * kBitsPerByte)),
211             c::IsWord32Or(
212                 c::IsWord32Shl(bytes[2], c::IsInt32Constant(1 * kBitsPerByte)),
213                 bytes[3])));
214   }
215 }
216 
217 Matcher<c::Node*>
IsSignedQuadOperand(int offset)218 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedQuadOperand(
219     int offset) {
220   if (TargetSupportsUnalignedAccess()) {
221     return IsLoad(
222         MachineType::Int32(),
223         c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
224         c::IsIntPtrAdd(
225             c::IsParameter(InterpreterDispatchDescriptor::kBytecodeOffset),
226             c::IsIntPtrConstant(offset)));
227   } else {
228 #if V8_TARGET_LITTLE_ENDIAN
229     const int kStep = -1;
230     int kMsbOffset = 3;
231 #elif V8_TARGET_BIG_ENDIAN
232     const int kStep = 1;
233     int kMsbOffset = 0;
234 #else
235 #error "Unknown Architecture"
236 #endif
237     Matcher<c::Node*> bytes[4];
238     for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) {
239       bytes[i] = IsLoad(
240           (i == 0) ? MachineType::Int8() : MachineType::Uint8(),
241           c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
242           c::IsIntPtrAdd(
243               c::IsParameter(InterpreterDispatchDescriptor::kBytecodeOffset),
244               c::IsIntPtrConstant(offset + kMsbOffset + kStep * i)));
245     }
246     return c::IsWord32Or(
247         c::IsWord32Shl(bytes[0], c::IsInt32Constant(3 * kBitsPerByte)),
248         c::IsWord32Or(
249             c::IsWord32Shl(bytes[1], c::IsInt32Constant(2 * kBitsPerByte)),
250             c::IsWord32Or(
251                 c::IsWord32Shl(bytes[2], c::IsInt32Constant(1 * kBitsPerByte)),
252                 bytes[3])));
253   }
254 }
255 
256 Matcher<c::Node*>
IsSignedOperand(int offset,OperandSize operand_size)257 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedOperand(
258     int offset, OperandSize operand_size) {
259   switch (operand_size) {
260     case OperandSize::kByte:
261       return IsSignedByteOperand(offset);
262     case OperandSize::kShort:
263       return IsSignedShortOperand(offset);
264     case OperandSize::kQuad:
265       return IsSignedQuadOperand(offset);
266     case OperandSize::kNone:
267       UNREACHABLE();
268   }
269   return nullptr;
270 }
271 
272 Matcher<c::Node*>
IsUnsignedOperand(int offset,OperandSize operand_size)273 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedOperand(
274     int offset, OperandSize operand_size) {
275   switch (operand_size) {
276     case OperandSize::kByte:
277       return IsUnsignedByteOperand(offset);
278     case OperandSize::kShort:
279       return IsUnsignedShortOperand(offset);
280     case OperandSize::kQuad:
281       return IsUnsignedQuadOperand(offset);
282     case OperandSize::kNone:
283       UNREACHABLE();
284   }
285   return nullptr;
286 }
287 
288 Matcher<c::Node*>
IsLoadRegisterOperand(int offset,OperandSize operand_size)289 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoadRegisterOperand(
290     int offset, OperandSize operand_size) {
291   Matcher<c::Node*> reg_operand =
292       IsChangeInt32ToIntPtr(IsSignedOperand(offset, operand_size));
293   return IsBitcastWordToTagged(IsLoad(
294       MachineType::Pointer(), c::IsLoadParentFramePointer(),
295       c::IsWordShl(reg_operand, c::IsIntPtrConstant(kSystemPointerSizeLog2))));
296 }
297 
TARGET_TEST_F(InterpreterAssemblerTest,BytecodeOperand)298 TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
299   static const OperandScale kOperandScales[] = {
300       OperandScale::kSingle, OperandScale::kDouble, OperandScale::kQuadruple};
301   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
302     TRACED_FOREACH(interpreter::OperandScale, operand_scale, kOperandScales) {
303       InterpreterAssemblerTestState state(this, bytecode);
304       InterpreterAssemblerForTest m(&state, bytecode, operand_scale);
305       int number_of_operands =
306           interpreter::Bytecodes::NumberOfOperands(bytecode);
307       for (int i = 0; i < number_of_operands; i++) {
308         int offset = interpreter::Bytecodes::GetOperandOffset(bytecode, i,
309                                                               operand_scale);
310         OperandType operand_type =
311             interpreter::Bytecodes::GetOperandType(bytecode, i);
312         OperandSize operand_size =
313             Bytecodes::SizeOfOperand(operand_type, operand_scale);
314         switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) {
315           case interpreter::OperandType::kRegCount:
316             EXPECT_THAT(m.BytecodeOperandCount(i),
317                         m.IsUnsignedOperand(offset, operand_size));
318             break;
319           case interpreter::OperandType::kFlag8:
320             EXPECT_THAT(m.BytecodeOperandFlag(i),
321                         m.IsUnsignedOperand(offset, operand_size));
322             break;
323           case interpreter::OperandType::kIdx:
324             EXPECT_THAT(m.BytecodeOperandIdx(i),
325                         c::IsChangeUint32ToWord(
326                             m.IsUnsignedOperand(offset, operand_size)));
327             break;
328           case interpreter::OperandType::kNativeContextIndex:
329             EXPECT_THAT(m.BytecodeOperandNativeContextIndex(i),
330                         c::IsChangeUint32ToWord(
331                             m.IsUnsignedOperand(offset, operand_size)));
332             break;
333           case interpreter::OperandType::kUImm:
334             EXPECT_THAT(m.BytecodeOperandUImm(i),
335                         m.IsUnsignedOperand(offset, operand_size));
336             break;
337           case interpreter::OperandType::kImm: {
338             EXPECT_THAT(m.BytecodeOperandImm(i),
339                         m.IsSignedOperand(offset, operand_size));
340             break;
341           }
342           case interpreter::OperandType::kRuntimeId:
343             EXPECT_THAT(m.BytecodeOperandRuntimeId(i),
344                         m.IsUnsignedOperand(offset, operand_size));
345             break;
346           case interpreter::OperandType::kIntrinsicId:
347             EXPECT_THAT(m.BytecodeOperandIntrinsicId(i),
348                         m.IsUnsignedOperand(offset, operand_size));
349             break;
350           case interpreter::OperandType::kRegList:
351           case interpreter::OperandType::kReg:
352           case interpreter::OperandType::kRegPair:
353           case interpreter::OperandType::kRegOut:
354           case interpreter::OperandType::kRegOutList:
355           case interpreter::OperandType::kRegOutPair:
356           case interpreter::OperandType::kRegOutTriple:
357             EXPECT_THAT(m.LoadRegisterAtOperandIndex(i),
358                         m.IsLoadRegisterOperand(offset, operand_size));
359             break;
360           case interpreter::OperandType::kNone:
361             UNREACHABLE();
362         }
363       }
364     }
365   }
366 }
367 
TARGET_TEST_F(InterpreterAssemblerTest,GetContext)368 TARGET_TEST_F(InterpreterAssemblerTest, GetContext) {
369   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
370     InterpreterAssemblerTestState state(this, bytecode);
371     InterpreterAssemblerForTest m(&state, bytecode);
372     EXPECT_THAT(
373         m.GetContext(),
374         IsBitcastWordToTagged(m.IsLoad(
375             MachineType::Pointer(), c::IsLoadParentFramePointer(),
376             c::IsIntPtrConstant(Register::current_context().ToOperand() *
377                                 kSystemPointerSize))));
378   }
379 }
380 
TARGET_TEST_F(InterpreterAssemblerTest,LoadConstantPoolEntry)381 TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) {
382   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
383     InterpreterAssemblerTestState state(this, bytecode);
384     InterpreterAssemblerForTest m(&state, bytecode);
385     {
386       TNode<IntPtrT> index = m.IntPtrConstant(2);
387       TNode<Object> load_constant = m.LoadConstantPoolEntry(index);
388       Matcher<c::Node*> constant_pool_matcher = m.IsLoadFromObject(
389           MachineType::AnyTagged(),
390           c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
391           c::IsIntPtrConstant(BytecodeArray::kConstantPoolOffset -
392                               kHeapObjectTag));
393       EXPECT_THAT(load_constant,
394                   m.IsLoadFromObject(
395                       MachineType::AnyTagged(), constant_pool_matcher,
396                       c::IsIntPtrConstant(FixedArray::OffsetOfElementAt(2) -
397                                           kHeapObjectTag)));
398     }
399     {
400       c::Node* index = m.UntypedParameter(2);
401       TNode<Object> load_constant =
402           m.LoadConstantPoolEntry(m.ReinterpretCast<IntPtrT>(index));
403       Matcher<c::Node*> constant_pool_matcher = m.IsLoadFromObject(
404           MachineType::AnyTagged(),
405           c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
406           c::IsIntPtrConstant(BytecodeArray::kConstantPoolOffset -
407                               kHeapObjectTag));
408       EXPECT_THAT(
409           load_constant,
410           m.IsLoadFromObject(
411               MachineType::AnyTagged(), constant_pool_matcher,
412               c::IsIntPtrAdd(
413                   c::IsIntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag),
414                   c::IsWordShl(index, c::IsIntPtrConstant(kTaggedSizeLog2)))));
415     }
416   }
417 }
418 
TARGET_TEST_F(InterpreterAssemblerTest,LoadObjectField)419 TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) {
420   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
421     InterpreterAssemblerTestState state(this, bytecode);
422     InterpreterAssemblerForTest m(&state, bytecode);
423     TNode<HeapObject> object =
424         m.ReinterpretCast<HeapObject>(m.IntPtrConstant(0xDEADBEEF));
425     int offset = 16;
426     TNode<Object> load_field = m.LoadObjectField(object, offset);
427       EXPECT_THAT(
428           load_field,
429           m.IsLoadFromObject(MachineType::AnyTagged(), Eq(object),
430                              c::IsIntPtrConstant(offset - kHeapObjectTag)));
431   }
432 }
433 
TARGET_TEST_F(InterpreterAssemblerTest,CallRuntime2)434 TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime2) {
435   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
436     InterpreterAssemblerTestState state(this, bytecode);
437     InterpreterAssemblerForTest m(&state, bytecode);
438     TNode<Object> arg1 = m.ReinterpretCast<Object>(m.Int32Constant(2));
439     TNode<Object> arg2 = m.ReinterpretCast<Object>(m.Int32Constant(3));
440     TNode<Object> context = m.ReinterpretCast<Object>(m.Int32Constant(4));
441     TNode<Object> call_runtime =
442         m.CallRuntime(Runtime::kAdd, context, arg1, arg2);
443     EXPECT_THAT(call_runtime,
444                 c::IsCall(_, _, Eq(arg1), Eq(arg2), _, c::IsInt32Constant(2),
445                           Eq(context), _, _));
446   }
447 }
448 
TARGET_TEST_F(InterpreterAssemblerTest,CallRuntime)449 TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) {
450   const int kResultSizes[] = {1, 2};
451   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
452     TRACED_FOREACH(int, result_size, kResultSizes) {
453       if (Bytecodes::IsCallRuntime(bytecode)) {
454         InterpreterAssemblerTestState state(this, bytecode);
455         InterpreterAssemblerForTest m(&state, bytecode);
456         Callable builtin =
457             CodeFactory::InterpreterCEntry(isolate(), result_size);
458 
459         TNode<Uint32T> function_id = m.Uint32Constant(0);
460         InterpreterAssembler::RegListNodePair registers(m.IntPtrConstant(1),
461                                                         m.Int32Constant(2));
462         TNode<Context> context = m.ReinterpretCast<Context>(m.Int32Constant(4));
463 
464         Matcher<c::Node*> function_table = c::IsExternalConstant(
465             ExternalReference::runtime_function_table_address_for_unittests(
466                 isolate()));
467         Matcher<c::Node*> function =
468             c::IsIntPtrAdd(function_table,
469                            c::IsChangeUint32ToWord(c::IsInt32Mul(
470                                Eq(function_id),
471                                c::IsInt32Constant(sizeof(Runtime::Function)))));
472         Matcher<c::Node*> function_entry =
473             m.IsLoad(MachineType::Pointer(), function,
474                      c::IsIntPtrConstant(offsetof(Runtime::Function, entry)));
475 
476         c::Node* call_runtime =
477             m.CallRuntimeN(function_id, context, registers, result_size);
478         EXPECT_THAT(call_runtime,
479                     c::IsCall(_, c::IsHeapConstant(builtin.code()),
480                               Eq(registers.reg_count()),
481                               Eq(registers.base_reg_location()), function_entry,
482                               Eq(context), _, _));
483       }
484     }
485   }
486 }
487 
TARGET_TEST_F(InterpreterAssemblerTest,LoadFeedbackVector)488 TARGET_TEST_F(InterpreterAssemblerTest, LoadFeedbackVector) {
489   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
490     InterpreterAssemblerTestState state(this, bytecode);
491     InterpreterAssemblerForTest m(&state, bytecode);
492     TNode<HeapObject> feedback_vector = m.LoadFeedbackVector();
493 
494     // Feedback vector is a phi node with two inputs. One of them is loading the
495     // feedback vector and the other is undefined constant (when feedback
496     // vectors aren't allocated). Find the input that loads feedback vector.
497     CHECK_EQ(static_cast<c::Node*>(feedback_vector)->opcode(),
498              i::compiler::IrOpcode::kPhi);
499     c::Node* value0 =
500         i::compiler::NodeProperties::GetValueInput(feedback_vector, 0);
501     c::Node* value1 =
502         i::compiler::NodeProperties::GetValueInput(feedback_vector, 1);
503     c::Node* load_feedback_vector = value0;
504     if (value0->opcode() == i::compiler::IrOpcode::kHeapConstant) {
505       load_feedback_vector = value1;
506     }
507 
508     Matcher<c::Node*> load_function_matcher = IsBitcastWordToTagged(
509         m.IsLoad(MachineType::Pointer(), c::IsLoadParentFramePointer(),
510                  c::IsIntPtrConstant(Register::function_closure().ToOperand() *
511                                      kSystemPointerSize)));
512     Matcher<c::Node*> load_vector_cell_matcher = m.IsLoadFromObject(
513         MachineType::TaggedPointer(), load_function_matcher,
514         c::IsIntPtrConstant(JSFunction::kFeedbackCellOffset - kHeapObjectTag));
515     EXPECT_THAT(load_feedback_vector,
516                 m.IsLoadFromObject(
517                     MachineType::TaggedPointer(), load_vector_cell_matcher,
518                     c::IsIntPtrConstant(Cell::kValueOffset - kHeapObjectTag)));
519   }
520 }
521 
522 }  // namespace interpreter_assembler_unittest
523 }  // namespace interpreter
524 }  // namespace internal
525 }  // namespace v8
526