Added first pass of verifier and supporting changes.

The verifier still needs to make a second pass through the code where it
checks the code flow. A TODO marks where it will be added.

Change-Id: I0abea5bad563776186df342d8132fb1ca8869652
diff --git a/src/class_linker.cc b/src/class_linker.cc
index e0461be..04a17cf 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1606,7 +1606,6 @@
     Method* method = klass->GetVirtualMethod(i);
     if (method->IsAbstract()) {
       LG << "AbstractMethodError";
-      method->code_off_ = 0xFFFFFFFF;
       // TODO: throw AbstractMethodError
     }
   }
diff --git a/src/dex_file.h b/src/dex_file.h
index 76b9c2f..2dcb3b2 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -229,7 +229,7 @@
 
       CatchHandlerIterator(const byte* handler_data) {
         current_data_ = handler_data;
-        remaining_count_ = DecodeUnsignedLeb128(&current_data_);
+        remaining_count_ = DecodeSignedLeb128(&current_data_);
 
         // If remaining_count_ is non-positive, then it is the negative of
         // the number of catch types, and the catches are followed by a
@@ -247,6 +247,10 @@
         return handler_;
       }
 
+      const byte* GetData() const {
+        return current_data_;
+      }
+
       void Next() {
         if (remaining_count_ > 0) {
           handler_.type_idx_ = DecodeUnsignedLeb128(&current_data_);
@@ -570,14 +574,14 @@
     *last_idx = idx;
   }
 
-  const TryItem* dexGetTryItems(const CodeItem& code_item, uint32_t offset) const {
+  static const TryItem* dexGetTryItems(const CodeItem& code_item, uint32_t offset) {
     const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_];
     return reinterpret_cast<const TryItem*>
         (RoundUp(reinterpret_cast<uint32_t>(insns_end_), 4)) + offset;
   }
 
   // Get the base of the encoded data for the given DexCode.
-  const byte* dexGetCatchHandlerData(const CodeItem& code_item, uint32_t offset) const {
+  static const byte* dexGetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
     const byte* handler_data = reinterpret_cast<const byte*>
         (dexGetTryItems(code_item, code_item.tries_size_));
     return handler_data + offset;
@@ -586,7 +590,7 @@
   // Find the handler associated with a given address, if any.
   // Initializes the given iterator and returns true if a match is
   // found. Returns end if there is no applicable handler.
-  CatchHandlerIterator dexFindCatchHandler(const CodeItem& code_item, uint32_t address) const {
+  static CatchHandlerIterator dexFindCatchHandler(const CodeItem& code_item, uint32_t address) {
     CatchHandlerItem handler;
     handler.address_ = -1;
     int32_t offset = -1;
@@ -619,9 +623,9 @@
     return CatchHandlerIterator();
   }
 
-  int32_t dexFindCatchHandlerOffset0(const CodeItem &code_item,
-                                     int32_t tries_size,
-                                     uint32_t address) const {
+  static int32_t dexFindCatchHandlerOffset0(const CodeItem &code_item,
+                                            int32_t tries_size,
+                                            uint32_t address) {
     // Note: Signed type is important for max and min.
     int32_t min = 0;
     int32_t max = tries_size - 1;
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
index d753204..39348ed 100644
--- a/src/dex_instruction.cc
+++ b/src/dex_instruction.cc
@@ -5,7 +5,7 @@
 namespace art {
 
 const char* const Instruction::kInstructionNames[] = {
-#define INSTRUCTION_NAME(o, c, pname, f, r, i, a) pname,
+#define INSTRUCTION_NAME(o, c, pname, f, r, i, a, v) pname,
 #include "dex_instruction_list.h"
   DEX_INSTRUCTION_LIST(INSTRUCTION_NAME)
 #undef DEX_INSTRUCTION_LIST
@@ -13,7 +13,7 @@
 };
 
 Instruction::InstructionFormat const Instruction::kInstructionFormats[] = {
-#define INSTRUCTION_FORMAT(o, c, p, format, r, i, a) format,
+#define INSTRUCTION_FORMAT(o, c, p, format, r, i, a, v) format,
 #include "dex_instruction_list.h"
   DEX_INSTRUCTION_LIST(INSTRUCTION_FORMAT)
 #undef DEX_INSTRUCTION_LIST
@@ -21,25 +21,185 @@
 };
 
 int const Instruction::kInstructionFlags[] = {
-#define INSTRUCTION_FLAGS(o, c, p, f, r, i, flags) flags,
+#define INSTRUCTION_FLAGS(o, c, p, f, r, i, flags, v) flags,
 #include "dex_instruction_list.h"
   DEX_INSTRUCTION_LIST(INSTRUCTION_FLAGS)
 #undef DEX_INSTRUCTION_LIST
 #undef INSTRUCTION_FLAGS
 };
 
+int const Instruction::kInstructionVerifyFlags[] = {
+#define INSTRUCTION_VERIFY_FLAGS(o, c, p, f, r, i, a, vflags) vflags,
+#include "dex_instruction_list.h"
+  DEX_INSTRUCTION_LIST(INSTRUCTION_VERIFY_FLAGS)
+#undef DEX_INSTRUCTION_LIST
+#undef INSTRUCTION_VERIFY_FLAGS
+};
+
+/*
+ * Handy macros for helping decode instructions.
+ */
+#define FETCH(_offset)      (insns[(_offset)])
+#define FETCH_u4(_offset)   (fetch_u4_impl((_offset), insns))
+#define INST_A(_insn)       (((uint16_t)(_insn) >> 8) & 0x0f)
+#define INST_B(_insn)       ((uint16_t)(_insn) >> 12)
+#define INST_AA(_insn)      ((_insn) >> 8)
+
+/* Helper for FETCH_u4, above. */
+static inline uint32_t fetch_u4_impl(uint32_t offset, const uint16_t* insns) {
+  return insns[offset] | ((uint32_t) insns[offset+1] << 16);
+}
+
+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;
+
+  switch (Format()) {
+    case k10x:       // op
+      /* nothing to do; copy the AA bits out for the verifier */
+      vA = INST_AA(insn);
+      break;
+    case k12x:       // op vA, vB
+      vA = INST_A(insn);
+      vB = INST_B(insn);
+      break;
+    case k11n:       // op vA, #+B
+      vA = INST_A(insn);
+      vB = (int32_t) (INST_B(insn) << 28) >> 28; // sign extend 4-bit value
+      break;
+    case k11x:       // op vAA
+      vA = INST_AA(insn);
+      break;
+    case k10t:       // op +AA
+      vA = (int8_t) INST_AA(insn);              // sign-extend 8-bit value
+      break;
+    case k20t:       // op +AAAA
+      vA = (int16_t) FETCH(1);                   // sign-extend 16-bit value
+      break;
+    case k21c:       // op vAA, thing@BBBB
+    case k22x:       // op vAA, vBBBB
+      vA = INST_AA(insn);
+      vB = FETCH(1);
+      break;
+    case k21s:       // op vAA, #+BBBB
+    case k21t:       // op vAA, +BBBB
+      vA = INST_AA(insn);
+      vB = (int16_t) FETCH(1);                   // sign-extend 16-bit value
+      break;
+    case k21h:       // op vAA, #+BBBB0000[00000000]
+      vA = INST_AA(insn);
+      /*
+       * The value should be treated as right-zero-extended, but we don't
+       * actually do that here. Among other things, we don't know if it's
+       * the top bits of a 32- or 64-bit value.
+       */
+      vB = FETCH(1);
+      break;
+    case k23x:       // op vAA, vBB, vCC
+      vA = INST_AA(insn);
+      vB = FETCH(1) & 0xff;
+      vC = FETCH(1) >> 8;
+      break;
+    case k22b:       // op vAA, vBB, #+CC
+      vA = INST_AA(insn);
+      vB = FETCH(1) & 0xff;
+      vC = (int8_t) (FETCH(1) >> 8);            // sign-extend 8-bit value
+      break;
+    case k22s:       // op vA, vB, #+CCCC
+    case k22t:       // op vA, vB, +CCCC
+      vA = INST_A(insn);
+      vB = INST_B(insn);
+      vC = (int16_t) FETCH(1);                   // sign-extend 16-bit value
+      break;
+    case k22c:       // op vA, vB, thing@CCCC
+      vA = INST_A(insn);
+      vB = INST_B(insn);
+      vC = FETCH(1);
+      break;
+    case k30t:       // op +AAAAAAAA
+      vA = FETCH_u4(1);                     // signed 32-bit value
+      break;
+    case k31t:       // op vAA, +BBBBBBBB
+    case k31c:       // op vAA, string@BBBBBBBB
+      vA = INST_AA(insn);
+      vB = FETCH_u4(1);                     // 32-bit value
+      break;
+    case k32x:       // op vAAAA, vBBBB
+      vA = FETCH(1);
+      vB = FETCH(2);
+      break;
+    case k31i:       // op vAA, #+BBBBBBBB
+      vA = INST_AA(insn);
+      vB = FETCH_u4(1);                     // signed 32-bit value
+      break;
+    case k35c:       // op {vC, vD, vE, vF, vG}, thing@BBBB
+      {
+        /*
+         * Note that the fields mentioned in the spec don't appear in
+         * their "usual" positions here compared to most formats. This
+         * was done so that the field names for the argument count and
+         * reference index match between this format and the corresponding
+         * range formats (3rc and friends).
+         *
+         * Bottom line: The argument count is always in vA, and the
+         * method constant (or equivalent) is always in vB.
+         */
+        uint16_t regList;
+        int count;
+
+        vA = INST_B(insn); // This is labeled A in the spec.
+        vB = FETCH(1);
+        regList = FETCH(2);
+
+        count = vA;
+
+        /*
+         * Copy the argument registers into the arg[] array, and
+         * also copy the first argument (if any) into vC. (The
+         * DecodedInstruction structure doesn't have separate
+         * fields for {vD, vE, vF, vG}, so there's no need to make
+         * copies of those.) Note that cases 5..2 fall through.
+         */
+        switch (count) {
+        case 5: arg[4] = INST_A(insn);
+        case 4: arg[3] = (regList >> 12) & 0x0f;
+        case 3: arg[2] = (regList >> 8) & 0x0f;
+        case 2: arg[1] = (regList >> 4) & 0x0f;
+        case 1: vC = arg[0] = regList & 0x0f; break;
+        case 0: break; // Valid, but no need to do anything.
+        default:
+          LOG(ERROR) << "Invalid arg count in 35c (" << count << ")";
+          return;
+        }
+      }
+      break;
+    case k3rc:       // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
+      vA = INST_AA(insn);
+      vB = FETCH(1);
+      vC = FETCH(2);
+        break;
+    case k51l:       // op vAA, #+BBBBBBBBBBBBBBBB
+      vA = INST_AA(insn);
+      vB_wide = FETCH_u4(1) | ((uint64_t) FETCH_u4(3) << 32);
+      break;
+    default:
+      LOG(ERROR) << "Can't decode unexpected format " << (int) Format() << " (op=" << opcode << ")";
+      return;
+  }
+}
+
 size_t Instruction::Size() const {
   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
-  size_t size = 0;
   if (*insns == kPackedSwitchSignature) {
-    size = 4 + insns[1] * 2;
+    return (4 + insns[1] * 2);
   } else if (*insns == kSparseSwitchSignature) {
-    size = 2 + insns[1] * 4;
+    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;
+    return (4 + (element_size * length + 1) / 2);
   } else {
     switch (Format()) {
       case k10x:
@@ -47,8 +207,7 @@
       case k11n:
       case k11x:
       case k10t:
-        size = 1;
-        break;
+        return 1;
       case k20t:
       case k22x:
       case k21t:
@@ -60,8 +219,7 @@
       case k22t:
       case k22s:
       case k22c:
-        size = 2;
-        break;
+        return 2;
       case k32x:
       case k30t:
       case k31t:
@@ -69,17 +227,14 @@
       case k31c:
       case k35c:
       case k3rc:
-        size = 3;
-        break;
+        return 3;
       case k51l:
-        size = 5;
-        break;
+        return 5;
       default:
         LOG(FATAL) << "Unreachable";
     }
   }
-  size *= sizeof(uint16_t);
-  return size;
+  return 0;
 }
 
 Instruction::Code Instruction::Opcode() const {
@@ -89,7 +244,7 @@
 }
 
 const Instruction* Instruction::Next() const {
-  size_t current_size = Size();
+  size_t current_size = Size() * sizeof(uint16_t);
   const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
   return reinterpret_cast<const Instruction*>(ptr + current_size);
 }
diff --git a/src/dex_instruction.h b/src/dex_instruction.h
index 617f818..8cf645d 100644
--- a/src/dex_instruction.h
+++ b/src/dex_instruction.h
@@ -19,7 +19,7 @@
   };
 
   enum Code {
-#define INSTRUCTION_ENUM(opcode, cname, p, f, r, i, a) cname = opcode,
+#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
@@ -63,6 +63,33 @@
     // TODO: kUnconditional
   };
 
+  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 bytes of this instruction.
   size_t Size() const;
 
@@ -78,9 +105,9 @@
   Code Opcode() const;
 
   // Reads an instruction out of the stream at the specified address.
-  static Instruction* At(byte* code) {
+  static const Instruction* At(const byte* code) {
     CHECK(code != NULL);
-    return reinterpret_cast<Instruction*>(code);
+    return reinterpret_cast<const Instruction*>(code);
   }
 
   // Returns the format of the current instruction.
@@ -93,6 +120,16 @@
     return (kInstructionFlags[Opcode()] & kBranch) != 0;
   }
 
+  // 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;
@@ -108,10 +145,30 @@
     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 | kVerifyRegBType | kVerifyRegBWide));
+  }
+
+  int GetVerifyExtraFlags() const {
+    return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget |
+             kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgRange | kVerifyError));
+  }
+
  private:
   static const char* const kInstructionNames[];
   static InstructionFormat const kInstructionFormats[];
   static int const kInstructionFlags[];
