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,const char * separator)110 std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale,
111 const char* separator) {
112 std::string value(ToString(bytecode));
113 if (operand_scale > OperandScale::kSingle) {
114 Bytecode prefix_bytecode = OperandScaleToPrefixBytecode(operand_scale);
115 std::string suffix = ToString(prefix_bytecode);
116 return value.append(separator).append(suffix);
117 } else {
118 return value;
119 }
120 }
121
122 // static
GetDebugBreak(Bytecode bytecode)123 Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) {
124 DCHECK(!IsDebugBreak(bytecode));
125 if (bytecode == Bytecode::kWide) {
126 return Bytecode::kDebugBreakWide;
127 }
128 if (bytecode == Bytecode::kExtraWide) {
129 return Bytecode::kDebugBreakExtraWide;
130 }
131 int bytecode_size = Size(bytecode, OperandScale::kSingle);
132 #define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name) \
133 if (bytecode_size == Size(Bytecode::k##Name, OperandScale::kSingle)) { \
134 return Bytecode::k##Name; \
135 }
136 DEBUG_BREAK_PLAIN_BYTECODE_LIST(RETURN_IF_DEBUG_BREAK_SIZE_MATCHES)
137 #undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES
138 UNREACHABLE();
139 }
140
141 // static
GetOperandOffset(Bytecode bytecode,int i,OperandScale operand_scale)142 int Bytecodes::GetOperandOffset(Bytecode bytecode, int i,
143 OperandScale operand_scale) {
144 DCHECK_LT(i, Bytecodes::NumberOfOperands(bytecode));
145 // TODO(oth): restore this to a statically determined constant.
146 int offset = 1;
147 for (int operand_index = 0; operand_index < i; ++operand_index) {
148 OperandSize operand_size =
149 GetOperandSize(bytecode, operand_index, operand_scale);
150 offset += static_cast<int>(operand_size);
151 }
152 return offset;
153 }
154
155 // static
GetJumpWithoutToBoolean(Bytecode bytecode)156 Bytecode Bytecodes::GetJumpWithoutToBoolean(Bytecode bytecode) {
157 switch (bytecode) {
158 case Bytecode::kJumpIfToBooleanTrue:
159 return Bytecode::kJumpIfTrue;
160 case Bytecode::kJumpIfToBooleanFalse:
161 return Bytecode::kJumpIfFalse;
162 case Bytecode::kJumpIfToBooleanTrueConstant:
163 return Bytecode::kJumpIfTrueConstant;
164 case Bytecode::kJumpIfToBooleanFalseConstant:
165 return Bytecode::kJumpIfFalseConstant;
166 default:
167 break;
168 }
169 UNREACHABLE();
170 }
171
172 // static
IsDebugBreak(Bytecode bytecode)173 bool Bytecodes::IsDebugBreak(Bytecode bytecode) {
174 switch (bytecode) {
175 #define CASE(Name, ...) case Bytecode::k##Name:
176 DEBUG_BREAK_BYTECODE_LIST(CASE);
177 #undef CASE
178 return true;
179 default:
180 break;
181 }
182 return false;
183 }
184
185 // static
IsRegisterOperandType(OperandType operand_type)186 bool Bytecodes::IsRegisterOperandType(OperandType operand_type) {
187 switch (operand_type) {
188 #define CASE(Name, _) \
189 case OperandType::k##Name: \
190 return true;
191 REGISTER_OPERAND_TYPE_LIST(CASE)
192 #undef CASE
193 #define CASE(Name, _) \
194 case OperandType::k##Name: \
195 break;
196 NON_REGISTER_OPERAND_TYPE_LIST(CASE)
197 #undef CASE
198 }
199 return false;
200 }
201
202 // static
IsRegisterListOperandType(OperandType operand_type)203 bool Bytecodes::IsRegisterListOperandType(OperandType operand_type) {
204 switch (operand_type) {
205 case OperandType::kRegList:
206 case OperandType::kRegOutList:
207 return true;
208 default:
209 return false;
210 }
211 }
212
MakesCallAlongCriticalPath(Bytecode bytecode)213 bool Bytecodes::MakesCallAlongCriticalPath(Bytecode bytecode) {
214 if (IsCallOrConstruct(bytecode) || IsCallRuntime(bytecode)) return true;
215 switch (bytecode) {
216 case Bytecode::kCreateWithContext:
217 case Bytecode::kCreateBlockContext:
218 case Bytecode::kCreateCatchContext:
219 case Bytecode::kCreateRegExpLiteral:
220 case Bytecode::kGetIterator:
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::kCallNoFeedback:
288 case Bytecode::kCallProperty:
289 case Bytecode::kCallProperty0:
290 case Bytecode::kCallProperty1:
291 case Bytecode::kCallProperty2:
292 case Bytecode::kCallUndefinedReceiver:
293 case Bytecode::kCallUndefinedReceiver0:
294 case Bytecode::kCallUndefinedReceiver1:
295 case Bytecode::kCallUndefinedReceiver2:
296 case Bytecode::kConstruct:
297 case Bytecode::kConstructWithSpread:
298 return true;
299 default:
300 return false;
301 }
302 }
303 return false;
304 }
305
306 // static
IsBytecodeWithScalableOperands(Bytecode bytecode)307 bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) {
308 for (int i = 0; i < NumberOfOperands(bytecode); i++) {
309 if (OperandIsScalable(bytecode, i)) return true;
310 }
311 return false;
312 }
313
314 // static
IsUnsignedOperandType(OperandType operand_type)315 bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) {
316 switch (operand_type) {
317 #define CASE(Name, _) \
318 case OperandType::k##Name: \
319 return OperandTraits<OperandType::k##Name>::TypeInfoTraits::kIsUnsigned;
320 OPERAND_TYPE_LIST(CASE)
321 #undef CASE
322 }
323 UNREACHABLE();
324 }
325
326 // static
BytecodeHasHandler(Bytecode bytecode,OperandScale operand_scale)327 bool Bytecodes::BytecodeHasHandler(Bytecode bytecode,
328 OperandScale operand_scale) {
329 return operand_scale == OperandScale::kSingle ||
330 Bytecodes::IsBytecodeWithScalableOperands(bytecode);
331 }
332
operator <<(std::ostream & os,const Bytecode & bytecode)333 std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) {
334 return os << Bytecodes::ToString(bytecode);
335 }
336
337 } // namespace interpreter
338 } // namespace internal
339 } // namespace v8
340