Chromium Code Reviews| Index: src/interpreter/bytecodes.cc |
| diff --git a/src/interpreter/bytecodes.cc b/src/interpreter/bytecodes.cc |
| index 5f7a9085aec33bdba04bcd4764a8cfac73a6e667..ae5b349a241c7221ea5d1073ad52a005a7bce472 100644 |
| --- a/src/interpreter/bytecodes.cc |
| +++ b/src/interpreter/bytecodes.cc |
| @@ -29,7 +29,7 @@ const char* Bytecodes::ToString(Bytecode bytecode) { |
| // static |
| const char* Bytecodes::OperandTypeToString(OperandType operand_type) { |
| switch (operand_type) { |
| -#define CASE(Name, _) \ |
| +#define CASE(Name, _, __) \ |
| case OperandType::k##Name: \ |
| return #Name; |
| OPERAND_TYPE_LIST(CASE) |
| @@ -49,6 +49,8 @@ const char* Bytecodes::OperandSizeToString(OperandSize operand_size) { |
| return "Byte"; |
| case OperandSize::kShort: |
| return "Short"; |
| + case OperandSize::kQuad: |
| + return "Quad"; |
| } |
| UNREACHABLE(); |
| return ""; |
| @@ -71,32 +73,28 @@ Bytecode Bytecodes::FromByte(uint8_t value) { |
| // static |
| -Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) { |
| - switch (Size(bytecode)) { |
| -#define CASE(Name, ...) \ |
| - case BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::kSize: \ |
| - return Bytecode::k##Name; |
| - DEBUG_BREAK_BYTECODE_LIST(CASE) |
| -#undef CASE |
| - default: |
| - break; |
| +Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode, int operand_scale) { |
| + int bytecode_size = Size(bytecode, operand_scale); |
| +#define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name, ...) \ |
| + if (bytecode_size == Size(Bytecode::k##Name, operand_scale)) { \ |
| + return Bytecode::k##Name; \ |
| } |
| + DEBUG_BREAK_BYTECODE_LIST(RETURN_IF_DEBUG_BREAK_SIZE_MATCHES) |
| +#undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES |
| UNREACHABLE(); |
| return static_cast<Bytecode>(-1); |
| } |
| // static |
| -int Bytecodes::Size(Bytecode bytecode) { |
| - DCHECK(bytecode <= Bytecode::kLast); |
| - switch (bytecode) { |
| -#define CASE(Name, ...) \ |
| - case Bytecode::k##Name: \ |
| - return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::kSize; |
| - BYTECODE_LIST(CASE) |
| -#undef CASE |
| +int Bytecodes::Size(Bytecode bytecode, int 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; |
| } |
| - UNREACHABLE(); |
| - return 0; |
| + return size; |
| } |
| @@ -131,6 +129,18 @@ int Bytecodes::NumberOfRegisterOperands(Bytecode bytecode) { |
| } |
| // static |
| +int Bytecodes::GetPrefixBytecodeScale(Bytecode bytecode) { |
| + switch (bytecode) { |
|
rmcilroy
2016/03/10 16:45:37
Could we make this DCHECK if it is passed a non-pr
oth
2016/03/11 16:26:12
Not really, this is one of the main ways of determ
oth
2016/03/17 13:48:38
Done.
|
| + case Bytecode::kExtraWide: |
| + return 4; |
| + case Bytecode::kWide: |
| + return 2; |
| + default: |
| + return 1; |
| + } |
| +} |
| + |
| +// static |
| OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) { |
| DCHECK(bytecode <= Bytecode::kLast); |
| switch (bytecode) { |
| @@ -144,23 +154,47 @@ OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) { |
| return OperandType::kNone; |
| } |
| +// TODO(oth): TEMPORARY |
| +namespace { |
| -// static |
| -OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i) { |
| - DCHECK(bytecode <= Bytecode::kLast); |
| - switch (bytecode) { |
| -#define CASE(Name, ...) \ |
| - case Bytecode::k##Name: \ |
| - return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::GetOperandSize(i); |
| - BYTECODE_LIST(CASE) |
| +template <OperandTypeTrait O> |
| +struct OperandScaler { |
| + static int Multiply(int size, int scale) { return 0; } |
| +}; |
| + |
| +template <> |
| +struct OperandScaler<OperandTypeTrait::kFixed> { |
| + static int Multiply(int size, int scale) { return size; } |
| +}; |
| + |
| +template <> |
| +struct OperandScaler<OperandTypeTrait::kScalable> { |
| + static int Multiply(int size, int scale) { return size * scale; } |
| +}; |
| + |
| +} // namespace |
| + |
| +// TODO(oth): TEMPORARY |
| +static int ScaledOperandSize(OperandType operand_type, int scale) { |
| + switch (operand_type) { |
| +#define CASE(Name, Size, Trait) \ |
| + case OperandType::k##Name: \ |
| + return OperandScaler<Trait>::Multiply(static_cast<int>(Size), scale); |
| + OPERAND_TYPE_LIST(CASE) |
| #undef CASE |
| } |
| UNREACHABLE(); |
| - return OperandSize::kNone; |
| + return 0; |
| } |
| // static |
| +OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i, int scale) { |
| + OperandType op_type = GetOperandType(bytecode, i); |
| + return static_cast<OperandSize>(ScaledOperandSize(op_type, scale)); |
| +} |
| + |
| +// static |
| int Bytecodes::GetRegisterOperandBitmap(Bytecode bytecode) { |
| DCHECK(bytecode <= Bytecode::kLast); |
| switch (bytecode) { |
| @@ -176,31 +210,18 @@ int Bytecodes::GetRegisterOperandBitmap(Bytecode bytecode) { |
| } |
| // static |
| -int Bytecodes::GetOperandOffset(Bytecode bytecode, int i) { |
| - DCHECK(bytecode <= Bytecode::kLast); |
| - switch (bytecode) { |
| -#define CASE(Name, ...) \ |
| - case Bytecode::k##Name: \ |
| - return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::GetOperandOffset(i); |
| - BYTECODE_LIST(CASE) |
| -#undef CASE |
| +int Bytecodes::GetOperandOffset(Bytecode bytecode, int i, int scale) { |
| + int offset = 1; |
| + for (int operand_index = 0; operand_index < i; ++operand_index) { |
| + OperandSize operand_size = GetOperandSize(bytecode, operand_index, scale); |
| + offset += static_cast<int>(operand_size); |
| } |
| - UNREACHABLE(); |
| - return 0; |
| + return offset; |
| } |
| - |
| // static |
| -OperandSize Bytecodes::SizeOfOperand(OperandType operand_type) { |
| - switch (operand_type) { |
| -#define CASE(Name, Size) \ |
| - case OperandType::k##Name: \ |
| - return Size; |
| - OPERAND_TYPE_LIST(CASE) |
| -#undef CASE |
| - } |
| - UNREACHABLE(); |
| - return OperandSize::kNone; |
| +OperandSize Bytecodes::SizeOfOperand(OperandType operand_type, int scale) { |
| + return static_cast<OperandSize>(ScaledOperandSize(operand_type, scale)); |
| } |
| @@ -227,24 +248,10 @@ bool Bytecodes::IsConditionalJumpConstant(Bytecode bytecode) { |
| bytecode == Bytecode::kJumpIfUndefinedConstant; |
| } |
| - |
| -// static |
| -bool Bytecodes::IsConditionalJumpConstantWide(Bytecode bytecode) { |
| - return bytecode == Bytecode::kJumpIfTrueConstantWide || |
| - bytecode == Bytecode::kJumpIfFalseConstantWide || |
| - bytecode == Bytecode::kJumpIfToBooleanTrueConstantWide || |
| - bytecode == Bytecode::kJumpIfToBooleanFalseConstantWide || |
| - bytecode == Bytecode::kJumpIfNotHoleConstantWide || |
| - bytecode == Bytecode::kJumpIfNullConstantWide || |
| - bytecode == Bytecode::kJumpIfUndefinedConstantWide; |
| -} |
| - |
| - |
| // static |
| bool Bytecodes::IsConditionalJump(Bytecode bytecode) { |
| return IsConditionalJumpImmediate(bytecode) || |
| - IsConditionalJumpConstant(bytecode) || |
| - IsConditionalJumpConstantWide(bytecode); |
| + IsConditionalJumpConstant(bytecode); |
| } |
| @@ -260,34 +267,22 @@ bool Bytecodes::IsJumpConstant(Bytecode bytecode) { |
| IsConditionalJumpConstant(bytecode); |
| } |
| - |
| -// static |
| -bool Bytecodes::IsJumpConstantWide(Bytecode bytecode) { |
| - return bytecode == Bytecode::kJumpConstantWide || |
| - IsConditionalJumpConstantWide(bytecode); |
| -} |
| - |
| - |
| // static |
| bool Bytecodes::IsJump(Bytecode bytecode) { |
| - return IsJumpImmediate(bytecode) || IsJumpConstant(bytecode) || |
| - IsJumpConstantWide(bytecode); |
| + return IsJumpImmediate(bytecode) || IsJumpConstant(bytecode); |
| } |
| // static |
| bool Bytecodes::IsCallOrNew(Bytecode bytecode) { |
| return bytecode == Bytecode::kCall || bytecode == Bytecode::kTailCall || |
| - bytecode == Bytecode::kNew || bytecode == Bytecode::kCallWide || |
| - bytecode == Bytecode::kTailCallWide || bytecode == Bytecode::kNewWide; |
| + bytecode == Bytecode::kNew; |
| } |
| // static |
| bool Bytecodes::IsCallRuntime(Bytecode bytecode) { |
| return bytecode == Bytecode::kCallRuntime || |
| - bytecode == Bytecode::kCallRuntimeWide || |
| - bytecode == Bytecode::kCallRuntimeForPair || |
| - bytecode == Bytecode::kCallRuntimeForPairWide; |
| + bytecode == Bytecode::kCallRuntimeForPair; |
| } |
| // static |
| @@ -304,42 +299,63 @@ bool Bytecodes::IsDebugBreak(Bytecode bytecode) { |
| } |
| // static |
| +bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) { |
| + switch (bytecode) { |
| +#define CASE(Name, ...) \ |
| + case Bytecode::k##Name: \ |
| + typedef BytecodeTraits<__VA_ARGS__, OPERAND_TERM> Name##Trait; \ |
| + return Name##Trait::IsScalable(); |
| + BYTECODE_LIST(CASE) |
| +#undef CASE |
| + } |
| + UNREACHABLE(); |
| + return false; |
| +} |
| + |
| +// static |
| bool Bytecodes::IsJumpOrReturn(Bytecode bytecode) { |
| return bytecode == Bytecode::kReturn || IsJump(bytecode); |
| } |
| // static |
| +bool Bytecodes::IsFlagOperandType(OperandType operand_type) { |
| + return operand_type == OperandType::kFlag8; |
| +} |
| + |
| +// static |
| bool Bytecodes::IsIndexOperandType(OperandType operand_type) { |
| - return operand_type == OperandType::kIdx8 || |
| - operand_type == OperandType::kIdx16; |
| + return operand_type == OperandType::kIdx; |
| } |
| // static |
| bool Bytecodes::IsImmediateOperandType(OperandType operand_type) { |
| - return operand_type == OperandType::kImm8; |
| + return operand_type == OperandType::kImm; |
| } |
| // static |
| bool Bytecodes::IsRegisterCountOperandType(OperandType operand_type) { |
| - return (operand_type == OperandType::kRegCount8 || |
| - operand_type == OperandType::kRegCount16); |
| + return operand_type == OperandType::kRegCount; |
| } |
| // static |
| bool Bytecodes::IsMaybeRegisterOperandType(OperandType operand_type) { |
| - return (operand_type == OperandType::kMaybeReg8 || |
| - operand_type == OperandType::kMaybeReg16); |
| + return operand_type == OperandType::kMaybeReg; |
| +} |
| + |
| +// static |
| +bool Bytecodes::IsRuntimeIdOperandType(OperandType operand_type) { |
|
rmcilroy
2016/03/10 16:45:37
Wondering whether these IsXXXOperandType are neces
oth
2016/03/11 16:26:12
Done. Removed all except the still useful IsRegist
|
| + return operand_type == OperandType::kRuntimeId; |
| } |
| // static |
| bool Bytecodes::IsRegisterOperandType(OperandType operand_type) { |
| switch (operand_type) { |
| -#define CASE(Name, _) \ |
| +#define CASE(Name, _, __) \ |
| case OperandType::k##Name: \ |
| return true; |
| REGISTER_OPERAND_TYPE_LIST(CASE) |
| #undef CASE |
| -#define CASE(Name, _) \ |
| +#define CASE(Name, _, __) \ |
| case OperandType::k##Name: \ |
| break; |
| NON_REGISTER_OPERAND_TYPE_LIST(CASE) |
| @@ -351,12 +367,12 @@ bool Bytecodes::IsRegisterOperandType(OperandType operand_type) { |
| // static |
| bool Bytecodes::IsRegisterInputOperandType(OperandType operand_type) { |
| switch (operand_type) { |
| -#define CASE(Name, _) \ |
| +#define CASE(Name, _, __) \ |
| case OperandType::k##Name: \ |
| return true; |
| REGISTER_INPUT_OPERAND_TYPE_LIST(CASE) |
| #undef CASE |
| -#define CASE(Name, _) \ |
| +#define CASE(Name, _, __) \ |
| case OperandType::k##Name: \ |
| break; |
| NON_REGISTER_OPERAND_TYPE_LIST(CASE) |
| @@ -369,12 +385,12 @@ bool Bytecodes::IsRegisterInputOperandType(OperandType operand_type) { |
| // static |
| bool Bytecodes::IsRegisterOutputOperandType(OperandType operand_type) { |
| switch (operand_type) { |
| -#define CASE(Name, _) \ |
| +#define CASE(Name, _, __) \ |
| case OperandType::k##Name: \ |
| return true; |
| REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE) |
| #undef CASE |
| -#define CASE(Name, _) \ |
| +#define CASE(Name, _, __) \ |
| case OperandType::k##Name: \ |
| break; |
| NON_REGISTER_OPERAND_TYPE_LIST(CASE) |
| @@ -386,18 +402,52 @@ bool Bytecodes::IsRegisterOutputOperandType(OperandType operand_type) { |
| namespace { |
| static Register DecodeRegister(const uint8_t* operand_start, |
| - OperandType operand_type) { |
| - switch (Bytecodes::SizeOfOperand(operand_type)) { |
| + OperandType operand_type, int operand_scale) { |
| + switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) { |
| case OperandSize::kByte: |
| return Register::FromOperand(*operand_start); |
| case OperandSize::kShort: |
| return Register::FromWideOperand(ReadUnalignedUInt16(operand_start)); |
| + case OperandSize::kQuad: |
| + return Register::FromWideOperand(ReadUnalignedUInt32(operand_start)); |
| case OperandSize::kNone: { |
| UNREACHABLE(); |
| } |
| } |
| return Register(); |
| } |
| + |
| +static uint32_t DecodeUnsignedOperand(const uint8_t* operand_start, |
| + OperandType operand_type, |
| + int operand_scale) { |
| + 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(); |
| + } |
| + return 0; |
| +} |
| + |
| +static int32_t DecodeSignedOperand(const uint8_t* operand_start, |
| + OperandType operand_type, |
| + int operand_scale) { |
| + 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(); |
| + } |
| + return 0; |
| +} |
| } // namespace |
| @@ -407,18 +457,31 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start, |
| Vector<char> buf = Vector<char>::New(50); |
| Bytecode bytecode = Bytecodes::FromByte(bytecode_start[0]); |
| - int bytecode_size = Bytecodes::Size(bytecode); |
| + int prefix_offset = 0; |
| + int operand_scale = Bytecodes::GetPrefixBytecodeScale(bytecode); |
| + if (operand_scale > 1) { |
| + prefix_offset += 1; |
| + bytecode = Bytecodes::FromByte(bytecode_start[1]); |
| + } |
| - for (int i = 0; i < bytecode_size; i++) { |
| + int bytecode_size = Bytecodes::Size(bytecode, operand_scale); |
| + |
| + for (int i = 0; i < prefix_offset + bytecode_size; i++) { |
| SNPrintF(buf, "%02x ", bytecode_start[i]); |
| os << buf.start(); |
| } |
| const int kBytecodeColumnSize = 6; |
| - for (int i = bytecode_size; i < kBytecodeColumnSize; i++) { |
| + for (int i = prefix_offset + bytecode_size; i < kBytecodeColumnSize; i++) { |
| os << " "; |
| } |
| - os << bytecode << " "; |
| + os << bytecode; |
| + if (operand_scale == 2) { |
| + os << "." << Bytecodes::ToString(Bytecode::kWide); |
| + } else if (operand_scale == 4) { |
| + os << "." << Bytecodes::ToString(Bytecode::kExtraWide); |
| + } |
| + os << " "; |
| // Operands for the debug break are from the original instruction. |
| if (IsDebugBreak(bytecode)) return os; |
| @@ -428,42 +491,41 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start, |
| for (int i = 0; i < number_of_operands; i++) { |
| OperandType op_type = GetOperandType(bytecode, i); |
| const uint8_t* operand_start = |
| - &bytecode_start[GetOperandOffset(bytecode, i)]; |
| + &bytecode_start[prefix_offset + |
| + GetOperandOffset(bytecode, i, operand_scale)]; |
| switch (op_type) { |
| - case interpreter::OperandType::kRegCount8: |
| - os << "#" << static_cast<unsigned int>(*operand_start); |
| - break; |
| - case interpreter::OperandType::kRegCount16: |
| - os << '#' << ReadUnalignedUInt16(operand_start); |
| + case interpreter::OperandType::kRegCount: |
| + os << "#" |
| + << DecodeUnsignedOperand(operand_start, op_type, operand_scale); |
| break; |
| - case interpreter::OperandType::kIdx8: |
| - os << "[" << static_cast<unsigned int>(*operand_start) << "]"; |
| + case interpreter::OperandType::kIdx: |
| + case interpreter::OperandType::kRuntimeId: |
| + os << "[" |
| + << DecodeUnsignedOperand(operand_start, op_type, operand_scale) |
| + << "]"; |
| break; |
| - case interpreter::OperandType::kIdx16: |
| - os << "[" << ReadUnalignedUInt16(operand_start) << "]"; |
| + case interpreter::OperandType::kImm: |
| + os << "[" << DecodeSignedOperand(operand_start, op_type, operand_scale) |
| + << "]"; |
| break; |
| - case interpreter::OperandType::kImm8: |
| - os << "#" << static_cast<int>(static_cast<int8_t>(*operand_start)); |
| + case interpreter::OperandType::kFlag8: |
| + os << "#" |
| + << DecodeUnsignedOperand(operand_start, op_type, operand_scale); |
| break; |
| - case interpreter::OperandType::kMaybeReg8: |
| - case interpreter::OperandType::kMaybeReg16: |
| - case interpreter::OperandType::kReg8: |
| - case interpreter::OperandType::kReg16: |
| - case interpreter::OperandType::kRegOut8: |
| - case interpreter::OperandType::kRegOut16: { |
| - Register reg = DecodeRegister(operand_start, op_type); |
| + case interpreter::OperandType::kMaybeReg: |
| + case interpreter::OperandType::kReg: |
| + case interpreter::OperandType::kRegOut: { |
| + Register reg = DecodeRegister(operand_start, op_type, operand_scale); |
| os << reg.ToString(parameter_count); |
| break; |
| } |
| - case interpreter::OperandType::kRegOutTriple8: |
| - case interpreter::OperandType::kRegOutTriple16: |
| + case interpreter::OperandType::kRegOutTriple: |
| range += 1; |
| - case interpreter::OperandType::kRegOutPair8: |
| - case interpreter::OperandType::kRegOutPair16: |
| - case interpreter::OperandType::kRegPair8: |
| - case interpreter::OperandType::kRegPair16: { |
| + case interpreter::OperandType::kRegOutPair: |
| + case interpreter::OperandType::kRegPair: { |
| range += 1; |
| - Register first_reg = DecodeRegister(operand_start, op_type); |
| + Register first_reg = |
| + DecodeRegister(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); |