• 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][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 // static
ToString(Bytecode bytecode)98 const char* Bytecodes::ToString(Bytecode bytecode) {
99   switch (bytecode) {
100 #define CASE(Name, ...)   \
101   case Bytecode::k##Name: \
102     return #Name;
103     BYTECODE_LIST(CASE)
104 #undef CASE
105   }
106   UNREACHABLE();
107 }
108 
109 // static
ToString(Bytecode bytecode,OperandScale operand_scale)110 std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale) {
111   static const char kSeparator = '.';
112 
113   std::string value(ToString(bytecode));
114   if (operand_scale > OperandScale::kSingle) {
115     Bytecode prefix_bytecode = OperandScaleToPrefixBytecode(operand_scale);
116     std::string suffix = ToString(prefix_bytecode);
117     return value.append(1, kSeparator).append(suffix);
118   } else {
119     return value;
120   }
121 }
122 
123 // static
GetDebugBreak(Bytecode bytecode)124 Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) {
125   DCHECK(!IsDebugBreak(bytecode));
126   if (bytecode == Bytecode::kWide) {
127     return Bytecode::kDebugBreakWide;
128   }
129   if (bytecode == Bytecode::kExtraWide) {
130     return Bytecode::kDebugBreakExtraWide;
131   }
132   int bytecode_size = Size(bytecode, OperandScale::kSingle);
133 #define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name)                         \
134   if (bytecode_size == Size(Bytecode::k##Name, OperandScale::kSingle)) { \
135     return Bytecode::k##Name;                                            \
136   }
137   DEBUG_BREAK_PLAIN_BYTECODE_LIST(RETURN_IF_DEBUG_BREAK_SIZE_MATCHES)
138 #undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES
139   UNREACHABLE();
140 }
141 
142 // static
GetOperandOffset(Bytecode bytecode,int i,OperandScale operand_scale)143 int Bytecodes::GetOperandOffset(Bytecode bytecode, int i,
144                                 OperandScale operand_scale) {
145   DCHECK_LT(i, Bytecodes::NumberOfOperands(bytecode));
146   // TODO(oth): restore this to a statically determined constant.
147   int offset = 1;
148   for (int operand_index = 0; operand_index < i; ++operand_index) {
149     OperandSize operand_size =
150         GetOperandSize(bytecode, operand_index, operand_scale);
151     offset += static_cast<int>(operand_size);
152   }
153   return offset;
154 }
155 
156 // static
GetJumpWithoutToBoolean(Bytecode bytecode)157 Bytecode Bytecodes::GetJumpWithoutToBoolean(Bytecode bytecode) {
158   switch (bytecode) {
159     case Bytecode::kJumpIfToBooleanTrue:
160       return Bytecode::kJumpIfTrue;
161     case Bytecode::kJumpIfToBooleanFalse:
162       return Bytecode::kJumpIfFalse;
163     case Bytecode::kJumpIfToBooleanTrueConstant:
164       return Bytecode::kJumpIfTrueConstant;
165     case Bytecode::kJumpIfToBooleanFalseConstant:
166       return Bytecode::kJumpIfFalseConstant;
167     default:
168       break;
169   }
170   UNREACHABLE();
171 }
172 
173 // static
IsDebugBreak(Bytecode bytecode)174 bool Bytecodes::IsDebugBreak(Bytecode bytecode) {
175   switch (bytecode) {
176 #define CASE(Name, ...) case Bytecode::k##Name:
177     DEBUG_BREAK_BYTECODE_LIST(CASE);
178 #undef CASE
179     return true;
180     default:
181       break;
182   }
183   return false;
184 }
185 
186 // static
IsRegisterOperandType(OperandType operand_type)187 bool Bytecodes::IsRegisterOperandType(OperandType operand_type) {
188   switch (operand_type) {
189 #define CASE(Name, _)        \
190   case OperandType::k##Name: \
191     return true;
192     REGISTER_OPERAND_TYPE_LIST(CASE)
193 #undef CASE
194 #define CASE(Name, _)        \
195   case OperandType::k##Name: \
196     break;
197     NON_REGISTER_OPERAND_TYPE_LIST(CASE)
198 #undef CASE
199   }
200   return false;
201 }
202 
203 // static
IsRegisterListOperandType(OperandType operand_type)204 bool Bytecodes::IsRegisterListOperandType(OperandType operand_type) {
205   switch (operand_type) {
206     case OperandType::kRegList:
207     case OperandType::kRegOutList:
208       return true;
209     default:
210       return false;
211   }
212 }
213 
MakesCallAlongCriticalPath(Bytecode bytecode)214 bool Bytecodes::MakesCallAlongCriticalPath(Bytecode bytecode) {
215   if (IsCallOrConstruct(bytecode) || IsCallRuntime(bytecode)) return true;
216   switch (bytecode) {
217     case Bytecode::kCreateWithContext:
218     case Bytecode::kCreateBlockContext:
219     case Bytecode::kCreateCatchContext:
220     case Bytecode::kCreateRegExpLiteral:
221       return true;
222     default:
223       return false;
224   }
225 }
226 
227 // static
IsRegisterInputOperandType(OperandType operand_type)228 bool Bytecodes::IsRegisterInputOperandType(OperandType operand_type) {
229   switch (operand_type) {
230 #define CASE(Name, _)        \
231   case OperandType::k##Name: \
232     return true;
233     REGISTER_INPUT_OPERAND_TYPE_LIST(CASE)
234 #undef CASE
235 #define CASE(Name, _)        \
236   case OperandType::k##Name: \
237     break;
238     NON_REGISTER_OPERAND_TYPE_LIST(CASE)
239     REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE)
240 #undef CASE
241   }
242   return false;
243 }
244 
245 // static
IsRegisterOutputOperandType(OperandType operand_type)246 bool Bytecodes::IsRegisterOutputOperandType(OperandType operand_type) {
247   switch (operand_type) {
248 #define CASE(Name, _)        \
249   case OperandType::k##Name: \
250     return true;
251     REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE)
252 #undef CASE
253 #define CASE(Name, _)        \
254   case OperandType::k##Name: \
255     break;
256     NON_REGISTER_OPERAND_TYPE_LIST(CASE)
257     REGISTER_INPUT_OPERAND_TYPE_LIST(CASE)
258 #undef CASE
259   }
260   return false;
261 }
262 
263 // static
IsStarLookahead(Bytecode bytecode,OperandScale operand_scale)264 bool Bytecodes::IsStarLookahead(Bytecode bytecode, OperandScale operand_scale) {
265   if (operand_scale == OperandScale::kSingle) {
266     switch (bytecode) {
267       case Bytecode::kLdaZero:
268       case Bytecode::kLdaSmi:
269       case Bytecode::kLdaNull:
270       case Bytecode::kLdaTheHole:
271       case Bytecode::kLdaConstant:
272       case Bytecode::kLdaUndefined:
273       case Bytecode::kLdaGlobal:
274       case Bytecode::kLdaNamedProperty:
275       case Bytecode::kLdaKeyedProperty:
276       case Bytecode::kLdaContextSlot:
277       case Bytecode::kLdaCurrentContextSlot:
278       case Bytecode::kAdd:
279       case Bytecode::kSub:
280       case Bytecode::kMul:
281       case Bytecode::kAddSmi:
282       case Bytecode::kSubSmi:
283       case Bytecode::kInc:
284       case Bytecode::kDec:
285       case Bytecode::kTypeOf:
286       case Bytecode::kCallAnyReceiver:
287       case Bytecode::kCallProperty:
288       case Bytecode::kCallProperty0:
289       case Bytecode::kCallProperty1:
290       case Bytecode::kCallProperty2:
291       case Bytecode::kCallUndefinedReceiver:
292       case Bytecode::kCallUndefinedReceiver0:
293       case Bytecode::kCallUndefinedReceiver1:
294       case Bytecode::kCallUndefinedReceiver2:
295       case Bytecode::kConstruct:
296       case Bytecode::kConstructWithSpread:
297         return true;
298       default:
299         return false;
300     }
301   }
302   return false;
303 }
304 
305 // static
IsBytecodeWithScalableOperands(Bytecode bytecode)306 bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) {
307   for (int i = 0; i < NumberOfOperands(bytecode); i++) {
308     if (OperandIsScalable(bytecode, i)) return true;
309   }
310   return false;
311 }
312 
313 // static
IsUnsignedOperandType(OperandType operand_type)314 bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) {
315   switch (operand_type) {
316 #define CASE(Name, _)        \
317   case OperandType::k##Name: \
318     return OperandTraits<OperandType::k##Name>::TypeInfoTraits::kIsUnsigned;
319     OPERAND_TYPE_LIST(CASE)
320 #undef CASE
321   }
322   UNREACHABLE();
323 }
324 
325 // static
BytecodeHasHandler(Bytecode bytecode,OperandScale operand_scale)326 bool Bytecodes::BytecodeHasHandler(Bytecode bytecode,
327                                    OperandScale operand_scale) {
328   return operand_scale == OperandScale::kSingle ||
329          Bytecodes::IsBytecodeWithScalableOperands(bytecode);
330 }
331 
operator <<(std::ostream & os,const Bytecode & bytecode)332 std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) {
333   return os << Bytecodes::ToString(bytecode);
334 }
335 
336 }  // namespace interpreter
337 }  // namespace internal
338 }  // namespace v8
339