• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 AccumulatorUse Bytecodes::kAccumulatorUse[] = {
36 #define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kAccumulatorUse,
37   BYTECODE_LIST(ENTRY)
38 #undef ENTRY
39 };
40 
41 const int Bytecodes::kBytecodeSizes[][3] = {
42 #define ENTRY(Name, ...)                            \
43   { BytecodeTraits<__VA_ARGS__>::kSingleScaleSize,  \
44     BytecodeTraits<__VA_ARGS__>::kDoubleScaleSize,  \
45     BytecodeTraits<__VA_ARGS__>::kQuadrupleScaleSize },
46   BYTECODE_LIST(ENTRY)
47 #undef ENTRY
48 };
49 
50 const OperandSize* const Bytecodes::kOperandSizes[][3] = {
51 #define ENTRY(Name, ...)                                    \
52   { BytecodeTraits<__VA_ARGS__>::kSingleScaleOperandSizes,  \
53     BytecodeTraits<__VA_ARGS__>::kDoubleScaleOperandSizes,  \
54     BytecodeTraits<__VA_ARGS__>::kQuadrupleScaleOperandSizes },
55   BYTECODE_LIST(ENTRY)
56 #undef ENTRY
57 };
58 // clang-format on
59 
60 // static
ToString(Bytecode bytecode)61 const char* Bytecodes::ToString(Bytecode bytecode) {
62   switch (bytecode) {
63 #define CASE(Name, ...)   \
64   case Bytecode::k##Name: \
65     return #Name;
66     BYTECODE_LIST(CASE)
67 #undef CASE
68   }
69   UNREACHABLE();
70   return "";
71 }
72 
73 // static
ToString(Bytecode bytecode,OperandScale operand_scale)74 std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale) {
75   static const char kSeparator = '.';
76 
77   std::string value(ToString(bytecode));
78   if (operand_scale > OperandScale::kSingle) {
79     Bytecode prefix_bytecode = OperandScaleToPrefixBytecode(operand_scale);
80     std::string suffix = ToString(prefix_bytecode);
81     return value.append(1, kSeparator).append(suffix);
82   } else {
83     return value;
84   }
85 }
86 
87 // static
GetDebugBreak(Bytecode bytecode)88 Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) {
89   DCHECK(!IsDebugBreak(bytecode));
90   if (bytecode == Bytecode::kWide) {
91     return Bytecode::kDebugBreakWide;
92   }
93   if (bytecode == Bytecode::kExtraWide) {
94     return Bytecode::kDebugBreakExtraWide;
95   }
96   int bytecode_size = Size(bytecode, OperandScale::kSingle);
97 #define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name)                         \
98   if (bytecode_size == Size(Bytecode::k##Name, OperandScale::kSingle)) { \
99     return Bytecode::k##Name;                                            \
100   }
101   DEBUG_BREAK_PLAIN_BYTECODE_LIST(RETURN_IF_DEBUG_BREAK_SIZE_MATCHES)
102 #undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES
103   UNREACHABLE();
104   return Bytecode::kIllegal;
105 }
106 
107 // static
GetOperandOffset(Bytecode bytecode,int i,OperandScale operand_scale)108 int Bytecodes::GetOperandOffset(Bytecode bytecode, int i,
109                                 OperandScale operand_scale) {
110   DCHECK_LT(i, Bytecodes::NumberOfOperands(bytecode));
111   // TODO(oth): restore this to a statically determined constant.
112   int offset = 1;
113   for (int operand_index = 0; operand_index < i; ++operand_index) {
114     OperandSize operand_size =
115         GetOperandSize(bytecode, operand_index, operand_scale);
116     offset += static_cast<int>(operand_size);
117   }
118   return offset;
119 }
120 
121 // static
GetJumpWithoutToBoolean(Bytecode bytecode)122 Bytecode Bytecodes::GetJumpWithoutToBoolean(Bytecode bytecode) {
123   switch (bytecode) {
124     case Bytecode::kJumpIfToBooleanTrue:
125       return Bytecode::kJumpIfTrue;
126     case Bytecode::kJumpIfToBooleanFalse:
127       return Bytecode::kJumpIfFalse;
128     case Bytecode::kJumpIfToBooleanTrueConstant:
129       return Bytecode::kJumpIfTrueConstant;
130     case Bytecode::kJumpIfToBooleanFalseConstant:
131       return Bytecode::kJumpIfFalseConstant;
132     default:
133       break;
134   }
135   UNREACHABLE();
136   return Bytecode::kIllegal;
137 }
138 
139 // static
IsDebugBreak(Bytecode bytecode)140 bool Bytecodes::IsDebugBreak(Bytecode bytecode) {
141   switch (bytecode) {
142 #define CASE(Name, ...) case Bytecode::k##Name:
143     DEBUG_BREAK_BYTECODE_LIST(CASE);
144 #undef CASE
145     return true;
146     default:
147       break;
148   }
149   return false;
150 }
151 
152 // static
IsRegisterOperandType(OperandType operand_type)153 bool Bytecodes::IsRegisterOperandType(OperandType operand_type) {
154   switch (operand_type) {
155 #define CASE(Name, _)        \
156   case OperandType::k##Name: \
157     return true;
158     REGISTER_OPERAND_TYPE_LIST(CASE)
159 #undef CASE
160 #define CASE(Name, _)        \
161   case OperandType::k##Name: \
162     break;
163     NON_REGISTER_OPERAND_TYPE_LIST(CASE)
164 #undef CASE
165   }
166   return false;
167 }
168 
MakesCallAlongCriticalPath(Bytecode bytecode)169 bool Bytecodes::MakesCallAlongCriticalPath(Bytecode bytecode) {
170   if (IsCallOrConstruct(bytecode) || IsCallRuntime(bytecode)) return true;
171   switch (bytecode) {
172     case Bytecode::kCreateWithContext:
173     case Bytecode::kCreateBlockContext:
174     case Bytecode::kCreateCatchContext:
175     case Bytecode::kCreateRegExpLiteral:
176       return true;
177     default:
178       return false;
179   }
180 }
181 
182 // static
IsRegisterInputOperandType(OperandType operand_type)183 bool Bytecodes::IsRegisterInputOperandType(OperandType operand_type) {
184   switch (operand_type) {
185 #define CASE(Name, _)        \
186   case OperandType::k##Name: \
187     return true;
188     REGISTER_INPUT_OPERAND_TYPE_LIST(CASE)
189 #undef CASE
190 #define CASE(Name, _)        \
191   case OperandType::k##Name: \
192     break;
193     NON_REGISTER_OPERAND_TYPE_LIST(CASE)
194     REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE)
195 #undef CASE
196   }
197   return false;
198 }
199 
200 // static
IsRegisterOutputOperandType(OperandType operand_type)201 bool Bytecodes::IsRegisterOutputOperandType(OperandType operand_type) {
202   switch (operand_type) {
203 #define CASE(Name, _)        \
204   case OperandType::k##Name: \
205     return true;
206     REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE)
207 #undef CASE
208 #define CASE(Name, _)        \
209   case OperandType::k##Name: \
210     break;
211     NON_REGISTER_OPERAND_TYPE_LIST(CASE)
212     REGISTER_INPUT_OPERAND_TYPE_LIST(CASE)
213 #undef CASE
214   }
215   return false;
216 }
217 
218 // static
IsStarLookahead(Bytecode bytecode,OperandScale operand_scale)219 bool Bytecodes::IsStarLookahead(Bytecode bytecode, OperandScale operand_scale) {
220   if (operand_scale == OperandScale::kSingle) {
221     switch (bytecode) {
222       case Bytecode::kLdaZero:
223       case Bytecode::kLdaSmi:
224       case Bytecode::kLdaNull:
225       case Bytecode::kLdaTheHole:
226       case Bytecode::kLdaConstant:
227       case Bytecode::kLdaUndefined:
228       case Bytecode::kLdaGlobal:
229       case Bytecode::kLdaNamedProperty:
230       case Bytecode::kLdaKeyedProperty:
231       case Bytecode::kLdaContextSlot:
232       case Bytecode::kLdaCurrentContextSlot:
233       case Bytecode::kAdd:
234       case Bytecode::kSub:
235       case Bytecode::kMul:
236       case Bytecode::kAddSmi:
237       case Bytecode::kSubSmi:
238       case Bytecode::kInc:
239       case Bytecode::kDec:
240       case Bytecode::kTypeOf:
241       case Bytecode::kCall:
242       case Bytecode::kCallProperty:
243       case Bytecode::kConstruct:
244       case Bytecode::kConstructWithSpread:
245         return true;
246       default:
247         return false;
248     }
249   }
250   return false;
251 }
252 
253 // static
IsBytecodeWithScalableOperands(Bytecode bytecode)254 bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) {
255   for (int i = 0; i < NumberOfOperands(bytecode); i++) {
256     if (OperandIsScalable(bytecode, i)) return true;
257   }
258   return false;
259 }
260 
261 // static
IsUnsignedOperandType(OperandType operand_type)262 bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) {
263   switch (operand_type) {
264 #define CASE(Name, _)        \
265   case OperandType::k##Name: \
266     return OperandTraits<OperandType::k##Name>::TypeInfoTraits::kIsUnsigned;
267     OPERAND_TYPE_LIST(CASE)
268 #undef CASE
269   }
270   UNREACHABLE();
271   return false;
272 }
273 
274 // static
SizeOfOperand(OperandType operand_type,OperandScale operand_scale)275 OperandSize Bytecodes::SizeOfOperand(OperandType operand_type,
276                                      OperandScale operand_scale) {
277   DCHECK_LE(operand_type, OperandType::kLast);
278   DCHECK_GE(operand_scale, OperandScale::kSingle);
279   DCHECK_LE(operand_scale, OperandScale::kLast);
280   STATIC_ASSERT(static_cast<int>(OperandScale::kQuadruple) == 4 &&
281                 OperandScale::kLast == OperandScale::kQuadruple);
282   int scale_index = static_cast<int>(operand_scale) >> 1;
283   // clang-format off
284   static const OperandSize kOperandSizes[][3] = {
285 #define ENTRY(Name, ...)                                \
286   { OperandScaler<OperandType::k##Name,                 \
287                  OperandScale::kSingle>::kOperandSize,  \
288     OperandScaler<OperandType::k##Name,                 \
289                  OperandScale::kDouble>::kOperandSize,  \
290     OperandScaler<OperandType::k##Name,                 \
291                  OperandScale::kQuadruple>::kOperandSize },
292     OPERAND_TYPE_LIST(ENTRY)
293 #undef ENTRY
294   };
295   // clang-format on
296   return kOperandSizes[static_cast<size_t>(operand_type)][scale_index];
297 }
298 
299 // static
BytecodeHasHandler(Bytecode bytecode,OperandScale operand_scale)300 bool Bytecodes::BytecodeHasHandler(Bytecode bytecode,
301                                    OperandScale operand_scale) {
302   return operand_scale == OperandScale::kSingle ||
303          Bytecodes::IsBytecodeWithScalableOperands(bytecode);
304 }
305 
operator <<(std::ostream & os,const Bytecode & bytecode)306 std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) {
307   return os << Bytecodes::ToString(bytecode);
308 }
309 
310 }  // namespace interpreter
311 }  // namespace internal
312 }  // namespace v8
313