int32_t Instruction::GetTargetOffset() const { switch (FormatOf(Opcode())) { // Cases for conditional branches follow. case k22t: return VRegC_22t(); case k21t: return VRegB_21t(); // Cases for unconditional branches follow. case k10t: return VRegA_10t(); case k20t: return VRegA_20t(); case k30t: return VRegA_30t(); default:
LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name()
<< " which does not have a target operand.";
UNREACHABLE();
}
}
size_t Instruction::SizeInCodeUnitsComplexOpcode() const { // Handle special NOP encoded variable length sequences.
uint16_t inst_data = Fetch16(0);
DCHECK_EQ(inst_data & 0xFF, 0) << DumpString(nullptr); switch (inst_data) { case kPackedSwitchSignature: return (4 + Fetch16(1) * 2); case kSparseSwitchSignature: return (2 + Fetch16(1) * 4); case kArrayDataSignature: {
uint16_t element_size = Fetch16(1);
uint32_t length = Fetch16(2) | ((static_cast<uint32_t>(Fetch16(3))) << 16); // The plus 1 is to round up for odd size and width.
uint32_t result = (4 + (element_size * length + 1) / 2); // This function is used only after the `MethodVerifier` checked that the 32-bit calculation // does not overflow. Let's `DCHECK()` the result against a 64-bit calculation.
DCHECK_EQ(result, 4 + (static_cast<uint64_t>(element_size) * static_cast<uint64_t>(length) + 1) / 2); return result;
} default: return1; // NOP.
}
}
std::string Instruction::DumpHex(size_t code_units) const {
size_t inst_length = SizeInCodeUnits(); if (inst_length > code_units) {
inst_length = code_units;
}
std::ostringstream os; const uint16_t* insn = reinterpret_cast<const uint16_t*>(this); for (size_t i = 0; i < inst_length; i++) {
os << StringPrintf("0x%04x", insn[i]) << " ";
} for (size_t i = inst_length; i < code_units; i++) {
os << " ";
} return os.str();
}
std::string Instruction::DumpHexLE(size_t instr_code_units) const {
size_t inst_length = SizeInCodeUnits(); if (inst_length > instr_code_units) {
inst_length = instr_code_units;
}
std::ostringstream os; const uint16_t* insn = reinterpret_cast<const uint16_t*>(this); for (size_t i = 0; i < inst_length; i++) {
os << StringPrintf("%02x%02x", static_cast<uint8_t>(insn[i] & 0x00FF), static_cast<uint8_t>((insn[i] & 0xFF00) >> 8)) << " ";
} for (size_t i = inst_length; i < instr_code_units; i++) {
os << " ";
} return os.str();
}
std::string Instruction::DumpString(const DexFile* file) const {
std::ostringstream os; constchar* opcode = kInstructionNames[Opcode()]; switch (FormatOf(Opcode())) { case k10x: os << opcode; break; case k12x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break; case k11n: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break; case k11x: os << StringPrintf("%s v%d", opcode, VRegA_11x()); break; case k10t: os << StringPrintf("%s %+d", opcode, VRegA_10t()); break; case k20t: os << StringPrintf("%s %+d", opcode, VRegA_20t()); break; case k22x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break; case k21t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break; case k21s: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break; case k21h: { // op vAA, #+BBBB0000[00000000] if (Opcode() == CONST_HIGH16) {
uint32_t value = VRegB_21h() << 16;
os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value);
} else {
uint64_t value = static_cast<uint64_t>(VRegB_21h()) << 48;
os << StringPrintf("%s v%d, #long %+" PRId64 " // 0x%" PRIx64, opcode, VRegA_21h(),
value, value);
}
} break; case k21c: { switch (Opcode()) { case CONST_STRING: if (file != nullptr) {
uint32_t string_idx = VRegB_21c(); if (string_idx < file->NumStringIds()) {
os << StringPrintf( "const-string v%d, %s // string@%d",
VRegA_21c(),
PrintableString(file->GetStringData(dex::StringIndex(string_idx))).c_str(),
string_idx);
} else {
os << StringPrintf("const-string v%d, <<invalid-string-idx-%d>> // string@%d",
VRegA_21c(),
string_idx,
string_idx);
} break;
}
FALLTHROUGH_INTENDED; case CHECK_CAST: case CONST_CLASS: case NEW_INSTANCE: if (file != nullptr) {
dex::TypeIndex type_idx(VRegB_21c());
os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", "
<< file->PrettyType(type_idx) << " // type@" << type_idx.index_; break;
}
FALLTHROUGH_INTENDED; case SGET: case SGET_WIDE: case SGET_OBJECT: case SGET_BOOLEAN: case SGET_BYTE: case SGET_CHAR: case SGET_SHORT: if (file != nullptr) {
uint32_t field_idx = VRegB_21c();
os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", "
<< file->PrettyField(field_idx, true) << " // field@" << field_idx; break;
}
FALLTHROUGH_INTENDED; case SPUT: case SPUT_WIDE: case SPUT_OBJECT: case SPUT_BOOLEAN: case SPUT_BYTE: case SPUT_CHAR: case SPUT_SHORT: if (file != nullptr) {
uint32_t field_idx = VRegB_21c();
os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", "
<< file->PrettyField(field_idx, true) << " // field@" << field_idx; break;
}
FALLTHROUGH_INTENDED; default:
os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c()); break;
} break;
} case k23x: os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break; case k22b: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break; case k22t: os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break; case k22s: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break; case k22c: { switch (Opcode()) { case IGET: case IGET_WIDE: case IGET_OBJECT: case IGET_BOOLEAN: case IGET_BYTE: case IGET_CHAR: case IGET_SHORT: if (file != nullptr) {
uint32_t field_idx = VRegC_22c();
os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
<< file->PrettyField(field_idx, true) << " // field@" << field_idx; break;
}
FALLTHROUGH_INTENDED; case IPUT: case IPUT_WIDE: case IPUT_OBJECT: case IPUT_BOOLEAN: case IPUT_BYTE: case IPUT_CHAR: case IPUT_SHORT: if (file != nullptr) {
uint32_t field_idx = VRegC_22c();
os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
<< file->PrettyField(field_idx, true) << " // field@" << field_idx; break;
}
FALLTHROUGH_INTENDED; case INSTANCE_OF: if (file != nullptr) {
dex::TypeIndex type_idx(VRegC_22c());
os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
<< static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
<< " // type@" << type_idx.index_; break;
}
FALLTHROUGH_INTENDED; case NEW_ARRAY: if (file != nullptr) {
dex::TypeIndex type_idx(VRegC_22c());
os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
<< static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
<< " // type@" << type_idx.index_; break;
}
FALLTHROUGH_INTENDED; default:
os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c()); break;
} break;
} case k32x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break; case k30t: os << StringPrintf("%s %+d", opcode, VRegA_30t()); break; case k31t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break; case k31i: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break; case k31c: if (Opcode() == CONST_STRING_JUMBO) {
uint32_t string_idx = VRegB_31c(); if (file != nullptr) { if (string_idx < file->NumStringIds()) {
os << StringPrintf( "%s v%d, %s // string@%d",
opcode,
VRegA_31c(),
PrintableString(file->GetStringData(dex::StringIndex(string_idx))).c_str(),
string_idx);
} else {
os << StringPrintf("%s v%d, <<invalid-string-idx-%d>> // string@%d",
opcode,
VRegA_31c(),
string_idx,
string_idx);
}
} else {
os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx);
}
} else {
os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break;
} break; case k35c: {
uint32_t arg[kMaxVarArgRegs];
GetVarArgs(arg);
os << opcode << " {"; for (size_t i = 0, count = VRegA_35c(); i < count; ++i) { if (i != 0) {
os << ", ";
}
os << "v" << arg[i];
}
os << "}, "; switch (Opcode()) { case FILLED_NEW_ARRAY: if (file != nullptr) {
os << file->PrettyType(dex::TypeIndex(VRegB_35c())) << " // ";
}
os << "type@" << VRegB_35c(); break; case INVOKE_VIRTUAL: case INVOKE_SUPER: case INVOKE_DIRECT: case INVOKE_STATIC: case INVOKE_INTERFACE: if (file != nullptr) {
uint32_t method_idx = VRegB_35c();
os << file->PrettyMethod(method_idx) << " // method@" << method_idx; break;
}
FALLTHROUGH_INTENDED; case INVOKE_CUSTOM: if (file != nullptr) {
uint32_t call_site_idx = VRegB_35c();
os << "call_site@" << call_site_idx; break;
}
FALLTHROUGH_INTENDED; default:
os << "thing@" << VRegB_35c(); break;
} break;
} case k3rc: {
uint16_t first_reg = VRegC_3rc();
uint16_t last_reg = VRegC_3rc() + VRegA_3rc() - 1;
os << opcode << ", {v" << first_reg << " .. v" << last_reg << "}, "; switch (Opcode()) { case FILLED_NEW_ARRAY_RANGE: if (file != nullptr) {
os << file->PrettyType(dex::TypeIndex(VRegB_3rc())) << " // ";
}
os << "type@" << VRegB_3rc(); break; case INVOKE_VIRTUAL_RANGE: case INVOKE_SUPER_RANGE: case INVOKE_DIRECT_RANGE: case INVOKE_STATIC_RANGE: case INVOKE_INTERFACE_RANGE: if (file != nullptr) {
uint32_t method_idx = VRegB_3rc();
os << file->PrettyMethod(method_idx) << " // method@" << method_idx; break;
}
FALLTHROUGH_INTENDED; case INVOKE_CUSTOM_RANGE: if (file != nullptr) {
uint32_t call_site_idx = VRegB_3rc();
os << "call_site@" << call_site_idx; break;
}
FALLTHROUGH_INTENDED; default:
os << "thing@" << VRegB_3rc(); break;
} break;
} case k45cc: {
uint32_t arg[kMaxVarArgRegs];
GetVarArgs(arg);
uint16_t method_idx = VRegB_45cc();
dex::ProtoIndex proto_idx(VRegH_45cc());
os << opcode << " {"; for (uint32_t i = 0; i < VRegA_45cc(); ++i) { if (i != 0) {
os << ", ";
}
os << "v" << arg[i];
}
os << "}"; if (file != nullptr) {
os << ", " << file->PrettyMethod(method_idx)
<< ", " << file->GetShorty(proto_idx)
<< " // ";
} else {
os << ", ";
}
os << "method@" << method_idx << ", proto@" << proto_idx; break;
} case k4rcc: switch (Opcode()) { case INVOKE_POLYMORPHIC_RANGE: { if (file != nullptr) {
uint16_t method_idx = VRegB_4rcc();
dex::ProtoIndex proto_idx(VRegH_4rcc());
os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
<< "}, " << file->PrettyMethod(method_idx)
<< ", " << file->GetShorty(dex::ProtoIndex(proto_idx))
<< " // method@" << method_idx << ", proto@" << proto_idx; break;
}
}
FALLTHROUGH_INTENDED; default: {
uint16_t method_idx = VRegB_4rcc();
dex::ProtoIndex proto_idx(VRegH_4rcc());
os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
<< "}, method@" << method_idx << ", proto@" << proto_idx;
}
} break; case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break; case kInvalidFormat: os << "<invalid-opcode-format>";
} return os.str();
}
// Add some checks that ensure the flags make sense. We need a subclass to be in the context of // Instruction. Otherwise the flags from the instruction list don't work. struct InstructionStaticAsserts : private Instruction { #define IMPLIES(a, b) (!(a) || (b))
uint32_t NoReceiverInstructionOperands::GetOperand(size_t operand_index) const {
DCHECK_LT(GetNumberOfOperands(), inner_->GetNumberOfOperands()); // The receiver is the first operand and since we're skipping it, we need to // add 1 to the operand_index. return inner_->GetOperand(operand_index + 1);
}
} // namespace art
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.