You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
763 lines
25 KiB
763 lines
25 KiB
/*
|
|
* Copyright (C) 2011 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_H_
|
|
#define ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_H_
|
|
|
|
#include <android-base/logging.h>
|
|
|
|
#include "base/globals.h"
|
|
#include "base/macros.h"
|
|
|
|
typedef uint8_t uint4_t;
|
|
typedef int8_t int4_t;
|
|
|
|
namespace art {
|
|
|
|
class DexFile;
|
|
|
|
enum {
|
|
kNumPackedOpcodes = 0x100
|
|
};
|
|
|
|
class Instruction {
|
|
public:
|
|
// NOP-encoded switch-statement signatures.
|
|
enum Signatures {
|
|
kPackedSwitchSignature = 0x0100,
|
|
kSparseSwitchSignature = 0x0200,
|
|
kArrayDataSignature = 0x0300,
|
|
};
|
|
|
|
struct PACKED(4) PackedSwitchPayload {
|
|
const uint16_t ident;
|
|
const uint16_t case_count;
|
|
const int32_t first_key;
|
|
const int32_t targets[];
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(PackedSwitchPayload);
|
|
};
|
|
|
|
struct PACKED(4) SparseSwitchPayload {
|
|
const uint16_t ident;
|
|
const uint16_t case_count;
|
|
const int32_t keys_and_targets[];
|
|
|
|
public:
|
|
const int32_t* GetKeys() const {
|
|
return keys_and_targets;
|
|
}
|
|
|
|
const int32_t* GetTargets() const {
|
|
return keys_and_targets + case_count;
|
|
}
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(SparseSwitchPayload);
|
|
};
|
|
|
|
struct PACKED(4) ArrayDataPayload {
|
|
const uint16_t ident;
|
|
const uint16_t element_width;
|
|
const uint32_t element_count;
|
|
const uint8_t data[];
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(ArrayDataPayload);
|
|
};
|
|
|
|
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),
|
|
#include "dex_instruction_list.h"
|
|
DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM)
|
|
#undef DEX_INSTRUCTION_LIST
|
|
#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
|
|
kIndexFieldOffset, // field offset (for static linked fields)
|
|
kIndexVtableOffset, // vtable offset (for static linked methods)
|
|
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)
|
|
};
|
|
|
|
enum VerifyFlag : uint32_t { // private marker to avoid generate-operator-out.py from processing.
|
|
kVerifyNothing = 0x0000000,
|
|
kVerifyRegA = 0x0000001,
|
|
kVerifyRegAWide = 0x0000002,
|
|
kVerifyRegB = 0x0000004,
|
|
kVerifyRegBField = 0x0000008,
|
|
kVerifyRegBMethod = 0x0000010,
|
|
kVerifyRegBNewInstance = 0x0000020,
|
|
kVerifyRegBString = 0x0000040,
|
|
kVerifyRegBType = 0x0000080,
|
|
kVerifyRegBWide = 0x0000100,
|
|
kVerifyRegC = 0x0000200,
|
|
kVerifyRegCField = 0x0000400,
|
|
kVerifyRegCNewArray = 0x0000800,
|
|
kVerifyRegCType = 0x0001000,
|
|
kVerifyRegCWide = 0x0002000,
|
|
kVerifyArrayData = 0x0004000,
|
|
kVerifyBranchTarget = 0x0008000,
|
|
kVerifySwitchTargets = 0x0010000,
|
|
kVerifyVarArg = 0x0020000,
|
|
kVerifyVarArgNonZero = 0x0040000,
|
|
kVerifyVarArgRange = 0x0080000,
|
|
kVerifyVarArgRangeNonZero = 0x0100000,
|
|
kVerifyRuntimeOnly = 0x0200000,
|
|
kVerifyError = 0x0400000,
|
|
kVerifyRegHPrototype = 0x0800000,
|
|
kVerifyRegBCallSite = 0x1000000,
|
|
kVerifyRegBMethodHandle = 0x2000000,
|
|
kVerifyRegBPrototype = 0x4000000,
|
|
};
|
|
|
|
// 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;
|
|
};
|
|
|
|
static constexpr uint32_t kMaxVarArgRegs = 5;
|
|
|
|
static constexpr bool kHaveExperimentalInstructions = false;
|
|
|
|
// Returns the size (in 2 byte code units) of this instruction.
|
|
size_t SizeInCodeUnits() const {
|
|
int8_t result = kInstructionDescriptors[Opcode()].size_in_code_units;
|
|
if (UNLIKELY(result < 0)) {
|
|
return SizeInCodeUnitsComplexOpcode();
|
|
} else {
|
|
return static_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);
|
|
|
|
// Code units required to calculate the size of the instruction.
|
|
size_t CodeUnitsRequiredForSizeComputation() const {
|
|
const int8_t result = kInstructionDescriptors[Opcode()].size_in_code_units;
|
|
return UNLIKELY(result < 0) ? CodeUnitsRequiredForSizeOfComplexOpcode() : 1;
|
|
}
|
|
|
|
// Reads an instruction out of the stream at the specified address.
|
|
static const Instruction* At(const uint16_t* code) {
|
|
DCHECK(code != nullptr);
|
|
return reinterpret_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.
|
|
const char* Name() const {
|
|
return Instruction::Name(Opcode());
|
|
}
|
|
|
|
// Returns the name of the given opcode.
|
|
static const char* Name(Code opcode) {
|
|
return kInstructionNames[opcode];
|
|
}
|
|
|
|
// VRegA
|
|
bool HasVRegA() const;
|
|
ALWAYS_INLINE int32_t VRegA() const;
|
|
ALWAYS_INLINE int32_t VRegA(Format format, uint16_t inst_data) const;
|
|
|
|
int8_t VRegA_10t() const {
|
|
return VRegA_10t(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_10x() const {
|
|
return VRegA_10x(Fetch16(0));
|
|
}
|
|
uint4_t VRegA_11n() const {
|
|
return VRegA_11n(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_11x() const {
|
|
return VRegA_11x(Fetch16(0));
|
|
}
|
|
uint4_t VRegA_12x() const {
|
|
return VRegA_12x(Fetch16(0));
|
|
}
|
|
int16_t VRegA_20t() const;
|
|
uint8_t VRegA_21c() const {
|
|
return VRegA_21c(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_21h() const {
|
|
return VRegA_21h(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_21s() const {
|
|
return VRegA_21s(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_21t() const {
|
|
return VRegA_21t(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_22b() const {
|
|
return VRegA_22b(Fetch16(0));
|
|
}
|
|
uint4_t VRegA_22c() const {
|
|
return VRegA_22c(Fetch16(0));
|
|
}
|
|
uint4_t VRegA_22s() const {
|
|
return VRegA_22s(Fetch16(0));
|
|
}
|
|
uint4_t VRegA_22t() const {
|
|
return VRegA_22t(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_22x() const {
|
|
return VRegA_22x(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_23x() const {
|
|
return VRegA_23x(Fetch16(0));
|
|
}
|
|
int32_t VRegA_30t() const;
|
|
uint8_t VRegA_31c() const {
|
|
return VRegA_31c(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_31i() const {
|
|
return VRegA_31i(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_31t() const {
|
|
return VRegA_31t(Fetch16(0));
|
|
}
|
|
uint16_t VRegA_32x() const;
|
|
uint4_t VRegA_35c() const {
|
|
return VRegA_35c(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_3rc() const {
|
|
return VRegA_3rc(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_51l() const {
|
|
return VRegA_51l(Fetch16(0));
|
|
}
|
|
uint4_t VRegA_45cc() const {
|
|
return VRegA_45cc(Fetch16(0));
|
|
}
|
|
uint8_t VRegA_4rcc() const {
|
|
return VRegA_4rcc(Fetch16(0));
|
|
}
|
|
|
|
// The following methods return the vA operand for various instruction formats. The "inst_data"
|
|
// parameter holds the first 16 bits of instruction which the returned value is decoded from.
|
|
int8_t VRegA_10t(uint16_t inst_data) const;
|
|
uint8_t VRegA_10x(uint16_t inst_data) const;
|
|
uint4_t VRegA_11n(uint16_t inst_data) const;
|
|
uint8_t VRegA_11x(uint16_t inst_data) const;
|
|
uint4_t VRegA_12x(uint16_t inst_data) const;
|
|
uint8_t VRegA_21c(uint16_t inst_data) const;
|
|
uint8_t VRegA_21h(uint16_t inst_data) const;
|
|
uint8_t VRegA_21s(uint16_t inst_data) const;
|
|
uint8_t VRegA_21t(uint16_t inst_data) const;
|
|
uint8_t VRegA_22b(uint16_t inst_data) const;
|
|
uint4_t VRegA_22c(uint16_t inst_data) const;
|
|
uint4_t VRegA_22s(uint16_t inst_data) const;
|
|
uint4_t VRegA_22t(uint16_t inst_data) const;
|
|
uint8_t VRegA_22x(uint16_t inst_data) const;
|
|
uint8_t VRegA_23x(uint16_t inst_data) const;
|
|
uint8_t VRegA_31c(uint16_t inst_data) const;
|
|
uint8_t VRegA_31i(uint16_t inst_data) const;
|
|
uint8_t VRegA_31t(uint16_t inst_data) const;
|
|
uint4_t VRegA_35c(uint16_t inst_data) const;
|
|
uint8_t VRegA_3rc(uint16_t inst_data) const;
|
|
uint8_t VRegA_51l(uint16_t inst_data) const;
|
|
uint4_t VRegA_45cc(uint16_t inst_data) const;
|
|
uint8_t VRegA_4rcc(uint16_t inst_data) const;
|
|
|
|
// VRegB
|
|
bool HasVRegB() const;
|
|
ALWAYS_INLINE int32_t VRegB() const;
|
|
ALWAYS_INLINE int32_t VRegB(Format format, uint16_t inst_data) const;
|
|
|
|
bool HasWideVRegB() const;
|
|
uint64_t WideVRegB() const;
|
|
|
|
int4_t VRegB_11n() const {
|
|
return VRegB_11n(Fetch16(0));
|
|
}
|
|
uint4_t VRegB_12x() const {
|
|
return VRegB_12x(Fetch16(0));
|
|
}
|
|
uint16_t VRegB_21c() const;
|
|
uint16_t VRegB_21h() const;
|
|
int16_t VRegB_21s() const;
|
|
int16_t VRegB_21t() const;
|
|
uint8_t VRegB_22b() const;
|
|
uint4_t VRegB_22c() const {
|
|
return VRegB_22c(Fetch16(0));
|
|
}
|
|
uint4_t VRegB_22s() const {
|
|
return VRegB_22s(Fetch16(0));
|
|
}
|
|
uint4_t VRegB_22t() const {
|
|
return VRegB_22t(Fetch16(0));
|
|
}
|
|
uint16_t VRegB_22x() const;
|
|
uint8_t VRegB_23x() const;
|
|
uint32_t VRegB_31c() const;
|
|
int32_t VRegB_31i() const;
|
|
int32_t VRegB_31t() const;
|
|
uint16_t VRegB_32x() const;
|
|
uint16_t VRegB_35c() const;
|
|
uint16_t VRegB_3rc() const;
|
|
uint64_t VRegB_51l() const; // vB_wide
|
|
uint16_t VRegB_45cc() const;
|
|
uint16_t VRegB_4rcc() const;
|
|
|
|
// 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;
|
|
|
|
// VRegC
|
|
bool HasVRegC() const;
|
|
ALWAYS_INLINE int32_t VRegC() const;
|
|
ALWAYS_INLINE int32_t VRegC(Format format) const;
|
|
|
|
int8_t VRegC_22b() const;
|
|
uint16_t VRegC_22c() const;
|
|
int16_t VRegC_22s() const;
|
|
int16_t VRegC_22t() const;
|
|
uint8_t VRegC_23x() const;
|
|
uint4_t VRegC_35c() const;
|
|
uint16_t VRegC_3rc() const;
|
|
uint4_t VRegC_45cc() const;
|
|
uint16_t VRegC_4rcc() const;
|
|
|
|
|
|
// VRegH
|
|
bool HasVRegH() const;
|
|
int32_t VRegH() const;
|
|
uint16_t VRegH_45cc() const;
|
|
uint16_t VRegH_4rcc() 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));
|
|
return static_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));
|
|
}
|
|
|
|
void SetOpcode(Code opcode) {
|
|
DCHECK_LT(static_cast<uint16_t>(opcode), 256u);
|
|
uint16_t* insns = reinterpret_cast<uint16_t*>(this);
|
|
insns[0] = (insns[0] & 0xff00) | static_cast<uint16_t>(opcode);
|
|
}
|
|
|
|
void SetVRegA_10x(uint8_t val) {
|
|
DCHECK(FormatOf(Opcode()) == k10x);
|
|
uint16_t* insns = reinterpret_cast<uint16_t*>(this);
|
|
insns[0] = (val << 8) | (insns[0] & 0x00ff);
|
|
}
|
|
|
|
void SetVRegB_3rc(uint16_t val) {
|
|
DCHECK(FormatOf(Opcode()) == k3rc);
|
|
uint16_t* insns = reinterpret_cast<uint16_t*>(this);
|
|
insns[1] = val;
|
|
}
|
|
|
|
void SetVRegB_35c(uint16_t val) {
|
|
DCHECK(FormatOf(Opcode()) == k35c);
|
|
uint16_t* insns = reinterpret_cast<uint16_t*>(this);
|
|
insns[1] = val;
|
|
}
|
|
|
|
void SetVRegC_22c(uint16_t val) {
|
|
DCHECK(FormatOf(Opcode()) == k22c);
|
|
uint16_t* insns = reinterpret_cast<uint16_t*>(this);
|
|
insns[1] = val;
|
|
}
|
|
|
|
void SetVRegA_21c(uint8_t val) {
|
|
DCHECK(FormatOf(Opcode()) == k21c);
|
|
uint16_t* insns = reinterpret_cast<uint16_t*>(this);
|
|
insns[0] = (val << 8) | (insns[0] & 0x00ff);
|
|
}
|
|
|
|
void SetVRegB_21c(uint16_t val) {
|
|
DCHECK(FormatOf(Opcode()) == k21c);
|
|
uint16_t* insns = reinterpret_cast<uint16_t*>(this);
|
|
insns[1] = val;
|
|
}
|
|
|
|
// Returns the format of the given opcode.
|
|
static Format FormatOf(Code opcode) {
|
|
return kInstructionDescriptors[opcode].format;
|
|
}
|
|
|
|
// Returns the index type of the given opcode.
|
|
static IndexType IndexTypeOf(Code opcode) {
|
|
return kInstructionDescriptors[opcode].index_type;
|
|
}
|
|
|
|
// Returns the flags for the given opcode.
|
|
static uint8_t FlagsOf(Code opcode) {
|
|
return kInstructionDescriptors[opcode].flags;
|
|
}
|
|
|
|
// Return the verify flags for the given opcode.
|
|
static uint32_t VerifyFlagsOf(Code opcode) {
|
|
return kInstructionDescriptors[opcode].verify_flags;
|
|
}
|
|
|
|
// Returns true if this instruction is a branch.
|
|
bool IsBranch() const {
|
|
return (kInstructionDescriptors[Opcode()].flags & kBranch) != 0;
|
|
}
|
|
|
|
// Returns true if this instruction is a unconditional branch.
|
|
bool IsUnconditional() const {
|
|
return (kInstructionDescriptors[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;
|
|
|
|
// Returns true if the instruction is a quickened instruction.
|
|
bool IsQuickened() const {
|
|
return (kInstructionDescriptors[Opcode()].index_type == kIndexFieldOffset) ||
|
|
(kInstructionDescriptors[Opcode()].index_type == kIndexVtableOffset);
|
|
}
|
|
|
|
// Returns true if this instruction is a switch.
|
|
bool IsSwitch() const {
|
|
return (kInstructionDescriptors[Opcode()].flags & kSwitch) != 0;
|
|
}
|
|
|
|
// Returns true if this instruction can throw.
|
|
bool IsThrow() const {
|
|
return (kInstructionDescriptors[Opcode()].flags & kThrow) != 0;
|
|
}
|
|
|
|
// Determine if the instruction is any of 'return' instructions.
|
|
bool IsReturn() const {
|
|
return (kInstructionDescriptors[Opcode()].flags & kReturn) != 0;
|
|
}
|
|
|
|
// 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 (kInstructionDescriptors[Opcode()].flags & kInvoke) != 0;
|
|
}
|
|
|
|
// Determine if this instruction is experimental.
|
|
bool IsExperimental() const {
|
|
return (kInstructionDescriptors[Opcode()].flags & kExperimental) != 0;
|
|
}
|
|
|
|
int GetVerifyTypeArgumentA() const {
|
|
return (kInstructionDescriptors[Opcode()].verify_flags & (kVerifyRegA | kVerifyRegAWide));
|
|
}
|
|
|
|
int GetVerifyTypeArgumentB() const {
|
|
return (kInstructionDescriptors[Opcode()].verify_flags & (kVerifyRegB | kVerifyRegBField |
|
|
kVerifyRegBMethod | kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType |
|
|
kVerifyRegBWide));
|
|
}
|
|
|
|
int GetVerifyTypeArgumentC() const {
|
|
return (kInstructionDescriptors[Opcode()].verify_flags & (kVerifyRegC | kVerifyRegCField |
|
|
kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
|
|
}
|
|
|
|
int GetVerifyTypeArgumentH() const {
|
|
return (kInstructionDescriptors[Opcode()].verify_flags & kVerifyRegHPrototype);
|
|
}
|
|
|
|
int GetVerifyExtraFlags() const {
|
|
return (kInstructionDescriptors[Opcode()].verify_flags & (kVerifyArrayData |
|
|
kVerifyBranchTarget | kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgNonZero |
|
|
kVerifyVarArgRange | kVerifyVarArgRangeNonZero | kVerifyError));
|
|
}
|
|
|
|
bool GetVerifyIsRuntimeOnly() const {
|
|
return (kInstructionDescriptors[Opcode()].verify_flags & kVerifyRuntimeOnly) != 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;
|
|
|
|
uint16_t Fetch16(size_t offset) const {
|
|
const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
|
|
return insns[offset];
|
|
}
|
|
|
|
private:
|
|
size_t SizeInCodeUnitsComplexOpcode() const;
|
|
|
|
// Return how many code unit words are required to compute the size of the opcode.
|
|
size_t CodeUnitsRequiredForSizeOfComplexOpcode() const;
|
|
|
|
uint32_t Fetch32(size_t offset) const {
|
|
return (Fetch16(offset) | ((uint32_t) Fetch16(offset + 1) << 16));
|
|
}
|
|
|
|
uint4_t InstA() const {
|
|
return InstA(Fetch16(0));
|
|
}
|
|
|
|
uint4_t InstB() const {
|
|
return InstB(Fetch16(0));
|
|
}
|
|
|
|
uint8_t InstAA() const {
|
|
return InstAA(Fetch16(0));
|
|
}
|
|
|
|
uint4_t InstA(uint16_t inst_data) const {
|
|
DCHECK_EQ(inst_data, Fetch16(0));
|
|
return static_cast<uint4_t>((inst_data >> 8) & 0x0f);
|
|
}
|
|
|
|
uint4_t InstB(uint16_t inst_data) const {
|
|
DCHECK_EQ(inst_data, Fetch16(0));
|
|
return static_cast<uint4_t>(inst_data >> 12);
|
|
}
|
|
|
|
uint8_t InstAA(uint16_t inst_data) const {
|
|
DCHECK_EQ(inst_data, Fetch16(0));
|
|
return static_cast<uint8_t>(inst_data >> 8);
|
|
}
|
|
|
|
static const char* const kInstructionNames[];
|
|
|
|
static const InstructionDescriptor kInstructionDescriptors[];
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
|
|
};
|
|
std::ostream& operator<<(std::ostream& os, Instruction::Code code);
|
|
std::ostream& operator<<(std::ostream& os, Instruction::Format format);
|
|
|
|
// 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_; }
|
|
|
|
private:
|
|
const size_t num_operands_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(InstructionOperands);
|
|
};
|
|
|
|
// 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;
|
|
|
|
private:
|
|
const uint32_t first_operand_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(RangeInstructionOperands);
|
|
};
|
|
|
|
// 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;
|
|
|
|
private:
|
|
const uint32_t (&operands_)[Instruction::kMaxVarArgRegs];
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(VarArgsInstructionOperands);
|
|
};
|
|
|
|
// 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;
|
|
|
|
private:
|
|
const InstructionOperands* const inner_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(NoReceiverInstructionOperands);
|
|
};
|
|
|
|
} // namespace art
|
|
|
|
#endif // ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_H_
|