summaryrefslogtreecommitdiffstats
path: root/runtime/dex_instruction.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/dex_instruction.h')
-rw-r--r--runtime/dex_instruction.h446
1 files changed, 446 insertions, 0 deletions
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
new file mode 100644
index 000000000..0407c5793
--- /dev/null
+++ b/runtime/dex_instruction.h
@@ -0,0 +1,446 @@
+/*
+ * 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_SRC_DEX_INSTRUCTION_H_
+#define ART_SRC_DEX_INSTRUCTION_H_
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "globals.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 {
+ 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);
+ };
+
+ // 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
+ 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
+ k51l, // op vAA, #+BBBBBBBBBBBBBBBB
+ };
+
+ enum Flags {
+ 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
+ };
+
+ enum VerifyFlag {
+ kVerifyNone = 0x00000,
+ kVerifyRegA = 0x00001,
+ kVerifyRegAWide = 0x00002,
+ kVerifyRegB = 0x00004,
+ kVerifyRegBField = 0x00008,
+ kVerifyRegBMethod = 0x00010,
+ kVerifyRegBNewInstance = 0x00020,
+ kVerifyRegBString = 0x00040,
+ kVerifyRegBType = 0x00080,
+ kVerifyRegBWide = 0x00100,
+ kVerifyRegC = 0x00200,
+ kVerifyRegCField = 0x00400,
+ kVerifyRegCNewArray = 0x00800,
+ kVerifyRegCType = 0x01000,
+ kVerifyRegCWide = 0x02000,
+ kVerifyArrayData = 0x04000,
+ kVerifyBranchTarget = 0x08000,
+ kVerifySwitchTargets = 0x10000,
+ kVerifyVarArg = 0x20000,
+ kVerifyVarArgRange = 0x40000,
+ kVerifyError = 0x80000,
+ };
+
+ // Decodes this instruction, populating its arguments.
+ 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 {
+ int result = kInstructionSizeInCodeUnits[Opcode()];
+ if (UNLIKELY(result < 0)) {
+ return SizeInCodeUnitsComplexOpcode();
+ } else {
+ return static_cast<size_t>(result);
+ }
+ }
+
+ // Reads an instruction out of the stream at the specified address.
+ static const Instruction* At(const uint16_t* code) {
+ DCHECK(code != NULL);
+ 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 {
+ 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 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
+ int32_t VRegA() const;
+ int8_t VRegA_10t() const;
+ uint8_t VRegA_10x() const;
+ uint4_t VRegA_11n() const;
+ uint8_t VRegA_11x() const;
+ uint4_t VRegA_12x() const;
+ int16_t VRegA_20t() const;
+ uint8_t VRegA_21c() const;
+ uint8_t VRegA_21h() const;
+ uint8_t VRegA_21s() const;
+ uint8_t VRegA_21t() const;
+ uint8_t VRegA_22b() const;
+ uint4_t VRegA_22c() const;
+ uint4_t VRegA_22s() const;
+ uint4_t VRegA_22t() const;
+ uint8_t VRegA_22x() const;
+ uint8_t VRegA_23x() const;
+ int32_t VRegA_30t() const;
+ uint8_t VRegA_31c() const;
+ uint8_t VRegA_31i() const;
+ uint8_t VRegA_31t() const;
+ uint16_t VRegA_32x() const;
+ uint4_t VRegA_35c() const;
+ uint8_t VRegA_3rc() const;
+ 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;
+ 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;
+ uint4_t VRegB_22s() const;
+ uint4_t VRegB_22t() const;
+ 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
+
+ // VRegC
+ int32_t VRegC() 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;
+
+ // Fills the given array with the 'arg' array of the instruction.
+ void GetArgs(uint32_t args[5]) const;
+
+ // Returns the opcode field of the instruction.
+ Code Opcode() const {
+ const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
+ int opcode = *insns & 0xFF;
+ return static_cast<Code>(opcode);
+ }
+
+ 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 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;
+ }
+
+ // Returns the format of the given opcode.
+ static Format FormatOf(Code opcode) {
+ return kInstructionFormats[opcode];
+ }
+
+ // Returns the flags for the given opcode.
+ static int FlagsOf(Code opcode) {
+ return kInstructionFlags[opcode];
+ }
+
+ // Returns true if this instruction is a branch.
+ bool IsBranch() const {
+ return (kInstructionFlags[Opcode()] & kBranch) != 0;
+ }
+
+ // Returns true if this instruction is a unconditional branch.
+ bool IsUnconditional() const {
+ 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;
+ }
+
+ // Returns true if this instruction can throw.
+ bool IsThrow() const {
+ return (kInstructionFlags[Opcode()] & kThrow) != 0;
+ }
+
+ // Determine if the instruction is any of 'return' instructions.
+ bool IsReturn() const {
+ return (kInstructionFlags[Opcode()] & 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 (kInstructionFlags[Opcode()] & kInvoke) != 0;
+ }
+
+ int GetVerifyTypeArgumentA() const {
+ return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegA | kVerifyRegAWide));
+ }
+
+ int GetVerifyTypeArgumentB() const {
+ return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegB | kVerifyRegBField | kVerifyRegBMethod |
+ kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType | kVerifyRegBWide));
+ }
+
+ int GetVerifyTypeArgumentC() const {
+ return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegC | kVerifyRegCField |
+ kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
+ }
+
+ int GetVerifyExtraFlags() const {
+ return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget |
+ kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgRange | kVerifyError));
+ }
+
+ // 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;
+
+ private:
+ size_t SizeInCodeUnitsComplexOpcode() const;
+
+ uint16_t Fetch16(size_t offset) const {
+ const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
+ return insns[offset];
+ }
+
+ uint32_t Fetch32(size_t offset) const {
+ return (Fetch16(offset) | ((uint32_t) Fetch16(offset + 1) << 16));
+ }
+
+ uint4_t InstA() const {
+ return static_cast<uint4_t>((Fetch16(0) >> 8) & 0x0f);
+ }
+
+ uint4_t InstB() const {
+ return static_cast<uint4_t>(Fetch16(0) >> 12);
+ }
+
+ uint8_t InstAA() const {
+ return static_cast<uint8_t>(Fetch16(0) >> 8);
+ }
+
+ 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.
+ */
+struct DecodedInstruction {
+ uint32_t vA;
+ uint32_t vB;
+ uint64_t vB_wide; /* for k51l */
+ uint32_t vC;
+ uint32_t arg[5]; /* vC/D/E/F/G in invoke or filled-new-array */
+ Instruction::Code opcode;
+
+ explicit DecodedInstruction(const Instruction* inst) {
+ inst->Decode(vA, vB, vB_wide, vC, arg);
+ opcode = inst->Opcode();
+ }
+};
+
+} // namespace art
+
+#endif // ART_SRC_DEX_INSTRUCTION_H_