OLD | NEW |
| (Empty) |
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/compiler/interpreter-assembler-unittest.h" | |
6 | |
7 #include "src/code-factory.h" | |
8 #include "src/compiler/graph.h" | |
9 #include "src/compiler/node.h" | |
10 #include "src/interface-descriptors.h" | |
11 #include "src/isolate.h" | |
12 #include "test/unittests/compiler/compiler-test-utils.h" | |
13 #include "test/unittests/compiler/node-test-utils.h" | |
14 | |
15 using ::testing::_; | |
16 | |
17 namespace v8 { | |
18 namespace internal { | |
19 namespace compiler { | |
20 | |
21 const interpreter::Bytecode kBytecodes[] = { | |
22 #define DEFINE_BYTECODE(Name, ...) interpreter::Bytecode::k##Name, | |
23 BYTECODE_LIST(DEFINE_BYTECODE) | |
24 #undef DEFINE_BYTECODE | |
25 }; | |
26 | |
27 | |
28 Matcher<Node*> IsIntPtrConstant(const intptr_t value) { | |
29 return kPointerSize == 8 ? IsInt64Constant(static_cast<int64_t>(value)) | |
30 : IsInt32Constant(static_cast<int32_t>(value)); | |
31 } | |
32 | |
33 | |
34 Matcher<Node*> IsIntPtrAdd(const Matcher<Node*>& lhs_matcher, | |
35 const Matcher<Node*>& rhs_matcher) { | |
36 return kPointerSize == 8 ? IsInt64Add(lhs_matcher, rhs_matcher) | |
37 : IsInt32Add(lhs_matcher, rhs_matcher); | |
38 } | |
39 | |
40 | |
41 Matcher<Node*> IsIntPtrSub(const Matcher<Node*>& lhs_matcher, | |
42 const Matcher<Node*>& rhs_matcher) { | |
43 return kPointerSize == 8 ? IsInt64Sub(lhs_matcher, rhs_matcher) | |
44 : IsInt32Sub(lhs_matcher, rhs_matcher); | |
45 } | |
46 | |
47 | |
48 Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher, | |
49 const Matcher<Node*>& rhs_matcher) { | |
50 return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher) | |
51 : IsWord32Shl(lhs_matcher, rhs_matcher); | |
52 } | |
53 | |
54 | |
55 Matcher<Node*> IsWordSar(const Matcher<Node*>& lhs_matcher, | |
56 const Matcher<Node*>& rhs_matcher) { | |
57 return kPointerSize == 8 ? IsWord64Sar(lhs_matcher, rhs_matcher) | |
58 : IsWord32Sar(lhs_matcher, rhs_matcher); | |
59 } | |
60 | |
61 | |
62 Matcher<Node*> IsWordOr(const Matcher<Node*>& lhs_matcher, | |
63 const Matcher<Node*>& rhs_matcher) { | |
64 return kPointerSize == 8 ? IsWord64Or(lhs_matcher, rhs_matcher) | |
65 : IsWord32Or(lhs_matcher, rhs_matcher); | |
66 } | |
67 | |
68 | |
69 Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoad( | |
70 const Matcher<LoadRepresentation>& rep_matcher, | |
71 const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher) { | |
72 return ::i::compiler::IsLoad(rep_matcher, base_matcher, index_matcher, _, _); | |
73 } | |
74 | |
75 | |
76 Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore( | |
77 const Matcher<StoreRepresentation>& rep_matcher, | |
78 const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher, | |
79 const Matcher<Node*>& value_matcher) { | |
80 return ::i::compiler::IsStore(rep_matcher, base_matcher, index_matcher, | |
81 value_matcher, _, _); | |
82 } | |
83 | |
84 | |
85 Matcher<Node*> | |
86 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand( | |
87 int offset) { | |
88 return IsLoad( | |
89 MachineType::Uint8(), | |
90 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
91 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
92 IsInt32Constant(offset))); | |
93 } | |
94 | |
95 | |
96 Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: | |
97 IsBytecodeOperandSignExtended(int offset) { | |
98 Matcher<Node*> load_matcher = IsLoad( | |
99 MachineType::Int8(), | |
100 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
101 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
102 IsInt32Constant(offset))); | |
103 if (kPointerSize == 8) { | |
104 load_matcher = IsChangeInt32ToInt64(load_matcher); | |
105 } | |
106 return load_matcher; | |
107 } | |
108 | |
109 | |
110 Matcher<Node*> | |
111 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperandShort( | |
112 int offset) { | |
113 if (TargetSupportsUnalignedAccess()) { | |
114 return IsLoad( | |
115 MachineType::Uint16(), | |
116 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
117 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
118 IsInt32Constant(offset))); | |
119 } else { | |
120 Matcher<Node*> first_byte = IsLoad( | |
121 MachineType::Uint8(), | |
122 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
123 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
124 IsInt32Constant(offset))); | |
125 Matcher<Node*> second_byte = IsLoad( | |
126 MachineType::Uint8(), | |
127 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
128 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
129 IsInt32Constant(offset + 1))); | |
130 #if V8_TARGET_LITTLE_ENDIAN | |
131 return IsWordOr(IsWordShl(second_byte, IsInt32Constant(kBitsPerByte)), | |
132 first_byte); | |
133 #elif V8_TARGET_BIG_ENDIAN | |
134 return IsWordOr(IsWordShl(first_byte, IsInt32Constant(kBitsPerByte)), | |
135 second_byte); | |
136 #else | |
137 #error "Unknown Architecture" | |
138 #endif | |
139 } | |
140 } | |
141 | |
142 | |
143 Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: | |
144 IsBytecodeOperandShortSignExtended(int offset) { | |
145 Matcher<Node*> load_matcher; | |
146 if (TargetSupportsUnalignedAccess()) { | |
147 load_matcher = IsLoad( | |
148 MachineType::Int16(), | |
149 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
150 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
151 IsInt32Constant(offset))); | |
152 } else { | |
153 #if V8_TARGET_LITTLE_ENDIAN | |
154 int hi_byte_offset = offset + 1; | |
155 int lo_byte_offset = offset; | |
156 | |
157 #elif V8_TARGET_BIG_ENDIAN | |
158 int hi_byte_offset = offset; | |
159 int lo_byte_offset = offset + 1; | |
160 #else | |
161 #error "Unknown Architecture" | |
162 #endif | |
163 Matcher<Node*> hi_byte = IsLoad( | |
164 MachineType::Int8(), | |
165 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
166 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
167 IsInt32Constant(hi_byte_offset))); | |
168 hi_byte = IsWord32Shl(hi_byte, IsInt32Constant(kBitsPerByte)); | |
169 Matcher<Node*> lo_byte = IsLoad( | |
170 MachineType::Uint8(), | |
171 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
172 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
173 IsInt32Constant(lo_byte_offset))); | |
174 load_matcher = IsWord32Or(hi_byte, lo_byte); | |
175 } | |
176 | |
177 if (kPointerSize == 8) { | |
178 load_matcher = IsChangeInt32ToInt64(load_matcher); | |
179 } | |
180 return load_matcher; | |
181 } | |
182 | |
183 | |
184 TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) { | |
185 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
186 InterpreterAssemblerForTest m(this, bytecode); | |
187 m.Dispatch(); | |
188 Graph* graph = m.graph(); | |
189 | |
190 Node* end = graph->end(); | |
191 EXPECT_EQ(1, end->InputCount()); | |
192 Node* tail_call_node = end->InputAt(0); | |
193 | |
194 Matcher<Node*> next_bytecode_offset_matcher = | |
195 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
196 IsInt32Constant(interpreter::Bytecodes::Size(bytecode))); | |
197 Matcher<Node*> target_bytecode_matcher = | |
198 m.IsLoad(MachineType::Uint8(), | |
199 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
200 next_bytecode_offset_matcher); | |
201 Matcher<Node*> code_target_matcher = | |
202 m.IsLoad(MachineType::Pointer(), | |
203 IsParameter(Linkage::kInterpreterDispatchTableParameter), | |
204 IsWord32Shl(target_bytecode_matcher, | |
205 IsInt32Constant(kPointerSizeLog2))); | |
206 | |
207 EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind()); | |
208 EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots); | |
209 EXPECT_THAT( | |
210 tail_call_node, | |
211 IsTailCall(m.call_descriptor(), code_target_matcher, | |
212 IsParameter(Linkage::kInterpreterAccumulatorParameter), | |
213 IsParameter(Linkage::kInterpreterRegisterFileParameter), | |
214 next_bytecode_offset_matcher, | |
215 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
216 IsParameter(Linkage::kInterpreterDispatchTableParameter), | |
217 IsParameter(Linkage::kInterpreterContextParameter), _, _)); | |
218 } | |
219 } | |
220 | |
221 | |
222 TARGET_TEST_F(InterpreterAssemblerTest, Jump) { | |
223 int jump_offsets[] = {-9710, -77, 0, +3, +97109}; | |
224 TRACED_FOREACH(int, jump_offset, jump_offsets) { | |
225 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
226 InterpreterAssemblerForTest m(this, bytecode); | |
227 m.Jump(m.Int32Constant(jump_offset)); | |
228 Graph* graph = m.graph(); | |
229 Node* end = graph->end(); | |
230 EXPECT_EQ(1, end->InputCount()); | |
231 Node* tail_call_node = end->InputAt(0); | |
232 | |
233 Matcher<Node*> next_bytecode_offset_matcher = | |
234 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
235 IsInt32Constant(jump_offset)); | |
236 Matcher<Node*> target_bytecode_matcher = | |
237 m.IsLoad(MachineType::Uint8(), | |
238 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
239 next_bytecode_offset_matcher); | |
240 Matcher<Node*> code_target_matcher = | |
241 m.IsLoad(MachineType::Pointer(), | |
242 IsParameter(Linkage::kInterpreterDispatchTableParameter), | |
243 IsWord32Shl(target_bytecode_matcher, | |
244 IsInt32Constant(kPointerSizeLog2))); | |
245 | |
246 EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind()); | |
247 EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots); | |
248 EXPECT_THAT( | |
249 tail_call_node, | |
250 IsTailCall(m.call_descriptor(), code_target_matcher, | |
251 IsParameter(Linkage::kInterpreterAccumulatorParameter), | |
252 IsParameter(Linkage::kInterpreterRegisterFileParameter), | |
253 next_bytecode_offset_matcher, | |
254 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
255 IsParameter(Linkage::kInterpreterDispatchTableParameter), | |
256 IsParameter(Linkage::kInterpreterContextParameter), _, _)); | |
257 } | |
258 } | |
259 } | |
260 | |
261 | |
262 TARGET_TEST_F(InterpreterAssemblerTest, JumpIfWordEqual) { | |
263 static const int kJumpIfTrueOffset = 73; | |
264 | |
265 MachineOperatorBuilder machine(zone()); | |
266 | |
267 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
268 InterpreterAssemblerForTest m(this, bytecode); | |
269 Node* lhs = m.IntPtrConstant(0); | |
270 Node* rhs = m.IntPtrConstant(1); | |
271 m.JumpIfWordEqual(lhs, rhs, m.Int32Constant(kJumpIfTrueOffset)); | |
272 Graph* graph = m.graph(); | |
273 Node* end = graph->end(); | |
274 EXPECT_EQ(2, end->InputCount()); | |
275 | |
276 int jump_offsets[] = {kJumpIfTrueOffset, | |
277 interpreter::Bytecodes::Size(bytecode)}; | |
278 for (int i = 0; i < static_cast<int>(arraysize(jump_offsets)); i++) { | |
279 Matcher<Node*> next_bytecode_offset_matcher = | |
280 IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
281 IsInt32Constant(jump_offsets[i])); | |
282 Matcher<Node*> target_bytecode_matcher = | |
283 m.IsLoad(MachineType::Uint8(), | |
284 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
285 next_bytecode_offset_matcher); | |
286 Matcher<Node*> code_target_matcher = | |
287 m.IsLoad(MachineType::Pointer(), | |
288 IsParameter(Linkage::kInterpreterDispatchTableParameter), | |
289 IsWord32Shl(target_bytecode_matcher, | |
290 IsInt32Constant(kPointerSizeLog2))); | |
291 EXPECT_THAT( | |
292 end->InputAt(i), | |
293 IsTailCall(m.call_descriptor(), code_target_matcher, | |
294 IsParameter(Linkage::kInterpreterAccumulatorParameter), | |
295 IsParameter(Linkage::kInterpreterRegisterFileParameter), | |
296 next_bytecode_offset_matcher, | |
297 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
298 IsParameter(Linkage::kInterpreterDispatchTableParameter), | |
299 IsParameter(Linkage::kInterpreterContextParameter), _, _)); | |
300 } | |
301 | |
302 // TODO(oth): test control flow paths. | |
303 } | |
304 } | |
305 | |
306 | |
307 TARGET_TEST_F(InterpreterAssemblerTest, Return) { | |
308 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
309 InterpreterAssemblerForTest m(this, bytecode); | |
310 m.Return(); | |
311 Graph* graph = m.graph(); | |
312 | |
313 Node* end = graph->end(); | |
314 EXPECT_EQ(1, end->InputCount()); | |
315 Node* tail_call_node = end->InputAt(0); | |
316 | |
317 EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind()); | |
318 EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots); | |
319 Handle<HeapObject> exit_trampoline = | |
320 isolate()->builtins()->InterpreterExitTrampoline(); | |
321 EXPECT_THAT( | |
322 tail_call_node, | |
323 IsTailCall(m.call_descriptor(), IsHeapConstant(exit_trampoline), | |
324 IsParameter(Linkage::kInterpreterAccumulatorParameter), | |
325 IsParameter(Linkage::kInterpreterRegisterFileParameter), | |
326 IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), | |
327 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
328 IsParameter(Linkage::kInterpreterDispatchTableParameter), | |
329 IsParameter(Linkage::kInterpreterContextParameter), _, _)); | |
330 } | |
331 } | |
332 | |
333 | |
334 TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { | |
335 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
336 InterpreterAssemblerForTest m(this, bytecode); | |
337 int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode); | |
338 for (int i = 0; i < number_of_operands; i++) { | |
339 int offset = interpreter::Bytecodes::GetOperandOffset(bytecode, i); | |
340 switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) { | |
341 case interpreter::OperandType::kRegCount8: | |
342 EXPECT_THAT(m.BytecodeOperandCount(i), m.IsBytecodeOperand(offset)); | |
343 break; | |
344 case interpreter::OperandType::kIdx8: | |
345 EXPECT_THAT(m.BytecodeOperandIdx(i), m.IsBytecodeOperand(offset)); | |
346 break; | |
347 case interpreter::OperandType::kImm8: | |
348 EXPECT_THAT(m.BytecodeOperandImm(i), | |
349 m.IsBytecodeOperandSignExtended(offset)); | |
350 break; | |
351 case interpreter::OperandType::kMaybeReg8: | |
352 case interpreter::OperandType::kReg8: | |
353 case interpreter::OperandType::kRegOut8: | |
354 case interpreter::OperandType::kRegOutPair8: | |
355 case interpreter::OperandType::kRegOutTriple8: | |
356 case interpreter::OperandType::kRegPair8: | |
357 EXPECT_THAT(m.BytecodeOperandReg(i), | |
358 m.IsBytecodeOperandSignExtended(offset)); | |
359 break; | |
360 case interpreter::OperandType::kRegCount16: | |
361 EXPECT_THAT(m.BytecodeOperandCount(i), | |
362 m.IsBytecodeOperandShort(offset)); | |
363 break; | |
364 case interpreter::OperandType::kIdx16: | |
365 EXPECT_THAT(m.BytecodeOperandIdx(i), | |
366 m.IsBytecodeOperandShort(offset)); | |
367 break; | |
368 case interpreter::OperandType::kMaybeReg16: | |
369 case interpreter::OperandType::kReg16: | |
370 case interpreter::OperandType::kRegOut16: | |
371 case interpreter::OperandType::kRegOutPair16: | |
372 case interpreter::OperandType::kRegOutTriple16: | |
373 case interpreter::OperandType::kRegPair16: | |
374 EXPECT_THAT(m.BytecodeOperandReg(i), | |
375 m.IsBytecodeOperandShortSignExtended(offset)); | |
376 break; | |
377 case interpreter::OperandType::kNone: | |
378 UNREACHABLE(); | |
379 break; | |
380 } | |
381 } | |
382 } | |
383 } | |
384 | |
385 | |
386 TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) { | |
387 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
388 InterpreterAssemblerForTest m(this, bytecode); | |
389 // Should be incoming accumulator if not set. | |
390 EXPECT_THAT(m.GetAccumulator(), | |
391 IsParameter(Linkage::kInterpreterAccumulatorParameter)); | |
392 | |
393 // Should be set by SedtAccumulator. | |
394 Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef); | |
395 m.SetAccumulator(accumulator_value_1); | |
396 EXPECT_THAT(m.GetAccumulator(), accumulator_value_1); | |
397 Node* accumulator_value_2 = m.Int32Constant(42); | |
398 m.SetAccumulator(accumulator_value_2); | |
399 EXPECT_THAT(m.GetAccumulator(), accumulator_value_2); | |
400 | |
401 // Should be passed to next bytecode handler on dispatch. | |
402 m.Dispatch(); | |
403 Graph* graph = m.graph(); | |
404 | |
405 Node* end = graph->end(); | |
406 EXPECT_EQ(1, end->InputCount()); | |
407 Node* tail_call_node = end->InputAt(0); | |
408 | |
409 EXPECT_THAT(tail_call_node, | |
410 IsTailCall(m.call_descriptor(), _, accumulator_value_2, _, _, _, | |
411 _, _, _)); | |
412 } | |
413 } | |
414 | |
415 | |
416 TARGET_TEST_F(InterpreterAssemblerTest, GetSetContext) { | |
417 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
418 InterpreterAssemblerForTest m(this, bytecode); | |
419 Node* context_node = m.Int32Constant(100); | |
420 m.SetContext(context_node); | |
421 EXPECT_THAT(m.GetContext(), context_node); | |
422 } | |
423 } | |
424 | |
425 | |
426 TARGET_TEST_F(InterpreterAssemblerTest, RegisterLocation) { | |
427 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
428 InterpreterAssemblerForTest m(this, bytecode); | |
429 Node* reg_index_node = m.Int32Constant(44); | |
430 Node* reg_location_node = m.RegisterLocation(reg_index_node); | |
431 EXPECT_THAT( | |
432 reg_location_node, | |
433 IsIntPtrAdd( | |
434 IsParameter(Linkage::kInterpreterRegisterFileParameter), | |
435 IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)))); | |
436 } | |
437 } | |
438 | |
439 | |
440 TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) { | |
441 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
442 InterpreterAssemblerForTest m(this, bytecode); | |
443 Node* reg_index_node = m.Int32Constant(44); | |
444 Node* load_reg_node = m.LoadRegister(reg_index_node); | |
445 EXPECT_THAT( | |
446 load_reg_node, | |
447 m.IsLoad(MachineType::AnyTagged(), | |
448 IsParameter(Linkage::kInterpreterRegisterFileParameter), | |
449 IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)))); | |
450 } | |
451 } | |
452 | |
453 | |
454 TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) { | |
455 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
456 InterpreterAssemblerForTest m(this, bytecode); | |
457 Node* store_value = m.Int32Constant(0xdeadbeef); | |
458 Node* reg_index_node = m.Int32Constant(44); | |
459 Node* store_reg_node = m.StoreRegister(store_value, reg_index_node); | |
460 EXPECT_THAT( | |
461 store_reg_node, | |
462 m.IsStore(StoreRepresentation(MachineRepresentation::kTagged, | |
463 kNoWriteBarrier), | |
464 IsParameter(Linkage::kInterpreterRegisterFileParameter), | |
465 IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)), | |
466 store_value)); | |
467 } | |
468 } | |
469 | |
470 | |
471 TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) { | |
472 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
473 InterpreterAssemblerForTest m(this, bytecode); | |
474 Node* value = m.Int32Constant(44); | |
475 EXPECT_THAT(m.SmiTag(value), | |
476 IsWordShl(value, IsInt32Constant(kSmiShiftSize + kSmiTagSize))); | |
477 EXPECT_THAT(m.SmiUntag(value), | |
478 IsWordSar(value, IsInt32Constant(kSmiShiftSize + kSmiTagSize))); | |
479 } | |
480 } | |
481 | |
482 | |
483 TARGET_TEST_F(InterpreterAssemblerTest, IntPtrAdd) { | |
484 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
485 InterpreterAssemblerForTest m(this, bytecode); | |
486 Node* a = m.Int32Constant(0); | |
487 Node* b = m.Int32Constant(1); | |
488 Node* add = m.IntPtrAdd(a, b); | |
489 EXPECT_THAT(add, IsIntPtrAdd(a, b)); | |
490 } | |
491 } | |
492 | |
493 | |
494 TARGET_TEST_F(InterpreterAssemblerTest, IntPtrSub) { | |
495 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
496 InterpreterAssemblerForTest m(this, bytecode); | |
497 Node* a = m.Int32Constant(0); | |
498 Node* b = m.Int32Constant(1); | |
499 Node* add = m.IntPtrSub(a, b); | |
500 EXPECT_THAT(add, IsIntPtrSub(a, b)); | |
501 } | |
502 } | |
503 | |
504 | |
505 TARGET_TEST_F(InterpreterAssemblerTest, WordShl) { | |
506 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
507 InterpreterAssemblerForTest m(this, bytecode); | |
508 Node* a = m.Int32Constant(0); | |
509 Node* add = m.WordShl(a, 10); | |
510 EXPECT_THAT(add, IsWordShl(a, IsInt32Constant(10))); | |
511 } | |
512 } | |
513 | |
514 | |
515 TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) { | |
516 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
517 InterpreterAssemblerForTest m(this, bytecode); | |
518 Node* index = m.Int32Constant(2); | |
519 Node* load_constant = m.LoadConstantPoolEntry(index); | |
520 Matcher<Node*> constant_pool_matcher = m.IsLoad( | |
521 MachineType::AnyTagged(), | |
522 IsParameter(Linkage::kInterpreterBytecodeArrayParameter), | |
523 IsIntPtrConstant(BytecodeArray::kConstantPoolOffset - kHeapObjectTag)); | |
524 EXPECT_THAT( | |
525 load_constant, | |
526 m.IsLoad(MachineType::AnyTagged(), constant_pool_matcher, | |
527 IsIntPtrAdd( | |
528 IsIntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag), | |
529 IsWordShl(index, IsInt32Constant(kPointerSizeLog2))))); | |
530 } | |
531 } | |
532 | |
533 | |
534 TARGET_TEST_F(InterpreterAssemblerTest, LoadFixedArrayElement) { | |
535 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
536 InterpreterAssemblerForTest m(this, bytecode); | |
537 int index = 3; | |
538 Node* fixed_array = m.IntPtrConstant(0xdeadbeef); | |
539 Node* load_element = m.LoadFixedArrayElement(fixed_array, index); | |
540 EXPECT_THAT( | |
541 load_element, | |
542 m.IsLoad(MachineType::AnyTagged(), fixed_array, | |
543 IsIntPtrAdd( | |
544 IsIntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag), | |
545 IsWordShl(IsInt32Constant(index), | |
546 IsInt32Constant(kPointerSizeLog2))))); | |
547 } | |
548 } | |
549 | |
550 | |
551 TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) { | |
552 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
553 InterpreterAssemblerForTest m(this, bytecode); | |
554 Node* object = m.IntPtrConstant(0xdeadbeef); | |
555 int offset = 16; | |
556 Node* load_field = m.LoadObjectField(object, offset); | |
557 EXPECT_THAT(load_field, | |
558 m.IsLoad(MachineType::AnyTagged(), object, | |
559 IsIntPtrConstant(offset - kHeapObjectTag))); | |
560 } | |
561 } | |
562 | |
563 | |
564 TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) { | |
565 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
566 InterpreterAssemblerForTest m(this, bytecode); | |
567 Node* context = m.Int32Constant(1); | |
568 Node* slot_index = m.Int32Constant(22); | |
569 Node* load_context_slot = m.LoadContextSlot(context, slot_index); | |
570 | |
571 Matcher<Node*> offset = | |
572 IsIntPtrAdd(IsWordShl(slot_index, IsInt32Constant(kPointerSizeLog2)), | |
573 IsInt32Constant(Context::kHeaderSize - kHeapObjectTag)); | |
574 EXPECT_THAT(load_context_slot, | |
575 m.IsLoad(MachineType::AnyTagged(), context, offset)); | |
576 } | |
577 } | |
578 | |
579 | |
580 TARGET_TEST_F(InterpreterAssemblerTest, StoreContextSlot) { | |
581 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
582 InterpreterAssemblerForTest m(this, bytecode); | |
583 Node* context = m.Int32Constant(1); | |
584 Node* slot_index = m.Int32Constant(22); | |
585 Node* value = m.Int32Constant(100); | |
586 Node* store_context_slot = m.StoreContextSlot(context, slot_index, value); | |
587 | |
588 Matcher<Node*> offset = | |
589 IsIntPtrAdd(IsWordShl(slot_index, IsInt32Constant(kPointerSizeLog2)), | |
590 IsInt32Constant(Context::kHeaderSize - kHeapObjectTag)); | |
591 EXPECT_THAT(store_context_slot, | |
592 m.IsStore(StoreRepresentation(MachineRepresentation::kTagged, | |
593 kFullWriteBarrier), | |
594 context, offset, value)); | |
595 } | |
596 } | |
597 | |
598 | |
599 TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime2) { | |
600 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
601 InterpreterAssemblerForTest m(this, bytecode); | |
602 Node* arg1 = m.Int32Constant(2); | |
603 Node* arg2 = m.Int32Constant(3); | |
604 Node* call_runtime = m.CallRuntime(Runtime::kAdd, arg1, arg2); | |
605 EXPECT_THAT( | |
606 call_runtime, | |
607 IsCall(_, _, arg1, arg2, _, IsInt32Constant(2), | |
608 IsParameter(Linkage::kInterpreterContextParameter), _, _)); | |
609 } | |
610 } | |
611 | |
612 | |
613 TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) { | |
614 const int kResultSizes[] = {1, 2}; | |
615 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
616 TRACED_FOREACH(int, result_size, kResultSizes) { | |
617 InterpreterAssemblerForTest m(this, bytecode); | |
618 Callable builtin = CodeFactory::InterpreterCEntry(isolate(), result_size); | |
619 | |
620 Node* function_id = m.Int32Constant(0); | |
621 Node* first_arg = m.Int32Constant(1); | |
622 Node* arg_count = m.Int32Constant(2); | |
623 | |
624 Matcher<Node*> function_table = IsExternalConstant( | |
625 ExternalReference::runtime_function_table_address(isolate())); | |
626 Matcher<Node*> function = IsIntPtrAdd( | |
627 function_table, | |
628 IsInt32Mul(function_id, IsInt32Constant(sizeof(Runtime::Function)))); | |
629 Matcher<Node*> function_entry = | |
630 m.IsLoad(MachineType::Pointer(), function, | |
631 IsInt32Constant(offsetof(Runtime::Function, entry))); | |
632 | |
633 Node* call_runtime = | |
634 m.CallRuntime(function_id, first_arg, arg_count, result_size); | |
635 EXPECT_THAT( | |
636 call_runtime, | |
637 IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg, | |
638 function_entry, | |
639 IsParameter(Linkage::kInterpreterContextParameter), _, _)); | |
640 } | |
641 } | |
642 } | |
643 | |
644 | |
645 TARGET_TEST_F(InterpreterAssemblerTest, CallIC) { | |
646 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
647 InterpreterAssemblerForTest m(this, bytecode); | |
648 LoadWithVectorDescriptor descriptor(isolate()); | |
649 Node* target = m.Int32Constant(1); | |
650 Node* arg1 = m.Int32Constant(2); | |
651 Node* arg2 = m.Int32Constant(3); | |
652 Node* arg3 = m.Int32Constant(4); | |
653 Node* arg4 = m.Int32Constant(5); | |
654 Node* call_ic = m.CallIC(descriptor, target, arg1, arg2, arg3, arg4); | |
655 EXPECT_THAT( | |
656 call_ic, | |
657 IsCall(_, target, arg1, arg2, arg3, arg4, | |
658 IsParameter(Linkage::kInterpreterContextParameter), _, _)); | |
659 } | |
660 } | |
661 | |
662 | |
663 TARGET_TEST_F(InterpreterAssemblerTest, CallJS) { | |
664 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
665 InterpreterAssemblerForTest m(this, bytecode); | |
666 Callable builtin = CodeFactory::InterpreterPushArgsAndCall(isolate()); | |
667 Node* function = m.Int32Constant(0); | |
668 Node* first_arg = m.Int32Constant(1); | |
669 Node* arg_count = m.Int32Constant(2); | |
670 Node* call_js = m.CallJS(function, first_arg, arg_count); | |
671 EXPECT_THAT( | |
672 call_js, | |
673 IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg, | |
674 function, IsParameter(Linkage::kInterpreterContextParameter), _, | |
675 _)); | |
676 } | |
677 } | |
678 | |
679 | |
680 TARGET_TEST_F(InterpreterAssemblerTest, LoadTypeFeedbackVector) { | |
681 TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { | |
682 InterpreterAssemblerForTest m(this, bytecode); | |
683 Node* feedback_vector = m.LoadTypeFeedbackVector(); | |
684 | |
685 Matcher<Node*> load_function_matcher = | |
686 m.IsLoad(MachineType::AnyTagged(), | |
687 IsParameter(Linkage::kInterpreterRegisterFileParameter), | |
688 IsIntPtrConstant( | |
689 InterpreterFrameConstants::kFunctionFromRegisterPointer)); | |
690 Matcher<Node*> load_shared_function_info_matcher = | |
691 m.IsLoad(MachineType::AnyTagged(), load_function_matcher, | |
692 IsIntPtrConstant(JSFunction::kSharedFunctionInfoOffset - | |
693 kHeapObjectTag)); | |
694 | |
695 EXPECT_THAT( | |
696 feedback_vector, | |
697 m.IsLoad(MachineType::AnyTagged(), load_shared_function_info_matcher, | |
698 IsIntPtrConstant(SharedFunctionInfo::kFeedbackVectorOffset - | |
699 kHeapObjectTag))); | |
700 } | |
701 } | |
702 | |
703 } // namespace compiler | |
704 } // namespace internal | |
705 } // namespace v8 | |
OLD | NEW |