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