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::kGetNamedProperty:
287 case Bytecode::kGetKeyedProperty:
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