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 15419 : 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 15419 : 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 15419 : 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 15419 : 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 : #ifdef V8_COMPRESS_POINTERS
438 : Matcher<Node*> constant_pool_matcher =
439 : IsChangeCompressedToTagged(m.IsLoad(
440 : MachineType::AnyCompressed(),
441 : c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
442 : c::IsIntPtrConstant(BytecodeArray::kConstantPoolOffset -
443 : kHeapObjectTag)));
444 : EXPECT_THAT(load_constant,
445 : IsChangeCompressedToTagged(m.IsLoad(
446 : MachineType::AnyCompressed(), constant_pool_matcher,
447 : c::IsIntPtrConstant(FixedArray::OffsetOfElementAt(2) -
448 : kHeapObjectTag),
449 : LoadSensitivity::kCritical)));
450 : #else
451 : Matcher<Node*> constant_pool_matcher = m.IsLoad(
452 : MachineType::AnyTagged(),
453 540 : c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
454 360 : c::IsIntPtrConstant(BytecodeArray::kConstantPoolOffset -
455 360 : kHeapObjectTag));
456 1080 : EXPECT_THAT(
457 : load_constant,
458 : m.IsLoad(MachineType::AnyTagged(), constant_pool_matcher,
459 : c::IsIntPtrConstant(FixedArray::OffsetOfElementAt(2) -
460 : kHeapObjectTag),
461 0 : LoadSensitivity::kCritical));
462 : #endif
463 : }
464 : {
465 180 : Node* index = m.Parameter(2);
466 180 : Node* load_constant = m.LoadConstantPoolEntry(index);
467 : #if V8_COMPRESS_POINTERS
468 : Matcher<Node*> constant_pool_matcher =
469 : IsChangeCompressedToTagged(m.IsLoad(
470 : MachineType::AnyCompressed(),
471 : c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
472 : c::IsIntPtrConstant(BytecodeArray::kConstantPoolOffset -
473 : kHeapObjectTag)));
474 : EXPECT_THAT(
475 : load_constant,
476 : IsChangeCompressedToTagged(m.IsLoad(
477 : MachineType::AnyCompressed(), constant_pool_matcher,
478 : c::IsIntPtrAdd(
479 : c::IsIntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag),
480 : c::IsWordShl(index, c::IsIntPtrConstant(kTaggedSizeLog2))),
481 : LoadSensitivity::kCritical)));
482 : #else
483 : Matcher<Node*> constant_pool_matcher = m.IsLoad(
484 : MachineType::AnyTagged(),
485 540 : c::IsParameter(InterpreterDispatchDescriptor::kBytecodeArray),
486 360 : c::IsIntPtrConstant(BytecodeArray::kConstantPoolOffset -
487 360 : kHeapObjectTag));
488 2160 : EXPECT_THAT(
489 : load_constant,
490 : m.IsLoad(
491 : MachineType::AnyTagged(), constant_pool_matcher,
492 : c::IsIntPtrAdd(
493 : c::IsIntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag),
494 : c::IsWordShl(index, c::IsIntPtrConstant(kTaggedSizeLog2))),
495 0 : LoadSensitivity::kCritical));
496 : #endif
497 : }
498 : }
499 1 : }
500 :
501 15419 : TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) {
502 721 : TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
503 180 : InterpreterAssemblerTestState state(this, bytecode);
504 360 : InterpreterAssemblerForTest m(&state, bytecode);
505 360 : Node* object = m.IntPtrConstant(0xDEADBEEF);
506 : int offset = 16;
507 180 : Node* load_field = m.LoadObjectField(object, offset);
508 : #ifdef V8_COMPRESS_POINTERS
509 : EXPECT_THAT(load_field, IsChangeCompressedToTagged(m.IsLoad(
510 : MachineType::AnyCompressed(), object,
511 : c::IsIntPtrConstant(offset - kHeapObjectTag))));
512 : #else
513 1260 : EXPECT_THAT(load_field,
514 : m.IsLoad(MachineType::AnyTagged(), object,
515 0 : c::IsIntPtrConstant(offset - kHeapObjectTag)));
516 : #endif
517 : }
518 1 : }
519 :
520 15419 : TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime2) {
521 721 : TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
522 180 : InterpreterAssemblerTestState state(this, bytecode);
523 360 : InterpreterAssemblerForTest m(&state, bytecode);
524 360 : Node* arg1 = m.Int32Constant(2);
525 360 : Node* arg2 = m.Int32Constant(3);
526 360 : Node* context = m.Int32Constant(4);
527 180 : Node* call_runtime = m.CallRuntime(Runtime::kAdd, context, arg1, arg2);
528 2880 : EXPECT_THAT(call_runtime, c::IsCall(_, _, arg1, arg2, _,
529 0 : c::IsInt32Constant(2), context, _, _));
530 : }
531 1 : }
532 :
533 15419 : TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) {
534 1 : const int kResultSizes[] = {1, 2};
535 721 : TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
536 1620 : TRACED_FOREACH(int, result_size, kResultSizes) {
537 720 : if (Bytecodes::IsCallRuntime(bytecode)) {
538 6 : InterpreterAssemblerTestState state(this, bytecode);
539 12 : InterpreterAssemblerForTest m(&state, bytecode);
540 : Callable builtin =
541 6 : CodeFactory::InterpreterCEntry(isolate(), result_size);
542 :
543 12 : Node* function_id = m.Int32Constant(0);
544 12 : InterpreterAssembler::RegListNodePair registers(m.IntPtrConstant(1),
545 12 : m.Int32Constant(2));
546 12 : Node* context = m.IntPtrConstant(4);
547 :
548 : Matcher<Node*> function_table = c::IsExternalConstant(
549 : ExternalReference::runtime_function_table_address_for_unittests(
550 12 : isolate()));
551 : Matcher<Node*> function = c::IsIntPtrAdd(
552 : function_table,
553 24 : c::IsChangeUint32ToWord(c::IsInt32Mul(
554 18 : function_id, c::IsInt32Constant(sizeof(Runtime::Function)))));
555 : Matcher<Node*> function_entry =
556 : m.IsLoad(MachineType::Pointer(), function,
557 18 : c::IsIntPtrConstant(offsetof(Runtime::Function, entry)));
558 :
559 : Node* call_runtime =
560 6 : m.CallRuntimeN(function_id, context, registers, result_size);
561 78 : EXPECT_THAT(
562 : call_runtime,
563 : c::IsCall(_, c::IsHeapConstant(builtin.code()),
564 : registers.reg_count(), registers.base_reg_location(),
565 0 : function_entry, context, _, _));
566 : }
567 : }
568 : }
569 1 : }
570 :
571 15419 : TARGET_TEST_F(InterpreterAssemblerTest, LoadFeedbackVector) {
572 721 : TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
573 180 : InterpreterAssemblerTestState state(this, bytecode);
574 360 : InterpreterAssemblerForTest m(&state, bytecode);
575 360 : Node* feedback_vector = m.LoadFeedbackVector();
576 :
577 : // Feedback vector is a phi node with two inputs. One of them is loading the
578 : // feedback vector and the other is undefined constant (when feedback
579 : // vectors aren't allocated). Find the input that loads feedback vector.
580 180 : CHECK(feedback_vector->opcode() == i::compiler::IrOpcode::kPhi);
581 : Node* value0 =
582 180 : i::compiler::NodeProperties::GetValueInput(feedback_vector, 0);
583 : Node* value1 =
584 180 : i::compiler::NodeProperties::GetValueInput(feedback_vector, 1);
585 180 : Node* load_feedback_vector = value0;
586 180 : if (value0->opcode() == i::compiler::IrOpcode::kHeapConstant) {
587 0 : load_feedback_vector = value1;
588 : }
589 :
590 : Matcher<Node*> load_function_matcher = IsBitcastWordToTagged(
591 720 : m.IsLoad(MachineType::Pointer(), c::IsLoadParentFramePointer(),
592 540 : c::IsIntPtrConstant(Register::function_closure().ToOperand() *
593 180 : kSystemPointerSize)));
594 : #ifdef V8_COMPRESS_POINTERS
595 : Matcher<Node*> load_vector_cell_matcher = IsChangeCompressedToTagged(
596 : m.IsLoad(MachineType::AnyCompressed(), load_function_matcher,
597 : c::IsIntPtrConstant(JSFunction::kFeedbackCellOffset -
598 : kHeapObjectTag)));
599 : EXPECT_THAT(load_feedback_vector,
600 : IsChangeCompressedToTagged(m.IsLoad(
601 : MachineType::AnyCompressed(), load_vector_cell_matcher,
602 : c::IsIntPtrConstant(Cell::kValueOffset - kHeapObjectTag))));
603 : #else
604 : Matcher<Node*> load_vector_cell_matcher = m.IsLoad(
605 : MachineType::AnyTagged(), load_function_matcher,
606 540 : c::IsIntPtrConstant(JSFunction::kFeedbackCellOffset - kHeapObjectTag));
607 1080 : EXPECT_THAT(
608 : load_feedback_vector,
609 : m.IsLoad(MachineType::AnyTagged(), load_vector_cell_matcher,
610 0 : c::IsIntPtrConstant(Cell::kValueOffset - kHeapObjectTag)));
611 : #endif
612 : }
613 1 : }
614 :
615 : } // namespace interpreter_assembler_unittest
616 : } // namespace interpreter
617 : } // namespace internal
618 9249 : } // namespace v8
|