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