diff options
Diffstat (limited to 'deps/v8/src/interpreter/bytecodes.cc')
-rw-r--r-- | deps/v8/src/interpreter/bytecodes.cc | 469 |
1 files changed, 202 insertions, 267 deletions
diff --git a/deps/v8/src/interpreter/bytecodes.cc b/deps/v8/src/interpreter/bytecodes.cc index fd27f391aa..09bcd22b92 100644 --- a/deps/v8/src/interpreter/bytecodes.cc +++ b/deps/v8/src/interpreter/bytecodes.cc @@ -6,14 +6,15 @@ #include <iomanip> -#include "src/frames.h" +#include "src/base/bits.h" +#include "src/globals.h" #include "src/interpreter/bytecode-traits.h" -#include "src/interpreter/interpreter.h" namespace v8 { namespace internal { namespace interpreter { +STATIC_CONST_MEMBER_DEFINITION const int Bytecodes::kMaxOperands; // static const char* Bytecodes::ToString(Bytecode bytecode) { @@ -74,15 +75,13 @@ const char* Bytecodes::OperandTypeToString(OperandType operand_type) { // static const char* Bytecodes::OperandScaleToString(OperandScale operand_scale) { switch (operand_scale) { - case OperandScale::kSingle: - return "Single"; - case OperandScale::kDouble: - return "Double"; - case OperandScale::kQuadruple: - return "Quadruple"; - case OperandScale::kInvalid: - UNREACHABLE(); +#define CASE(Name, _) \ + case OperandScale::k##Name: \ + return #Name; + OPERAND_SCALE_LIST(CASE) +#undef CASE } + UNREACHABLE(); return ""; } @@ -102,14 +101,12 @@ const char* Bytecodes::OperandSizeToString(OperandSize operand_size) { return ""; } - // static uint8_t Bytecodes::ToByte(Bytecode bytecode) { - DCHECK(bytecode <= Bytecode::kLast); + DCHECK_LE(bytecode, Bytecode::kLast); return static_cast<uint8_t>(bytecode); } - // static Bytecode Bytecodes::FromByte(uint8_t value) { Bytecode bytecode = static_cast<Bytecode>(value); @@ -117,7 +114,6 @@ Bytecode Bytecodes::FromByte(uint8_t value) { return bytecode; } - // static Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) { DCHECK(!IsDebugBreak(bytecode)); @@ -150,6 +146,10 @@ int Bytecodes::Size(Bytecode bytecode, OperandScale operand_scale) { return size; } +// static +size_t Bytecodes::ReturnCount(Bytecode bytecode) { + return bytecode == Bytecode::kReturn ? 1 : 0; +} // static int Bytecodes::NumberOfOperands(Bytecode bytecode) { @@ -165,7 +165,6 @@ int Bytecodes::NumberOfOperands(Bytecode bytecode) { return 0; } - // static int Bytecodes::NumberOfRegisterOperands(Bytecode bytecode) { DCHECK(bytecode <= Bytecode::kLast); @@ -241,44 +240,122 @@ bool Bytecodes::WritesAccumulator(Bytecode bytecode) { } // 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::kForInDone: + 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(bytecode <= Bytecode::kLast); switch (bytecode) { #define CASE(Name, ...) \ case Bytecode::k##Name: \ - return BytecodeTraits<__VA_ARGS__>::GetOperandType(i); + return BytecodeTraits<__VA_ARGS__>::GetOperandTypes(); BYTECODE_LIST(CASE) #undef CASE } UNREACHABLE(); - return OperandType::kNone; -} - -// static -OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i, - OperandScale operand_scale) { - OperandType op_type = GetOperandType(bytecode, i); - return ScaledOperandSize(op_type, operand_scale); + return nullptr; } // static -int Bytecodes::GetRegisterOperandBitmap(Bytecode bytecode) { +const OperandTypeInfo* Bytecodes::GetOperandTypeInfos(Bytecode bytecode) { DCHECK(bytecode <= Bytecode::kLast); switch (bytecode) { -#define CASE(Name, ...) \ - case Bytecode::k##Name: \ - typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \ - return Name##Trait::kRegisterOperandBitmap; +#define CASE(Name, ...) \ + case Bytecode::k##Name: \ + return BytecodeTraits<__VA_ARGS__>::GetOperandTypeInfos(); BYTECODE_LIST(CASE) #undef CASE } UNREACHABLE(); - return false; + 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 int Bytecodes::GetOperandOffset(Bytecode bytecode, int i, OperandScale operand_scale) { + DCHECK_LT(i, Bytecodes::NumberOfOperands(bytecode)); // TODO(oth): restore this to a statically determined constant. int offset = 1; for (int operand_index = 0; operand_index < i; ++operand_index) { @@ -307,7 +384,6 @@ bool Bytecodes::IsConditionalJumpImmediate(Bytecode bytecode) { bytecode == Bytecode::kJumpIfUndefined; } - // static bool Bytecodes::IsConditionalJumpConstant(Bytecode bytecode) { return bytecode == Bytecode::kJumpIfTrueConstant || @@ -343,6 +419,31 @@ 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: + return Bytecode::kJumpIfTrue; + case Bytecode::kJumpIfToBooleanFalse: + return Bytecode::kJumpIfFalse; + case Bytecode::kJumpIfToBooleanTrueConstant: + return Bytecode::kJumpIfTrueConstant; + case Bytecode::kJumpIfToBooleanFalseConstant: + return Bytecode::kJumpIfFalseConstant; + default: + break; + } + UNREACHABLE(); + return Bytecode::kIllegal; +} // static bool Bytecodes::IsCallOrNew(Bytecode bytecode) { @@ -371,6 +472,11 @@ bool Bytecodes::IsDebugBreak(Bytecode bytecode) { } // static +bool Bytecodes::IsLdarOrStar(Bytecode bytecode) { + return bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar; +} + +// static bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) { switch (bytecode) { #define CASE(Name, ...) \ @@ -398,6 +504,11 @@ bool Bytecodes::IsPrefixScalingBytecode(Bytecode bytecode) { } // static +bool Bytecodes::PutsNameInAccumulator(Bytecode bytecode) { + return bytecode == Bytecode::kTypeOf; +} + +// static bool Bytecodes::IsJumpOrReturn(Bytecode bytecode) { return bytecode == Bytecode::kReturn || IsJump(bytecode); } @@ -461,160 +572,83 @@ bool Bytecodes::IsRegisterOutputOperandType(OperandType operand_type) { } // static -bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) { - switch (operand_type) { -#define CASE(Name, _) \ - case OperandType::k##Name: \ - return OperandTraits<OperandType::k##Name>::TypeInfo::kIsUnsigned; - OPERAND_TYPE_LIST(CASE) -#undef CASE +bool Bytecodes::IsStarLookahead(Bytecode bytecode, OperandScale operand_scale) { + if (operand_scale == OperandScale::kSingle) { + switch (bytecode) { + case Bytecode::kLdaZero: + case Bytecode::kLdaSmi: + case Bytecode::kLdaNull: + case Bytecode::kLdaTheHole: + case Bytecode::kLdaConstant: + case Bytecode::kAdd: + case Bytecode::kSub: + case Bytecode::kMul: + case Bytecode::kAddSmi: + case Bytecode::kSubSmi: + case Bytecode::kInc: + case Bytecode::kDec: + case Bytecode::kTypeOf: + case Bytecode::kCall: + case Bytecode::kNew: + return true; + default: + return false; + } } - UNREACHABLE(); return false; } // static -OperandScale Bytecodes::NextOperandScale(OperandScale operand_scale) { - DCHECK(operand_scale >= OperandScale::kSingle && - operand_scale <= OperandScale::kMaxValid); - return static_cast<OperandScale>(2 * static_cast<int>(operand_scale)); -} - -// static -Register Bytecodes::DecodeRegisterOperand(const uint8_t* operand_start, - OperandType operand_type, - OperandScale operand_scale) { - DCHECK(Bytecodes::IsRegisterOperandType(operand_type)); - int32_t operand = - DecodeSignedOperand(operand_start, operand_type, operand_scale); - return Register::FromOperand(operand); +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 -int32_t Bytecodes::DecodeSignedOperand(const uint8_t* operand_start, - OperandType operand_type, - OperandScale operand_scale) { - DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type)); - switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) { - case OperandSize::kByte: - return static_cast<int8_t>(*operand_start); - case OperandSize::kShort: - return static_cast<int16_t>(ReadUnalignedUInt16(operand_start)); - case OperandSize::kQuad: - return static_cast<int32_t>(ReadUnalignedUInt32(operand_start)); - case OperandSize::kNone: - UNREACHABLE(); +bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) { + switch (operand_type) { +#define CASE(Name, _) \ + case OperandType::k##Name: \ + return OperandTraits<OperandType::k##Name>::TypeInfoTraits::kIsUnsigned; + OPERAND_TYPE_LIST(CASE) +#undef CASE } - return 0; + UNREACHABLE(); + return false; } // static -uint32_t Bytecodes::DecodeUnsignedOperand(const uint8_t* operand_start, - OperandType operand_type, - OperandScale operand_scale) { - DCHECK(Bytecodes::IsUnsignedOperandType(operand_type)); - switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) { - case OperandSize::kByte: - return *operand_start; - case OperandSize::kShort: - return ReadUnalignedUInt16(operand_start); - case OperandSize::kQuad: - return ReadUnalignedUInt32(operand_start); - case OperandSize::kNone: - UNREACHABLE(); +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; } - return 0; } // static -std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start, - int parameter_count) { - Bytecode bytecode = Bytecodes::FromByte(bytecode_start[0]); - int prefix_offset = 0; - OperandScale operand_scale = OperandScale::kSingle; - if (IsPrefixScalingBytecode(bytecode)) { - prefix_offset = 1; - operand_scale = Bytecodes::PrefixBytecodeToOperandScale(bytecode); - bytecode = Bytecodes::FromByte(bytecode_start[1]); - } - - // Prepare to print bytecode and operands as hex digits. - std::ios saved_format(nullptr); - saved_format.copyfmt(saved_format); - os.fill('0'); - os.flags(std::ios::hex); - - int bytecode_size = Bytecodes::Size(bytecode, operand_scale); - for (int i = 0; i < prefix_offset + bytecode_size; i++) { - os << std::setw(2) << static_cast<uint32_t>(bytecode_start[i]) << ' '; - } - os.copyfmt(saved_format); - - const int kBytecodeColumnSize = 6; - for (int i = prefix_offset + bytecode_size; i < kBytecodeColumnSize; i++) { - os << " "; - } - - os << Bytecodes::ToString(bytecode, operand_scale) << " "; - - // Operands for the debug break are from the original instruction. - if (IsDebugBreak(bytecode)) return os; - - int number_of_operands = NumberOfOperands(bytecode); - int range = 0; - for (int i = 0; i < number_of_operands; i++) { - OperandType op_type = GetOperandType(bytecode, i); - const uint8_t* operand_start = - &bytecode_start[prefix_offset + - GetOperandOffset(bytecode, i, operand_scale)]; - switch (op_type) { - case interpreter::OperandType::kRegCount: - os << "#" - << DecodeUnsignedOperand(operand_start, op_type, operand_scale); - break; - case interpreter::OperandType::kIdx: - case interpreter::OperandType::kRuntimeId: - os << "[" - << DecodeUnsignedOperand(operand_start, op_type, operand_scale) - << "]"; - break; - case interpreter::OperandType::kImm: - os << "[" << DecodeSignedOperand(operand_start, op_type, operand_scale) - << "]"; - break; - case interpreter::OperandType::kFlag8: - os << "#" - << DecodeUnsignedOperand(operand_start, op_type, operand_scale); - break; - case interpreter::OperandType::kMaybeReg: - case interpreter::OperandType::kReg: - case interpreter::OperandType::kRegOut: { - Register reg = - DecodeRegisterOperand(operand_start, op_type, operand_scale); - os << reg.ToString(parameter_count); - break; - } - case interpreter::OperandType::kRegOutTriple: - range += 1; - case interpreter::OperandType::kRegOutPair: - case interpreter::OperandType::kRegPair: { - range += 1; - Register first_reg = - DecodeRegisterOperand(operand_start, op_type, operand_scale); - Register last_reg = Register(first_reg.index() + range); - os << first_reg.ToString(parameter_count) << "-" - << last_reg.ToString(parameter_count); - break; - } - case interpreter::OperandType::kNone: - UNREACHABLE(); - break; - } - if (i != number_of_operands - 1) { - os << ", "; - } +OperandSize Bytecodes::SizeForUnsignedOperand(uint32_t value) { + if (value <= kMaxUInt8) { + return OperandSize::kByte; + } else if (value <= kMaxUInt16) { + return OperandSize::kShort; + } else { + return OperandSize::kQuad; } - return os; } // static @@ -644,105 +678,6 @@ std::ostream& operator<<(std::ostream& os, const OperandType& operand_type) { return os << Bytecodes::OperandTypeToString(operand_type); } -static const int kLastParamRegisterIndex = - -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize; -static const int kFunctionClosureRegisterIndex = - -InterpreterFrameConstants::kFunctionFromRegisterPointer / kPointerSize; -static const int kCurrentContextRegisterIndex = - -InterpreterFrameConstants::kContextFromRegisterPointer / kPointerSize; -static const int kNewTargetRegisterIndex = - -InterpreterFrameConstants::kNewTargetFromRegisterPointer / kPointerSize; - -bool Register::is_byte_operand() const { - return index_ >= -kMaxInt8 && index_ <= -kMinInt8; -} - -bool Register::is_short_operand() const { - return index_ >= -kMaxInt16 && index_ <= -kMinInt16; -} - -Register Register::FromParameterIndex(int index, int parameter_count) { - DCHECK_GE(index, 0); - DCHECK_LT(index, parameter_count); - int register_index = kLastParamRegisterIndex - parameter_count + index + 1; - DCHECK_LT(register_index, 0); - return Register(register_index); -} - - -int Register::ToParameterIndex(int parameter_count) const { - DCHECK(is_parameter()); - return index() - kLastParamRegisterIndex + parameter_count - 1; -} - - -Register Register::function_closure() { - return Register(kFunctionClosureRegisterIndex); -} - - -bool Register::is_function_closure() const { - return index() == kFunctionClosureRegisterIndex; -} - - -Register Register::current_context() { - return Register(kCurrentContextRegisterIndex); -} - - -bool Register::is_current_context() const { - return index() == kCurrentContextRegisterIndex; -} - - -Register Register::new_target() { return Register(kNewTargetRegisterIndex); } - - -bool Register::is_new_target() const { - return index() == kNewTargetRegisterIndex; -} - -bool Register::AreContiguous(Register reg1, Register reg2, Register reg3, - Register reg4, Register reg5) { - if (reg1.index() + 1 != reg2.index()) { - return false; - } - if (reg3.is_valid() && reg2.index() + 1 != reg3.index()) { - return false; - } - if (reg4.is_valid() && reg3.index() + 1 != reg4.index()) { - return false; - } - if (reg5.is_valid() && reg4.index() + 1 != reg5.index()) { - return false; - } - return true; -} - -std::string Register::ToString(int parameter_count) { - if (is_current_context()) { - return std::string("<context>"); - } else if (is_function_closure()) { - return std::string("<closure>"); - } else if (is_new_target()) { - return std::string("<new.target>"); - } else if (is_parameter()) { - int parameter_index = ToParameterIndex(parameter_count); - if (parameter_index == 0) { - return std::string("<this>"); - } else { - std::ostringstream s; - s << "a" << parameter_index - 1; - return s.str(); - } - } else { - std::ostringstream s; - s << "r" << index(); - return s.str(); - } -} - } // namespace interpreter } // namespace internal } // namespace v8 |