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/build/Android.common.mk b/build/Android.common.mk
index 78743a7..5ca76ac 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -373,6 +373,7 @@
 
 
 LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \
+	src/dex_instruction.h \
 	src/heap.h \
 	src/indirect_reference_table.h \
 	src/instruction_set.h \
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;