+  static int const kInstructionVerifyFlags[];
   DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
 };
 
diff --git a/src/dex_instruction_list.h b/src/dex_instruction_list.h
index b2c1fa6..009573e 100644
--- a/src/dex_instruction_list.h
+++ b/src/dex_instruction_list.h
@@ -1,259 +1,285 @@
 // Copyright 2011 Google Inc. All Rights Reserved.
 
 #define DEX_INSTRUCTION_LIST(V) \
-  V(0x00, NOP, "nop", k10x, false, kNone, kContinue) \
-  V(0x01, MOVE, "move", k12x, true, kNone, kContinue) \
-  V(0x02, MOVE_FROM16, "move/from16", k22x, true, kNone, kContinue) \
-  V(0x03, MOVE_16, "move/16", k32x, true, kNone, kContinue) \
-  V(0x04, MOVE_WIDE, "move-wide", k12x, true, kNone, kContinue) \
-  V(0x05, MOVE_WIDE_FROM16, "move-wide/from16", k22x, true, kNone, kContinue) \
-  V(0x06, MOVE_WIDE_16, "move-wide/16", k32x, true, kNone, kContinue) \
-  V(0x07, MOVE_OBJECT, "move-object", k12x, true, kNone, kContinue) \
-  V(0x08, MOVE_OBJECT_FROM16, "move-object/from16", k22x, true, kNone, kContinue) \
-  V(0x09, MOVE_OBJECT_16, "move-object/16", k32x, true, kNone, kContinue) \
-  V(0x0A, MOVE_RESULT, "move-result", k11x, true, kNone, kContinue) \
-  V(0x0B, MOVE_RESULT_WIDE, "move-result-wide", k11x, true, kNone, kContinue) \
-  V(0x0C, MOVE_RESULT_OBJECT, "move-result-object", k11x, true, kNone, kContinue) \
-  V(0x0D, MOVE_EXCEPTION, "move-exception", k11x, true, kNone, kContinue) \
-  V(0x0E, RETURN_VOID, "return-void", k10x, false, kNone, kReturn) \
-  V(0x0F, RETURN, "return", k11x, false, kNone, kReturn) \
-  V(0x10, RETURN_WIDE, "return-wide", k11x, false, kNone, kReturn) \
-  V(0x11, RETURN_OBJECT, "return-object", k11x, false, kNone, kReturn) \
-  V(0x12, CONST_4, "const/4", k11n, true, kNone, kContinue) \
-  V(0x13, CONST_16, "const/16", k21s, true, kNone, kContinue) \
-  V(0x14, CONST, "const", k31i, true, kNone, kContinue) \
-  V(0x15, CONST_HIGH16, "const/high16", k21h, true, kNone, kContinue) \
-  V(0x16, CONST_WIDE_16, "const-wide/16", k21s, true, kNone, kContinue) \
-  V(0x17, CONST_WIDE_32, "const-wide/32", k31i, true, kNone, kContinue) \
-  V(0x18, CONST_WIDE, "const-wide", k51l, true, kNone, kContinue) \
-  V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, true, kNone, kContinue) \
-  V(0x1A, CONST_STRING, "const-string", k21c, true, kStringRef, kContinue | kThrow) \
-  V(0x1B, CONST_STRING_JUMBO, "const-string/jumbo", k31c, true, kStringRef, kContinue | kThrow) \
-  V(0x1C, CONST_CLASS, "const-class", k21c, true, kTypeRef, kContinue | kThrow) \
-  V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, false, kNone, kContinue | kThrow) \
-  V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, false, kNone, kContinue | kThrow) \
-  V(0x1F, CHECK_CAST, "check-cast", k21c, true, kTypeRef, kContinue | kThrow) \
-  V(0x20, INSTANCE_OF, "instance-of", k22c, true, kTypeRef, kContinue | kThrow) \
-  V(0x21, ARRAY_LENGTH, "array-length", k12x, true, kNone, kContinue | kThrow) \
-  V(0x22, NEW_INSTANCE, "new-instance", k21c, true, kTypeRef, kContinue | kThrow) \
-  V(0x23, NEW_ARRAY, "new-array", k22c, true, kTypeRef, kContinue | kThrow) \
-  V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, false, kTypeRef, kContinue | kThrow) \
-  V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, false, kTypeRef, kContinue | kThrow) \
-  V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, false, kNone, kContinue) \
-  V(0x27, THROW, "throw", k11x, false, kNone, kThrow) \
-  V(0x28, GOTO, "goto", k10t, false, kNone, kBranch) \
-  V(0x29, GOTO_16, "goto/16", k20t, false, kNone, kBranch) \
-  V(0x2A, GOTO_32, "goto/32", k30t, false, kNone, kBranch) \
-  V(0x2B, PACKED_SWITCH, "packed-switch", k31t, false, kNone, kContinue | kSwitch) \
-  V(0x2C, SPARSE_SWITCH, "sparse-switch", k31t, false, kNone, kContinue | kSwitch) \
-  V(0x2D, CMPL_FLOAT, "cmpl-float", k23x, true, kNone, kContinue) \
-  V(0x2E, CMPG_FLOAT, "cmpg-float", k23x, true, kNone, kContinue) \
-  V(0x2F, CMPL_DOUBLE, "cmpl-double", k23x, true, kNone, kContinue) \
-  V(0x30, CMPG_DOUBLE, "cmpg-double", k23x, true, kNone, kContinue) \
-  V(0x31, CMP_LONG, "cmp-long", k23x, true, kNone, kContinue) \
-  V(0x32, IF_EQ, "if-eq", k22t, false, kNone, kContinue | kBranch) \
-  V(0x33, IF_NE, "if-ne", k22t, false, kNone, kContinue | kBranch) \
-  V(0x34, IF_LT, "if-lt", k22t, false, kNone, kContinue | kBranch) \
-  V(0x35, IF_GE, "if-ge", k22t, false, kNone, kContinue | kBranch) \
-  V(0x36, IF_GT, "if-gt", k22t, false, kNone, kContinue | kBranch) \
-  V(0x37, IF_LE, "if-le", k22t, false, kNone, kContinue | kBranch) \
-  V(0x38, IF_EQZ, "if-eqz", k21t, false, kNone, kContinue | kBranch) \
-  V(0x39, IF_NEZ, "if-nez", k21t, false, kNone, kContinue | kBranch) \
-  V(0x3A, IF_LTZ, "if-ltz", k21t, false, kNone, kContinue | kBranch) \
-  V(0x3B, IF_GEZ, "if-gez", k21t, false, kNone, kContinue | kBranch) \
-  V(0x3C, IF_GTZ, "if-gtz", k21t, false, kNone, kContinue | kBranch) \
-  V(0x3D, IF_LEZ, "if-lez", k21t, false, kNone, kContinue | kBranch) \
-  V(0x3E, UNUSED_3E, "unused-3e", k10x, false, kUnknown, 0) \
-  V(0x3F, UNUSED_3F, "unused-3f", k10x, false, kUnknown, 0) \
-  V(0x40, UNUSED_40, "unused-40", k10x, false, kUnknown, 0) \
-  V(0x41, UNUSED_41, "unused-41", k10x, false, kUnknown, 0) \
-  V(0x42, UNUSED_42, "unused-42", k10x, false, kUnknown, 0) \
-  V(0x43, UNUSED_43, "unused-43", k10x, false, kUnknown, 0) \
-  V(0x44, AGET, "aget", k23x, true, kNone, kContinue | kThrow) \
-  V(0x45, AGET_WIDE, "aget-wide", k23x, true, kNone, kContinue | kThrow) \
-  V(0x46, AGET_OBJECT, "aget-object", k23x, true, kNone, kContinue | kThrow) \
-  V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, true, kNone, kContinue | kThrow) \
-  V(0x48, AGET_BYTE, "aget-byte", k23x, true, kNone, kContinue | kThrow) \
-  V(0x49, AGET_CHAR, "aget-char", k23x, true, kNone, kContinue | kThrow) \
-  V(0x4A, AGET_SHORT, "aget-short", k23x, true, kNone, kContinue | kThrow) \
-  V(0x4B, APUT, "aput", k23x, false, kNone, kContinue | kThrow) \
-  V(0x4C, APUT_WIDE, "aput-wide", k23x, false, kNone, kContinue | kThrow) \
-  V(0x4D, APUT_OBJECT, "aput-object", k23x, false, kNone, kContinue | kThrow) \
-  V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, false, kNone, kContinue | kThrow) \
-  V(0x4F, APUT_BYTE, "aput-byte", k23x, false, kNone, kContinue | kThrow) \
-  V(0x50, APUT_CHAR, "aput-char", k23x, false, kNone, kContinue | kThrow) \
-  V(0x51, APUT_SHORT, "aput-short", k23x, false, kNone, kContinue | kThrow) \
-  V(0x52, IGET, "iget", k22c, true, kFieldRef, kContinue | kThrow) \
-  V(0x53, IGET_WIDE, "iget-wide", k22c, true, kFieldRef, kContinue | kThrow) \
-  V(0x54, IGET_OBJECT, "iget-object", k22c, true, kFieldRef, kContinue | kThrow) \
-  V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, true, kFieldRef, kContinue | kThrow) \
-  V(0x56, IGET_BYTE, "iget-byte", k22c, true, kFieldRef, kContinue | kThrow) \
-  V(0x57, IGET_CHAR, "iget-char", k22c, true, kFieldRef, kContinue | kThrow) \
-  V(0x58, IGET_SHORT, "iget-short", k22c, true, kFieldRef, kContinue | kThrow) \
-  V(0x59, IPUT, "iput", k22c, false, kFieldRef, kContinue | kThrow) \
-  V(0x5A, IPUT_WIDE, "iput-wide", k22c, false, kFieldRef, kContinue | kThrow) \
-  V(0x5B, IPUT_OBJECT, "iput-object", k22c, false, kFieldRef, kContinue | kThrow) \
-  V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, false, kFieldRef, kContinue | kThrow) \
-  V(0x5D, IPUT_BYTE, "iput-byte", k22c, false, kFieldRef, kContinue | kThrow) \
-  V(0x5E, IPUT_CHAR, "iput-char", k22c, false, kFieldRef, kContinue | kThrow) \
-  V(0x5F, IPUT_SHORT, "iput-short", k22c, false, kFieldRef, kContinue | kThrow) \
-  V(0x60, SGET, "sget", k21c, true, kFieldRef, kContinue | kThrow) \
-  V(0x61, SGET_WIDE, "sget-wide", k21c, true, kFieldRef, kContinue | kThrow) \
-  V(0x62, SGET_OBJECT, "sget-object", k21c, true, kFieldRef, kContinue | kThrow) \
-  V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, true, kFieldRef, kContinue | kThrow) \
-  V(0x64, SGET_BYTE, "sget-byte", k21c, true, kFieldRef, kContinue | kThrow) \
-  V(0x65, SGET_CHAR, "sget-char", k21c, true, kFieldRef, kContinue | kThrow) \
-  V(0x66, SGET_SHORT, "sget-short", k21c, true, kFieldRef, kContinue | kThrow) \
-  V(0x67, SPUT, "sput", k21c, false, kFieldRef, kContinue | kThrow) \
-  V(0x68, SPUT_WIDE, "sput-wide", k21c, false, kFieldRef, kContinue | kThrow) \
-  V(0x69, SPUT_OBJECT, "sput-object", k21c, false, kFieldRef, kContinue | kThrow) \
-  V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, false, kFieldRef, kContinue | kThrow) \
-  V(0x6B, SPUT_BYTE, "sput-byte", k21c, false, kFieldRef, kContinue | kThrow) \
-  V(0x6C, SPUT_CHAR, "sput-char", k21c, false, kFieldRef, kContinue | kThrow) \
-  V(0x6D, SPUT_SHORT, "sput-short", k21c, false, kFieldRef, kContinue | kThrow) \
-  V(0x6E, INVOKE_VIRTUAL, "invoke-virtual", k35c, false, kMethodRef, kContinue | kThrow | kInvoke) \
-  V(0x6F, INVOKE_SUPER, "invoke-super", k35c, false, kMethodRef, kContinue | kThrow | kInvoke) \
-  V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, false, kMethodRef, kContinue | kThrow | kInvoke) \
-  V(0x71, INVOKE_STATIC, "invoke-static", k35c, false, kMethodRef, kContinue | kThrow | kInvoke) \
-  V(0x72, INVOKE_INTERFACE, "invoke-interface", k35c, false, kMethodRef, kContinue | kThrow | kInvoke) \
-  V(0x73, UNUSED_73, "unused-73", k10x, false, kUnknown, 0) \
-  V(0x74, INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke) \
-  V(0x75, INVOKE_SUPER_RANGE, "invoke-super/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke) \
-  V(0x76, INVOKE_DIRECT_RANGE, "invoke-direct/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke) \
-  V(0x77, INVOKE_STATIC_RANGE, "invoke-static/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke) \
-  V(0x78, INVOKE_INTERFACE_RANGE, "invoke-interface/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke) \
-  V(0x79, UNUSED_79, "unused-79", k10x, false, kUnknown, 0) \
-  V(0x7A, UNUSED_7A, "unused-7a", k10x, false, kUnknown, 0) \
-  V(0x7B, NEG_INT, "neg-int", k12x, true, kNone, kContinue) \
-  V(0x7C, NOT_INT, "not-int", k12x, true, kNone, kContinue) \
-  V(0x7D, NEG_LONG, "neg-long", k12x, true, kNone, kContinue) \
-  V(0x7E, NOT_LONG, "not-long", k12x, true, kNone, kContinue) \
-  V(0x7F, NEG_FLOAT, "neg-float", k12x, true, kNone, kContinue) \
-  V(0x80, NEG_DOUBLE, "neg-double", k12x, true, kNone, kContinue) \
-  V(0x81, INT_TO_LONG, "int-to-long", k12x, true, kNone, kContinue) \
-  V(0x82, INT_TO_FLOAT, "int-to-float", k12x, true, kNone, kContinue) \
-  V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, true, kNone, kContinue) \
-  V(0x84, LONG_TO_INT, "long-to-int", k12x, true, kNone, kContinue) \
-  V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, true, kNone, kContinue) \
-  V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, true, kNone, kContinue) \
-  V(0x87, FLOAT_TO_INT, "float-to-int", k12x, true, kNone, kContinue) \
-  V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, true, kNone, kContinue) \
-  V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, true, kNone, kContinue) \
-  V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, true, kNone, kContinue) \
-  V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, true, kNone, kContinue) \
-  V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, true, kNone, kContinue) \
-  V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, true, kNone, kContinue) \
-  V(0x8E, INT_TO_CHAR, "int-to-char", k12x, true, kNone, kContinue) \
-  V(0x8F, INT_TO_SHORT, "int-to-short", k12x, true, kNone, kContinue) \
-  V(0x90, ADD_INT, "add-int", k23x, true, kNone, kContinue) \
-  V(0x91, SUB_INT, "sub-int", k23x, true, kNone, kContinue) \
-  V(0x92, MUL_INT, "mul-int", k23x, true, kNone, kContinue) \
-  V(0x93, DIV_INT, "div-int", k23x, true, kNone, kContinue | kThrow) \
-  V(0x94, REM_INT, "rem-int", k23x, true, kNone, kContinue | kThrow) \
-  V(0x95, AND_INT, "and-int", k23x, true, kNone, kContinue) \
-  V(0x96, OR_INT, "or-int", k23x, true, kNone, kContinue) \
-  V(0x97, XOR_INT, "xor-int", k23x, true, kNone, kContinue) \
-  V(0x98, SHL_INT, "shl-int", k23x, true, kNone, kContinue) \
-  V(0x99, SHR_INT, "shr-int", k23x, true, kNone, kContinue) \
-  V(0x9A, USHR_INT, "ushr-int", k23x, true, kNone, kContinue) \
-  V(0x9B, ADD_LONG, "add-long", k23x, true, kNone, kContinue) \
-  V(0x9C, SUB_LONG, "sub-long", k23x, true, kNone, kContinue) \
-  V(0x9D, MUL_LONG, "mul-long", k23x, true, kNone, kContinue) \
-  V(0x9E, DIV_LONG, "div-long", k23x, true, kNone, kContinue | kThrow) \
-  V(0x9F, REM_LONG, "rem-long", k23x, true, kNone, kContinue | kThrow) \
-  V(0xA0, AND_LONG, "and-long", k23x, true, kNone, kContinue) \
-  V(0xA1, OR_LONG, "or-long", k23x, true, kNone, kContinue) \
-  V(0xA2, XOR_LONG, "xor-long", k23x, true, kNone, kContinue) \
-  V(0xA3, SHL_LONG, "shl-long", k23x, true, kNone, kContinue) \
-  V(0xA4, SHR_LONG, "shr-long", k23x, true, kNone, kContinue) \
-  V(0xA5, USHR_LONG, "ushr-long", k23x, true, kNone, kContinue) \
-  V(0xA6, ADD_FLOAT, "add-float", k23x, true, kNone, kContinue) \
-  V(0xA7, SUB_FLOAT, "sub-float", k23x, true, kNone, kContinue) \
-  V(0xA8, MUL_FLOAT, "mul-float", k23x, true, kNone, kContinue) \
-  V(0xA9, DIV_FLOAT, "div-float", k23x, true, kNone, kContinue) \
-  V(0xAA, REM_FLOAT, "rem-float", k23x, true, kNone, kContinue) \
-  V(0xAB, ADD_DOUBLE, "add-double", k23x, true, kNone, kContinue) \
-  V(0xAC, SUB_DOUBLE, "sub-double", k23x, true, kNone, kContinue) \
-  V(0xAD, MUL_DOUBLE, "mul-double", k23x, true, kNone, kContinue) \
-  V(0xAE, DIV_DOUBLE, "div-double", k23x, true, kNone, kContinue) \
-  V(0xAF, REM_DOUBLE, "rem-double", k23x, true, kNone, kContinue) \
-  V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, true, kNone, kContinue) \
-  V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, true, kNone, kContinue) \
-  V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, true, kNone, kContinue) \
-  V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, true, kNone, kContinue | kThrow) \
-  V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, true, kNone, kContinue | kThrow) \
-  V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, true, kNone, kContinue) \
-  V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, true, kNone, kContinue) \
-  V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, true, kNone, kContinue) \
-  V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, true, kNone, kContinue) \
-  V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, true, kNone, kContinue) \
-  V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, true, kNone, kContinue) \
-  V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, true, kNone, kContinue) \
-  V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, true, kNone, kContinue) \
-  V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, true, kNone, kContinue) \
-  V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, true, kNone, kContinue | kThrow) \
-  V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, true, kNone, kContinue | kThrow) \
-  V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, true, kNone, kContinue) \
-  V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, true, kNone, kContinue) \
-  V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, true, kNone, kContinue) \
-  V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, true, kNone, kContinue) \
-  V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, true, kNone, kContinue) \
-  V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, true, kNone, kContinue) \
-  V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, true, kNone, kContinue) \
-  V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, true, kNone, kContinue) \
-  V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, true, kNone, kContinue) \
-  V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, true, kNone, kContinue) \
-  V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, true, kNone, kContinue) \
-  V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, true, kNone, kContinue) \
-  V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, true, kNone, kContinue) \
-  V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, true, kNone, kContinue) \
-  V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, true, kNone, kContinue) \
-  V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, true, kNone, kContinue) \
-  V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, true, kNone, kContinue) \
-  V(0xD1, RSUB_INT, "rsub-int", k22s, true, kNone, kContinue) \
-  V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, true, kNone, kContinue) \
-  V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, true, kNone, kContinue | kThrow) \
-  V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, true, kNone, kContinue | kThrow) \
-  V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, true, kNone, kContinue) \
-  V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, true, kNone, kContinue) \
-  V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, true, kNone, kContinue) \
-  V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, true, kNone, kContinue) \
-  V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, true, kNone, kContinue) \
-  V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, true, kNone, kContinue) \
-  V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, true, kNone, kContinue | kThrow) \
-  V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, true, kNone, kContinue | kThrow) \
-  V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, true, kNone, kContinue) \
-  V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, true, kNone, kContinue) \
-  V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, true, kNone, kContinue) \
-  V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue) \
-  V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue) \
-  V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue) \
-  V(0xE3, UNUSED_E3, "unused-e3", k10x, false, kUnknown, 0) \
-  V(0xE4, UNUSED_E4, "unused-e4", k10x, false, kUnknown, 0) \
-  V(0xE5, UNUSED_E5, "unused-e5", k10x, false, kUnknown, 0) \
-  V(0xE6, UNUSED_E6, "unused-e6", k10x, false, kUnknown, 0) \
-  V(0xE7, UNUSED_E7, "unused-e7", k10x, false, kUnknown, 0) \
-  V(0xE8, UNUSED_E8, "unused-e8", k10x, false, kUnknown, 0) \
-  V(0xE9, UNUSED_E9, "unused-e9", k10x, false, kUnknown, 0) \
-  V(0xEA, UNUSED_EA, "unused-ea", k10x, false, kUnknown, 0) \
-  V(0xEB, UNUSED_EB, "unused-eb", k10x, false, kUnknown, 0) \
-  V(0xEC, UNUSED_EC, "unused-ec", k10x, false, kUnknown, 0) \
-  V(0xED, UNUSED_ED, "unused-ed", k10x, false, kUnknown, 0) \
-  V(0xEE, UNUSED_EE, "unused-ee", k10x, false, kUnknown, 0) \
-  V(0xEF, UNUSED_EF, "unused-ef", k10x, false, kUnknown, 0) \
-  V(0xF0, UNUSED_F0, "unused-f0", k10x, false, kUnknown, 0) \
-  V(0xF1, UNUSED_F1, "unused-f1", k10x, false, kUnknown, 0) \
-  V(0xF2, UNUSED_F2, "unused-f2", k10x, false, kUnknown, 0) \
-  V(0xF3, UNUSED_F3, "unused-f3", k10x, false, kUnknown, 0) \
-  V(0xF4, UNUSED_F4, "unused-f4", k10x, false, kUnknown, 0) \
-  V(0xF5, UNUSED_F5, "unused-f5", k10x, false, kUnknown, 0) \
-  V(0xF6, UNUSED_F6, "unused-f6", k10x, false, kUnknown, 0) \
-  V(0xF7, UNUSED_F7, "unused-f7", k10x, false, kUnknown, 0) \
-  V(0xF8, UNUSED_F8, "unused-f8", k10x, false, kUnknown, 0) \
-  V(0xF9, UNUSED_F9, "unused-f9", k10x, false, kUnknown, 0) \
-  V(0xFA, UNUSED_FA, "unused-fa", k10x, false, kUnknown, 0) \
-  V(0xFB, UNUSED_FB, "unused-fb", k10x, false, kUnknown, 0) \
-  V(0xFC, UNUSED_FC, "unused-fc", k10x, false, kUnknown, 0) \
-  V(0xFD, UNUSED_FD, "unused-fd", k10x, false, kUnknown, 0) \
-  V(0xFE, UNUSED_FE, "unused-fe", k10x, false, kUnknown, 0) \
-  V(0xFF, UNUSED_FF, "unused-ff", k10x, false, kUnknown, 0)
+  V(0x00, NOP, "nop", k10x, false, kNone, kContinue, kVerifyNone) \
+  V(0x01, MOVE, "move", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x02, MOVE_FROM16, "move/from16", k22x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x03, MOVE_16, "move/16", k32x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x04, MOVE_WIDE, "move-wide", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x05, MOVE_WIDE_FROM16, "move-wide/from16", k22x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x06, MOVE_WIDE_16, "move-wide/16", k32x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x07, MOVE_OBJECT, "move-object", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x08, MOVE_OBJECT_FROM16, "move-object/from16", k22x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x09, MOVE_OBJECT_16, "move-object/16", k32x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x0A, MOVE_RESULT, "move-result", k11x, true, kNone, kContinue, kVerifyRegA) \
+  V(0x0B, MOVE_RESULT_WIDE, "move-result-wide", k11x, true, kNone, kContinue, kVerifyRegAWide) \
+  V(0x0C, MOVE_RESULT_OBJECT, "move-result-object", k11x, true, kNone, kContinue, kVerifyRegA) \
+  V(0x0D, MOVE_EXCEPTION, "move-exception", k11x, true, kNone, kContinue, kVerifyRegA) \
+  V(0x0E, RETURN_VOID, "return-void", k10x, false, kNone, kReturn, kVerifyNone) \
+  V(0x0F, RETURN, "return", k11x, false, kNone, kReturn, kVerifyRegA) \
+  V(0x10, RETURN_WIDE, "return-wide", k11x, false, kNone, kReturn, kVerifyRegAWide) \
+  V(0x11, RETURN_OBJECT, "return-object", k11x, false, kNone, kReturn, kVerifyRegA) \
+  V(0x12, CONST_4, "const/4", k11n, true, kNone, kContinue, kVerifyRegA) \
+  V(0x13, CONST_16, "const/16", k21s, true, kNone, kContinue, kVerifyRegA) \
+  V(0x14, CONST, "const", k31i, true, kNone, kContinue, kVerifyRegA) \
+  V(0x15, CONST_HIGH16, "const/high16", k21h, true, kNone, kContinue, kVerifyRegA) \
+  V(0x16, CONST_WIDE_16, "const-wide/16", k21s, true, kNone, kContinue, kVerifyRegAWide) \
+  V(0x17, CONST_WIDE_32, "const-wide/32", k31i, true, kNone, kContinue, kVerifyRegAWide) \
+  V(0x18, CONST_WIDE, "const-wide", k51l, true, kNone, kContinue, kVerifyRegAWide) \
+  V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, true, kNone, kContinue, kVerifyRegAWide) \
+  V(0x1A, CONST_STRING, "const-string", k21c, true, kStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \
+  V(0x1B, CONST_STRING_JUMBO, "const-string/jumbo", k31c, true, kStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \
+  V(0x1C, CONST_CLASS, "const-class", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \
+  V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, false, kNone, kContinue | kThrow, kVerifyRegA) \
+  V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, false, kNone, kContinue | kThrow, kVerifyRegA) \
+  V(0x1F, CHECK_CAST, "check-cast", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \
+  V(0x20, INSTANCE_OF, "instance-of", k22c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCType) \
+  V(0x21, ARRAY_LENGTH, "array-length", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+  V(0x22, NEW_INSTANCE, "new-instance", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBNewInstance) \
+  V(0x23, NEW_ARRAY, "new-array", k22c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCNewArray) \
+  V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, false, kTypeRef, kContinue | kThrow, kVerifyRegBType | kVerifyVarArg) \
+  V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, false, kTypeRef, kContinue | kThrow, kVerifyRegBType | kVerifyVarArgRange) \
+  V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, false, kNone, kContinue, kVerifyRegA | kVerifyArrayData) \
+  V(0x27, THROW, "throw", k11x, false, kNone, kThrow, kVerifyRegA) \
+  V(0x28, GOTO, "goto", k10t, false, kNone, kBranch, kVerifyBranchTarget) \
+  V(0x29, GOTO_16, "goto/16", k20t, false, kNone, kBranch, kVerifyBranchTarget) \
+  V(0x2A, GOTO_32, "goto/32", k30t, false, kNone, kBranch, kVerifyBranchTarget) \
+  V(0x2B, PACKED_SWITCH, "packed-switch", k31t, false, kNone, kContinue | kSwitch, kVerifyRegA | kVerifySwitchTargets) \
+  V(0x2C, SPARSE_SWITCH, "sparse-switch", k31t, false, kNone, kContinue | kSwitch, kVerifyRegA | kVerifySwitchTargets) \
+  V(0x2D, CMPL_FLOAT, "cmpl-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x2E, CMPG_FLOAT, "cmpg-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x2F, CMPL_DOUBLE, "cmpl-double", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x30, CMPG_DOUBLE, "cmpg-double", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x31, CMP_LONG, "cmp-long", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x32, IF_EQ, "if-eq", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x33, IF_NE, "if-ne", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x34, IF_LT, "if-lt", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x35, IF_GE, "if-ge", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x36, IF_GT, "if-gt", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x37, IF_LE, "if-le", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x38, IF_EQZ, "if-eqz", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x39, IF_NEZ, "if-nez", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x3A, IF_LTZ, "if-ltz", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x3B, IF_GEZ, "if-gez", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x3C, IF_GTZ, "if-gtz", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x3D, IF_LEZ, "if-lez", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x3E, UNUSED_3E, "unused-3e", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0x3F, UNUSED_3F, "unused-3f", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0x40, UNUSED_40, "unused-40", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0x41, UNUSED_41, "unused-41", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0x42, UNUSED_42, "unused-42", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0x43, UNUSED_43, "unused-43", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0x44, AGET, "aget", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x45, AGET_WIDE, "aget-wide", k23x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
+  V(0x46, AGET_OBJECT, "aget-object", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x48, AGET_BYTE, "aget-byte", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x49, AGET_CHAR, "aget-char", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x4A, AGET_SHORT, "aget-short", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x4B, APUT, "aput", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x4C, APUT_WIDE, "aput-wide", k23x, false, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
+  V(0x4D, APUT_OBJECT, "aput-object", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x4F, APUT_BYTE, "aput-byte", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x50, APUT_CHAR, "aput-char", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x51, APUT_SHORT, "aput-short", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x52, IGET, "iget", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x53, IGET_WIDE, "iget-wide", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
+  V(0x54, IGET_OBJECT, "iget-object", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x56, IGET_BYTE, "iget-byte", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x57, IGET_CHAR, "iget-char", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x58, IGET_SHORT, "iget-short", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x59, IPUT, "iput", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x5A, IPUT_WIDE, "iput-wide", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
+  V(0x5B, IPUT_OBJECT, "iput-object", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x5D, IPUT_BYTE, "iput-byte", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x5E, IPUT_CHAR, "iput-char", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x5F, IPUT_SHORT, "iput-short", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x60, SGET, "sget", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x61, SGET_WIDE, "sget-wide", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBField) \
+  V(0x62, SGET_OBJECT, "sget-object", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x64, SGET_BYTE, "sget-byte", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x65, SGET_CHAR, "sget-char", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x66, SGET_SHORT, "sget-short", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x67, SPUT, "sput", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x68, SPUT_WIDE, "sput-wide", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x69, SPUT_OBJECT, "sput-object", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x6B, SPUT_BYTE, "sput-byte", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x6C, SPUT_CHAR, "sput-char", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x6D, SPUT_SHORT, "sput-short", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+  V(0x6E, INVOKE_VIRTUAL, "invoke-virtual", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \
+  V(0x6F, INVOKE_SUPER, "invoke-super", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \
+  V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \
+  V(0x71, INVOKE_STATIC, "invoke-static", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \
+  V(0x72, INVOKE_INTERFACE, "invoke-interface", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \
+  V(0x73, UNUSED_73, "unused-73", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0x74, INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \
+  V(0x75, INVOKE_SUPER_RANGE, "invoke-super/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \
+  V(0x76, INVOKE_DIRECT_RANGE, "invoke-direct/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \
+  V(0x77, INVOKE_STATIC_RANGE, "invoke-static/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \
+  V(0x78, INVOKE_INTERFACE_RANGE, "invoke-interface/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \
+  V(0x79, UNUSED_79, "unused-79", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0x7A, UNUSED_7A, "unused-7a", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0x7B, NEG_INT, "neg-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x7C, NOT_INT, "not-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x7D, NEG_LONG, "neg-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x7E, NOT_LONG, "not-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x7F, NEG_FLOAT, "neg-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x80, NEG_DOUBLE, "neg-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x81, INT_TO_LONG, "int-to-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
+  V(0x82, INT_TO_FLOAT, "int-to-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
+  V(0x84, LONG_TO_INT, "long-to-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \
+  V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \
+  V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x87, FLOAT_TO_INT, "float-to-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
+  V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
+  V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \
+  V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \
+  V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x8E, INT_TO_CHAR, "int-to-char", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x8F, INT_TO_SHORT, "int-to-short", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x90, ADD_INT, "add-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x91, SUB_INT, "sub-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x92, MUL_INT, "mul-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x93, DIV_INT, "div-int", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x94, REM_INT, "rem-int", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x95, AND_INT, "and-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x96, OR_INT, "or-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x97, XOR_INT, "xor-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x98, SHL_INT, "shl-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x99, SHR_INT, "shr-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x9A, USHR_INT, "ushr-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x9B, ADD_LONG, "add-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x9C, SUB_LONG, "sub-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x9D, MUL_LONG, "mul-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x9E, DIV_LONG, "div-long", k23x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x9F, REM_LONG, "rem-long", k23x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xA0, AND_LONG, "and-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xA1, OR_LONG, "or-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xA2, XOR_LONG, "xor-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xA3, SHL_LONG, "shl-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
+  V(0xA4, SHR_LONG, "shr-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
+  V(0xA5, USHR_LONG, "ushr-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
+  V(0xA6, ADD_FLOAT, "add-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0xA7, SUB_FLOAT, "sub-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0xA8, MUL_FLOAT, "mul-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0xA9, DIV_FLOAT, "div-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0xAA, REM_FLOAT, "rem-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0xAB, ADD_DOUBLE, "add-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xAC, SUB_DOUBLE, "sub-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xAD, MUL_DOUBLE, "mul-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xAE, DIV_DOUBLE, "div-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xAF, REM_DOUBLE, "rem-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+  V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+  V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
+  V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
+  V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
+  V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xD1, RSUB_INT, "rsub-int", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+  V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+  V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+  V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+  V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0xE3, UNUSED_E3, "unused-e3", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xE4, UNUSED_E4, "unused-e4", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xE5, UNUSED_E5, "unused-e5", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xE6, UNUSED_E6, "unused-e6", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xE7, UNUSED_E7, "unused-e7", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xE8, UNUSED_E8, "unused-e8", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xE9, UNUSED_E9, "unused-e9", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xEA, UNUSED_EA, "unused-ea", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xEB, UNUSED_EB, "unused-eb", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xEC, UNUSED_EC, "unused-ec", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xED, UNUSED_ED, "unused-ed", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xEE, UNUSED_EE, "unused-ee", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xEF, UNUSED_EF, "unused-ef", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xF0, UNUSED_F0, "unused-f0", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xF1, UNUSED_F1, "unused-f1", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xF2, UNUSED_F2, "unused-f2", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xF3, UNUSED_F3, "unused-f3", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xF4, UNUSED_F4, "unused-f4", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xF5, UNUSED_F5, "unused-f5", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xF6, UNUSED_F6, "unused-f6", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xF7, UNUSED_F7, "unused-f7", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xF8, UNUSED_F8, "unused-f8", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xF9, UNUSED_F9, "unused-f9", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xFA, UNUSED_FA, "unused-fa", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xFB, UNUSED_FB, "unused-fb", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xFC, UNUSED_FC, "unused-fc", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xFD, UNUSED_FD, "unused-fd", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xFE, UNUSED_FE, "unused-fe", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xFF, UNUSED_FF, "unused-ff", k10x, false, kUnknown, 0, kVerifyError)
+
+#define DEX_INSTRUCTION_FORMAT_LIST(V) \
+  V(k10x) \
+  V(k12x) \
+  V(k11n) \
+  V(k11x) \
+  V(k10t) \
+  V(k20t) \
+  V(k22x) \
+  V(k21t) \
+  V(k21s) \
+  V(k21h) \
+  V(k21c) \
+  V(k23x) \
+  V(k22b) \
+  V(k22t) \
+  V(k22s) \
+  V(k22c) \
+  V(k32x) \
+  V(k30t) \
+  V(k31t) \
+  V(k31i) \
+  V(k31c) \
+  V(k35c) \
+  V(k3rc) \
+  V(k51l)
diff --git a/src/dex_instruction_visitor.h b/src/dex_instruction_visitor.h
index 73b4b3e..6a6bc3e 100644
--- a/src/dex_instruction_visitor.h
+++ b/src/dex_instruction_visitor.h
@@ -11,17 +11,17 @@
 template<typename T>
 class DexInstructionVisitor {
  public:
-  void Visit(uint16_t* code, size_t size) {
+  void Visit(const uint16_t* code, size_t size) {
     T* derived = static_cast<T*>(this);
-    byte* ptr = reinterpret_cast<byte*>(code);
-    byte* end = ptr + size;
+    const byte* ptr = reinterpret_cast<const byte*>(code);
+    const byte* end = ptr + size;
     while (ptr != end) {
-      Instruction* inst = Instruction::At(ptr);
+      const Instruction* inst = Instruction::At(ptr);
       switch (inst->Opcode()) {
-#define INSTRUCTION_CASE(o, cname, p, f, r, i, a)  \
-        case Instruction::cname: {                 \
-          derived->Do_ ## cname(inst);             \
-          break;                                   \
+#define INSTRUCTION_CASE(o, cname, p, f, r, i, a, v)  \
+        case Instruction::cname: {                    \
+          derived->Do_ ## cname(inst);                \
+          break;                                      \
         }
 #include "dex_instruction_list.h"
         DEX_INSTRUCTION_LIST(INSTRUCTION_CASE)
@@ -30,17 +30,17 @@
         default:
           CHECK(true);
       }
-      ptr += inst->Size();
+      ptr += inst->Size() * sizeof(uint16_t);
       CHECK_LE(ptr, end);
     }
   }
 
  private:
   // Specific handlers for each instruction.
-#define INSTRUCTION_VISITOR(o, cname, p, f, r, i, a)    \
-  void Do_ ## cname(Instruction* inst) {                \
-    T* derived = static_cast<T*>(this);                 \
-    derived->Do_Default(inst);                          \
+#define INSTRUCTION_VISITOR(o, cname, p, f, r, i, a, v)    \
+  void Do_ ## cname(const Instruction* inst) {             \
+    T* derived = static_cast<T*>(this);                    \
+    derived->Do_Default(inst);                             \
   }
 #include "dex_instruction_list.h"
   DEX_INSTRUCTION_LIST(INSTRUCTION_VISITOR)
@@ -48,11 +48,12 @@
 #undef INSTRUCTION_VISITOR
 
   // The default instruction handler.
-  void Do_Default(Instruction* inst) {
+  void Do_Default(const Instruction* inst) {
     return;
   }
 };
 
+
 }  // namespace art
 
 #endif  // ART_SRC_DEX_INSTRUCTION_VISITOR_H_
diff --git a/src/dex_instruction_visitor_test.cc b/src/dex_instruction_visitor_test.cc
index ff24e52..0edf160 100644
--- a/src/dex_instruction_visitor_test.cc
+++ b/src/dex_instruction_visitor_test.cc
@@ -20,34 +20,34 @@
 
   CountVisitor() : count_(0) {}
 
-  void Do_Default(Instruction* inst) {
+  void Do_Default(const Instruction* inst) {
     ++count_;
   }
 };
 
 TEST(InstructionTest, Count) {
   CountVisitor v0;
-  uint16_t c0[] = {};
+  const uint16_t c0[] = {};
   v0.Visit(c0, sizeof(c0));
   EXPECT_EQ(0, v0.count_);
 
   CountVisitor v1;
-  uint16_t c1[] = { 0 };
+  const uint16_t c1[] = { 0 };
   v1.Visit(c1, sizeof(c1));
   EXPECT_EQ(1, v1.count_);
 
   CountVisitor v2;
-  uint16_t c2[] = { 0, 0 };
+  const uint16_t c2[] = { 0, 0 };
   v2.Visit(c2, sizeof(c2));
   EXPECT_EQ(2, v2.count_);
 
   CountVisitor v3;
-  uint16_t c3[] = { 0, 0, 0, };
+  const uint16_t c3[] = { 0, 0, 0, };
   v3.Visit(c3, sizeof(c3));
   EXPECT_EQ(3, v3.count_);
 
   CountVisitor v4;
-  uint16_t c4[] = { 0, 0, 0, 0  };
+  const uint16_t c4[] = { 0, 0, 0, 0  };
   v4.Visit(c4, sizeof(c4));
   EXPECT_EQ(4, v4.count_);
 }
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index f55b20e..e0702b7 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -1,5 +1,9 @@
 // Copyright 2011 Google Inc. All Rights Reserved.
 
+#include "class_linker.h"
+#include "dex_file.h"
+#include "dex_instruction.h"
+#include "dex_instruction_visitor.h"
 #include "dex_verifier.h"
 
 #include <iostream>
@@ -9,6 +13,620 @@
 
 namespace art {
 
+/*
+ * Returns "true" if the flags indicate that this address holds the start
+ * of an instruction.
+ */
+inline bool InsnIsOpcode(const uint32_t insn_flags[], int addr) {
+  return (insn_flags[addr] & DexVerify::kInsnFlagWidthMask) != 0;
+}
+
+/*
+ * Extract the unsigned 16-bit instruction width from "flags".
+ */
+inline int InsnGetWidth(const uint32_t insn_flags[], int addr) {
+  return insn_flags[addr] & DexVerify::kInsnFlagWidthMask;
+}
+
+/*
+ * Changed?
+ */
+inline bool InsnIsChanged(const uint32_t insn_flags[], int addr) {
+    return (insn_flags[addr] & DexVerify::kInsnFlagChanged) != 0;
+}
+inline void InsnSetChanged(uint32_t insn_flags[], int addr, bool changed) {
+  if (changed)
+    insn_flags[addr] |= DexVerify::kInsnFlagChanged;
+  else
+    insn_flags[addr] &= ~DexVerify::kInsnFlagChanged;
+}
+
+/*
+ * Visited?
+ */
+inline bool InsnIsVisited(const uint32_t insn_flags[], int addr) {
+    return (insn_flags[addr] & DexVerify::kInsnFlagVisited) != 0;
+}
+inline void InsnSetVisited(uint32_t insn_flags[], int addr, bool changed) {
+  if (changed)
+    insn_flags[addr] |= DexVerify::kInsnFlagVisited;
+  else
+    insn_flags[addr] &= ~DexVerify::kInsnFlagVisited;
+}
+
+/*
+ * Visited or changed?
+ */
+inline bool InsnIsVisitedOrChanged(const uint32_t insn_flags[], int addr) {
+  return (insn_flags[addr] & (DexVerify::kInsnFlagVisited |
+                              DexVerify::kInsnFlagChanged)) != 0;
+}
+
+/*
+ * In a "try" block?
+ */
+inline bool InsnIsInTry(const uint32_t insn_flags[], int addr) {
+  return (insn_flags[addr] & DexVerify::kInsnFlagInTry) != 0;
+}
+inline void InsnSetInTry(uint32_t insn_flags[], int addr, bool inTry) {
+  insn_flags[addr] |= DexVerify::kInsnFlagInTry;
+}
+
+/*
+ * Instruction is a branch target or exception handler?
+ */
+inline bool InsnIsBranchTarget(const uint32_t insn_flags[], int addr) {
+  return (insn_flags[addr] & DexVerify::kInsnFlagBranchTarget) != 0;
+}
+inline void InsnSetBranchTarget(uint32_t insn_flags[], int addr, bool isBranch)
+{
+  insn_flags[addr] |= DexVerify::kInsnFlagBranchTarget;
+}
+
+/*
+ * Instruction is a GC point?
+ */
+inline bool InsnIsGcPoint(const uint32_t insn_flags[], int addr) {
+  return (insn_flags[addr] & DexVerify::kInsnFlagGcPoint) != 0;
+}
+inline void InsnSetGcPoint(uint32_t insn_flags[], int addr, bool isGcPoint) {
+  insn_flags[addr] |= DexVerify::kInsnFlagGcPoint;
+}
+
+
+/*
+ * Extract the relative offset from a branch instruction.
+ *
+ * Returns "false" on failure (e.g. this isn't a branch instruction).
+ */
+bool GetBranchOffset(const DexFile::CodeItem* code_item,
+    const uint32_t insn_flags[], int cur_offset, int32_t* pOffset,
+    bool* pConditional, bool* selfOkay) {
+  const uint16_t* insns = code_item->insns_ + cur_offset;
+
+  switch (*insns & 0xff) {
+    case Instruction::GOTO:
+      *pOffset = ((int16_t) *insns) >> 8;
+      *pConditional = false;
+      *selfOkay = false;
+      break;
+    case Instruction::GOTO_32:
+      *pOffset = insns[1] | (((uint32_t) insns[2]) << 16);
+      *pConditional = false;
+      *selfOkay = true;
+      break;
+    case Instruction::GOTO_16:
+      *pOffset = (int16_t) insns[1];
+      *pConditional = false;
+      *selfOkay = false;
+      break;
+    case Instruction::IF_EQ:
+    case Instruction::IF_NE:
+    case Instruction::IF_LT:
+    case Instruction::IF_GE:
+    case Instruction::IF_GT:
+    case Instruction::IF_LE:
+    case Instruction::IF_EQZ:
+    case Instruction::IF_NEZ:
+    case Instruction::IF_LTZ:
+    case Instruction::IF_GEZ:
+    case Instruction::IF_GTZ:
+    case Instruction::IF_LEZ:
+      *pOffset = (int16_t) insns[1];
+      *pConditional = true;
+      *selfOkay = false;
+      break;
+    default:
+      return false;
+      break;
+  }
+
+  return true;
+}
+
+
+/*
+ * Verify an array data table.  "cur_offset" is the offset of the
+ * fill-array-data instruction.
+ */
+static bool CheckArrayData(const DexFile::CodeItem* code_item,
+    uint32_t cur_offset) {
+  const uint32_t insn_count = code_item->insns_size_;
+  const uint16_t* insns = code_item->insns_ + cur_offset;
+  const uint16_t* array_data;
+  int32_t array_data_offset;
+
+  assert(cur_offset < insn_count);
+
+  /* make sure the start of the array data table is in range */
+  array_data_offset = insns[1] | (((int32_t) insns[2]) << 16);
+  if ((int32_t) cur_offset + array_data_offset < 0 ||
+      cur_offset + array_data_offset + 2 >= insn_count)
+  {
+    LOG(ERROR) << "VFY: invalid array data start: at " << cur_offset
+               << ", data offset " << array_data_offset << ", count "
+               << insn_count;
+    return false;
+  }
+
+  /* offset to array data table is a relative branch-style offset */
+  array_data = insns + array_data_offset;
+
+  /* make sure the table is 32-bit aligned */
+  if ((((uint32_t) array_data) & 0x03) != 0) {
+    LOG(ERROR) << "VFY: unaligned array data table: at " << cur_offset
+               << ", data offset " << array_data_offset;
+    return false;
+  }
+
+  uint32_t value_width = array_data[1];
+  uint32_t value_count = *(uint32_t*) (&array_data[2]);
+  uint32_t table_size = 4 + (value_width * value_count + 1) / 2;
+
+  /* make sure the end of the switch is in range */
+  if (cur_offset + array_data_offset + table_size > insn_count) {
+    LOG(ERROR) << "VFY: invalid array data end: at " << cur_offset
+               << ", data offset " << array_data_offset << ", end "
+               << cur_offset + array_data_offset + table_size << ", count "
+               << insn_count;
+    return false;
+  }
+
+  return true;
+}
+
+/*
+ * Perform static checks on a "new-instance" instruction.  Specifically,
+ * make sure the class reference isn't for an array class.
+ *
+ * We don't need the actual class, just a pointer to the class name.
+ */
+static bool CheckNewInstance(const DexFile* dex_file, uint32_t idx) {
+  if (idx >= dex_file->GetHeader().type_ids_size_) {
+    LOG(ERROR) << "VFY: bad type index " << idx << " (max "
+               << dex_file->GetHeader().type_ids_size_ << ")";
+    return false;
+  }
+
+  const char* descriptor = dex_file->dexStringByTypeIdx(idx);
+  if (descriptor[0] != 'L') {
+    LOG(ERROR) << "VFY: can't call new-instance on type '"
+               << descriptor << "'";
+    return false;
+  }
+
+  return true;
+}
+
+/*
+ * Perform static checks on a "new-array" instruction.  Specifically, make
+ * sure they aren't creating an array of arrays that causes the number of
+ * dimensions to exceed 255.
+ */
+static bool CheckNewArray(const DexFile* dex_file, uint32_t idx) {
+  if (idx >= dex_file->GetHeader().type_ids_size_) {
+    LOG(ERROR) << "VFY: bad type index " << idx << " (max "
+               << dex_file->GetHeader().type_ids_size_ << ")";
+    return false;
+  }
+
+  int bracket_count = 0;
+  const char* descriptor = dex_file->dexStringByTypeIdx(idx);
+  const char* cp = descriptor;
+  while (*cp++ == '[')
+    bracket_count++;
+
+  if (bracket_count == 0) {
+    /* The given class must be an array type. */
+    LOG(ERROR) << "VFY: can't new-array class '" << descriptor
+               << "' (not an array)";
+    return false;
+  } else if (bracket_count > 255) {
+    /* It is illegal to create an array of more than 255 dimensions. */
+    LOG(ERROR) << "VFY: can't new-array class '" << descriptor
+               << "' (exceeds limit)";
+    return false;
+  }
+
+  return true;
+}
+
+/*
+ * Perform static checks on an instruction that takes a class constant.
+ * Ensure that the class index is in the valid range.
+ */
+static bool CheckTypeIndex(const DexFile* dex_file, uint32_t idx) {
+  if (idx >= dex_file->GetHeader().type_ids_size_) {
+    LOG(ERROR) << "VFY: bad type index " << idx << " (max "
+               << dex_file->GetHeader().type_ids_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+/*
+ * Perform static checks on a field get or set instruction.  All we do
+ * here is ensure that the field index is in the valid range.
+ */
+static bool CheckFieldIndex(const DexFile* dex_file, uint32_t idx) {
+  if (idx >= dex_file->GetHeader().field_ids_size_) {
+    LOG(ERROR) << "VFY: bad field index " << idx << " (max "
+               << dex_file->GetHeader().field_ids_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+/*
+ * Perform static checks on a method invocation instruction.  All we do
+ * here is ensure that the method index is in the valid range.
+ */
+static bool CheckMethodIndex(const DexFile* dex_file, uint32_t idx) {
+  if (idx >= dex_file->GetHeader().method_ids_size_) {
+    LOG(ERROR) << "VFY: bad method index " << idx << " (max "
+               << dex_file->GetHeader().method_ids_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+/*
+ * Ensure that the string index is in the valid range.
+ */
+static bool CheckStringIndex(const DexFile* dex_file, uint32_t idx) {
+  if (idx >= dex_file->GetHeader().string_ids_size_) {
+    LOG(ERROR) << "VFY: bad string index " << idx << " (max "
+               << dex_file->GetHeader().string_ids_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+/*
+ * Ensure that the register index is valid for this code item.
+ */
+static bool CheckRegisterIndex(const DexFile::CodeItem* code_item, uint32_t idx)
+{
+  if (idx >= code_item->registers_size_) {
+    LOG(ERROR) << "VFY: register index out of range (" << idx << " >= "
+               << code_item->registers_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+/*
+ * Ensure that the wide register index is valid for this code item.
+ */
+static bool CheckWideRegisterIndex(const DexFile::CodeItem* code_item,
+    uint32_t idx) {
+  if (idx + 1 >= code_item->registers_size_) {
+    LOG(ERROR) << "VFY: wide register index out of range (" << idx
+               << "+1 >= " << code_item->registers_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+/*
+ * Check the register indices used in a "vararg" instruction, such as
+ * invoke-virtual or filled-new-array.
+ *
+ * vA holds word count (0-5), args[] have values.
+ *
+ * There are some tests we don't do here, e.g. we don't try to verify
+ * that invoking a method that takes a double is done with consecutive
+ * registers.  This requires parsing the target method signature, which
+ * we will be doing later on during the code flow analysis.
+ */
+static bool CheckVarArgRegs(const DexFile::CodeItem* code_item, uint32_t vA,
+    uint32_t arg[]) {
+  uint16_t registers_size = code_item->registers_size_;
+  uint32_t idx;
+
+  if (vA > 5) {
+    LOG(ERROR) << "VFY: invalid arg count (" << vA << ") in non-range invoke)";
+    return false;
+  }
+
+  for (idx = 0; idx < vA; idx++) {
+    if (arg[idx] > registers_size) {
+      LOG(ERROR) << "VFY: invalid reg index (" << arg[idx]
+                 << ") in non-range invoke (> " << registers_size << ")";
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/*
+ * Check the register indices used in a "vararg/range" instruction, such as
+ * invoke-virtual/range or filled-new-array/range.
+ *
+ * vA holds word count, vC holds index of first reg.
+ */
+static bool CheckVarArgRangeRegs(const DexFile::CodeItem* code_item,
+    uint32_t vA, uint32_t vC) {
+  uint16_t registers_size = code_item->registers_size_;
+
+  /*
+   * vA/vC are unsigned 8-bit/16-bit quantities for /range instructions,
+   * so there's no risk of integer overflow when adding them here.
+   */
+  if (vA + vC > registers_size) {
+    LOG(ERROR) << "VFY: invalid reg index " << vA << "+" << vC
+               << " in range invoke (> " << registers_size << ")";
+    return false;
+  }
+
+  return true;
+}
+
+/*
+ * Verify a switch table. "cur_offset" is the offset of the switch instruction.
+ *
+ * Updates "insnFlags", setting the "branch target" flag.
+ */
+static bool CheckSwitchTargets(const DexFile::CodeItem* code_item,
+    uint32_t insn_flags[], uint32_t cur_offset) {
+  const uint32_t insn_count = code_item->insns_size_;
+  const uint16_t* insns = code_item->insns_ + cur_offset;
+  const uint16_t* switch_insns;
+  uint16_t expected_signature;
+  uint32_t switch_count, table_size;
+  int32_t switch_offset, keys_offset, targets_offset;
+  int32_t offset, abs_offset;
+  uint32_t targ;
+
+  /* make sure the start of the switch is in range */
+  switch_offset = insns[1] | ((int32_t) insns[2]) << 16;
+  if ((int32_t) cur_offset + switch_offset < 0 ||
+      cur_offset + switch_offset + 2 >= insn_count) {
+    LOG(ERROR) << "VFY: invalid switch start: at " << cur_offset
+               << ", switch offset " << switch_offset << ", count "
+               << insn_count;
+    return false;
+  }
+
+  /* offset to switch table is a relative branch-style offset */
+  switch_insns = insns + switch_offset;
+
+  /* make sure the table is 32-bit aligned */
+  if ((((uint32_t) switch_insns) & 0x03) != 0) {
+    LOG(ERROR) << "VFY: unaligned switch table: at " << cur_offset
+               << ", switch offset " << switch_offset;
+    return false;
+  }
+
+  switch_count = switch_insns[1];
+
+  if ((*insns & 0xff) == Instruction::PACKED_SWITCH) {
+    /* 0=sig, 1=count, 2/3=firstKey */
+    targets_offset = 4;
+    keys_offset = -1;
+    expected_signature = Instruction::kPackedSwitchSignature;
+  } else {
+    /* 0=sig, 1=count, 2..count*2 = keys */
+    keys_offset = 2;
+    targets_offset = 2 + 2 * switch_count;
+    expected_signature = Instruction::kSparseSwitchSignature;
+  }
+  table_size = targets_offset + switch_count * 2;
+
+  if (switch_insns[0] != expected_signature) {
+    LOG(ERROR) << "VFY: wrong signature for switch table (0x" << switch_insns[0]
+               << ", wanted 0x" << expected_signature << ")";
+    return false;
+  }
+
+  /* make sure the end of the switch is in range */
+  if (cur_offset + switch_offset + table_size > (uint32_t) insn_count) {
+      LOG(ERROR) << "VFY: invalid switch end: at " << cur_offset
+                 << ", switch offset " << switch_offset << ", end "
+                 << cur_offset + switch_offset + table_size << ", count "
+                 << insn_count;
+    return false;
+  }
+
+  /* for a sparse switch, verify the keys are in ascending order */
+  if (keys_offset > 0 && switch_count > 1) {
+    int32_t last_key;
+
+    last_key = switch_insns[keys_offset] |
+               (switch_insns[keys_offset + 1] << 16);
+    for (targ = 1; targ < switch_count; targ++) {
+      int32_t key = (int32_t) switch_insns[keys_offset + targ * 2] |
+                    (int32_t) (switch_insns[keys_offset + targ * 2 + 1] << 16);
+      if (key <= last_key) {
+        LOG(ERROR) << "VFY: invalid packed switch: last key=" << last_key
+                   << ", this=" << key;
+        return false;
+      }
+
+      last_key = key;
+    }
+  }
+
+  /* verify each switch target */
+  for (targ = 0; targ < switch_count; targ++) {
+    offset = (int32_t) switch_insns[targets_offset + targ * 2] |
+             (int32_t) (switch_insns[targets_offset + targ * 2 + 1] << 16);
+    abs_offset = cur_offset + offset;
+
+    if (abs_offset < 0 || abs_offset >= (int32_t) insn_count ||
+        !InsnIsOpcode(insn_flags, abs_offset)) {
+      LOG(ERROR) << "VFY: invalid switch target " << offset << " (-> "
+                 << abs_offset << ") at " << cur_offset << "[" << targ << "]";
+      return false;
+    }
+    InsnSetBranchTarget(insn_flags, abs_offset, true);
+  }
+
+  return true;
+}
+
+/*
+ * Verify that the target of a branch instruction is valid.
+ *
+ * We don't expect code to jump directly into an exception handler, but
+ * it's valid to do so as long as the target isn't a "move-exception"
+ * instruction.  We verify that in a later stage.
+ *
+ * The VM spec doesn't forbid an instruction from branching to itself,
+ * but the Dalvik spec declares that only certain instructions can do so.
+ *
+ * Updates "insnFlags", setting the "branch target" flag.
+ */
+static bool CheckBranchTarget(const DexFile::CodeItem* code_item,
+    uint32_t insn_flags[], int cur_offset) {
+  const int insn_count = code_item->insns_size_;
+  int32_t offset, abs_offset;
+  bool isConditional, selfOkay;
+
+  if (!GetBranchOffset(code_item, insn_flags, cur_offset, &offset,
+                       &isConditional, &selfOkay))
+    return false;
+
+  if (!selfOkay && offset == 0) {
+    LOG(ERROR) << "VFY: branch offset of zero not allowed at" << cur_offset;
+    return false;
+  }
+
+  /*
+   * Check for 32-bit overflow.  This isn't strictly necessary if we can
+   * depend on the VM to have identical "wrap-around" behavior, but
+   * it's unwise to depend on that.
+   */
+  if (((int64_t) cur_offset + (int64_t) offset) !=
+      (int64_t)(cur_offset + offset)) {
+    LOG(ERROR) << "VFY: branch target overflow " << cur_offset << " +"
+               << offset;
+    return false;
+  }
+  abs_offset = cur_offset + offset;
+  if (abs_offset < 0 || abs_offset >= insn_count ||
+      !InsnIsOpcode(insn_flags, abs_offset))
+  {
+    LOG(ERROR) << "VFY: invalid branch target " << offset << " (-> "
+               << abs_offset << ") at " << cur_offset;
+    return false;
+  }
+  InsnSetBranchTarget(insn_flags, abs_offset, true);
+
+  return true;
+}
+
+bool CheckInsnWidth(const uint16_t* insns, uint32_t insns_size,
+    uint32_t insn_flags[]) {
+  const byte* ptr = reinterpret_cast<const byte*>(insns);
+  const Instruction* inst = Instruction::At(ptr);
+
+  size_t width = 0;
+
+  while (width < insns_size) {
+    insn_flags[width] |= inst->Size();
+    width += inst->Size();
+    inst = inst->Next();
+  }
+
+  if (width != insns_size) {
+    LOG(ERROR) << "VFY: code did not end where expected (" << width << " vs. "
+               << insns_size << ")";
+    return false;
+  }
+
+  return true;
+}
+
+/*
+ * Set the "in try" flags for all instructions protected by "try" statements.
+ * Also sets the "branch target" flags for exception handlers.
+ *
+ * Call this after widths have been set in "insn_flags".
+ *
+ * Returns "false" if something in the exception table looks fishy, but
+ * we're expecting the exception table to be somewhat sane.
+ */
+static bool ScanTryCatchBlocks(const DexFile::CodeItem* code_item,
+    uint32_t insn_flags[]) {
+  uint32_t insns_size = code_item->insns_size_;
+  uint32_t tries_size = code_item->tries_size_;
+
+  if (tries_size == 0) {
+    return true;
+  }
+
+  const DexFile::TryItem* tries = DexFile::dexGetTryItems(*code_item, 0);
+
+  for (uint32_t idx = 0; idx < tries_size; idx++) {
+    const DexFile::TryItem* try_item = &tries[idx];
+    uint32_t start = try_item->start_addr_;
+    uint32_t end = start + try_item->insn_count_;
+
+    if ((start >= end) || (start >= insns_size) || (end > insns_size)) {
+      LOG(ERROR) << "VFY: bad exception entry: startAddr=" << start
+                 << " endAddr=" << end << " (size=" << insns_size << ")";
+      return false;
+    }
+
+    if (InsnGetWidth(insn_flags, start) == 0) {
+      LOG(ERROR) << "VFY: 'try' block starts inside an instruction ("
+                 << start << ")";
+      return false;
+    }
+
+    uint32_t addr;
+    for (addr = start; addr < end; addr += InsnGetWidth(insn_flags, addr)) {
+      InsnSetInTry(insn_flags, addr, true);
+    }
+  }
+
+  /* Iterate over each of the handlers to verify target addresses. */
+  const byte* handlers_ptr = DexFile::dexGetCatchHandlerData(*code_item, 0);
+  uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+  for (uint32_t idx = 0; idx < handlers_size; idx++) {
+    DexFile::CatchHandlerIterator iterator(handlers_ptr);
+
+    for (; !iterator.HasNext(); iterator.Next()) {
+      uint32_t addr = iterator.Get().address_;
+      if (InsnGetWidth(insn_flags, addr) == 0) {
+        LOG(ERROR) << "VFY: exception handler starts at bad address ("
+                   << addr << ")";
+        return false;
+      }
+
+      InsnSetBranchTarget(insn_flags, addr, true);
+    }
+
+    handlers_ptr = iterator.GetData();
+  }
+
+  return true;
+}
+
+
+
 bool DexVerify::VerifyClass(Class* klass) {
   if (klass->IsVerified()) {
     return true;
@@ -16,14 +634,16 @@
   for (size_t i = 0; i < klass->NumDirectMethods(); ++i) {
     Method* method = klass->GetDirectMethod(i);
     if (!VerifyMethod(method)) {
-        LOG(ERROR) << "Verifier rejected class " << klass->GetDescriptor()->ToModifiedUtf8();
+        LOG(ERROR) << "Verifier rejected class "
+                   << klass->GetDescriptor()->ToModifiedUtf8();
       return false;
     }
   }
   for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
     Method* method = klass->GetVirtualMethod(i);
     if (!VerifyMethod(method)) {
-        LOG(ERROR) << "Verifier rejected class " << klass->GetDescriptor()->ToModifiedUtf8();
+        LOG(ERROR) << "Verifier rejected class "
+                   << klass->GetDescriptor()->ToModifiedUtf8();
       return false;
     }
   }
@@ -31,7 +651,190 @@
 }
 
 bool DexVerify::VerifyMethod(Method* method) {
-  return true;  // TODO
+  const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
+  const DexFile::CodeItem *code_item = dex_file.GetCodeItem(method->code_off_);
+
+  /*
+   * If there aren't any instructions, make sure that's expected, then
+   * exit successfully.
+   */
+  if (code_item == NULL) {
+    if (!method->IsNative() && !method->IsAbstract()) {
+      LOG(ERROR) << "VFY: zero-length code in concrete non-native method";
+      return false;
+    }
+    return true;
+  }
+
+  /*
+   * Sanity-check the register counts.  ins + locals = registers, so make
+   * sure that ins <= registers.
+   */
+  if (code_item->ins_size_ > code_item->registers_size_) {
+    LOG(ERROR) << "VFY: bad register counts (ins=" << code_item->ins_size_
+               << " regs=" << code_item->registers_size_;
+    return false;
+  }
+
+  /*
+   * Allocate and initialize an array to hold instruction data.
+   */
+  uint32_t* insn_flags = new uint32_t[code_item->insns_size_]();
+
+  /*
+   * Run through the instructions and see if the width checks out.
+   */
+  if (!CheckInsnWidth(code_item->insns_, code_item->insns_size_, insn_flags)) {
+    delete insn_flags;
+    return false;
+  }
+
+  /*
+   * Flag instructions guarded by a "try" block and check exception handlers.
+   */
+  if (!ScanTryCatchBlocks(code_item, insn_flags)) {
+    delete insn_flags;
+    return false;
+  }
+
+  /*
+   * Perform static instruction verification.
+   */
+  if (!VerifyInstructions(&dex_file, code_item, insn_flags)) {
+    delete insn_flags;
+    return false;
+  }
+
+  /*
+   * TODO: Code flow analysis
+   */
+
+  delete insn_flags;
+  return true;
 }
 
+bool DexVerify::VerifyInstructions(const DexFile* dex_file,
+    const DexFile::CodeItem* code_item, uint32_t insn_flags[]) {
+  const byte* ptr = reinterpret_cast<const byte*>(code_item->insns_);
+  const Instruction* inst = Instruction::At(ptr);
+
+  /* Flag the start of the method as a branch target. */
+  InsnSetBranchTarget(insn_flags, 0, true);
+
+  uint32_t width = 0;
+  uint32_t insns_size = code_item->insns_size_;
+
+  while (width < insns_size) {
+    if (!VerifyInstruction(dex_file, inst, width, code_item, insn_flags)) {
+      LOG(ERROR) << "VFY:  rejecting opcode 0x" << std::hex
+                 << (int) inst->Opcode() << " at 0x" << width << std::dec;
+      return false;
+    }
+
+    /* Flag instructions that are garbage collection points */
+    if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow() ||
+        inst->IsReturn()) {
+      InsnSetGcPoint(insn_flags, width, true);
+    }
+
+    width += inst->Size();
+    inst = inst->Next();
+  }
+  return true;
+}
+
+bool DexVerify::VerifyInstruction(const DexFile* dex_file,
+    const Instruction* inst, uint32_t code_offset,
+    const DexFile::CodeItem* code_item, uint32_t insn_flags[]) {
+  Instruction::Code opcode = inst->Opcode();
+  bool result = true;
+  uint32_t vA, vB, vC;
+  uint64_t vB_wide;
+  uint32_t arg[5];
+
+  inst->Decode(vA, vB, vB_wide, vC, arg);
+
+  int argumentA = inst->GetVerifyTypeArgumentA();
+  int argumentB = inst->GetVerifyTypeArgumentB();
+  int argumentC = inst->GetVerifyTypeArgumentC();
+  int extra_flags = inst->GetVerifyExtraFlags();
+
+  switch (argumentA) {
+    case Instruction::kVerifyRegA:
+      result &= CheckRegisterIndex(code_item, vA);
+      break;
+    case Instruction::kVerifyRegAWide:
+      result &= CheckWideRegisterIndex(code_item, vA);
+      break;
+  }
+
+  switch (argumentB) {
+    case Instruction::kVerifyRegB:
+      result &= CheckRegisterIndex(code_item, vB);
+      break;
+    case Instruction::kVerifyRegBField:
+      result &= CheckFieldIndex(dex_file, vB);
+      break;
+    case Instruction::kVerifyRegBMethod:
+      result &= CheckMethodIndex(dex_file, vB);
+      break;
+    case Instruction::kVerifyRegBNewInstance:
+      result &= CheckNewInstance(dex_file, vB);
+      break;
+    case Instruction::kVerifyRegBString:
+      result &= CheckStringIndex(dex_file, vB);
+      break;
+    case Instruction::kVerifyRegBType:
+      result &= CheckTypeIndex(dex_file, vB);
+      break;
+    case Instruction::kVerifyRegBWide:
+      result &= CheckWideRegisterIndex(code_item, vB);
+      break;
+  }
+
+  switch (argumentC) {
+    case Instruction::kVerifyRegC:
+      result &= CheckRegisterIndex(code_item, vC);
+      break;
+    case Instruction::kVerifyRegCField:
+      result &= CheckFieldIndex(dex_file, vC);
+      break;
+    case Instruction::kVerifyRegCNewArray:
+      result &= CheckNewArray(dex_file, vC);
+      break;
+    case Instruction::kVerifyRegCType:
+      result &= CheckTypeIndex(dex_file, vC);
+      break;
+    case Instruction::kVerifyRegCWide:
+      result &= CheckWideRegisterIndex(code_item, vC);
+      break;
+  }
+
+  switch (extra_flags) {
+    case Instruction::kVerifyArrayData:
+      result &= CheckArrayData(code_item, code_offset);
+      break;
+    case Instruction::kVerifyBranchTarget:
+      result &= CheckBranchTarget(code_item, insn_flags, code_offset);
+      break;
+    case Instruction::kVerifySwitchTargets:
+      result &= CheckSwitchTargets(code_item, insn_flags, code_offset);
+      break;
+    case Instruction::kVerifyVarArg:
+      result &= CheckVarArgRegs(code_item, vA, arg);
+      break;
+    case Instruction::kVerifyVarArgRange:
+      result &= CheckVarArgRangeRegs(code_item, vA, vC);
+      break;
+    case Instruction::kVerifyError:
+      LOG(ERROR) << "VFY: unexpected opcode " << (int) opcode;
+      result = false;
+      break;
+  }
+
+  return result;
+};
+
 }  // namespace art
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index 03b2c96..29dc140 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -5,15 +5,33 @@
 
 #include "macros.h"
 #include "object.h"
+#include "dex_instruction.h"
 
 namespace art {
 
 class DexVerify {
  public:
+  enum {
+    kInsnFlagWidthMask = 0x0000ffff,
+    kInsnFlagInTry = (1 << 16),
+    kInsnFlagBranchTarget = (1 << 17),
+    kInsnFlagGcPoint = (1 << 18),
+    kInsnFlagVisited = (1 << 30),
+    kInsnFlagChanged = (1 << 31),
+  };
+
   static bool VerifyClass(Class* klass);
 
  private:
   static bool VerifyMethod(Method* method);
+  static bool VerifyInstructions(const DexFile* dex_file,
+                                 const DexFile::CodeItem* code_item,
+                                 uint32_t insn_flags[]);
+  static bool VerifyInstruction(const DexFile* dex_file,
+                                const Instruction* inst,
+                                uint32_t code_offset,
+                                const DexFile::CodeItem* code_item,
+                                uint32_t insn_flags[]);
 
   DISALLOW_COPY_AND_ASSIGN(DexVerify);
 };
diff --git a/src/dex_verifier_test.cc b/src/dex_verifier_test.cc
new file mode 100644
index 0000000..f1d99e6
--- /dev/null
+++ b/src/dex_verifier_test.cc
@@ -0,0 +1,49 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "class_linker.h"
+#include "common_test.h"
+#include "compiler_test.h"
+#include "dex_file.h"
+#include "dex_verifier.h"
+#include "scoped_ptr.h"
+
+#include <stdio.h>
+#include "gtest/gtest.h"
+
+namespace art {
+
+class DexVerifierTest : public CommonTest {
+ protected:
+  void VerifyClass(ClassLoader* class_loader, const StringPiece& descriptor) {
+    ASSERT_TRUE(descriptor != NULL);
+    Class* klass = class_linker_->FindSystemClass(descriptor);
+
+    // Verify the class
+    ASSERT_TRUE(DexVerify::VerifyClass(klass));
+  }
+
+  void VerifyDexFile(const DexFile* dex, ClassLoader* class_loader) {
+    ASSERT_TRUE(dex != NULL);
+
+    // Verify all the classes defined in this file
+    for (size_t i = 0; i < dex->NumClassDefs(); i++) {
+      const DexFile::ClassDef& class_def = dex->GetClassDef(i);
+      const char* descriptor = dex->GetClassDescriptor(class_def);
+      VerifyClass(class_loader, descriptor);
+    }
+  }
+
+};
+
+TEST_F(DexVerifierTest, LibCore) {
+  VerifyDexFile(java_lang_dex_file_.get(), NULL);
+}
+
+TEST_F(DexVerifierTest, IntMath) {
+  const DexFile* dex = OpenDexFileBase64(kIntMathDex, "kIntMathDex");
+  PathClassLoader* class_loader = AllocPathClassLoader(dex);
+  Class* klass = class_linker_->FindClass("LIntMath;", class_loader);
+  ASSERT_TRUE(DexVerify::VerifyClass(klass));
+}
+
+}  // namespace art