| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/interpreter/bytecodes.h" | 5 #include "src/interpreter/bytecodes.h" |
| 6 | 6 |
| 7 #include <iomanip> | 7 #include <iomanip> |
| 8 | 8 |
| 9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 10 #include "src/globals.h" | |
| 11 #include "src/interpreter/bytecode-traits.h" | 10 #include "src/interpreter/bytecode-traits.h" |
| 12 | 11 |
| 13 namespace v8 { | 12 namespace v8 { |
| 14 namespace internal { | 13 namespace internal { |
| 15 namespace interpreter { | 14 namespace interpreter { |
| 16 | 15 |
| 17 STATIC_CONST_MEMBER_DEFINITION const int Bytecodes::kMaxOperands; | 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 |
| 18 | 59 |
| 19 // static | 60 // static |
| 20 const char* Bytecodes::ToString(Bytecode bytecode) { | 61 const char* Bytecodes::ToString(Bytecode bytecode) { |
| 21 switch (bytecode) { | 62 switch (bytecode) { |
| 22 #define CASE(Name, ...) \ | 63 #define CASE(Name, ...) \ |
| 23 case Bytecode::k##Name: \ | 64 case Bytecode::k##Name: \ |
| 24 return #Name; | 65 return #Name; |
| 25 BYTECODE_LIST(CASE) | 66 BYTECODE_LIST(CASE) |
| 26 #undef CASE | 67 #undef CASE |
| 27 } | 68 } |
| 28 UNREACHABLE(); | 69 UNREACHABLE(); |
| 29 return ""; | 70 return ""; |
| 30 } | 71 } |
| 31 | 72 |
| 32 // static | 73 // static |
| 33 std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale) { | 74 std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale) { |
| 34 static const char kSeparator = '.'; | 75 static const char kSeparator = '.'; |
| 35 | 76 |
| 36 std::string value(ToString(bytecode)); | 77 std::string value(ToString(bytecode)); |
| 37 if (operand_scale > OperandScale::kSingle) { | 78 if (operand_scale > OperandScale::kSingle) { |
| 38 Bytecode prefix_bytecode = OperandScaleToPrefixBytecode(operand_scale); | 79 Bytecode prefix_bytecode = OperandScaleToPrefixBytecode(operand_scale); |
| 39 std::string suffix = ToString(prefix_bytecode); | 80 std::string suffix = ToString(prefix_bytecode); |
| 40 return value.append(1, kSeparator).append(suffix); | 81 return value.append(1, kSeparator).append(suffix); |
| 41 } else { | 82 } else { |
| 42 return value; | 83 return value; |
| 43 } | 84 } |
| 44 } | 85 } |
| 45 | 86 |
| 46 // static | 87 // static |
| 47 const char* Bytecodes::AccumulatorUseToString(AccumulatorUse accumulator_use) { | |
| 48 switch (accumulator_use) { | |
| 49 case AccumulatorUse::kNone: | |
| 50 return "None"; | |
| 51 case AccumulatorUse::kRead: | |
| 52 return "Read"; | |
| 53 case AccumulatorUse::kWrite: | |
| 54 return "Write"; | |
| 55 case AccumulatorUse::kReadWrite: | |
| 56 return "ReadWrite"; | |
| 57 } | |
| 58 UNREACHABLE(); | |
| 59 return ""; | |
| 60 } | |
| 61 | |
| 62 // static | |
| 63 const char* Bytecodes::OperandTypeToString(OperandType operand_type) { | |
| 64 switch (operand_type) { | |
| 65 #define CASE(Name, _) \ | |
| 66 case OperandType::k##Name: \ | |
| 67 return #Name; | |
| 68 OPERAND_TYPE_LIST(CASE) | |
| 69 #undef CASE | |
| 70 } | |
| 71 UNREACHABLE(); | |
| 72 return ""; | |
| 73 } | |
| 74 | |
| 75 // static | |
| 76 const char* Bytecodes::OperandScaleToString(OperandScale operand_scale) { | |
| 77 switch (operand_scale) { | |
| 78 #define CASE(Name, _) \ | |
| 79 case OperandScale::k##Name: \ | |
| 80 return #Name; | |
| 81 OPERAND_SCALE_LIST(CASE) | |
| 82 #undef CASE | |
| 83 } | |
| 84 UNREACHABLE(); | |
| 85 return ""; | |
| 86 } | |
| 87 | |
| 88 // static | |
| 89 const char* Bytecodes::OperandSizeToString(OperandSize operand_size) { | |
| 90 switch (operand_size) { | |
| 91 case OperandSize::kNone: | |
| 92 return "None"; | |
| 93 case OperandSize::kByte: | |
| 94 return "Byte"; | |
| 95 case OperandSize::kShort: | |
| 96 return "Short"; | |
| 97 case OperandSize::kQuad: | |
| 98 return "Quad"; | |
| 99 } | |
| 100 UNREACHABLE(); | |
| 101 return ""; | |
| 102 } | |
| 103 | |
| 104 // static | |
| 105 uint8_t Bytecodes::ToByte(Bytecode bytecode) { | |
| 106 DCHECK_LE(bytecode, Bytecode::kLast); | |
| 107 return static_cast<uint8_t>(bytecode); | |
| 108 } | |
| 109 | |
| 110 // static | |
| 111 Bytecode Bytecodes::FromByte(uint8_t value) { | |
| 112 Bytecode bytecode = static_cast<Bytecode>(value); | |
| 113 DCHECK(bytecode <= Bytecode::kLast); | |
| 114 return bytecode; | |
| 115 } | |
| 116 | |
| 117 // static | |
| 118 Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) { | 88 Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) { |
| 119 DCHECK(!IsDebugBreak(bytecode)); | 89 DCHECK(!IsDebugBreak(bytecode)); |
| 120 if (bytecode == Bytecode::kWide) { | 90 if (bytecode == Bytecode::kWide) { |
| 121 return Bytecode::kDebugBreakWide; | 91 return Bytecode::kDebugBreakWide; |
| 122 } | 92 } |
| 123 if (bytecode == Bytecode::kExtraWide) { | 93 if (bytecode == Bytecode::kExtraWide) { |
| 124 return Bytecode::kDebugBreakExtraWide; | 94 return Bytecode::kDebugBreakExtraWide; |
| 125 } | 95 } |
| 126 int bytecode_size = Size(bytecode, OperandScale::kSingle); | 96 int bytecode_size = Size(bytecode, OperandScale::kSingle); |
| 127 #define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name, ...) \ | 97 #define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name) \ |
| 128 if (bytecode_size == Size(Bytecode::k##Name, OperandScale::kSingle)) { \ | 98 if (bytecode_size == Size(Bytecode::k##Name, OperandScale::kSingle)) { \ |
| 129 return Bytecode::k##Name; \ | 99 return Bytecode::k##Name; \ |
| 130 } | 100 } |
| 131 DEBUG_BREAK_PLAIN_BYTECODE_LIST(RETURN_IF_DEBUG_BREAK_SIZE_MATCHES) | 101 DEBUG_BREAK_PLAIN_BYTECODE_LIST(RETURN_IF_DEBUG_BREAK_SIZE_MATCHES) |
| 132 #undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES | 102 #undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES |
| 133 UNREACHABLE(); | 103 UNREACHABLE(); |
| 134 return Bytecode::kIllegal; | 104 return Bytecode::kIllegal; |
| 135 } | 105 } |
| 136 | 106 |
| 137 // static | 107 // static |
| 138 int Bytecodes::Size(Bytecode bytecode, OperandScale operand_scale) { | |
| 139 int size = 1; | |
| 140 for (int i = 0; i < NumberOfOperands(bytecode); i++) { | |
| 141 OperandSize operand_size = GetOperandSize(bytecode, i, operand_scale); | |
| 142 int delta = static_cast<int>(operand_size); | |
| 143 DCHECK(base::bits::IsPowerOfTwo32(static_cast<uint32_t>(delta))); | |
| 144 size += delta; | |
| 145 } | |
| 146 return size; | |
| 147 } | |
| 148 | |
| 149 // static | |
| 150 size_t Bytecodes::ReturnCount(Bytecode bytecode) { | |
| 151 return bytecode == Bytecode::kReturn ? 1 : 0; | |
| 152 } | |
| 153 | |
| 154 // static | |
| 155 int Bytecodes::NumberOfOperands(Bytecode bytecode) { | |
| 156 DCHECK(bytecode <= Bytecode::kLast); | |
| 157 switch (bytecode) { | |
| 158 #define CASE(Name, ...) \ | |
| 159 case Bytecode::k##Name: \ | |
| 160 return BytecodeTraits<__VA_ARGS__>::kOperandCount; | |
| 161 BYTECODE_LIST(CASE) | |
| 162 #undef CASE | |
| 163 } | |
| 164 UNREACHABLE(); | |
| 165 return 0; | |
| 166 } | |
| 167 | |
| 168 // static | |
| 169 int Bytecodes::NumberOfRegisterOperands(Bytecode bytecode) { | |
| 170 DCHECK(bytecode <= Bytecode::kLast); | |
| 171 switch (bytecode) { | |
| 172 #define CASE(Name, ...) \ | |
| 173 case Bytecode::k##Name: \ | |
| 174 typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \ | |
| 175 return Name##Trait::kRegisterOperandCount; | |
| 176 BYTECODE_LIST(CASE) | |
| 177 #undef CASE | |
| 178 } | |
| 179 UNREACHABLE(); | |
| 180 return false; | |
| 181 } | |
| 182 | |
| 183 // static | |
| 184 Bytecode Bytecodes::OperandScaleToPrefixBytecode(OperandScale operand_scale) { | |
| 185 switch (operand_scale) { | |
| 186 case OperandScale::kQuadruple: | |
| 187 return Bytecode::kExtraWide; | |
| 188 case OperandScale::kDouble: | |
| 189 return Bytecode::kWide; | |
| 190 default: | |
| 191 UNREACHABLE(); | |
| 192 return Bytecode::kIllegal; | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 // static | |
| 197 bool Bytecodes::OperandScaleRequiresPrefixBytecode(OperandScale operand_scale) { | |
| 198 return operand_scale != OperandScale::kSingle; | |
| 199 } | |
| 200 | |
| 201 // static | |
| 202 OperandScale Bytecodes::PrefixBytecodeToOperandScale(Bytecode bytecode) { | |
| 203 switch (bytecode) { | |
| 204 case Bytecode::kExtraWide: | |
| 205 case Bytecode::kDebugBreakExtraWide: | |
| 206 return OperandScale::kQuadruple; | |
| 207 case Bytecode::kWide: | |
| 208 case Bytecode::kDebugBreakWide: | |
| 209 return OperandScale::kDouble; | |
| 210 default: | |
| 211 UNREACHABLE(); | |
| 212 return OperandScale::kSingle; | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 // static | |
| 217 AccumulatorUse Bytecodes::GetAccumulatorUse(Bytecode bytecode) { | |
| 218 DCHECK(bytecode <= Bytecode::kLast); | |
| 219 switch (bytecode) { | |
| 220 #define CASE(Name, ...) \ | |
| 221 case Bytecode::k##Name: \ | |
| 222 return BytecodeTraits<__VA_ARGS__>::kAccumulatorUse; | |
| 223 BYTECODE_LIST(CASE) | |
| 224 #undef CASE | |
| 225 } | |
| 226 UNREACHABLE(); | |
| 227 return AccumulatorUse::kNone; | |
| 228 } | |
| 229 | |
| 230 // static | |
| 231 bool Bytecodes::ReadsAccumulator(Bytecode bytecode) { | |
| 232 return (GetAccumulatorUse(bytecode) & AccumulatorUse::kRead) == | |
| 233 AccumulatorUse::kRead; | |
| 234 } | |
| 235 | |
| 236 // static | |
| 237 bool Bytecodes::WritesAccumulator(Bytecode bytecode) { | |
| 238 return (GetAccumulatorUse(bytecode) & AccumulatorUse::kWrite) == | |
| 239 AccumulatorUse::kWrite; | |
| 240 } | |
| 241 | |
| 242 // static | |
| 243 bool Bytecodes::WritesBooleanToAccumulator(Bytecode bytecode) { | |
| 244 switch (bytecode) { | |
| 245 case Bytecode::kLdaTrue: | |
| 246 case Bytecode::kLdaFalse: | |
| 247 case Bytecode::kToBooleanLogicalNot: | |
| 248 case Bytecode::kLogicalNot: | |
| 249 case Bytecode::kTestEqual: | |
| 250 case Bytecode::kTestNotEqual: | |
| 251 case Bytecode::kTestEqualStrict: | |
| 252 case Bytecode::kTestLessThan: | |
| 253 case Bytecode::kTestLessThanOrEqual: | |
| 254 case Bytecode::kTestGreaterThan: | |
| 255 case Bytecode::kTestGreaterThanOrEqual: | |
| 256 case Bytecode::kTestInstanceOf: | |
| 257 case Bytecode::kTestIn: | |
| 258 case Bytecode::kForInContinue: | |
| 259 return true; | |
| 260 default: | |
| 261 return false; | |
| 262 } | |
| 263 } | |
| 264 | |
| 265 // static | |
| 266 bool Bytecodes::IsAccumulatorLoadWithoutEffects(Bytecode bytecode) { | |
| 267 switch (bytecode) { | |
| 268 case Bytecode::kLdaZero: | |
| 269 case Bytecode::kLdaSmi: | |
| 270 case Bytecode::kLdaUndefined: | |
| 271 case Bytecode::kLdaNull: | |
| 272 case Bytecode::kLdaTheHole: | |
| 273 case Bytecode::kLdaTrue: | |
| 274 case Bytecode::kLdaFalse: | |
| 275 case Bytecode::kLdaConstant: | |
| 276 case Bytecode::kLdar: | |
| 277 return true; | |
| 278 default: | |
| 279 return false; | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 // static | |
| 284 bool Bytecodes::IsJumpWithoutEffects(Bytecode bytecode) { | |
| 285 return IsJump(bytecode) && !IsJumpIfToBoolean(bytecode); | |
| 286 } | |
| 287 | |
| 288 // static | |
| 289 bool Bytecodes::IsRegisterLoadWithoutEffects(Bytecode bytecode) { | |
| 290 switch (bytecode) { | |
| 291 case Bytecode::kMov: | |
| 292 case Bytecode::kPopContext: | |
| 293 case Bytecode::kPushContext: | |
| 294 case Bytecode::kStar: | |
| 295 case Bytecode::kLdrUndefined: | |
| 296 return true; | |
| 297 default: | |
| 298 return false; | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 // static | |
| 303 bool Bytecodes::IsWithoutExternalSideEffects(Bytecode bytecode) { | |
| 304 // These bytecodes only manipulate interpreter frame state and will | |
| 305 // never throw. | |
| 306 return (IsAccumulatorLoadWithoutEffects(bytecode) || | |
| 307 IsRegisterLoadWithoutEffects(bytecode) || | |
| 308 bytecode == Bytecode::kNop || IsJumpWithoutEffects(bytecode)); | |
| 309 } | |
| 310 | |
| 311 // static | |
| 312 OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) { | |
| 313 DCHECK_LE(bytecode, Bytecode::kLast); | |
| 314 DCHECK_LT(i, NumberOfOperands(bytecode)); | |
| 315 DCHECK_GE(i, 0); | |
| 316 return GetOperandTypes(bytecode)[i]; | |
| 317 } | |
| 318 | |
| 319 // static | |
| 320 const OperandType* Bytecodes::GetOperandTypes(Bytecode bytecode) { | |
| 321 DCHECK_LE(bytecode, Bytecode::kLast); | |
| 322 switch (bytecode) { | |
| 323 #define CASE(Name, ...) \ | |
| 324 case Bytecode::k##Name: \ | |
| 325 return BytecodeTraits<__VA_ARGS__>::GetOperandTypes(); | |
| 326 BYTECODE_LIST(CASE) | |
| 327 #undef CASE | |
| 328 } | |
| 329 UNREACHABLE(); | |
| 330 return nullptr; | |
| 331 } | |
| 332 | |
| 333 // static | |
| 334 const OperandTypeInfo* Bytecodes::GetOperandTypeInfos(Bytecode bytecode) { | |
| 335 DCHECK(bytecode <= Bytecode::kLast); | |
| 336 switch (bytecode) { | |
| 337 #define CASE(Name, ...) \ | |
| 338 case Bytecode::k##Name: \ | |
| 339 return BytecodeTraits<__VA_ARGS__>::GetOperandTypeInfos(); | |
| 340 BYTECODE_LIST(CASE) | |
| 341 #undef CASE | |
| 342 } | |
| 343 UNREACHABLE(); | |
| 344 return nullptr; | |
| 345 } | |
| 346 | |
| 347 // static | |
| 348 OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i, | |
| 349 OperandScale operand_scale) { | |
| 350 DCHECK_LT(i, NumberOfOperands(bytecode)); | |
| 351 OperandType operand_type = GetOperandType(bytecode, i); | |
| 352 return SizeOfOperand(operand_type, operand_scale); | |
| 353 } | |
| 354 | |
| 355 // static | |
| 356 int Bytecodes::GetOperandOffset(Bytecode bytecode, int i, | 108 int Bytecodes::GetOperandOffset(Bytecode bytecode, int i, |
| 357 OperandScale operand_scale) { | 109 OperandScale operand_scale) { |
| 358 DCHECK_LT(i, Bytecodes::NumberOfOperands(bytecode)); | 110 DCHECK_LT(i, Bytecodes::NumberOfOperands(bytecode)); |
| 359 // TODO(oth): restore this to a statically determined constant. | 111 // TODO(oth): restore this to a statically determined constant. |
| 360 int offset = 1; | 112 int offset = 1; |
| 361 for (int operand_index = 0; operand_index < i; ++operand_index) { | 113 for (int operand_index = 0; operand_index < i; ++operand_index) { |
| 362 OperandSize operand_size = | 114 OperandSize operand_size = |
| 363 GetOperandSize(bytecode, operand_index, operand_scale); | 115 GetOperandSize(bytecode, operand_index, operand_scale); |
| 364 offset += static_cast<int>(operand_size); | 116 offset += static_cast<int>(operand_size); |
| 365 } | 117 } |
| 366 return offset; | 118 return offset; |
| 367 } | 119 } |
| 368 | 120 |
| 369 // static | 121 // static |
| 370 OperandSize Bytecodes::SizeOfOperand(OperandType operand_type, | |
| 371 OperandScale operand_scale) { | |
| 372 DCHECK_LE(operand_type, OperandType::kLast); | |
| 373 DCHECK_GE(operand_scale, OperandScale::kSingle); | |
| 374 DCHECK_LE(operand_scale, OperandScale::kLast); | |
| 375 return static_cast<OperandSize>( | |
| 376 ScaledOperandSize(operand_type, operand_scale)); | |
| 377 } | |
| 378 | |
| 379 // static | |
| 380 bool Bytecodes::IsConditionalJumpImmediate(Bytecode bytecode) { | |
| 381 return bytecode == Bytecode::kJumpIfTrue || | |
| 382 bytecode == Bytecode::kJumpIfFalse || | |
| 383 bytecode == Bytecode::kJumpIfToBooleanTrue || | |
| 384 bytecode == Bytecode::kJumpIfToBooleanFalse || | |
| 385 bytecode == Bytecode::kJumpIfNotHole || | |
| 386 bytecode == Bytecode::kJumpIfNull || | |
| 387 bytecode == Bytecode::kJumpIfUndefined; | |
| 388 } | |
| 389 | |
| 390 // static | |
| 391 bool Bytecodes::IsConditionalJumpConstant(Bytecode bytecode) { | |
| 392 return bytecode == Bytecode::kJumpIfTrueConstant || | |
| 393 bytecode == Bytecode::kJumpIfFalseConstant || | |
| 394 bytecode == Bytecode::kJumpIfToBooleanTrueConstant || | |
| 395 bytecode == Bytecode::kJumpIfToBooleanFalseConstant || | |
| 396 bytecode == Bytecode::kJumpIfNotHoleConstant || | |
| 397 bytecode == Bytecode::kJumpIfNullConstant || | |
| 398 bytecode == Bytecode::kJumpIfUndefinedConstant; | |
| 399 } | |
| 400 | |
| 401 // static | |
| 402 bool Bytecodes::IsConditionalJump(Bytecode bytecode) { | |
| 403 return IsConditionalJumpImmediate(bytecode) || | |
| 404 IsConditionalJumpConstant(bytecode); | |
| 405 } | |
| 406 | |
| 407 | |
| 408 // static | |
| 409 bool Bytecodes::IsJumpImmediate(Bytecode bytecode) { | |
| 410 return bytecode == Bytecode::kJump || bytecode == Bytecode::kJumpLoop || | |
| 411 IsConditionalJumpImmediate(bytecode); | |
| 412 } | |
| 413 | |
| 414 | |
| 415 // static | |
| 416 bool Bytecodes::IsJumpConstant(Bytecode bytecode) { | |
| 417 return bytecode == Bytecode::kJumpConstant || | |
| 418 IsConditionalJumpConstant(bytecode); | |
| 419 } | |
| 420 | |
| 421 // static | |
| 422 bool Bytecodes::IsJump(Bytecode bytecode) { | |
| 423 return IsJumpImmediate(bytecode) || IsJumpConstant(bytecode); | |
| 424 } | |
| 425 | |
| 426 // static | |
| 427 bool Bytecodes::IsJumpIfToBoolean(Bytecode bytecode) { | |
| 428 return bytecode == Bytecode::kJumpIfToBooleanTrue || | |
| 429 bytecode == Bytecode::kJumpIfToBooleanFalse || | |
| 430 bytecode == Bytecode::kJumpIfToBooleanTrueConstant || | |
| 431 bytecode == Bytecode::kJumpIfToBooleanFalseConstant; | |
| 432 } | |
| 433 | |
| 434 // static | |
| 435 Bytecode Bytecodes::GetJumpWithoutToBoolean(Bytecode bytecode) { | 122 Bytecode Bytecodes::GetJumpWithoutToBoolean(Bytecode bytecode) { |
| 436 switch (bytecode) { | 123 switch (bytecode) { |
| 437 case Bytecode::kJumpIfToBooleanTrue: | 124 case Bytecode::kJumpIfToBooleanTrue: |
| 438 return Bytecode::kJumpIfTrue; | 125 return Bytecode::kJumpIfTrue; |
| 439 case Bytecode::kJumpIfToBooleanFalse: | 126 case Bytecode::kJumpIfToBooleanFalse: |
| 440 return Bytecode::kJumpIfFalse; | 127 return Bytecode::kJumpIfFalse; |
| 441 case Bytecode::kJumpIfToBooleanTrueConstant: | 128 case Bytecode::kJumpIfToBooleanTrueConstant: |
| 442 return Bytecode::kJumpIfTrueConstant; | 129 return Bytecode::kJumpIfTrueConstant; |
| 443 case Bytecode::kJumpIfToBooleanFalseConstant: | 130 case Bytecode::kJumpIfToBooleanFalseConstant: |
| 444 return Bytecode::kJumpIfFalseConstant; | 131 return Bytecode::kJumpIfFalseConstant; |
| 445 default: | 132 default: |
| 446 break; | 133 break; |
| 447 } | 134 } |
| 448 UNREACHABLE(); | 135 UNREACHABLE(); |
| 449 return Bytecode::kIllegal; | 136 return Bytecode::kIllegal; |
| 450 } | 137 } |
| 451 | 138 |
| 452 // static | 139 // static |
| 453 bool Bytecodes::IsCallOrNew(Bytecode bytecode) { | |
| 454 return bytecode == Bytecode::kCall || bytecode == Bytecode::kTailCall || | |
| 455 bytecode == Bytecode::kNew; | |
| 456 } | |
| 457 | |
| 458 // static | |
| 459 bool Bytecodes::IsCallRuntime(Bytecode bytecode) { | |
| 460 return bytecode == Bytecode::kCallRuntime || | |
| 461 bytecode == Bytecode::kCallRuntimeForPair || | |
| 462 bytecode == Bytecode::kInvokeIntrinsic; | |
| 463 } | |
| 464 | |
| 465 // static | |
| 466 bool Bytecodes::IsDebugBreak(Bytecode bytecode) { | 140 bool Bytecodes::IsDebugBreak(Bytecode bytecode) { |
| 467 switch (bytecode) { | 141 switch (bytecode) { |
| 468 #define CASE(Name, ...) case Bytecode::k##Name: | 142 #define CASE(Name, ...) case Bytecode::k##Name: |
| 469 DEBUG_BREAK_BYTECODE_LIST(CASE); | 143 DEBUG_BREAK_BYTECODE_LIST(CASE); |
| 470 #undef CASE | 144 #undef CASE |
| 471 return true; | 145 return true; |
| 472 default: | 146 default: |
| 473 break; | 147 break; |
| 474 } | 148 } |
| 475 return false; | 149 return false; |
| 476 } | 150 } |
| 477 | 151 |
| 478 // static | 152 // static |
| 479 bool Bytecodes::IsLdarOrStar(Bytecode bytecode) { | |
| 480 return bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar; | |
| 481 } | |
| 482 | |
| 483 // static | |
| 484 bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) { | |
| 485 switch (bytecode) { | |
| 486 #define CASE(Name, ...) \ | |
| 487 case Bytecode::k##Name: \ | |
| 488 typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \ | |
| 489 return Name##Trait::IsScalable(); | |
| 490 BYTECODE_LIST(CASE) | |
| 491 #undef CASE | |
| 492 } | |
| 493 UNREACHABLE(); | |
| 494 return false; | |
| 495 } | |
| 496 | |
| 497 // static | |
| 498 bool Bytecodes::IsPrefixScalingBytecode(Bytecode bytecode) { | |
| 499 switch (bytecode) { | |
| 500 case Bytecode::kExtraWide: | |
| 501 case Bytecode::kDebugBreakExtraWide: | |
| 502 case Bytecode::kWide: | |
| 503 case Bytecode::kDebugBreakWide: | |
| 504 return true; | |
| 505 default: | |
| 506 return false; | |
| 507 } | |
| 508 } | |
| 509 | |
| 510 // static | |
| 511 bool Bytecodes::PutsNameInAccumulator(Bytecode bytecode) { | |
| 512 return bytecode == Bytecode::kTypeOf; | |
| 513 } | |
| 514 | |
| 515 // static | |
| 516 bool Bytecodes::IsJumpOrReturn(Bytecode bytecode) { | |
| 517 return bytecode == Bytecode::kReturn || IsJump(bytecode); | |
| 518 } | |
| 519 | |
| 520 // static | |
| 521 bool Bytecodes::IsMaybeRegisterOperandType(OperandType operand_type) { | |
| 522 return operand_type == OperandType::kMaybeReg; | |
| 523 } | |
| 524 | |
| 525 // static | |
| 526 bool Bytecodes::IsRegisterOperandType(OperandType operand_type) { | 153 bool Bytecodes::IsRegisterOperandType(OperandType operand_type) { |
| 527 switch (operand_type) { | 154 switch (operand_type) { |
| 528 #define CASE(Name, _) \ | 155 #define CASE(Name, _) \ |
| 529 case OperandType::k##Name: \ | 156 case OperandType::k##Name: \ |
| 530 return true; | 157 return true; |
| 531 REGISTER_OPERAND_TYPE_LIST(CASE) | 158 REGISTER_OPERAND_TYPE_LIST(CASE) |
| 532 #undef CASE | 159 #undef CASE |
| 533 #define CASE(Name, _) \ | 160 #define CASE(Name, _) \ |
| 534 case OperandType::k##Name: \ | 161 case OperandType::k##Name: \ |
| 535 break; | 162 break; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 596 case Bytecode::kNew: | 223 case Bytecode::kNew: |
| 597 return true; | 224 return true; |
| 598 default: | 225 default: |
| 599 return false; | 226 return false; |
| 600 } | 227 } |
| 601 } | 228 } |
| 602 return false; | 229 return false; |
| 603 } | 230 } |
| 604 | 231 |
| 605 // static | 232 // static |
| 606 int Bytecodes::GetNumberOfRegistersRepresentedBy(OperandType operand_type) { | 233 bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) { |
| 607 switch (operand_type) { | 234 for (int i = 0; i < NumberOfOperands(bytecode); i++) { |
| 608 case OperandType::kMaybeReg: | 235 if (OperandIsScalable(bytecode, i)) return true; |
| 609 case OperandType::kReg: | |
| 610 case OperandType::kRegOut: | |
| 611 return 1; | |
| 612 case OperandType::kRegPair: | |
| 613 case OperandType::kRegOutPair: | |
| 614 return 2; | |
| 615 case OperandType::kRegOutTriple: | |
| 616 return 3; | |
| 617 default: | |
| 618 return 0; | |
| 619 } | 236 } |
| 620 return 0; | 237 return false; |
| 621 } | 238 } |
| 622 | 239 |
| 623 // static | 240 // static |
| 624 bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) { | 241 bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) { |
| 625 switch (operand_type) { | 242 switch (operand_type) { |
| 626 #define CASE(Name, _) \ | 243 #define CASE(Name, _) \ |
| 627 case OperandType::k##Name: \ | 244 case OperandType::k##Name: \ |
| 628 return OperandTraits<OperandType::k##Name>::TypeInfoTraits::kIsUnsigned; | 245 return OperandTraits<OperandType::k##Name>::TypeInfoTraits::kIsUnsigned; |
| 629 OPERAND_TYPE_LIST(CASE) | 246 OPERAND_TYPE_LIST(CASE) |
| 630 #undef CASE | 247 #undef CASE |
| 631 } | 248 } |
| 632 UNREACHABLE(); | 249 UNREACHABLE(); |
| 633 return false; | 250 return false; |
| 634 } | 251 } |
| 635 | 252 |
| 636 // static | 253 // static |
| 637 OperandSize Bytecodes::SizeForSignedOperand(int value) { | 254 OperandSize Bytecodes::SizeOfOperand(OperandType operand_type, |
| 638 if (value >= kMinInt8 && value <= kMaxInt8) { | 255 OperandScale operand_scale) { |
| 639 return OperandSize::kByte; | 256 DCHECK_LE(operand_type, OperandType::kLast); |
| 640 } else if (value >= kMinInt16 && value <= kMaxInt16) { | 257 DCHECK_GE(operand_scale, OperandScale::kSingle); |
| 641 return OperandSize::kShort; | 258 DCHECK_LE(operand_scale, OperandScale::kLast); |
| 642 } else { | 259 STATIC_ASSERT(static_cast<int>(OperandScale::kQuadruple) == 4 && |
| 643 return OperandSize::kQuad; | 260 OperandScale::kLast == OperandScale::kQuadruple); |
| 644 } | 261 int scale_index = static_cast<int>(operand_scale) >> 1; |
| 262 // clang-format off |
| 263 static const OperandSize kOperandSizes[][3] = { |
| 264 #define ENTRY(Name, ...) \ |
| 265 { OperandScaler<OperandType::k##Name, \ |
| 266 OperandScale::kSingle>::kOperandSize, \ |
| 267 OperandScaler<OperandType::k##Name, \ |
| 268 OperandScale::kDouble>::kOperandSize, \ |
| 269 OperandScaler<OperandType::k##Name, \ |
| 270 OperandScale::kQuadruple>::kOperandSize }, |
| 271 OPERAND_TYPE_LIST(ENTRY) |
| 272 #undef ENTRY |
| 273 }; |
| 274 // clang-format on |
| 275 return kOperandSizes[static_cast<size_t>(operand_type)][scale_index]; |
| 645 } | 276 } |
| 646 | 277 |
| 647 // static | 278 // static |
| 648 OperandSize Bytecodes::SizeForUnsignedOperand(uint32_t value) { | |
| 649 if (value <= kMaxUInt8) { | |
| 650 return OperandSize::kByte; | |
| 651 } else if (value <= kMaxUInt16) { | |
| 652 return OperandSize::kShort; | |
| 653 } else { | |
| 654 return OperandSize::kQuad; | |
| 655 } | |
| 656 } | |
| 657 | |
| 658 // static | |
| 659 bool Bytecodes::BytecodeHasHandler(Bytecode bytecode, | 279 bool Bytecodes::BytecodeHasHandler(Bytecode bytecode, |
| 660 OperandScale operand_scale) { | 280 OperandScale operand_scale) { |
| 661 return operand_scale == OperandScale::kSingle || | 281 return operand_scale == OperandScale::kSingle || |
| 662 Bytecodes::IsBytecodeWithScalableOperands(bytecode); | 282 Bytecodes::IsBytecodeWithScalableOperands(bytecode); |
| 663 } | 283 } |
| 664 | 284 |
| 665 std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) { | 285 std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) { |
| 666 return os << Bytecodes::ToString(bytecode); | 286 return os << Bytecodes::ToString(bytecode); |
| 667 } | 287 } |
| 668 | 288 |
| 669 std::ostream& operator<<(std::ostream& os, const AccumulatorUse& use) { | |
| 670 return os << Bytecodes::AccumulatorUseToString(use); | |
| 671 } | |
| 672 | |
| 673 std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size) { | |
| 674 return os << Bytecodes::OperandSizeToString(operand_size); | |
| 675 } | |
| 676 | |
| 677 std::ostream& operator<<(std::ostream& os, const OperandScale& operand_scale) { | |
| 678 return os << Bytecodes::OperandScaleToString(operand_scale); | |
| 679 } | |
| 680 | |
| 681 std::ostream& operator<<(std::ostream& os, const OperandType& operand_type) { | |
| 682 return os << Bytecodes::OperandTypeToString(operand_type); | |
| 683 } | |
| 684 | |
| 685 } // namespace interpreter | 289 } // namespace interpreter |
| 686 } // namespace internal | 290 } // namespace internal |
| 687 } // namespace v8 | 291 } // namespace v8 |
| OLD | NEW |