Make dex instruction size a lookup.
Add ostream operators for dex instruction enums.
Move simple methods to header file.
Change-Id: I9644bfb975896a491ee73ef9a8ef13c062c5fcbd
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index 6fe0659..0058575 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -875,7 +875,7 @@
flags = 0;
} else {
str.append(Instruction::Name(insn.opcode));
- flags = Instruction::Flags(insn.opcode);
+ flags = Instruction::FlagsOf(insn.opcode);
}
if (note) {
@@ -983,7 +983,7 @@
}
/* For branches, decode the instructions to print out the branch targets */
- if (Instruction::Flags(insn->opcode) & Instruction::kBranch) {
+ if (Instruction::FlagsOf(insn->opcode) & Instruction::kBranch) {
Instruction::Format dalvikFormat = Instruction::FormatOf(insn->opcode);
int delta = 0;
switch (dalvikFormat) {
@@ -1265,7 +1265,7 @@
// If not a pseudo-op, note non-leaf or can throw
if (static_cast<int>(mir->dalvikInsn.opcode) <
static_cast<int>(kNumPackedOpcodes)) {
- int flags = Instruction::Flags(mir->dalvikInsn.opcode);
+ int flags = Instruction::FlagsOf(mir->dalvikInsn.opcode);
if (flags & Instruction::kThrow) {
cUnit->attrs &= ~METHOD_IS_THROW_FREE;
@@ -2292,7 +2292,7 @@
return false;
}
Instruction::Code opcode = bb->lastMIRInsn->dalvikInsn.opcode;
- if (Instruction::Flags(opcode) & Instruction::kBranch) {
+ if (Instruction::FlagsOf(opcode) & Instruction::kBranch) {
if (bb->taken && (bb->taken->startOffset <= bb->startOffset)) {
DCHECK(bb->dominators != NULL);
if (oatIsBitSet(bb->dominators, bb->taken->id)) {
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 1a09427..31d8aa5 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -986,7 +986,7 @@
oatAppendMIR(curBlock, insn);
codePtr += width;
- int flags = Instruction::Flags(insn->dalvikInsn.opcode);
+ int flags = Instruction::FlagsOf(insn->dalvikInsn.opcode);
int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
diff --git a/src/compiler/Ralloc.cc b/src/compiler/Ralloc.cc
index 623d4ea..bf69ce4 100644
--- a/src/compiler/Ralloc.cc
+++ b/src/compiler/Ralloc.cc
@@ -214,7 +214,7 @@
// Special-case handling for format 35c/3rc invokes
Instruction::Code opcode = mir->dalvikInsn.opcode;
int flags = (static_cast<int>(opcode) >= kNumPackedOpcodes)
- ? 0 : Instruction::Flags(mir->dalvikInsn.opcode);
+ ? 0 : Instruction::FlagsOf(mir->dalvikInsn.opcode);
if ((flags & Instruction::kInvoke) &&
(attrs & (DF_FORMAT_35C | DF_FORMAT_3RC))) {
DCHECK_EQ(next, 0);
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
index 80a7d9d..0de7523 100644
--- a/src/dex_instruction.cc
+++ b/src/dex_instruction.cc
@@ -53,6 +53,20 @@
#undef INSTRUCTION_VERIFY_FLAGS
};
+int const Instruction::kInstructionSizeInCodeUnits[] = {
+#define INSTRUCTION_SIZE(opcode, c, p, format, r, i, a, v) \
+ (( opcode == NOP ) ? -1 : \
+ ((format >= k10x) && (format <= k10t)) ? 1 : \
+ ((format >= k20t) && (format <= k22c)) ? 2 : \
+ ((format >= k32x) && (format <= k3rc)) ? 3 : \
+ ( format == k51l ) ? 5 : -1 \
+ ),
+#include "dex_instruction_list.h"
+ DEX_INSTRUCTION_LIST(INSTRUCTION_SIZE)
+#undef DEX_INSTRUCTION_LIST
+#undef INSTRUCTION_SIZE
+};
+
/*
* Handy macros for helping decode instructions.
*/
@@ -70,9 +84,9 @@
void Instruction::Decode(uint32_t &vA, uint32_t &vB, uint64_t &vB_wide, uint32_t &vC, uint32_t arg[]) const {
const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
uint16_t insn = *insns;
- int opcode = insn & 0xFF;
+ Code opcode = static_cast<Code>(insn & 0xFF);
- switch (FormatOf(Opcode())) {
+ switch (FormatOf(opcode)) {
case k10x: // op
/* nothing to do; copy the AA bits out for the verifier */
vA = INST_AA(insn);
@@ -201,69 +215,33 @@
vB_wide = FETCH_u4(1) | ((uint64_t) FETCH_u4(3) << 32);
break;
default:
- LOG(ERROR) << "Can't decode unexpected format " << static_cast<int>(FormatOf(Opcode())) << " (op=" << opcode << ")";
+ LOG(ERROR) << "Can't decode unexpected format " << FormatOf(opcode) << " (op=" << opcode << ")";
return;
}
}
-size_t Instruction::SizeInCodeUnits() const {
+size_t Instruction::SizeInCodeUnitsComplexOpcode() const {
const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
- if (*insns == Instruction::kPackedSwitchSignature) {
- return (4 + insns[1] * 2);
- } else if (*insns == Instruction::kSparseSwitchSignature) {
- return (2 + insns[1] * 4);
- } else if (*insns == kArrayDataSignature) {
- uint16_t element_size = insns[1];
- uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16);
- // The plus 1 is to round up for odd size and width.
- return (4 + (element_size * length + 1) / 2);
- } else {
- switch (FormatOf(Opcode())) {
- case k10x:
- case k12x:
- case k11n:
- case k11x:
- case k10t:
- return 1;
- case k20t:
- case k22x:
- case k21t:
- case k21s:
- case k21h:
- case k21c:
- case k23x:
- case k22b:
- case k22t:
- case k22s:
- case k22c:
- return 2;
- case k32x:
- case k30t:
- case k31t:
- case k31i:
- case k31c:
- case k35c:
- case k3rc:
- return 3;
- case k51l:
- return 5;
- default:
- LOG(FATAL) << "Unreachable";
+ // Handle special NOP encoded variable length sequences.
+ switch (*insns) {
+ case kPackedSwitchSignature:
+ return (4 + insns[1] * 2);
+ case kSparseSwitchSignature:
+ return (2 + insns[1] * 4);
+ case kArrayDataSignature: {
+ uint16_t element_size = insns[1];
+ uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16);
+ // The plus 1 is to round up for odd size and width.
+ return (4 + (element_size * length + 1) / 2);
}
+ default:
+ if ((*insns & 0xFF) == 0) {
+ return 1; // NOP.
+ } else {
+ LOG(FATAL) << "Unreachable: " << DumpString(NULL);
+ return 0;
+ }
}
- return 0;
-}
-
-Instruction::Code Instruction::Opcode() const {
- const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
- int opcode = *insns & 0xFF;
- return static_cast<Code>(opcode);
-}
-
-const Instruction* Instruction::Next() const {
- size_t current_size_in_bytes = SizeInCodeUnits() * sizeof(uint16_t);
- const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
- return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
}
std::string Instruction::DumpHex(size_t code_units) const {
@@ -449,9 +427,8 @@
return os.str();
}
-DecodedInstruction::DecodedInstruction(const Instruction* inst) {
- inst->Decode(vA, vB, vB_wide, vC, arg);
- opcode = inst->Opcode();
+std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) {
+ return os << Instruction::Name(code);
}
} // namespace art
diff --git a/src/dex_instruction.h b/src/dex_instruction.h
index 91aa042..90dca69 100644
--- a/src/dex_instruction.h
+++ b/src/dex_instruction.h
@@ -74,13 +74,16 @@
DISALLOW_COPY_AND_ASSIGN(ArrayDataPayload);
};
- enum Code {
+ // TODO: the code layout below is deliberate to avoid this enum being picked up by
+ // generate-operator-out.py.
+ enum Code
+ {
#define INSTRUCTION_ENUM(opcode, cname, p, f, r, i, a, v) cname = opcode,
#include "dex_instruction_list.h"
DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM)
#undef DEX_INSTRUCTION_LIST
#undef INSTRUCTION_ENUM
- };
+ } ;
enum Format {
k10x, // op
@@ -147,10 +150,21 @@
void Decode(uint32_t &vA, uint32_t &vB, uint64_t &vB_wide, uint32_t &vC, uint32_t arg[]) const;
// Returns the size (in 2 byte code units) of this instruction.
- size_t SizeInCodeUnits() const;
+ size_t SizeInCodeUnits() const {
+ int result = kInstructionSizeInCodeUnits[Opcode()];
+ if (UNLIKELY(result < 0)) {
+ return SizeInCodeUnitsComplexOpcode();
+ } else {
+ return static_cast<size_t>(result);
+ }
+ }
// Returns a pointer to the next instruction in the stream.
- const Instruction* Next() const;
+ const Instruction* Next() const {
+ size_t current_size_in_bytes = SizeInCodeUnits() * sizeof(uint16_t);
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
+ return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+ }
// Returns the name of this instruction's opcode.
const char* Name() const {
@@ -163,7 +177,11 @@
}
// Returns the opcode field of the instruction.
- Code Opcode() const;
+ Code Opcode() const {
+ const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
+ int opcode = *insns & 0xFF;
+ return static_cast<Code>(opcode);
+ }
// Reads an instruction out of the stream at the specified address.
static const Instruction* At(const uint16_t* code) {
@@ -177,7 +195,7 @@
}
// Returns the flags for the given opcode.
- static int Flags(Code opcode) {
+ static int FlagsOf(Code opcode) {
return kInstructionFlags[opcode];
}
@@ -242,12 +260,19 @@
std::string DumpHex(size_t code_units) const;
private:
+ size_t SizeInCodeUnitsComplexOpcode() const;
+
static const char* const kInstructionNames[];
static Format const kInstructionFormats[];
static int const kInstructionFlags[];
static int const kInstructionVerifyFlags[];
+ static int const kInstructionSizeInCodeUnits[];
DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
};
+std::ostream& operator<<(std::ostream& os, const Instruction::Code& code);
+std::ostream& operator<<(std::ostream& os, const Instruction::Format& format);
+std::ostream& operator<<(std::ostream& os, const Instruction::Flags& flags);
+std::ostream& operator<<(std::ostream& os, const Instruction::VerifyFlag& vflags);
/*
* Holds the contents of a decoded instruction.
@@ -260,7 +285,10 @@
uint32_t arg[5]; /* vC/D/E/F/G in invoke or filled-new-array */
Instruction::Code opcode;
- explicit DecodedInstruction(const Instruction* inst);
+ explicit DecodedInstruction(const Instruction* inst) {
+ inst->Decode(vA, vB, vB_wide, vC, arg);
+ opcode = inst->Opcode();
+ }
};
} // namespace art
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index f4884ad..b7fe324 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -1333,7 +1333,7 @@
const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
const Instruction* inst = Instruction::At(insns);
DecodedInstruction dec_insn(inst);
- int opcode_flags = Instruction::Flags(inst->Opcode());
+ int opcode_flags = Instruction::FlagsOf(inst->Opcode());
int32_t branch_target = 0;
bool just_set_result = false;