Index: src/interpreter/bytecodes.cc |
diff --git a/src/interpreter/bytecodes.cc b/src/interpreter/bytecodes.cc |
index 0c600843aebc6219dc04885895033191d1cacab6..8b78ee2e4929036f0acd5e54af2e27e9654d88eb 100644 |
--- a/src/interpreter/bytecodes.cc |
+++ b/src/interpreter/bytecodes.cc |
@@ -7,59 +7,14 @@ |
#include <iomanip> |
#include "src/base/bits.h" |
+#include "src/globals.h" |
#include "src/interpreter/bytecode-traits.h" |
namespace v8 { |
namespace internal { |
namespace interpreter { |
-// clang-format off |
-STATIC_CONST_MEMBER_DEFINITION |
-const OperandType* const Bytecodes::kOperandTypes[] = { |
-#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kOperandTypes, |
- BYTECODE_LIST(ENTRY) |
-#undef ENTRY |
-}; |
- |
-STATIC_CONST_MEMBER_DEFINITION |
-const OperandTypeInfo* const Bytecodes::kOperandTypeInfos[] = { |
-#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kOperandTypeInfos, |
- BYTECODE_LIST(ENTRY) |
-#undef ENTRY |
-}; |
- |
-STATIC_CONST_MEMBER_DEFINITION const int Bytecodes::kOperandCount[] = { |
-#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kOperandCount, |
- BYTECODE_LIST(ENTRY) |
-#undef ENTRY |
-}; |
- |
-STATIC_CONST_MEMBER_DEFINITION |
-const AccumulatorUse Bytecodes::kAccumulatorUse[] = { |
-#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kAccumulatorUse, |
- BYTECODE_LIST(ENTRY) |
-#undef ENTRY |
-}; |
- |
-STATIC_CONST_MEMBER_DEFINITION const int Bytecodes::kBytecodeSizes[][3] = { |
-#define ENTRY(Name, ...) \ |
- { BytecodeTraits<__VA_ARGS__>::kSingleScaleSize, \ |
- BytecodeTraits<__VA_ARGS__>::kDoubleScaleSize, \ |
- BytecodeTraits<__VA_ARGS__>::kQuadrupleScaleSize }, |
- BYTECODE_LIST(ENTRY) |
-#undef ENTRY |
-}; |
- |
-STATIC_CONST_MEMBER_DEFINITION |
-const OperandSize* const Bytecodes::kOperandSizes[][3] = { |
-#define ENTRY(Name, ...) \ |
- { BytecodeTraits<__VA_ARGS__>::kSingleScaleOperandSizes, \ |
- BytecodeTraits<__VA_ARGS__>::kDoubleScaleOperandSizes, \ |
- BytecodeTraits<__VA_ARGS__>::kQuadrupleScaleOperandSizes }, |
- BYTECODE_LIST(ENTRY) |
-#undef ENTRY |
-}; |
-// clang-format on |
+STATIC_CONST_MEMBER_DEFINITION const int Bytecodes::kMaxOperands; |
// static |
const char* Bytecodes::ToString(Bytecode bytecode) { |
@@ -89,6 +44,77 @@ |
} |
// static |
+const char* Bytecodes::AccumulatorUseToString(AccumulatorUse accumulator_use) { |
+ switch (accumulator_use) { |
+ case AccumulatorUse::kNone: |
+ return "None"; |
+ case AccumulatorUse::kRead: |
+ return "Read"; |
+ case AccumulatorUse::kWrite: |
+ return "Write"; |
+ case AccumulatorUse::kReadWrite: |
+ return "ReadWrite"; |
+ } |
+ UNREACHABLE(); |
+ return ""; |
+} |
+ |
+// static |
+const char* Bytecodes::OperandTypeToString(OperandType operand_type) { |
+ switch (operand_type) { |
+#define CASE(Name, _) \ |
+ case OperandType::k##Name: \ |
+ return #Name; |
+ OPERAND_TYPE_LIST(CASE) |
+#undef CASE |
+ } |
+ UNREACHABLE(); |
+ return ""; |
+} |
+ |
+// static |
+const char* Bytecodes::OperandScaleToString(OperandScale operand_scale) { |
+ switch (operand_scale) { |
+#define CASE(Name, _) \ |
+ case OperandScale::k##Name: \ |
+ return #Name; |
+ OPERAND_SCALE_LIST(CASE) |
+#undef CASE |
+ } |
+ UNREACHABLE(); |
+ return ""; |
+} |
+ |
+// static |
+const char* Bytecodes::OperandSizeToString(OperandSize operand_size) { |
+ switch (operand_size) { |
+ case OperandSize::kNone: |
+ return "None"; |
+ case OperandSize::kByte: |
+ return "Byte"; |
+ case OperandSize::kShort: |
+ return "Short"; |
+ case OperandSize::kQuad: |
+ return "Quad"; |
+ } |
+ UNREACHABLE(); |
+ return ""; |
+} |
+ |
+// static |
+uint8_t Bytecodes::ToByte(Bytecode bytecode) { |
+ DCHECK_LE(bytecode, Bytecode::kLast); |
+ return static_cast<uint8_t>(bytecode); |
+} |
+ |
+// static |
+Bytecode Bytecodes::FromByte(uint8_t value) { |
+ Bytecode bytecode = static_cast<Bytecode>(value); |
+ DCHECK(bytecode <= Bytecode::kLast); |
+ return bytecode; |
+} |
+ |
+// static |
Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) { |
DCHECK(!IsDebugBreak(bytecode)); |
if (bytecode == Bytecode::kWide) { |
@@ -98,7 +124,7 @@ |
return Bytecode::kDebugBreakExtraWide; |
} |
int bytecode_size = Size(bytecode, OperandScale::kSingle); |
-#define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name) \ |
+#define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name, ...) \ |
if (bytecode_size == Size(Bytecode::k##Name, OperandScale::kSingle)) { \ |
return Bytecode::k##Name; \ |
} |
@@ -106,6 +132,224 @@ |
#undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES |
UNREACHABLE(); |
return Bytecode::kIllegal; |
+} |
+ |
+// static |
+int Bytecodes::Size(Bytecode bytecode, OperandScale operand_scale) { |
+ int size = 1; |
+ for (int i = 0; i < NumberOfOperands(bytecode); i++) { |
+ OperandSize operand_size = GetOperandSize(bytecode, i, operand_scale); |
+ int delta = static_cast<int>(operand_size); |
+ DCHECK(base::bits::IsPowerOfTwo32(static_cast<uint32_t>(delta))); |
+ size += delta; |
+ } |
+ return size; |
+} |
+ |
+// static |
+size_t Bytecodes::ReturnCount(Bytecode bytecode) { |
+ return bytecode == Bytecode::kReturn ? 1 : 0; |
+} |
+ |
+// static |
+int Bytecodes::NumberOfOperands(Bytecode bytecode) { |
+ DCHECK(bytecode <= Bytecode::kLast); |
+ switch (bytecode) { |
+#define CASE(Name, ...) \ |
+ case Bytecode::k##Name: \ |
+ return BytecodeTraits<__VA_ARGS__>::kOperandCount; |
+ BYTECODE_LIST(CASE) |
+#undef CASE |
+ } |
+ UNREACHABLE(); |
+ return 0; |
+} |
+ |
+// static |
+int Bytecodes::NumberOfRegisterOperands(Bytecode bytecode) { |
+ DCHECK(bytecode <= Bytecode::kLast); |
+ switch (bytecode) { |
+#define CASE(Name, ...) \ |
+ case Bytecode::k##Name: \ |
+ typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \ |
+ return Name##Trait::kRegisterOperandCount; |
+ BYTECODE_LIST(CASE) |
+#undef CASE |
+ } |
+ UNREACHABLE(); |
+ return false; |
+} |
+ |
+// static |
+Bytecode Bytecodes::OperandScaleToPrefixBytecode(OperandScale operand_scale) { |
+ switch (operand_scale) { |
+ case OperandScale::kQuadruple: |
+ return Bytecode::kExtraWide; |
+ case OperandScale::kDouble: |
+ return Bytecode::kWide; |
+ default: |
+ UNREACHABLE(); |
+ return Bytecode::kIllegal; |
+ } |
+} |
+ |
+// static |
+bool Bytecodes::OperandScaleRequiresPrefixBytecode(OperandScale operand_scale) { |
+ return operand_scale != OperandScale::kSingle; |
+} |
+ |
+// static |
+OperandScale Bytecodes::PrefixBytecodeToOperandScale(Bytecode bytecode) { |
+ switch (bytecode) { |
+ case Bytecode::kExtraWide: |
+ case Bytecode::kDebugBreakExtraWide: |
+ return OperandScale::kQuadruple; |
+ case Bytecode::kWide: |
+ case Bytecode::kDebugBreakWide: |
+ return OperandScale::kDouble; |
+ default: |
+ UNREACHABLE(); |
+ return OperandScale::kSingle; |
+ } |
+} |
+ |
+// static |
+AccumulatorUse Bytecodes::GetAccumulatorUse(Bytecode bytecode) { |
+ DCHECK(bytecode <= Bytecode::kLast); |
+ switch (bytecode) { |
+#define CASE(Name, ...) \ |
+ case Bytecode::k##Name: \ |
+ return BytecodeTraits<__VA_ARGS__>::kAccumulatorUse; |
+ BYTECODE_LIST(CASE) |
+#undef CASE |
+ } |
+ UNREACHABLE(); |
+ return AccumulatorUse::kNone; |
+} |
+ |
+// static |
+bool Bytecodes::ReadsAccumulator(Bytecode bytecode) { |
+ return (GetAccumulatorUse(bytecode) & AccumulatorUse::kRead) == |
+ AccumulatorUse::kRead; |
+} |
+ |
+// static |
+bool Bytecodes::WritesAccumulator(Bytecode bytecode) { |
+ return (GetAccumulatorUse(bytecode) & AccumulatorUse::kWrite) == |
+ AccumulatorUse::kWrite; |
+} |
+ |
+// static |
+bool Bytecodes::WritesBooleanToAccumulator(Bytecode bytecode) { |
+ switch (bytecode) { |
+ case Bytecode::kLdaTrue: |
+ case Bytecode::kLdaFalse: |
+ case Bytecode::kToBooleanLogicalNot: |
+ case Bytecode::kLogicalNot: |
+ case Bytecode::kTestEqual: |
+ case Bytecode::kTestNotEqual: |
+ case Bytecode::kTestEqualStrict: |
+ case Bytecode::kTestLessThan: |
+ case Bytecode::kTestLessThanOrEqual: |
+ case Bytecode::kTestGreaterThan: |
+ case Bytecode::kTestGreaterThanOrEqual: |
+ case Bytecode::kTestInstanceOf: |
+ case Bytecode::kTestIn: |
+ case Bytecode::kForInContinue: |
+ return true; |
+ default: |
+ return false; |
+ } |
+} |
+ |
+// static |
+bool Bytecodes::IsAccumulatorLoadWithoutEffects(Bytecode bytecode) { |
+ switch (bytecode) { |
+ case Bytecode::kLdaZero: |
+ case Bytecode::kLdaSmi: |
+ case Bytecode::kLdaUndefined: |
+ case Bytecode::kLdaNull: |
+ case Bytecode::kLdaTheHole: |
+ case Bytecode::kLdaTrue: |
+ case Bytecode::kLdaFalse: |
+ case Bytecode::kLdaConstant: |
+ case Bytecode::kLdar: |
+ return true; |
+ default: |
+ return false; |
+ } |
+} |
+ |
+// static |
+bool Bytecodes::IsJumpWithoutEffects(Bytecode bytecode) { |
+ return IsJump(bytecode) && !IsJumpIfToBoolean(bytecode); |
+} |
+ |
+// static |
+bool Bytecodes::IsRegisterLoadWithoutEffects(Bytecode bytecode) { |
+ switch (bytecode) { |
+ case Bytecode::kMov: |
+ case Bytecode::kPopContext: |
+ case Bytecode::kPushContext: |
+ case Bytecode::kStar: |
+ case Bytecode::kLdrUndefined: |
+ return true; |
+ default: |
+ return false; |
+ } |
+} |
+ |
+// static |
+bool Bytecodes::IsWithoutExternalSideEffects(Bytecode bytecode) { |
+ // These bytecodes only manipulate interpreter frame state and will |
+ // never throw. |
+ return (IsAccumulatorLoadWithoutEffects(bytecode) || |
+ IsRegisterLoadWithoutEffects(bytecode) || |
+ bytecode == Bytecode::kNop || IsJumpWithoutEffects(bytecode)); |
+} |
+ |
+// static |
+OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) { |
+ DCHECK_LE(bytecode, Bytecode::kLast); |
+ DCHECK_LT(i, NumberOfOperands(bytecode)); |
+ DCHECK_GE(i, 0); |
+ return GetOperandTypes(bytecode)[i]; |
+} |
+ |
+// static |
+const OperandType* Bytecodes::GetOperandTypes(Bytecode bytecode) { |
+ DCHECK_LE(bytecode, Bytecode::kLast); |
+ switch (bytecode) { |
+#define CASE(Name, ...) \ |
+ case Bytecode::k##Name: \ |
+ return BytecodeTraits<__VA_ARGS__>::GetOperandTypes(); |
+ BYTECODE_LIST(CASE) |
+#undef CASE |
+ } |
+ UNREACHABLE(); |
+ return nullptr; |
+} |
+ |
+// static |
+const OperandTypeInfo* Bytecodes::GetOperandTypeInfos(Bytecode bytecode) { |
+ DCHECK(bytecode <= Bytecode::kLast); |
+ switch (bytecode) { |
+#define CASE(Name, ...) \ |
+ case Bytecode::k##Name: \ |
+ return BytecodeTraits<__VA_ARGS__>::GetOperandTypeInfos(); |
+ BYTECODE_LIST(CASE) |
+#undef CASE |
+ } |
+ UNREACHABLE(); |
+ return nullptr; |
+} |
+ |
+// static |
+OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i, |
+ OperandScale operand_scale) { |
+ DCHECK_LT(i, NumberOfOperands(bytecode)); |
+ OperandType operand_type = GetOperandType(bytecode, i); |
+ return SizeOfOperand(operand_type, operand_scale); |
} |
// static |
@@ -123,6 +367,71 @@ |
} |
// static |
+OperandSize Bytecodes::SizeOfOperand(OperandType operand_type, |
+ OperandScale operand_scale) { |
+ DCHECK_LE(operand_type, OperandType::kLast); |
+ DCHECK_GE(operand_scale, OperandScale::kSingle); |
+ DCHECK_LE(operand_scale, OperandScale::kLast); |
+ return static_cast<OperandSize>( |
+ ScaledOperandSize(operand_type, operand_scale)); |
+} |
+ |
+// static |
+bool Bytecodes::IsConditionalJumpImmediate(Bytecode bytecode) { |
+ return bytecode == Bytecode::kJumpIfTrue || |
+ bytecode == Bytecode::kJumpIfFalse || |
+ bytecode == Bytecode::kJumpIfToBooleanTrue || |
+ bytecode == Bytecode::kJumpIfToBooleanFalse || |
+ bytecode == Bytecode::kJumpIfNotHole || |
+ bytecode == Bytecode::kJumpIfNull || |
+ bytecode == Bytecode::kJumpIfUndefined; |
+} |
+ |
+// static |
+bool Bytecodes::IsConditionalJumpConstant(Bytecode bytecode) { |
+ return bytecode == Bytecode::kJumpIfTrueConstant || |
+ bytecode == Bytecode::kJumpIfFalseConstant || |
+ bytecode == Bytecode::kJumpIfToBooleanTrueConstant || |
+ bytecode == Bytecode::kJumpIfToBooleanFalseConstant || |
+ bytecode == Bytecode::kJumpIfNotHoleConstant || |
+ bytecode == Bytecode::kJumpIfNullConstant || |
+ bytecode == Bytecode::kJumpIfUndefinedConstant; |
+} |
+ |
+// static |
+bool Bytecodes::IsConditionalJump(Bytecode bytecode) { |
+ return IsConditionalJumpImmediate(bytecode) || |
+ IsConditionalJumpConstant(bytecode); |
+} |
+ |
+ |
+// static |
+bool Bytecodes::IsJumpImmediate(Bytecode bytecode) { |
+ return bytecode == Bytecode::kJump || bytecode == Bytecode::kJumpLoop || |
+ IsConditionalJumpImmediate(bytecode); |
+} |
+ |
+ |
+// static |
+bool Bytecodes::IsJumpConstant(Bytecode bytecode) { |
+ return bytecode == Bytecode::kJumpConstant || |
+ IsConditionalJumpConstant(bytecode); |
+} |
+ |
+// static |
+bool Bytecodes::IsJump(Bytecode bytecode) { |
+ return IsJumpImmediate(bytecode) || IsJumpConstant(bytecode); |
+} |
+ |
+// static |
+bool Bytecodes::IsJumpIfToBoolean(Bytecode bytecode) { |
+ return bytecode == Bytecode::kJumpIfToBooleanTrue || |
+ bytecode == Bytecode::kJumpIfToBooleanFalse || |
+ bytecode == Bytecode::kJumpIfToBooleanTrueConstant || |
+ bytecode == Bytecode::kJumpIfToBooleanFalseConstant; |
+} |
+ |
+// static |
Bytecode Bytecodes::GetJumpWithoutToBoolean(Bytecode bytecode) { |
switch (bytecode) { |
case Bytecode::kJumpIfToBooleanTrue: |
@@ -141,6 +450,19 @@ |
} |
// static |
+bool Bytecodes::IsCallOrNew(Bytecode bytecode) { |
+ return bytecode == Bytecode::kCall || bytecode == Bytecode::kTailCall || |
+ bytecode == Bytecode::kNew; |
+} |
+ |
+// static |
+bool Bytecodes::IsCallRuntime(Bytecode bytecode) { |
+ return bytecode == Bytecode::kCallRuntime || |
+ bytecode == Bytecode::kCallRuntimeForPair || |
+ bytecode == Bytecode::kInvokeIntrinsic; |
+} |
+ |
+// static |
bool Bytecodes::IsDebugBreak(Bytecode bytecode) { |
switch (bytecode) { |
#define CASE(Name, ...) case Bytecode::k##Name: |
@@ -151,6 +473,53 @@ |
break; |
} |
return false; |
+} |
+ |
+// static |
+bool Bytecodes::IsLdarOrStar(Bytecode bytecode) { |
+ return bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar; |
+} |
+ |
+// static |
+bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) { |
+ switch (bytecode) { |
+#define CASE(Name, ...) \ |
+ case Bytecode::k##Name: \ |
+ typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \ |
+ return Name##Trait::IsScalable(); |
+ BYTECODE_LIST(CASE) |
+#undef CASE |
+ } |
+ UNREACHABLE(); |
+ return false; |
+} |
+ |
+// static |
+bool Bytecodes::IsPrefixScalingBytecode(Bytecode bytecode) { |
+ switch (bytecode) { |
+ case Bytecode::kExtraWide: |
+ case Bytecode::kDebugBreakExtraWide: |
+ case Bytecode::kWide: |
+ case Bytecode::kDebugBreakWide: |
+ return true; |
+ default: |
+ return false; |
+ } |
+} |
+ |
+// static |
+bool Bytecodes::PutsNameInAccumulator(Bytecode bytecode) { |
+ return bytecode == Bytecode::kTypeOf; |
+} |
+ |
+// static |
+bool Bytecodes::IsJumpOrReturn(Bytecode bytecode) { |
+ return bytecode == Bytecode::kReturn || IsJump(bytecode); |
+} |
+ |
+// static |
+bool Bytecodes::IsMaybeRegisterOperandType(OperandType operand_type) { |
+ return operand_type == OperandType::kMaybeReg; |
} |
// static |
@@ -234,11 +603,21 @@ |
} |
// static |
-bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) { |
- for (int i = 0; i < NumberOfOperands(bytecode); i++) { |
- if (OperandIsScalable(bytecode, i)) return true; |
- } |
- return false; |
+int Bytecodes::GetNumberOfRegistersRepresentedBy(OperandType operand_type) { |
+ switch (operand_type) { |
+ case OperandType::kMaybeReg: |
+ case OperandType::kReg: |
+ case OperandType::kRegOut: |
+ return 1; |
+ case OperandType::kRegPair: |
+ case OperandType::kRegOutPair: |
+ return 2; |
+ case OperandType::kRegOutTriple: |
+ return 3; |
+ default: |
+ return 0; |
+ } |
+ return 0; |
} |
// static |
@@ -255,28 +634,25 @@ |
} |
// static |
-OperandSize Bytecodes::SizeOfOperand(OperandType operand_type, |
- OperandScale operand_scale) { |
- DCHECK_LE(operand_type, OperandType::kLast); |
- DCHECK_GE(operand_scale, OperandScale::kSingle); |
- DCHECK_LE(operand_scale, OperandScale::kLast); |
- STATIC_ASSERT(static_cast<int>(OperandScale::kQuadruple) == 4 && |
- OperandScale::kLast == OperandScale::kQuadruple); |
- int scale_index = static_cast<int>(operand_scale) >> 1; |
- // clang-format off |
- static const OperandSize kOperandSizes[][3] = { |
-#define ENTRY(Name, ...) \ |
- { OperandScaler<OperandType::k##Name, \ |
- OperandScale::kSingle>::kOperandSize, \ |
- OperandScaler<OperandType::k##Name, \ |
- OperandScale::kDouble>::kOperandSize, \ |
- OperandScaler<OperandType::k##Name, \ |
- OperandScale::kQuadruple>::kOperandSize }, |
- OPERAND_TYPE_LIST(ENTRY) |
-#undef ENTRY |
- }; |
- // clang-format on |
- return kOperandSizes[static_cast<size_t>(operand_type)][scale_index]; |
+OperandSize Bytecodes::SizeForSignedOperand(int value) { |
+ if (value >= kMinInt8 && value <= kMaxInt8) { |
+ return OperandSize::kByte; |
+ } else if (value >= kMinInt16 && value <= kMaxInt16) { |
+ return OperandSize::kShort; |
+ } else { |
+ return OperandSize::kQuad; |
+ } |
+} |
+ |
+// static |
+OperandSize Bytecodes::SizeForUnsignedOperand(uint32_t value) { |
+ if (value <= kMaxUInt8) { |
+ return OperandSize::kByte; |
+ } else if (value <= kMaxUInt16) { |
+ return OperandSize::kShort; |
+ } else { |
+ return OperandSize::kQuad; |
+ } |
} |
// static |
@@ -290,6 +666,22 @@ |
return os << Bytecodes::ToString(bytecode); |
} |
+std::ostream& operator<<(std::ostream& os, const AccumulatorUse& use) { |
+ return os << Bytecodes::AccumulatorUseToString(use); |
+} |
+ |
+std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size) { |
+ return os << Bytecodes::OperandSizeToString(operand_size); |
+} |
+ |
+std::ostream& operator<<(std::ostream& os, const OperandScale& operand_scale) { |
+ return os << Bytecodes::OperandScaleToString(operand_scale); |
+} |
+ |
+std::ostream& operator<<(std::ostream& os, const OperandType& operand_type) { |
+ return os << Bytecodes::OperandTypeToString(operand_type); |
+} |
+ |
} // namespace interpreter |
} // namespace internal |
} // namespace v8 |