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 <vector>
6 
7 #include "src/init/v8.h"
8 
9 #include "src/interpreter/bytecode-register.h"
10 #include "src/interpreter/bytecodes.h"
11 #include "test/unittests/test-utils.h"
12 
13 namespace v8 {
14 namespace internal {
15 namespace interpreter {
16 
TEST(OperandConversion,Registers)17 TEST(OperandConversion, Registers) {
18   int register_count = 128;
19   int step = register_count / 7;
20   for (int i = 0; i < register_count; i += step) {
21     if (i <= kMaxInt8) {
22       uint32_t operand0 = Register(i).ToOperand();
23       Register reg0 = Register::FromOperand(operand0);
24       CHECK_EQ(i, reg0.index());
25     }
26 
27     uint32_t operand1 = Register(i).ToOperand();
28     Register reg1 = Register::FromOperand(operand1);
29     CHECK_EQ(i, reg1.index());
30 
31     uint32_t operand2 = Register(i).ToOperand();
32     Register reg2 = Register::FromOperand(operand2);
33     CHECK_EQ(i, reg2.index());
34   }
35 }
36 
TEST(OperandConversion,Parameters)37 TEST(OperandConversion, Parameters) {
38   int parameter_counts[] = {7, 13, 99};
39 
40   size_t count = sizeof(parameter_counts) / sizeof(parameter_counts[0]);
41   for (size_t p = 0; p < count; p++) {
42     int parameter_count = parameter_counts[p];
43     for (int i = 0; i < parameter_count; i++) {
44       Register r = Register::FromParameterIndex(i, parameter_count);
45       uint32_t operand_value = r.ToOperand();
46       Register s = Register::FromOperand(operand_value);
47       CHECK_EQ(i, s.ToParameterIndex(parameter_count));
48     }
49   }
50 }
51 
TEST(OperandConversion,RegistersParametersNoOverlap)52 TEST(OperandConversion, RegistersParametersNoOverlap) {
53   int register_count = 128;
54   int parameter_count = 100;
55   int32_t register_space_size = base::bits::RoundUpToPowerOfTwo32(
56       static_cast<uint32_t>(register_count + parameter_count));
57   uint32_t range = static_cast<uint32_t>(register_space_size);
58   std::vector<uint8_t> operand_count(range);
59 
60   for (int i = 0; i < register_count; i += 1) {
61     Register r = Register(i);
62     int32_t operand = r.ToOperand();
63     uint8_t index = static_cast<uint8_t>(operand);
64     CHECK_LT(index, operand_count.size());
65     operand_count[index] += 1;
66     CHECK_EQ(operand_count[index], 1);
67   }
68 
69   for (int i = 0; i < parameter_count; i += 1) {
70     Register r = Register::FromParameterIndex(i, parameter_count);
71     uint32_t operand = r.ToOperand();
72     uint8_t index = static_cast<uint8_t>(operand);
73     CHECK_LT(index, operand_count.size());
74     operand_count[index] += 1;
75     CHECK_EQ(operand_count[index], 1);
76   }
77 }
78 
TEST(OperandScaling,ScalableAndNonScalable)79 TEST(OperandScaling, ScalableAndNonScalable) {
80   const OperandScale kOperandScales[] = {
81 #define VALUE(Name, _) OperandScale::k##Name,
82       OPERAND_SCALE_LIST(VALUE)
83 #undef VALUE
84   };
85 
86   for (OperandScale operand_scale : kOperandScales) {
87     int scale = static_cast<int>(operand_scale);
88     CHECK_EQ(Bytecodes::Size(Bytecode::kCallRuntime, operand_scale),
89              1 + 2 + 2 * scale);
90     CHECK_EQ(Bytecodes::Size(Bytecode::kCreateObjectLiteral, operand_scale),
91              1 + 2 * scale + 1);
92     CHECK_EQ(Bytecodes::Size(Bytecode::kTestIn, operand_scale), 1 + 2 * scale);
93   }
94 }
95 
TEST(Bytecodes,RegisterOperands)96 TEST(Bytecodes, RegisterOperands) {
97   CHECK(Bytecodes::IsRegisterOperandType(OperandType::kReg));
98   CHECK(Bytecodes::IsRegisterOperandType(OperandType::kRegPair));
99   CHECK(Bytecodes::IsRegisterInputOperandType(OperandType::kReg));
100   CHECK(Bytecodes::IsRegisterInputOperandType(OperandType::kRegPair));
101   CHECK(Bytecodes::IsRegisterInputOperandType(OperandType::kRegList));
102   CHECK(!Bytecodes::IsRegisterOutputOperandType(OperandType::kReg));
103   CHECK(!Bytecodes::IsRegisterInputOperandType(OperandType::kRegOut));
104   CHECK(Bytecodes::IsRegisterOutputOperandType(OperandType::kRegOut));
105   CHECK(Bytecodes::IsRegisterOutputOperandType(OperandType::kRegOutPair));
106 }
107 
TEST(Bytecodes,DebugBreakExistForEachBytecode)108 TEST(Bytecodes, DebugBreakExistForEachBytecode) {
109   static const OperandScale kOperandScale = OperandScale::kSingle;
110 #define CHECK_DEBUG_BREAK_SIZE(Name, ...)                                  \
111   if (!Bytecodes::IsDebugBreak(Bytecode::k##Name) &&                       \
112       !Bytecodes::IsPrefixScalingBytecode(Bytecode::k##Name)) {            \
113     Bytecode debug_bytecode = Bytecodes::GetDebugBreak(Bytecode::k##Name); \
114     CHECK_EQ(Bytecodes::Size(Bytecode::k##Name, kOperandScale),            \
115              Bytecodes::Size(debug_bytecode, kOperandScale));              \
116   }
117   BYTECODE_LIST(CHECK_DEBUG_BREAK_SIZE)
118 #undef CHECK_DEBUG_BREAK_SIZE
119 }
120 
TEST(Bytecodes,DebugBreakForPrefixBytecodes)121 TEST(Bytecodes, DebugBreakForPrefixBytecodes) {
122   CHECK_EQ(Bytecode::kDebugBreakWide,
123            Bytecodes::GetDebugBreak(Bytecode::kWide));
124   CHECK_EQ(Bytecode::kDebugBreakExtraWide,
125            Bytecodes::GetDebugBreak(Bytecode::kExtraWide));
126 }
127 
TEST(Bytecodes,PrefixMappings)128 TEST(Bytecodes, PrefixMappings) {
129   Bytecode prefixes[] = {Bytecode::kWide, Bytecode::kExtraWide};
130   TRACED_FOREACH(Bytecode, prefix, prefixes) {
131     CHECK_EQ(prefix, Bytecodes::OperandScaleToPrefixBytecode(
132                          Bytecodes::PrefixBytecodeToOperandScale(prefix)));
133   }
134 }
135 
TEST(Bytecodes,ScaleForSignedOperand)136 TEST(Bytecodes, ScaleForSignedOperand) {
137   CHECK_EQ(Bytecodes::ScaleForSignedOperand(0), OperandScale::kSingle);
138   CHECK_EQ(Bytecodes::ScaleForSignedOperand(kMaxInt8), OperandScale::kSingle);
139   CHECK_EQ(Bytecodes::ScaleForSignedOperand(kMinInt8), OperandScale::kSingle);
140   CHECK_EQ(Bytecodes::ScaleForSignedOperand(kMaxInt8 + 1),
141            OperandScale::kDouble);
142   CHECK_EQ(Bytecodes::ScaleForSignedOperand(kMinInt8 - 1),
143            OperandScale::kDouble);
144   CHECK_EQ(Bytecodes::ScaleForSignedOperand(kMaxInt16), OperandScale::kDouble);
145   CHECK_EQ(Bytecodes::ScaleForSignedOperand(kMinInt16), OperandScale::kDouble);
146   CHECK_EQ(Bytecodes::ScaleForSignedOperand(kMaxInt16 + 1),
147            OperandScale::kQuadruple);
148   CHECK_EQ(Bytecodes::ScaleForSignedOperand(kMinInt16 - 1),
149            OperandScale::kQuadruple);
150   CHECK_EQ(Bytecodes::ScaleForSignedOperand(kMaxInt), OperandScale::kQuadruple);
151   CHECK_EQ(Bytecodes::ScaleForSignedOperand(kMinInt), OperandScale::kQuadruple);
152 }
153 
TEST(Bytecodes,ScaleForUnsignedOperands)154 TEST(Bytecodes, ScaleForUnsignedOperands) {
155   // int overloads
156   CHECK_EQ(Bytecodes::ScaleForUnsignedOperand(0), OperandScale::kSingle);
157   CHECK_EQ(Bytecodes::ScaleForUnsignedOperand(kMaxUInt8),
158            OperandScale::kSingle);
159   CHECK_EQ(Bytecodes::ScaleForUnsignedOperand(kMaxUInt8 + 1),
160            OperandScale::kDouble);
161   CHECK_EQ(Bytecodes::ScaleForUnsignedOperand(kMaxUInt16),
162            OperandScale::kDouble);
163   CHECK_EQ(Bytecodes::ScaleForUnsignedOperand(kMaxUInt16 + 1),
164            OperandScale::kQuadruple);
165   // size_t overloads
166   CHECK_EQ(Bytecodes::ScaleForUnsignedOperand(static_cast<size_t>(0)),
167            OperandScale::kSingle);
168   CHECK_EQ(Bytecodes::ScaleForUnsignedOperand(static_cast<size_t>(kMaxUInt8)),
169            OperandScale::kSingle);
170   CHECK(Bytecodes::ScaleForUnsignedOperand(
171             static_cast<size_t>(kMaxUInt8 + 1)) == OperandScale::kDouble);
172   CHECK_EQ(Bytecodes::ScaleForUnsignedOperand(static_cast<size_t>(kMaxUInt16)),
173            OperandScale::kDouble);
174   CHECK(Bytecodes::ScaleForUnsignedOperand(
175             static_cast<size_t>(kMaxUInt16 + 1)) == OperandScale::kQuadruple);
176   CHECK_EQ(Bytecodes::ScaleForUnsignedOperand(static_cast<size_t>(kMaxUInt32)),
177            OperandScale::kQuadruple);
178 }
179 
TEST(Bytecodes,SizesForUnsignedOperands)180 TEST(Bytecodes, SizesForUnsignedOperands) {
181   // int overloads
182   CHECK_EQ(Bytecodes::SizeForUnsignedOperand(0), OperandSize::kByte);
183   CHECK_EQ(Bytecodes::SizeForUnsignedOperand(kMaxUInt8), OperandSize::kByte);
184   CHECK_EQ(Bytecodes::SizeForUnsignedOperand(kMaxUInt8 + 1),
185            OperandSize::kShort);
186   CHECK_EQ(Bytecodes::SizeForUnsignedOperand(kMaxUInt16), OperandSize::kShort);
187   CHECK_EQ(Bytecodes::SizeForUnsignedOperand(kMaxUInt16 + 1),
188            OperandSize::kQuad);
189   // size_t overloads
190   CHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<size_t>(0)),
191            OperandSize::kByte);
192   CHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<size_t>(kMaxUInt8)),
193            OperandSize::kByte);
194   CHECK_EQ(
195       Bytecodes::SizeForUnsignedOperand(static_cast<size_t>(kMaxUInt8 + 1)),
196       OperandSize::kShort);
197   CHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<size_t>(kMaxUInt16)),
198            OperandSize::kShort);
199   CHECK(Bytecodes::SizeForUnsignedOperand(
200             static_cast<size_t>(kMaxUInt16 + 1)) == OperandSize::kQuad);
201   CHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<size_t>(kMaxUInt32)),
202            OperandSize::kQuad);
203 }
204 
205 // Helper macros to generate a check for if a bytecode is in a macro list of
206 // bytecodes. We can use these to exhaustively test a check over all bytecodes,
207 // both those that should pass and those that should fail the check.
208 #define OR_IS_BYTECODE(Name, ...) || bytecode == Bytecode::k##Name
209 #define IN_BYTECODE_LIST(BYTECODE, LIST) \
210   ([](Bytecode bytecode) { return false LIST(OR_IS_BYTECODE); }(BYTECODE))
211 
TEST(Bytecodes,IsJump)212 TEST(Bytecodes, IsJump) {
213 #define TEST_BYTECODE(Name, ...)                                 \
214   if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_BYTECODE_LIST)) { \
215     EXPECT_TRUE(Bytecodes::IsJump(Bytecode::k##Name));           \
216   } else {                                                       \
217     EXPECT_FALSE(Bytecodes::IsJump(Bytecode::k##Name));          \
218   }
219 
220   BYTECODE_LIST(TEST_BYTECODE)
221 #undef TEST_BYTECODE
222 }
223 
TEST(Bytecodes,IsForwardJump)224 TEST(Bytecodes, IsForwardJump) {
225 #define TEST_BYTECODE(Name, ...)                                         \
226   if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_FORWARD_BYTECODE_LIST)) { \
227     EXPECT_TRUE(Bytecodes::IsForwardJump(Bytecode::k##Name));            \
228   } else {                                                               \
229     EXPECT_FALSE(Bytecodes::IsForwardJump(Bytecode::k##Name));           \
230   }
231 
232   BYTECODE_LIST(TEST_BYTECODE)
233 #undef TEST_BYTECODE
234 }
235 
TEST(Bytecodes,IsConditionalJump)236 TEST(Bytecodes, IsConditionalJump) {
237 #define TEST_BYTECODE(Name, ...)                                             \
238   if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_CONDITIONAL_BYTECODE_LIST)) { \
239     EXPECT_TRUE(Bytecodes::IsConditionalJump(Bytecode::k##Name));            \
240   } else {                                                                   \
241     EXPECT_FALSE(Bytecodes::IsConditionalJump(Bytecode::k##Name));           \
242   }
243 
244   BYTECODE_LIST(TEST_BYTECODE)
245 #undef TEST_BYTECODE
246 }
247 
TEST(Bytecodes,IsUnconditionalJump)248 TEST(Bytecodes, IsUnconditionalJump) {
249 #define TEST_BYTECODE(Name, ...)                                               \
250   if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_UNCONDITIONAL_BYTECODE_LIST)) { \
251     EXPECT_TRUE(Bytecodes::IsUnconditionalJump(Bytecode::k##Name));            \
252   } else {                                                                     \
253     EXPECT_FALSE(Bytecodes::IsUnconditionalJump(Bytecode::k##Name));           \
254   }
255 
256   BYTECODE_LIST(TEST_BYTECODE)
257 #undef TEST_BYTECODE
258 }
259 
TEST(Bytecodes,IsJumpImmediate)260 TEST(Bytecodes, IsJumpImmediate) {
261 #define TEST_BYTECODE(Name, ...)                                           \
262   if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_IMMEDIATE_BYTECODE_LIST)) { \
263     EXPECT_TRUE(Bytecodes::IsJumpImmediate(Bytecode::k##Name));            \
264   } else {                                                                 \
265     EXPECT_FALSE(Bytecodes::IsJumpImmediate(Bytecode::k##Name));           \
266   }
267 
268   BYTECODE_LIST(TEST_BYTECODE)
269 #undef TEST_BYTECODE
270 }
271 
TEST(Bytecodes,IsJumpConstant)272 TEST(Bytecodes, IsJumpConstant) {
273 #define TEST_BYTECODE(Name, ...)                                          \
274   if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_CONSTANT_BYTECODE_LIST)) { \
275     EXPECT_TRUE(Bytecodes::IsJumpConstant(Bytecode::k##Name));            \
276   } else {                                                                \
277     EXPECT_FALSE(Bytecodes::IsJumpConstant(Bytecode::k##Name));           \
278   }
279 
280   BYTECODE_LIST(TEST_BYTECODE)
281 #undef TEST_BYTECODE
282 }
283 
TEST(Bytecodes,IsConditionalJumpImmediate)284 TEST(Bytecodes, IsConditionalJumpImmediate) {
285 #define TEST_BYTECODE(Name, ...)                                             \
286   if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_CONDITIONAL_BYTECODE_LIST) && \
287       IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_IMMEDIATE_BYTECODE_LIST)) {   \
288     EXPECT_TRUE(Bytecodes::IsConditionalJumpImmediate(Bytecode::k##Name));   \
289   } else {                                                                   \
290     EXPECT_FALSE(Bytecodes::IsConditionalJumpImmediate(Bytecode::k##Name));  \
291   }
292 
293   BYTECODE_LIST(TEST_BYTECODE)
294 #undef TEST_BYTECODE
295 }
296 
TEST(Bytecodes,IsConditionalJumpConstant)297 TEST(Bytecodes, IsConditionalJumpConstant) {
298 #define TEST_BYTECODE(Name, ...)                                             \
299   if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_CONDITIONAL_BYTECODE_LIST) && \
300       IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_CONSTANT_BYTECODE_LIST)) {    \
301     EXPECT_TRUE(Bytecodes::IsConditionalJumpConstant(Bytecode::k##Name));    \
302   } else {                                                                   \
303     EXPECT_FALSE(Bytecodes::IsConditionalJumpConstant(Bytecode::k##Name));   \
304   }
305 
306   BYTECODE_LIST(TEST_BYTECODE)
307 #undef TEST_BYTECODE
308 }
309 
TEST(Bytecodes,IsJumpIfToBoolean)310 TEST(Bytecodes, IsJumpIfToBoolean) {
311 #define TEST_BYTECODE(Name, ...)                                            \
312   if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_TO_BOOLEAN_BYTECODE_LIST)) { \
313     EXPECT_TRUE(Bytecodes::IsJumpIfToBoolean(Bytecode::k##Name));           \
314   } else {                                                                  \
315     EXPECT_FALSE(Bytecodes::IsJumpIfToBoolean(Bytecode::k##Name));          \
316   }
317 
318   BYTECODE_LIST(TEST_BYTECODE)
319 #undef TEST_BYTECODE
320 }
321 
322 #undef OR_IS_BYTECODE
323 #undef IN_BYTECODE_LIST
324 
TEST(OperandScale,PrefixesRequired)325 TEST(OperandScale, PrefixesRequired) {
326   CHECK(!Bytecodes::OperandScaleRequiresPrefixBytecode(OperandScale::kSingle));
327   CHECK(Bytecodes::OperandScaleRequiresPrefixBytecode(OperandScale::kDouble));
328   CHECK(
329       Bytecodes::OperandScaleRequiresPrefixBytecode(OperandScale::kQuadruple));
330   CHECK_EQ(Bytecodes::OperandScaleToPrefixBytecode(OperandScale::kDouble),
331            Bytecode::kWide);
332   CHECK_EQ(Bytecodes::OperandScaleToPrefixBytecode(OperandScale::kQuadruple),
333            Bytecode::kExtraWide);
334 }
335 
TEST(ImplicitRegisterUse,LogicalOperators)336 TEST(ImplicitRegisterUse, LogicalOperators) {
337   CHECK_EQ(ImplicitRegisterUse::kNone | ImplicitRegisterUse::kReadAccumulator,
338            ImplicitRegisterUse::kReadAccumulator);
339   CHECK_EQ(ImplicitRegisterUse::kReadAccumulator |
340                ImplicitRegisterUse::kWriteAccumulator,
341            ImplicitRegisterUse::kReadWriteAccumulator);
342   CHECK_EQ(ImplicitRegisterUse::kReadAccumulator &
343                ImplicitRegisterUse::kReadWriteAccumulator,
344            ImplicitRegisterUse::kReadAccumulator);
345   CHECK_EQ(ImplicitRegisterUse::kReadAccumulator &
346                ImplicitRegisterUse::kWriteAccumulator,
347            ImplicitRegisterUse::kNone);
348 }
349 
TEST(ImplicitRegisterUse,SampleBytecodes)350 TEST(ImplicitRegisterUse, SampleBytecodes) {
351   CHECK(Bytecodes::ReadsAccumulator(Bytecode::kStar));
352   CHECK(!Bytecodes::WritesAccumulator(Bytecode::kStar));
353   CHECK_EQ(Bytecodes::GetImplicitRegisterUse(Bytecode::kStar),
354            ImplicitRegisterUse::kReadAccumulator);
355   CHECK(!Bytecodes::ReadsAccumulator(Bytecode::kLdar));
356   CHECK(Bytecodes::WritesAccumulator(Bytecode::kLdar));
357   CHECK_EQ(Bytecodes::GetImplicitRegisterUse(Bytecode::kLdar),
358            ImplicitRegisterUse::kWriteAccumulator);
359   CHECK(Bytecodes::ReadsAccumulator(Bytecode::kAdd));
360   CHECK(Bytecodes::WritesAccumulator(Bytecode::kAdd));
361   CHECK_EQ(Bytecodes::GetImplicitRegisterUse(Bytecode::kAdd),
362            ImplicitRegisterUse::kReadWriteAccumulator);
363 }
364 
365 }  // namespace interpreter
366 }  // namespace internal
367 }  // namespace v8
368