Added wrapper functions for register acccess in Instruction.
The VRegB and VRegC functions allow uniform
access to the parameter registers, no matter what the
instruction format is.
Change-Id: I3b33358ea0ed071e22bc6d51bd01fce29bbd432c
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
index e002727..c5901aa 100644
--- a/src/dex_instruction.cc
+++ b/src/dex_instruction.cc
@@ -82,6 +82,68 @@
return insns[offset] | ((uint32_t) insns[offset+1] << 16);
}
+int32_t Instruction::VRegC() const {
+ switch (FormatOf(Opcode())) {
+ case k22b: return VRegC_22b();
+ case k22c: return VRegC_22c();
+ case k22s: return VRegC_22s();
+ case k22t: return VRegC_22t();
+ case k23x: return VRegC_23x();
+ case k35c: return VRegC_35c();
+ case k3rc: return VRegC_3rc();
+ default: LOG(FATAL) << "Tried to access vC of instruction " << Name() <<
+ " which has no C operand.";
+ }
+ return 0;
+}
+
+int32_t Instruction::VRegB() const {
+ switch (FormatOf(Opcode())) {
+ case k11n: return VRegB_11n();
+ case k12x: return VRegB_12x();
+ case k21c: return VRegB_21c();
+ case k21h: return VRegB_21h();
+ case k21t: return VRegB_21t();
+ case k22b: return VRegB_22b();
+ case k22c: return VRegB_22c();
+ case k22s: return VRegB_22s();
+ case k22t: return VRegB_22t();
+ case k22x: return VRegB_22x();
+ case k31c: return VRegB_31c();
+ case k31i: return VRegB_31i();
+ case k31t: return VRegB_31t();
+ case k32x: return VRegB_32x();
+ case k35c: return VRegB_35c();
+ case k3rc: return VRegB_3rc();
+ case k51l: return VRegB_51l();
+ default: LOG(FATAL) << "Tried to access vB of instruction " << Name() <<
+ " which has no B operand.";
+ }
+ return 0;
+}
+
+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.";
+ }
+ return 0;
+}
+
+bool Instruction::CanFlowThrough() const {
+ const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
+ uint16_t insn = *insns;
+ Code opcode = static_cast<Code>(insn & 0xFF);
+ return FlagsOf(opcode) & Instruction::kContinue;
+}
+
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;
diff --git a/src/dex_instruction.h b/src/dex_instruction.h
index 8a49216..602667a 100644
--- a/src/dex_instruction.h
+++ b/src/dex_instruction.h
@@ -46,6 +46,7 @@
const uint16_t case_count;
const int32_t first_key;
const int32_t targets[];
+
private:
DISALLOW_COPY_AND_ASSIGN(PackedSwitchPayload);
};
@@ -73,6 +74,7 @@
const uint16_t element_width;
const uint32_t element_count;
const uint8_t data[];
+
private:
DISALLOW_COPY_AND_ASSIGN(ArrayDataPayload);
};
@@ -239,6 +241,7 @@
uint8_t VRegA_51l() const;
// VRegB
+ int32_t VRegB() const;
int4_t VRegB_11n() const;
uint4_t VRegB_12x() const;
uint16_t VRegB_21c() const;
@@ -257,9 +260,10 @@
uint16_t VRegB_32x() const;
uint16_t VRegB_35c() const;
uint16_t VRegB_3rc() const;
- uint64_t VRegB_51l() const; // vB_wide
+ uint64_t VRegB_51l() const; // vB_wide
// VRegC
+ int32_t VRegC() const;
int8_t VRegC_22b() const;
uint16_t VRegC_22c() const;
int16_t VRegC_22s() const;
@@ -322,6 +326,12 @@
return (kInstructionFlags[Opcode()] & 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 this instruction is a switch.
bool IsSwitch() const {
return (kInstructionFlags[Opcode()] & kSwitch) != 0;