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