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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 300 bool Bytecodes::BytecodeHasHandler(Bytecode bytecode, 301 OperandScale operand_scale) { 302 return operand_scale == OperandScale::kSingle || 303 Bytecodes::IsBytecodeWithScalableOperands(bytecode); 304 } 305 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