// Copyright 2015 the V8 project authors. All rights reserved.
|
// Use of this source code is governed by a BSD-style license that can be
|
// found in the LICENSE file.
|
|
#include "src/interpreter/bytecode-decoder.h"
|
|
#include <iomanip>
|
|
#include "src/contexts.h"
|
#include "src/interpreter/interpreter-intrinsics.h"
|
#include "src/objects-inl.h"
|
|
namespace v8 {
|
namespace internal {
|
namespace interpreter {
|
|
// static
|
Register BytecodeDecoder::DecodeRegisterOperand(Address 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);
|
}
|
|
// static
|
RegisterList BytecodeDecoder::DecodeRegisterListOperand(
|
Address operand_start, uint32_t count, OperandType operand_type,
|
OperandScale operand_scale) {
|
Register first_reg =
|
DecodeRegisterOperand(operand_start, operand_type, operand_scale);
|
return RegisterList(first_reg.index(), static_cast<int>(count));
|
}
|
|
// static
|
int32_t BytecodeDecoder::DecodeSignedOperand(Address operand_start,
|
OperandType operand_type,
|
OperandScale operand_scale) {
|
DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type));
|
switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) {
|
case OperandSize::kByte:
|
return *reinterpret_cast<const 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;
|
}
|
|
// static
|
uint32_t BytecodeDecoder::DecodeUnsignedOperand(Address operand_start,
|
OperandType operand_type,
|
OperandScale operand_scale) {
|
DCHECK(Bytecodes::IsUnsignedOperandType(operand_type));
|
switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) {
|
case OperandSize::kByte:
|
return *reinterpret_cast<const uint8_t*>(operand_start);
|
case OperandSize::kShort:
|
return ReadUnalignedUInt16(operand_start);
|
case OperandSize::kQuad:
|
return ReadUnalignedUInt32(operand_start);
|
case OperandSize::kNone:
|
UNREACHABLE();
|
}
|
return 0;
|
}
|
|
namespace {
|
|
const char* NameForRuntimeId(uint32_t idx) {
|
switch (idx) {
|
#define CASE(name, nargs, ressize) \
|
case Runtime::k##name: \
|
return #name; \
|
case Runtime::kInline##name: \
|
return "_" #name;
|
FOR_EACH_INTRINSIC(CASE)
|
#undef CASE
|
default:
|
UNREACHABLE();
|
}
|
}
|
|
const char* NameForNativeContextIndex(uint32_t idx) {
|
switch (idx) {
|
#define CASE(index_name, type, name) \
|
case Context::index_name: \
|
return #name;
|
NATIVE_CONTEXT_FIELDS(CASE)
|
#undef CASE
|
default:
|
UNREACHABLE();
|
}
|
}
|
|
} // anonymous namespace
|
|
// static
|
std::ostream& BytecodeDecoder::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 (Bytecodes::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 (Bytecodes::IsDebugBreak(bytecode)) return os;
|
|
int number_of_operands = Bytecodes::NumberOfOperands(bytecode);
|
for (int i = 0; i < number_of_operands; i++) {
|
OperandType op_type = Bytecodes::GetOperandType(bytecode, i);
|
int operand_offset =
|
Bytecodes::GetOperandOffset(bytecode, i, operand_scale);
|
Address operand_start = reinterpret_cast<Address>(
|
&bytecode_start[prefix_offset + operand_offset]);
|
switch (op_type) {
|
case interpreter::OperandType::kIdx:
|
case interpreter::OperandType::kUImm:
|
os << "["
|
<< DecodeUnsignedOperand(operand_start, op_type, operand_scale)
|
<< "]";
|
break;
|
case interpreter::OperandType::kIntrinsicId: {
|
auto id = static_cast<IntrinsicsHelper::IntrinsicId>(
|
DecodeUnsignedOperand(operand_start, op_type, operand_scale));
|
os << "[" << NameForRuntimeId(IntrinsicsHelper::ToRuntimeId(id)) << "]";
|
break;
|
}
|
case interpreter::OperandType::kNativeContextIndex: {
|
auto id = DecodeUnsignedOperand(operand_start, op_type, operand_scale);
|
os << "[" << NameForNativeContextIndex(id) << "]";
|
break;
|
}
|
case interpreter::OperandType::kRuntimeId:
|
os << "[" << NameForRuntimeId(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::kReg:
|
case interpreter::OperandType::kRegOut: {
|
Register reg =
|
DecodeRegisterOperand(operand_start, op_type, operand_scale);
|
os << reg.ToString(parameter_count);
|
break;
|
}
|
case interpreter::OperandType::kRegOutTriple: {
|
RegisterList reg_list =
|
DecodeRegisterListOperand(operand_start, 3, op_type, operand_scale);
|
os << reg_list.first_register().ToString(parameter_count) << "-"
|
<< reg_list.last_register().ToString(parameter_count);
|
break;
|
}
|
case interpreter::OperandType::kRegOutPair:
|
case interpreter::OperandType::kRegPair: {
|
RegisterList reg_list =
|
DecodeRegisterListOperand(operand_start, 2, op_type, operand_scale);
|
os << reg_list.first_register().ToString(parameter_count) << "-"
|
<< reg_list.last_register().ToString(parameter_count);
|
break;
|
}
|
case interpreter::OperandType::kRegOutList:
|
case interpreter::OperandType::kRegList: {
|
DCHECK_LT(i, number_of_operands - 1);
|
DCHECK_EQ(Bytecodes::GetOperandType(bytecode, i + 1),
|
OperandType::kRegCount);
|
int reg_count_offset =
|
Bytecodes::GetOperandOffset(bytecode, i + 1, operand_scale);
|
Address reg_count_operand = reinterpret_cast<Address>(
|
&bytecode_start[prefix_offset + reg_count_offset]);
|
uint32_t count = DecodeUnsignedOperand(
|
reg_count_operand, OperandType::kRegCount, operand_scale);
|
RegisterList reg_list = DecodeRegisterListOperand(
|
operand_start, count, op_type, operand_scale);
|
os << reg_list.first_register().ToString(parameter_count) << "-"
|
<< reg_list.last_register().ToString(parameter_count);
|
i++; // Skip kRegCount.
|
break;
|
}
|
case interpreter::OperandType::kNone:
|
case interpreter::OperandType::kRegCount: // Dealt with in kRegList.
|
UNREACHABLE();
|
break;
|
}
|
if (i != number_of_operands - 1) {
|
os << ", ";
|
}
|
}
|
return os;
|
}
|
|
} // namespace interpreter
|
} // namespace internal
|
} // namespace v8
|