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 "src/interpreter/bytecodes.h"
6 
7 #include <iomanip>
8 
9 #include "src/base/bits.h"
10 #include "src/interpreter/bytecode-traits.h"
11 
12 namespace v8 {
13 namespace internal {
14 namespace interpreter {
15 
16 // clang-format off
17 const OperandType* const Bytecodes::kOperandTypes[] = {
18 #define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kOperandTypes,
19   BYTECODE_LIST(ENTRY)
20 #undef ENTRY
21 };
22 
23 const OperandTypeInfo* const Bytecodes::kOperandTypeInfos[] = {
24 #define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kOperandTypeInfos,
25   BYTECODE_LIST(ENTRY)
26 #undef ENTRY
27 };
28 
29 const int Bytecodes::kOperandCount[] = {
30 #define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kOperandCount,
31   BYTECODE_LIST(ENTRY)
32 #undef ENTRY
33 };
34 
35 const ImplicitRegisterUse Bytecodes::kImplicitRegisterUse[] = {
36 #define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kImplicitRegisterUse,
37   BYTECODE_LIST(ENTRY)
38 #undef ENTRY
39 };
40 
41 const uint8_t Bytecodes::kBytecodeSizes[3][kBytecodeCount] = {
42   {
43 #define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kSingleScaleSize,
44   BYTECODE_LIST(ENTRY)
45 #undef ENTRY
46   }, {
47 #define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kDoubleScaleSize,
48   BYTECODE_LIST(ENTRY)
49 #undef ENTRY
50   }, {
51 #define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kQuadrupleScaleSize,
52   BYTECODE_LIST(ENTRY)
53 #undef ENTRY
54   }
55 };
56 
57 const OperandSize* const Bytecodes::kOperandSizes[3][kBytecodeCount] = {
58   {
59 #define ENTRY(Name, ...)  \
60     BytecodeTraits<__VA_ARGS__>::kSingleScaleOperandSizes,
61   BYTECODE_LIST(ENTRY)
62 #undef ENTRY
63   }, {
64 #define ENTRY(Name, ...)  \
65     BytecodeTraits<__VA_ARGS__>::kDoubleScaleOperandSizes,
66   BYTECODE_LIST(ENTRY)
67 #undef ENTRY
68   }, {
69 #define ENTRY(Name, ...)  \
70     BytecodeTraits<__VA_ARGS__>::kQuadrupleScaleOperandSizes,
71   BYTECODE_LIST(ENTRY)
72 #undef ENTRY
73   }
74 };
75 
76 const OperandSize
77 Bytecodes::kOperandKindSizes[3][BytecodeOperands::kOperandTypeCount] = {
78   {
79 #define ENTRY(Name, ...)  \
80     OperandScaler<OperandType::k##Name, OperandScale::kSingle>::kOperandSize,
81   OPERAND_TYPE_LIST(ENTRY)
82 #undef ENTRY
83   }, {
84 #define ENTRY(Name, ...)  \
85     OperandScaler<OperandType::k##Name, OperandScale::kDouble>::kOperandSize,
86   OPERAND_TYPE_LIST(ENTRY)
87 #undef ENTRY
88   }, {
89 #define ENTRY(Name, ...)  \
90     OperandScaler<OperandType::k##Name, OperandScale::kQuadruple>::kOperandSize,
91   OPERAND_TYPE_LIST(ENTRY)
92 #undef ENTRY
93   }
94 };
95 // clang-format on
96 
97 // Make sure kFirstShortStar and kLastShortStar are set correctly.
98 #define ASSERT_SHORT_STAR_RANGE(Name, ...)                        \
99   STATIC_ASSERT(Bytecode::k##Name >= Bytecode::kFirstShortStar && \
100                 Bytecode::k##Name <= Bytecode::kLastShortStar);
SHORT_STAR_BYTECODE_LIST(ASSERT_SHORT_STAR_RANGE) const101 SHORT_STAR_BYTECODE_LIST(ASSERT_SHORT_STAR_RANGE)
102 #undef ASSERT_SHORT_STAR_RANGE
103 
104 // static
105 const char* Bytecodes::ToString(Bytecode bytecode) {
106   switch (bytecode) {
107 #define CASE(Name, ...)   \
108   case Bytecode::k##Name: \
109     return #Name;
110     BYTECODE_LIST(CASE)
111 #undef CASE
112   }
113   UNREACHABLE();
114 }
115 
116 // static
ToString(Bytecode bytecode,OperandScale operand_scale,const char * separator)117 std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale,
118                                 const char* separator) {
119   std::string value(ToString(bytecode));
120   if (operand_scale > OperandScale::kSingle) {
121     Bytecode prefix_bytecode = OperandScaleToPrefixBytecode(operand_scale);
122     std::string suffix = ToString(prefix_bytecode);
123     return value.append(separator).append(suffix);
124   } else {
125     return value;
126   }
127 }
128 
129 // static
GetDebugBreak(Bytecode bytecode)130 Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) {
131   DCHECK(!IsDebugBreak(bytecode));
132   if (bytecode == Bytecode::kWide) {
133     return Bytecode::kDebugBreakWide;
134   }
135   if (bytecode == Bytecode::kExtraWide) {
136     return Bytecode::kDebugBreakExtraWide;
137   }
138   int bytecode_size = Size(bytecode, OperandScale::kSingle);
139 #define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name)                         \
140   if (bytecode_size == Size(Bytecode::k##Name, OperandScale::kSingle)) { \
141     return Bytecode::k##Name;                                            \
142   }
143   DEBUG_BREAK_PLAIN_BYTECODE_LIST(RETURN_IF_DEBUG_BREAK_SIZE_MATCHES)
144 #undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES
145   UNREACHABLE();
146 }
147 
148 // static
GetOperandOffset(Bytecode bytecode,int i,OperandScale operand_scale)149 int Bytecodes::GetOperandOffset(Bytecode bytecode, int i,
150                                 OperandScale operand_scale) {
151   DCHECK_LT(i, Bytecodes::NumberOfOperands(bytecode));
152   // TODO(oth): restore this to a statically determined constant.
153   int offset = 1;
154   for (int operand_index = 0; operand_index < i; ++operand_index) {
155     OperandSize operand_size =
156         GetOperandSize(bytecode, operand_index, operand_scale);
157     offset += static_cast<int>(operand_size);
158   }
159   return offset;
160 }
161 
162 // static
GetJumpWithoutToBoolean(Bytecode bytecode)163 Bytecode Bytecodes::GetJumpWithoutToBoolean(Bytecode bytecode) {
164   switch (bytecode) {
165     case Bytecode::kJumpIfToBooleanTrue:
166       return Bytecode::kJumpIfTrue;
167     case Bytecode::kJumpIfToBooleanFalse:
168       return Bytecode::kJumpIfFalse;
169     case Bytecode::kJumpIfToBooleanTrueConstant:
170       return Bytecode::kJumpIfTrueConstant;
171     case Bytecode::kJumpIfToBooleanFalseConstant:
172       return Bytecode::kJumpIfFalseConstant;
173     default:
174       break;
175   }
176   UNREACHABLE();
177 }
178 
179 // static
IsDebugBreak(Bytecode bytecode)180 bool Bytecodes::IsDebugBreak(Bytecode bytecode) {
181   switch (bytecode) {
182 #define CASE(Name, ...) case Bytecode::k##Name:
183     DEBUG_BREAK_BYTECODE_LIST(CASE);
184 #undef CASE
185     return true;
186     default:
187       break;
188   }
189   return false;
190 }
191 
192 // static
IsRegisterOperandType(OperandType operand_type)193 bool Bytecodes::IsRegisterOperandType(OperandType operand_type) {
194   switch (operand_type) {
195 #define CASE(Name, _)        \
196   case OperandType::k##Name: \
197     return true;
198     REGISTER_OPERAND_TYPE_LIST(CASE)
199 #undef CASE
200 #define CASE(Name, _)        \
201   case OperandType::k##Name: \
202     break;
203     NON_REGISTER_OPERAND_TYPE_LIST(CASE)
204 #undef CASE
205   }
206   return false;
207 }
208 
209 // static
IsRegisterListOperandType(OperandType operand_type)210 bool Bytecodes::IsRegisterListOperandType(OperandType operand_type) {
211   switch (operand_type) {
212     case OperandType::kRegList:
213     case OperandType::kRegOutList:
214       return true;
215     default:
216       return false;
217   }
218 }
219 
MakesCallAlongCriticalPath(Bytecode bytecode)220 bool Bytecodes::MakesCallAlongCriticalPath(Bytecode bytecode) {
221   if (IsCallOrConstruct(bytecode) || IsCallRuntime(bytecode)) return true;
222   switch (bytecode) {
223     case Bytecode::kCreateWithContext:
224     case Bytecode::kCreateBlockContext:
225     case Bytecode::kCreateCatchContext:
226     case Bytecode::kCreateRegExpLiteral:
227     case Bytecode::kGetIterator:
228       return true;
229     default:
230       return false;
231   }
232 }
233 
234 // static
IsRegisterInputOperandType(OperandType operand_type)235 bool Bytecodes::IsRegisterInputOperandType(OperandType operand_type) {
236   switch (operand_type) {
237 #define CASE(Name, _)        \
238   case OperandType::k##Name: \
239     return true;
240     REGISTER_INPUT_OPERAND_TYPE_LIST(CASE)
241 #undef CASE
242 #define CASE(Name, _)        \
243   case OperandType::k##Name: \
244     break;
245     NON_REGISTER_OPERAND_TYPE_LIST(CASE)
246     REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE)
247 #undef CASE
248   }
249   return false;
250 }
251 
252 // static
IsRegisterOutputOperandType(OperandType operand_type)253 bool Bytecodes::IsRegisterOutputOperandType(OperandType operand_type) {
254   switch (operand_type) {
255 #define CASE(Name, _)        \
256   case OperandType::k##Name: \
257     return true;
258     REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE)
259 #undef CASE
260 #define CASE(Name, _)        \
261   case OperandType::k##Name: \
262     break;
263     NON_REGISTER_OPERAND_TYPE_LIST(CASE)
264     REGISTER_INPUT_OPERAND_TYPE_LIST(CASE)
265 #undef CASE
266   }
267   return false;
268 }
269 
270 // static
IsStarLookahead(Bytecode bytecode,OperandScale operand_scale)271 bool Bytecodes::IsStarLookahead(Bytecode bytecode, OperandScale operand_scale) {
272   if (operand_scale == OperandScale::kSingle) {
273     switch (bytecode) {
274       // Short-star lookahead is required for correctness on kDebugBreak0. The
275       // handler for all short-star codes re-reads the opcode from the bytecode
276       // array and would not work correctly if it instead read kDebugBreak0.
277       case Bytecode::kDebugBreak0:
278 
279       case Bytecode::kLdaZero:
280       case Bytecode::kLdaSmi:
281       case Bytecode::kLdaNull:
282       case Bytecode::kLdaTheHole:
283       case Bytecode::kLdaConstant:
284       case Bytecode::kLdaUndefined:
285       case Bytecode::kLdaGlobal:
286       case Bytecode::kLdaNamedProperty:
287       case Bytecode::kLdaKeyedProperty:
288       case Bytecode::kLdaContextSlot:
289       case Bytecode::kLdaImmutableContextSlot:
290       case Bytecode::kLdaCurrentContextSlot:
291       case Bytecode::kLdaImmutableCurrentContextSlot:
292       case Bytecode::kAdd:
293       case Bytecode::kSub:
294       case Bytecode::kMul:
295       case Bytecode::kAddSmi:
296       case Bytecode::kSubSmi:
297       case Bytecode::kInc:
298       case Bytecode::kDec:
299       case Bytecode::kTypeOf:
300       case Bytecode::kCallAnyReceiver:
301       case Bytecode::kCallProperty:
302       case Bytecode::kCallProperty0:
303       case Bytecode::kCallProperty1:
304       case Bytecode::kCallProperty2:
305       case Bytecode::kCallUndefinedReceiver:
306       case Bytecode::kCallUndefinedReceiver0:
307       case Bytecode::kCallUndefinedReceiver1:
308       case Bytecode::kCallUndefinedReceiver2:
309       case Bytecode::kConstruct:
310       case Bytecode::kConstructWithSpread:
311       case Bytecode::kCreateObjectLiteral:
312       case Bytecode::kCreateArrayLiteral:
313       case Bytecode::kThrowReferenceErrorIfHole:
314       case Bytecode::kGetTemplateObject:
315         return true;
316       default:
317         return false;
318     }
319   }
320   return false;
321 }
322 
323 // static
IsBytecodeWithScalableOperands(Bytecode bytecode)324 bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) {
325   for (int i = 0; i < NumberOfOperands(bytecode); i++) {
326     if (OperandIsScalable(bytecode, i)) return true;
327   }
328   return false;
329 }
330 
331 // static
IsUnsignedOperandType(OperandType operand_type)332 bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) {
333   switch (operand_type) {
334 #define CASE(Name, _)        \
335   case OperandType::k##Name: \
336     return OperandTraits<OperandType::k##Name>::TypeInfoTraits::kIsUnsigned;
337     OPERAND_TYPE_LIST(CASE)
338 #undef CASE
339   }
340   UNREACHABLE();
341 }
342 
343 // static
BytecodeHasHandler(Bytecode bytecode,OperandScale operand_scale)344 bool Bytecodes::BytecodeHasHandler(Bytecode bytecode,
345                                    OperandScale operand_scale) {
346   return (operand_scale == OperandScale::kSingle &&
347           (!IsShortStar(bytecode) || bytecode == Bytecode::kStar0)) ||
348          Bytecodes::IsBytecodeWithScalableOperands(bytecode);
349 }
350 
operator <<(std::ostream & os,const Bytecode & bytecode)351 std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) {
352   return os << Bytecodes::ToString(bytecode);
353 }
354 
355 }  // namespace interpreter
356 }  // namespace internal
357 }  // namespace v8
358