enum Code { // private marker to avoid generate-operator-out.py from processing. #define INSTRUCTION_ENUM(opcode, cname, p, f, i, a, e, v) cname = (opcode),
DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM) #undef INSTRUCTION_ENUM
RSUB_INT_LIT16 = RSUB_INT,
};
enum Format : uint8_t {
k10x, // op
k12x, // op vA, vB
k11n, // op vA, #+B
k11x, // op vAA
k10t, // op +AA
k20t, // op +AAAA
k22x, // op vAA, vBBBB
k21t, // op vAA, +BBBB
k21s, // op vAA, #+BBBB
k21h, // op vAA, #+BBBB00000[00000000]
k21c, // op vAA, thing@BBBB
k23x, // op vAA, vBB, vCC
k22b, // op vAA, vBB, #+CC
k22t, // op vA, vB, +CCCC
k22s, // op vA, vB, #+CCCC
k22c, // op vA, vB, thing@CCCC
k32x, // op vAAAA, vBBBB
k30t, // op +AAAAAAAA
k31t, // op vAA, +BBBBBBBB
k31i, // op vAA, #+BBBBBBBB
k31c, // op vAA, thing@BBBBBBBB
k35c, // op {vC, vD, vE, vF, vG}, thing@BBBB (B: count, A: vG)
k3rc, // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
// op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH (A: count) // format: AG op BBBB FEDC HHHH
k45cc,
// op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH (AA: count) // format: AA op BBBB CCCC HHHH
k4rcc, // op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH (AA: count)
k51l, // op vAA, #+BBBBBBBBBBBBBBBB
kInvalidFormat,
};
enum IndexType : uint8_t {
kIndexUnknown = 0,
kIndexNone, // has no index
kIndexTypeRef, // type reference index
kIndexStringRef, // string reference index
kIndexMethodRef, // method reference index
kIndexFieldRef, // field reference index
kIndexMethodAndProtoRef, // method and a proto reference index (for invoke-polymorphic)
kIndexCallSiteRef, // call site reference index
kIndexMethodHandleRef, // constant method handle reference index
kIndexProtoRef, // prototype reference index
};
enum Flags : uint8_t { // private marker to avoid generate-operator-out.py from processing.
kBranch = 0x01, // conditional or unconditional branch
kContinue = 0x02, // flow can continue to next statement
kSwitch = 0x04, // switch statement
kThrow = 0x08, // could cause an exception to be thrown
kReturn = 0x10, // returns, no additional statements
kInvoke = 0x20, // a flavor of invoke
kUnconditional = 0x40, // unconditional branch
kExperimental = 0x80, // is an experimental opcode
};
// Old flags. Keeping them around in case we might need them again some day. enum ExtendedFlags : uint32_t {
kAdd = 0x0000080, // addition
kSubtract = 0x0000100, // subtract
kMultiply = 0x0000200, // multiply
kDivide = 0x0000400, // division
kRemainder = 0x0000800, // remainder
kAnd = 0x0001000, // and
kOr = 0x0002000, // or
kXor = 0x0004000, // xor
kShl = 0x0008000, // shl
kShr = 0x0010000, // shr
kUshr = 0x0020000, // ushr
kCast = 0x0040000, // cast
kStore = 0x0080000, // store opcode
kLoad = 0x0100000, // load opcode
kClobber = 0x0200000, // clobbers memory in a big way (not just a write)
kRegCFieldOrConstant = 0x0400000, // is the third virtual register a field or literal constant (vC)
kRegBFieldOrConstant = 0x0800000, // is the second virtual register a field or literal constant (vB)
};
// Collect the enums in a struct for better locality. struct InstructionDescriptor {
uint32_t verify_flags; // Set of VerifyFlag.
Format format;
IndexType index_type;
uint8_t flags; // Set of Flags.
int8_t size_in_code_units;
};
// Returns the size (in 2 byte code units) of this instruction.
size_t SizeInCodeUnits() const {
int8_t result = InstructionDescriptorOf(Opcode()).size_in_code_units; if (UNLIKELY(result < 0)) { return SizeInCodeUnitsComplexOpcode();
} else { returnstatic_cast<size_t>(result);
}
}
// Returns the size (in 2 byte code units) of the given instruction format.
ALWAYS_INLINE static constexpr size_t SizeInCodeUnits(Format format);
// Reads an instruction out of the stream at the specified address. staticconst Instruction* At(const uint16_t* code) {
DCHECK(code != nullptr); returnreinterpret_cast<const Instruction*>(code);
}
// Reads an instruction out of the stream from the current address plus an offset. const Instruction* RelativeAt(int32_t offset) const WARN_UNUSED { return At(reinterpret_cast<const uint16_t*>(this) + offset);
}
// Returns a pointer to the next instruction in the stream. const Instruction* Next() const { return RelativeAt(SizeInCodeUnits());
}
// Returns a pointer to the instruction after this 1xx instruction in the stream. const Instruction* Next_1xx() const {
DCHECK(FormatOf(Opcode()) >= k10x && FormatOf(Opcode()) <= k10t); return RelativeAt(1);
}
// Returns a pointer to the instruction after this 2xx instruction in the stream. const Instruction* Next_2xx() const {
DCHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k22c); return RelativeAt(2);
}
// Returns a pointer to the instruction after this 3xx instruction in the stream. const Instruction* Next_3xx() const {
DCHECK(FormatOf(Opcode()) >= k32x && FormatOf(Opcode()) <= k3rc); return RelativeAt(3);
}
// Returns a pointer to the instruction after this 4xx instruction in the stream. const Instruction* Next_4xx() const {
DCHECK(FormatOf(Opcode()) >= k45cc && FormatOf(Opcode()) <= k4rcc); return RelativeAt(4);
}
// Returns a pointer to the instruction after this 51l instruction in the stream. const Instruction* Next_51l() const {
DCHECK(FormatOf(Opcode()) == k51l); return RelativeAt(5);
}
// Returns the name of this instruction's opcode. constchar* Name() const { return Instruction::Name(Opcode());
}
// Returns the name of the given opcode. staticconstchar* Name(Code opcode) { return kInstructionNames[opcode];
}
// The following methods return the vB operand for all instruction formats where it is encoded in // the first 16 bits of instruction. The "inst_data" parameter holds these 16 bits. The returned // value is decoded from it.
int4_t VRegB_11n(uint16_t inst_data) const;
uint4_t VRegB_12x(uint16_t inst_data) const;
uint4_t VRegB_22c(uint16_t inst_data) const;
uint4_t VRegB_22s(uint16_t inst_data) const;
uint4_t VRegB_22t(uint16_t inst_data) const;
// Fills the given array with the 'arg' array of the instruction. bool HasVarArgs() const;
uint32_t GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const;
uint32_t GetVarArgs(uint32_t args[kMaxVarArgRegs]) const { return GetVarArgs(args, Fetch16(0));
}
// Returns the opcode field of the instruction. The given "inst_data" parameter must be the first // 16 bits of instruction.
Code Opcode(uint16_t inst_data) const {
DCHECK_EQ(inst_data, Fetch16(0)); returnstatic_cast<Code>(inst_data & 0xFF);
}
// Returns the opcode field of the instruction from the first 16 bits of instruction.
Code Opcode() const { return Opcode(Fetch16(0));
}
// Returns the format of the given opcode. static constexpr Format FormatOf(Code opcode) { return InstructionDescriptorOf(opcode).format;
}
// Returns the index type of the given opcode. static constexpr IndexType IndexTypeOf(Code opcode) { return InstructionDescriptorOf(opcode).index_type;
}
// Returns the flags for the given opcode. static constexpr uint8_t FlagsOf(Code opcode) { return InstructionDescriptorOf(opcode).flags;
}
// Return the verify flags for the given opcode. static constexpr uint32_t VerifyFlagsOf(Code opcode) { return InstructionDescriptorOf(opcode).verify_flags;
}
// Returns true if this instruction is a branch. bool IsBranch() const { return (InstructionDescriptorOf(Opcode()).flags & kBranch) != 0;
}
// Returns true if this instruction is a unconditional branch. bool IsUnconditional() const { return (InstructionDescriptorOf(Opcode()).flags & kUnconditional) != 0;
}
// Returns the branch offset if this instruction is a branch.
int32_t GetTargetOffset() const;
// Returns true if the instruction allows control flow to go to the following instruction. bool CanFlowThrough() const { return (FlagsOf(Opcode()) & Instruction::kContinue) != 0;
}
// Returns true if this instruction is a switch. bool IsSwitch() const { return (InstructionDescriptorOf(Opcode()).flags & kSwitch) != 0;
}
// Returns true if this instruction can throw. bool IsThrow() const { return (InstructionDescriptorOf(Opcode()).flags & kThrow) != 0;
}
// Determine if the instruction is any of 'return' instructions. static constexpr bool IsReturn(Code opcode) { return (InstructionDescriptorOf(opcode).flags & kReturn) != 0;
} bool IsReturn() const { return IsReturn(Opcode());
}
// Determine if this instruction ends execution of its basic block. bool IsBasicBlockEnd() const { return IsBranch() || IsReturn() || Opcode() == THROW;
}
// Determine if this instruction is an invoke. bool IsInvoke() const { return (InstructionDescriptorOf(Opcode()).flags & kInvoke) != 0;
}
// Determine if this instruction is experimental. bool IsExperimental() const { return (InstructionDescriptorOf(Opcode()).flags & kExperimental) != 0;
}
// Get the dex PC of this instruction as a offset in code units from the beginning of insns.
uint32_t GetDexPc(const uint16_t* insns) const { return (reinterpret_cast<const uint16_t*>(this) - insns);
}
// Dump decoded version of instruction
std::string DumpString(const DexFile*) const;
// Dump code_units worth of this instruction, padding to code_units for shorter instructions
std::string DumpHex(size_t code_units) const;
// Little-endian dump code_units worth of this instruction, padding to code_units for // shorter instructions
std::string DumpHexLE(size_t instr_code_units) const;
// Base class for accessing instruction operands. Unifies operand // access for instructions that have range and varargs forms // (e.g. invoke-polymoprhic/range and invoke-polymorphic). class InstructionOperands { public: explicit InstructionOperands(size_t num_operands) : num_operands_(num_operands) {} virtual ~InstructionOperands() {} virtual uint32_t GetOperand(size_t index) const = 0;
size_t GetNumberOfOperands() const { return num_operands_; }
// Class for accessing operands for instructions with a range format // (e.g. 3rc and 4rcc). class RangeInstructionOperands final : public InstructionOperands { public:
RangeInstructionOperands(uint32_t first_operand, size_t num_operands)
: InstructionOperands(num_operands), first_operand_(first_operand) {}
~RangeInstructionOperands() {}
uint32_t GetOperand(size_t operand_index) const override;
// Class for accessing operands for instructions with a variable // number of arguments format (e.g. 35c and 45cc). class VarArgsInstructionOperands final : public InstructionOperands { public:
VarArgsInstructionOperands(const uint32_t (&operands)[Instruction::kMaxVarArgRegs],
size_t num_operands)
: InstructionOperands(num_operands), operands_(operands) {}
~VarArgsInstructionOperands() {}
uint32_t GetOperand(size_t operand_index) const override;
// Class for accessing operands without the receiver by wrapping an // existing InstructionOperands instance. class NoReceiverInstructionOperands final : public InstructionOperands { public: explicit NoReceiverInstructionOperands(const InstructionOperands* const inner)
: InstructionOperands(inner->GetNumberOfOperands() - 1), inner_(inner) {}
~NoReceiverInstructionOperands() {}
uint32_t GetOperand(size_t operand_index) const override;
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.