Verifier clean up.

This is the first part in trying to move to a more rigorous mode of
asserting the validity of garbage collection maps.
In the bring over of the verifier from Dalvik a large class had been
created where all of the Dalvik/Dex functions were static methods of
that class. This rewrite introduces 3 key classes, Verifier that
orchestrates the verification of a method, RegisterLine which describes
the types associated with registers for a particular PC and RegType
which describes the current type of a register within a line. The
functionality is brought over from Dalvik but cleaned up to not do
things like goto. Failing within the verifier is also cleaned up. By
virtue of having stateful objects the interfaces between different
aspects of the verifier are greatly simplified.
To save space, RegTypes are cached upto a maximum possible 2^16, and
given an Id. As the number of RegTypes is typically small this means
that we have a full OO implementation but at a lower space cost than the
current convention that uses botched together enum values requiring
32bits of storage in a RegisterLine rather than 16bits (ie half the
space requirement per register in a register line). To make use of
this space more rigorous monitor verification is brought back, and
ultimately I think we can work around bug 3215458 with richer RegTypes
that are aware of literal objects.
The code removes short cuts that had been added to Dalvik's verifier and
appear illegitimate, it also fixes a large number of bugs in the
description of the verifier.
Where possible the spaghetti of code is replaced with straight line
if-then-elsif.. code that clearly follows the ordering semantics of the
specification. The code is also aiming toward having a more type
rigorous description of the verification process, and when this isn't
possible following the description convention of the specification.

Change-Id: Id25b742018a2ad5ea95687973cca610d7e19513c
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 589213a..de35d33 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1635,7 +1635,7 @@
   CHECK_EQ(klass->GetStatus(), Class::kStatusResolved);
   klass->SetStatus(Class::kStatusVerifying);
 
-  if (DexVerifier::VerifyClass(klass)) {
+  if (verifier::DexVerifier::VerifyClass(klass)) {
     klass->SetStatus(Class::kStatusVerified);
   } else {
     LOG(ERROR) << "Verification failed on class " << PrettyClass(klass);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index d1be1de..1b43825 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -439,8 +439,7 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_methods_),           "shadow$_dex_cache_resolved_methods_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_types_),             "shadow$_dex_cache_resolved_types_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_strings_),                    "shadow$_dex_cache_strings_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, register_map_data_),                    "shadow$_register_map_data_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, register_map_header_),                  "shadow$_register_map_header_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, gc_map_),                               "shadow$_gc_map_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, shorty_),                               "shadow$_shorty_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, signature_),                            "shadow$_signature_"));
 
@@ -461,7 +460,6 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_outs_),                             "shadow$_num_outs_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_registers_),                        "shadow$_num_registers_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, proto_idx_),                            "shadow$_proto_idx_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, return_pc_offset_in_bytes_),            "shadow$_return_pc_offset_in_bytes_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, vmap_table_),                           "shadow$_vmap_table_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_slot_),                            "slot"));
   };
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index bee0376..95bff2b 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -703,7 +703,7 @@
     const art::DexFile::CodeItem* code_item =
          dex_file.GetCodeItem(method->GetCodeItemOffset());
     const u2* codePtr = code_item->insns_;
-    const u2* codeEnd = code_item->insns_ + code_item->insns_size_;
+    const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
     int numBlocks = 0;
     unsigned int curOffset = 0;
 
@@ -715,7 +715,7 @@
     cUnit->method = method;
     cUnit->instructionSet = (OatInstructionSetType)insnSet;
     cUnit->insns = code_item->insns_;
-    cUnit->insnsSize = code_item->insns_size_;
+    cUnit->insnsSize = code_item->insns_size_in_code_units_;
     bool useMatch = compilerMethodMatch.length() != 0;
     bool match = useMatch && (compilerFlipMatch ^
         (PrettyMethod(method).find(compilerMethodMatch) != std::string::npos));
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 7a41845..fea8009 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -5,6 +5,7 @@
 #include <fcntl.h>
 #include <limits.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/file.h>
 #include <sys/mman.h>
@@ -410,6 +411,11 @@
   return true;
 }
 
+uint32_t DexFile::GetVersion() const {
+  const char* version = reinterpret_cast<const char*>(&GetHeader().magic_[sizeof(kDexMagic)]);
+  return atoi(version);
+}
+
 void DexFile::InitIndex() {
   CHECK_EQ(index_.size(), 0U);
   for (size_t i = 0; i < NumClassDefs(); ++i) {
diff --git a/src/dex_file.h b/src/dex_file.h
index 3077ae6..c30c5ca 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -206,7 +206,7 @@
     uint16_t outs_size_;
     uint16_t tries_size_;
     uint32_t debug_info_off_;  // file offset to debug info stream
-    uint32_t insns_size_;  // size of the insns array, in 2 byte code units
+    uint32_t insns_size_in_code_units_;  // size of the insns array, in 2 byte code units
     uint16_t insns_[1];
    private:
     DISALLOW_COPY_AND_ASSIGN(CodeItem);
@@ -350,6 +350,8 @@
   // Looks up a class definition index by its class descriptor.
   bool FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const;
 
+  uint32_t GetVersion() const;
+
   // Looks up a class definition by its class descriptor.
   const ClassDef* FindClassDef(const StringPiece& descriptor) const;
 
@@ -609,7 +611,7 @@
   }
 
   static const TryItem* dexGetTryItems(const CodeItem& code_item, uint32_t offset) {
-    const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_];
+    const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_in_code_units_];
     return reinterpret_cast<const TryItem*>
         (RoundUp(reinterpret_cast<uint32_t>(insns_end_), 4)) + offset;
   }
@@ -808,7 +810,7 @@
       dexDecodeDebugInfo0(code_item, method, posCb, local_cb, cnxt, stream, local_in_reg);
     }
     for (int reg = 0; reg < code_item->registers_size_; reg++) {
-      InvokeLocalCbIfLive(cnxt, reg, code_item->insns_size_, local_in_reg, local_cb);
+      InvokeLocalCbIfLive(cnxt, reg, code_item->insns_size_in_code_units_, local_in_reg, local_cb);
     }
   }
 
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
index 4db8846..eb8e96e 100644
--- a/src/dex_instruction.cc
+++ b/src/dex_instruction.cc
@@ -2,6 +2,9 @@
 
 #include "dex_instruction.h"
 
+#include "dex_file.h"
+#include <iomanip>
+
 namespace art {
 
 const char* const Instruction::kInstructionNames[] = {
@@ -191,7 +194,7 @@
   }
 }
 
-size_t Instruction::Size() const {
+size_t Instruction::SizeInCodeUnits() const {
   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
   if (*insns == kPackedSwitchSignature) {
     return (4 + insns[1] * 2);
@@ -246,9 +249,81 @@
 }
 
 const Instruction* Instruction::Next() const {
-  size_t current_size = Size() * sizeof(uint16_t);
+  size_t current_size_in_bytes = SizeInCodeUnits() * sizeof(uint16_t);
   const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-  return reinterpret_cast<const Instruction*>(ptr + current_size);
+  return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+}
+
+void Instruction::DumpHex(std::ostream& os, size_t code_units) const {
+  size_t inst_length = SizeInCodeUnits();
+  if (inst_length > code_units) {
+    inst_length = code_units;
+  }
+  const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
+  for (size_t i = 0; i < inst_length; i++) {
+    os << "0x" << StringPrintf("0x%04X", insn[i]) << " ";
+  }
+  for (size_t i = inst_length; i < code_units; i++) {
+    os << "       ";
+  }
+}
+
+void Instruction::Dump(std::ostream& os, const DexFile* file) const {
+  DecodedInstruction insn(this);
+  const char* opcode = kInstructionNames[insn.opcode_];
+  switch (Format()) {
+    case k10x: os << opcode; break;
+    case k12x: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_; break;
+    case k11n: os << opcode << " v" << insn.vA_ << ", #+" << insn.vB_; break;
+    case k11x: os << opcode << " v" << insn.vA_; break;
+    case k10t: os << opcode << " +" << (int)insn.vA_; break;
+    case k20bc: os << opcode << " " << insn.vA_ << ", kind@" << insn.vB_; break;
+    case k20t: os << opcode << " +" << (int)insn.vA_; break;
+    case k22x: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_; break;
+    case k21t: os << opcode << " v" << insn.vA_ << ", +" << insn.vB_; break;
+    case k21s: os << opcode << " v" << insn.vA_ << ", #+" << insn.vB_; break;
+    case k21h: os << opcode << " v" << insn.vA_ << ", #+" << insn.vB_ << "00000[00000000]"; break;
+    case k21c: os << opcode << " " << insn.vA_ << ", thing@" << insn.vB_; break;
+    case k23x: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_ << ", v" << insn.vC_; break;
+    case k22b: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_ << ", #+" << insn.vC_; break;
+    case k22t: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_ << ", +" << insn.vC_; break;
+    case k22s: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_ << ", #+" << insn.vC_; break;
+    case k22c: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_ << ", thing@" << insn.vC_; break;
+    case k32x: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_; break;
+    case k30t: os << opcode << " +" << (int)insn.vA_; break;
+    case k31t: os << opcode << " v" << insn.vA_ << ", +" << insn.vB_; break;
+    case k31i: os << opcode << " v" << insn.vA_ << ", #+" << insn.vB_; break;
+    case k31c: os << opcode << " v" << insn.vA_ << ", thing@" << insn.vB_; break;
+    case k35c: {
+      switch (insn.opcode_) {
+        case INVOKE_VIRTUAL:
+        case INVOKE_SUPER:
+        case INVOKE_DIRECT:
+        case INVOKE_STATIC:
+        case INVOKE_INTERFACE:
+          if (file != NULL) {
+            const DexFile::MethodId& meth_id = file->GetMethodId(insn.vB_);
+            os << opcode << " {v" << insn.arg_[0] << ", v" << insn.arg_[1] << ", v" << insn.arg_[2]
+                         << ", v" << insn.arg_[3] << ", v" << insn.arg_[4] << "}, "
+                         << file->GetMethodName(meth_id) << file->GetMethodSignature(meth_id)
+                         << " // method@" << insn.vB_;
+            break;
+          }  // else fall-through
+        default:
+          os << opcode << " {v" << insn.arg_[0] << ", v" << insn.arg_[1] << ", v" << insn.arg_[2]
+                       << ", v" << insn.arg_[3] << ", v" << insn.arg_[4] << "}, thing@" << insn.vB_;
+          break;
+      }
+      break;
+    }
+    case k3rc: os << opcode << " {v" << insn.vC_ << " .. v" << (insn.vC_+ insn.vA_ - 1) << "}, method@" << insn.vB_; break;
+    case k51l: os << opcode << " v" << insn.vA_ << ", #+" << insn.vB_; break;
+  }
+}
+
+std::ostream& operator<<(std::ostream& os, const Instruction& rhs) {
+  rhs.Dump(os, NULL);
+  return os;
 }
 
 }  // namespace art
diff --git a/src/dex_instruction.h b/src/dex_instruction.h
index 2c1a397..36ea295 100644
--- a/src/dex_instruction.h
+++ b/src/dex_instruction.h
@@ -9,6 +9,8 @@
 
 namespace art {
 
+class DexFile;
+
 class Instruction {
  public:
   // NOP-encoded switch-statement signatures.
@@ -108,8 +110,8 @@
   // 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;
+  // Returns the size in 2 byte code units, for this instruction.
+  size_t SizeInCodeUnits() const;
 
   // Returns a pointer to the next instruction in the stream.
   const Instruction* Next() const;
@@ -123,7 +125,7 @@
   Code Opcode() const;
 
   // Reads an instruction out of the stream at the specified address.
-  static const Instruction* At(const byte* code) {
+  static const Instruction* At(const uint16_t* code) {
     CHECK(code != NULL);
     return reinterpret_cast<const Instruction*>(code);
   }
@@ -187,6 +189,12 @@
              kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgRange | kVerifyError));
   }
 
+  // Dump code_units worth of this instruction, padding to code_units for shorter instructions
+  void DumpHex(std::ostream& os, size_t code_units) const;
+
+  // Dump decoded version of instruction
+  void Dump(std::ostream& os, const DexFile*) const;
+
  private:
   static const char* const kInstructionNames[];
   static InstructionFormat const kInstructionFormats[];
@@ -194,6 +202,7 @@
   static int const kInstructionVerifyFlags[];
   DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
 };
+std::ostream& operator<<(std::ostream& os, const Instruction& rhs);
 
 }  // namespace art
 
diff --git a/src/dex_instruction_visitor.h b/src/dex_instruction_visitor.h
index 7b7704b..2e1041d 100644
--- a/src/dex_instruction_visitor.h
+++ b/src/dex_instruction_visitor.h
@@ -11,12 +11,12 @@
 template<typename T>
 class DexInstructionVisitor {
  public:
-  void Visit(const uint16_t* code, size_t size) {
+  void Visit(const uint16_t* code, size_t size_in_bytes) {
     T* derived = static_cast<T*>(this);
-    const byte* ptr = reinterpret_cast<const byte*>(code);
-    const byte* end = ptr + size;
-    while (ptr != end) {
-      const Instruction* inst = Instruction::At(ptr);
+    size_t size_in_code_units = size_in_bytes / sizeof(uint16_t);
+    size_t i = 0;
+    while (i < size_in_code_units) {
+      const Instruction* inst = Instruction::At(&code[i]);
       switch (inst->Opcode()) {
 #define INSTRUCTION_CASE(o, cname, p, f, r, i, a, v)  \
         case Instruction::cname: {                    \
@@ -30,8 +30,7 @@
         default:
           CHECK(false);
       }
-      ptr += inst->Size() * sizeof(uint16_t);
-      CHECK_LE(ptr, end);
+      i += inst->SizeInCodeUnits();
     }
   }
 
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 6c7335e..878069b 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -15,65 +15,204 @@
 #include "stringpiece.h"
 
 namespace art {
+namespace verifier {
 
-#define k_  kRegTypeUnknown
-#define kU  kRegTypeUninit
-#define kX  kRegTypeConflict
-#define k0  kRegTypeZero
-#define k1  kRegTypeOne
-#define kZ  kRegTypeBoolean
-#define ky  kRegTypeConstPosByte
-#define kY  kRegTypeConstByte
-#define kh  kRegTypeConstPosShort
-#define kH  kRegTypeConstShort
-#define kc  kRegTypeConstChar
-#define ki  kRegTypeConstInteger
-#define kb  kRegTypePosByte
-#define kB  kRegTypeByte
-#define ks  kRegTypePosShort
-#define kS  kRegTypeShort
-#define kC  kRegTypeChar
-#define kI  kRegTypeInteger
-#define kF  kRegTypeFloat
-#define kN  kRegTypeConstLo
-#define kn  kRegTypeConstHi
-#define kJ  kRegTypeLongLo
-#define kj  kRegTypeLongHi
-#define kD  kRegTypeDoubleLo
-#define kd  kRegTypeDoubleHi
+std::ostream& operator<<(std::ostream& os, const VerifyError& rhs) {
+  return os << (int)rhs;
+}
 
-const char DexVerifier::merge_table_[kRegTypeMAX][kRegTypeMAX] =
+static const char type_chars[RegType::kRegTypeMAX + 1 /* for '\0' */ ] = "UX01ZyYhHcibBsSCIFNnJjDdL";
+
+void RegType::Dump(std::ostream& os) const {
+  DCHECK(type_ < kRegTypeMAX);
+  os << type_chars[type_];
+  if (type_ == kRegTypeReference) {
+    if (IsUninitializedReference()) {
+      os << "[uninitialized-" << PrettyClass(GetClass())
+          << ", allocated@" << allocation_pc_ <<"]";
+    } else {
+      os << "[" << PrettyDescriptor(GetClass()->GetDescriptor()) << "]";
+    }
+  }
+}
+
+const RegType& RegType::HighHalf(RegTypeCache* cache) const {
+  CHECK(IsLowHalf());
+  if (type_ == kRegTypeLongLo) {
+    return cache->FromType(kRegTypeLongHi);
+  } else if (type_ == kRegTypeDoubleLo) {
+    return cache->FromType(kRegTypeDoubleHi);
+  } else {
+    return cache->FromType(kRegTypeConstHi);
+  }
+}
+
+/*
+ * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
+ * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
+ * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
+ * is the deepest (lowest upper bound) parent of S and T).
+ *
+ * This operation applies for regular classes and arrays, however, for interface types there needn't
+ * be a partial ordering on the types. We could solve the problem of a lack of a partial order by
+ * introducing sets of types, however, the only operation permissible on an interface is
+ * invoke-interface. In the tradition of Java verifiers we defer the verification of interface
+ * types until an invoke-interface call on the interface typed reference at runtime and allow
+ * the perversion of Object being assignable to an interface type (note, however, that we don't
+ * allow assignment of Object or Interface to any concrete class and are therefore type safe;
+ * further the Join on a Object cannot result in a sub-class by definition).
+ */
+Class* RegType::ClassJoin(Class* s, Class* t) {
+  DCHECK(!s->IsPrimitive()) << PrettyClass(s);
+  DCHECK(!t->IsPrimitive()) << PrettyClass(t);
+  if (s == t) {
+    return s;
+  } else if (s->IsAssignableFrom(t)) {
+    return s;
+  } else if (t->IsAssignableFrom(s)) {
+    return t;
+  } else if (s->IsArrayClass() && t->IsArrayClass()) {
+    Class* s_ct = s->GetComponentType();
+    Class* t_ct = t->GetComponentType();
+    if (s_ct->IsPrimitive() || t_ct->IsPrimitive()) {
+      // Given the types aren't the same, if either array is of primitive types then the only
+      // common parent is java.lang.Object
+      Class* result = s->GetSuperClass();  // short-cut to java.lang.Object
+      DCHECK(result->IsObjectClass());
+      return result;
+    }
+    Class* common_elem = ClassJoin(s_ct, t_ct);
+    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+    const ClassLoader* class_loader = s->GetClassLoader();
+    std::string descriptor = "[" + common_elem->GetDescriptor()->ToModifiedUtf8();
+    Class* array_class = class_linker->FindClass(descriptor.c_str(), class_loader);
+    DCHECK(array_class != NULL);
+    return array_class;
+  } else {
+    size_t s_depth = s->Depth();
+    size_t t_depth = t->Depth();
+    // Get s and t to the same depth in the hierarchy
+    if (s_depth > t_depth) {
+      while (s_depth > t_depth) {
+        s = s->GetSuperClass();
+        s_depth--;
+      }
+    } else {
+      while (t_depth > s_depth) {
+        t = t->GetSuperClass();
+        t_depth--;
+      }
+    }
+    // Go up the hierarchy until we get to the common parent
+    while (s != t) {
+      s = s->GetSuperClass();
+      t = t->GetSuperClass();
+    }
+    return s;
+  }
+}
+
+const RegType& RegType::VerifyAgainst(const RegType& check_type, RegTypeCache* reg_types) const {
+  if (Equals(check_type)) {
+    return *this;
+  } else {
+    switch (check_type.GetType()) {
+      case RegType::kRegTypeBoolean:
+        return IsBooleanTypes() ? check_type : reg_types->Conflict();
+        break;
+      case RegType::kRegTypeByte:
+        return IsByteTypes() ? check_type : reg_types->Conflict();
+        break;
+      case RegType::kRegTypeShort:
+        return IsShortTypes() ? check_type : reg_types->Conflict();
+        break;
+      case RegType::kRegTypeChar:
+        return IsCharTypes() ? check_type : reg_types->Conflict();
+        break;
+      case RegType::kRegTypeInteger:
+        return IsIntegralTypes() ? check_type : reg_types->Conflict();
+        break;
+      case RegType::kRegTypeFloat:
+        return IsFloatTypes() ? check_type : reg_types->Conflict();
+        break;
+      case RegType::kRegTypeLongLo:
+        return IsLongTypes() ? check_type : reg_types->Conflict();
+        break;
+      case RegType::kRegTypeDoubleLo:
+        return IsDoubleTypes() ? check_type : reg_types->Conflict();
+        break;
+      case RegType::kRegTypeReference:
+        if (IsZero()) {
+          return check_type;
+        } else if (IsUninitializedReference()) {
+          return reg_types->Conflict();  // Nonsensical to Join two uninitialized classes
+        } else if (IsReference() && check_type.GetClass()->IsAssignableFrom(GetClass())) {
+          return check_type;
+        } else {
+          return reg_types->Conflict();
+        }
+      default:
+        LOG(FATAL) << "Unexpected register type verification against " << check_type;
+        return reg_types->Conflict();
+    }
+  }
+}
+
+#define k_  RegType::kRegTypeUnknown
+#define kX  RegType::kRegTypeConflict
+#define k0  RegType::kRegTypeZero
+#define k1  RegType::kRegTypeOne
+#define kZ  RegType::kRegTypeBoolean
+#define ky  RegType::kRegTypeConstPosByte
+#define kY  RegType::kRegTypeConstByte
+#define kh  RegType::kRegTypeConstPosShort
+#define kH  RegType::kRegTypeConstShort
+#define kc  RegType::kRegTypeConstChar
+#define ki  RegType::kRegTypeConstInteger
+#define kb  RegType::kRegTypePosByte
+#define kB  RegType::kRegTypeByte
+#define ks  RegType::kRegTypePosShort
+#define kS  RegType::kRegTypeShort
+#define kC  RegType::kRegTypeChar
+#define kI  RegType::kRegTypeInteger
+#define kF  RegType::kRegTypeFloat
+#define kN  RegType::kRegTypeConstLo
+#define kn  RegType::kRegTypeConstHi
+#define kJ  RegType::kRegTypeLongLo
+#define kj  RegType::kRegTypeLongHi
+#define kD  RegType::kRegTypeDoubleLo
+#define kd  RegType::kRegTypeDoubleHi
+
+const RegType::Type RegType::merge_table_[kRegTypeReference][kRegTypeReference] =
   {
-    /* chk:  _  U  X  0  1  Z  y  Y  h  H  c  i  b  B  s  S  C  I  F  N  n  J  j  D  d */
-    { /*_*/ k_,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX },
-    { /*U*/ kX,kU,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX },
-    { /*X*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX },
-    { /*0*/ kX,kX,kX,k0,kZ,kZ,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
-    { /*1*/ kX,kX,kX,kZ,k1,kZ,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
-    { /*Z*/ kX,kX,kX,kZ,kZ,kZ,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
-    { /*y*/ kX,kX,kX,ky,ky,ky,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
-    { /*Y*/ kX,kX,kX,kY,kY,kY,kY,kY,kh,kH,kc,ki,kB,kB,kS,kS,kI,kI,kF,kX,kX,kX,kX,kX,kX },
-    { /*h*/ kX,kX,kX,kh,kh,kh,kh,kh,kh,kH,kc,ki,ks,kS,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
-    { /*H*/ kX,kX,kX,kH,kH,kH,kH,kH,kH,kH,kc,ki,kS,kS,kS,kS,kI,kI,kF,kX,kX,kX,kX,kX,kX },
-    { /*c*/ kX,kX,kX,kc,kc,kc,kc,kc,kc,kc,kc,ki,kC,kI,kC,kI,kC,kI,kF,kX,kX,kX,kX,kX,kX },
-    { /*i*/ kX,kX,kX,ki,ki,ki,ki,ki,ki,ki,ki,ki,kI,kI,kI,kI,kI,kI,kF,kX,kX,kX,kX,kX,kX },
-    { /*b*/ kX,kX,kX,kb,kb,kb,kb,kB,ks,kS,kC,kI,kb,kB,ks,kS,kC,kI,kX,kX,kX,kX,kX,kX,kX },
-    { /*B*/ kX,kX,kX,kB,kB,kB,kB,kB,kS,kS,kI,kI,kB,kB,kS,kS,kI,kI,kX,kX,kX,kX,kX,kX,kX },
-    { /*s*/ kX,kX,kX,ks,ks,ks,ks,kS,ks,kS,kC,kI,ks,kS,ks,kS,kC,kI,kX,kX,kX,kX,kX,kX,kX },
-    { /*S*/ kX,kX,kX,kS,kS,kS,kS,kS,kS,kS,kI,kI,kS,kS,kS,kS,kI,kI,kX,kX,kX,kX,kX,kX,kX },
-    { /*C*/ kX,kX,kX,kC,kC,kC,kC,kI,kC,kI,kC,kI,kC,kI,kC,kI,kC,kI,kX,kX,kX,kX,kX,kX,kX },
-    { /*I*/ kX,kX,kX,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kX,kX,kX,kX,kX,kX,kX },
-    { /*F*/ kX,kX,kX,kF,kF,kF,kF,kF,kF,kF,kF,kF,kX,kX,kX,kX,kX,kX,kF,kX,kX,kX,kX,kX,kX },
-    { /*N*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kN,kX,kJ,kX,kD,kX },
-    { /*n*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kn,kX,kj,kX,kd },
-    { /*J*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kJ,kX,kJ,kX,kX,kX },
-    { /*j*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kj,kX,kj,kX,kX },
-    { /*D*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kD,kX,kX,kX,kD,kX },
-    { /*d*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kd,kX,kX,kX,kd },
+    /* chk:  _ X  0  1  Z  y  Y  h  H  c  i  b  B  s  S  C  I  F  N  n  J  j  D  d */
+    { /*_*/ k_,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX },
+    { /*X*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX },
+    { /*0*/ kX,kX,k0,kZ,kZ,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
+    { /*1*/ kX,kX,kZ,k1,kZ,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
+    { /*Z*/ kX,kX,kZ,kZ,kZ,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
+    { /*y*/ kX,kX,ky,ky,ky,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
+    { /*Y*/ kX,kX,kY,kY,kY,kY,kY,kh,kH,kc,ki,kB,kB,kS,kS,kI,kI,kF,kX,kX,kX,kX,kX,kX },
+    { /*h*/ kX,kX,kh,kh,kh,kh,kh,kh,kH,kc,ki,ks,kS,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
+    { /*H*/ kX,kX,kH,kH,kH,kH,kH,kH,kH,kc,ki,kS,kS,kS,kS,kI,kI,kF,kX,kX,kX,kX,kX,kX },
+    { /*c*/ kX,kX,kc,kc,kc,kc,kc,kc,kc,kc,ki,kC,kI,kC,kI,kC,kI,kF,kX,kX,kX,kX,kX,kX },
+    { /*i*/ kX,kX,ki,ki,ki,ki,ki,ki,ki,ki,ki,kI,kI,kI,kI,kI,kI,kF,kX,kX,kX,kX,kX,kX },
+    { /*b*/ kX,kX,kb,kb,kb,kb,kB,ks,kS,kC,kI,kb,kB,ks,kS,kC,kI,kX,kX,kX,kX,kX,kX,kX },
+    { /*B*/ kX,kX,kB,kB,kB,kB,kB,kS,kS,kI,kI,kB,kB,kS,kS,kI,kI,kX,kX,kX,kX,kX,kX,kX },
+    { /*s*/ kX,kX,ks,ks,ks,ks,kS,ks,kS,kC,kI,ks,kS,ks,kS,kC,kI,kX,kX,kX,kX,kX,kX,kX },
+    { /*S*/ kX,kX,kS,kS,kS,kS,kS,kS,kS,kI,kI,kS,kS,kS,kS,kI,kI,kX,kX,kX,kX,kX,kX,kX },
+    { /*C*/ kX,kX,kC,kC,kC,kC,kI,kC,kI,kC,kI,kC,kI,kC,kI,kC,kI,kX,kX,kX,kX,kX,kX,kX },
+    { /*I*/ kX,kX,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kX,kX,kX,kX,kX,kX,kX },
+    { /*F*/ kX,kX,kF,kF,kF,kF,kF,kF,kF,kF,kF,kX,kX,kX,kX,kX,kX,kF,kX,kX,kX,kX,kX,kX },
+    { /*N*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kN,kX,kJ,kX,kD,kX },
+    { /*n*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kn,kX,kj,kX,kd },
+    { /*J*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kJ,kX,kJ,kX,kX,kX },
+    { /*j*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kj,kX,kj,kX,kX },
+    { /*D*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kD,kX,kX,kX,kD,kX },
+    { /*d*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kd,kX,kX,kX,kd },
   };
 
 #undef k_
-#undef kU
 #undef kX
 #undef k0
 #undef k1
@@ -98,21 +237,614 @@
 #undef kD
 #undef kd
 
-bool DexVerifier::VerifyClass(Class* klass) {
+const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const {
+  DCHECK(!Equals(incoming_type));  // Trivial equality handled by caller
+  if (type_ < kRegTypeReference) {
+    if (incoming_type.type_ < kRegTypeReference) {
+      // Merge of primitive types, unknown or conflict use lookup table
+      RegType::Type table_type = merge_table_[type_][incoming_type.type_];
+      // Check if we got an identity result before hitting the cache
+      if (type_ == table_type) {
+        return *this;
+      } else if (incoming_type.type_ == table_type) {
+        return incoming_type;
+      } else {
+        return reg_types->FromType(table_type);
+      }
+    } else if (IsZero()) {  // Merge of primitive zero and reference => reference
+      return incoming_type;
+    } else {  // Merge with non-zero with reference => conflict
+      return reg_types->Conflict();
+    }
+  } else if (!incoming_type.IsReference()) {
+    DCHECK(IsReference());
+    if (incoming_type.IsZero()) {  // Merge of primitive zero and reference => reference
+      return *this;
+    } else {  // Merge with non-zero with reference => conflict
+      return reg_types->Conflict();
+    }
+  } else if (IsUninitializedReference()) {
+    // Can only merge an uninitialized type with itself, but we already checked this
+    return reg_types->Conflict();
+  } else {  // Two reference types, compute Join
+    Class* c1 = GetClass();
+    Class* c2 = incoming_type.GetClass();
+    DCHECK(c1 != NULL && !c1->IsPrimitive());
+    DCHECK(c2 != NULL && !c2->IsPrimitive());
+    Class* join_class = ClassJoin(c1, c2);
+    if (c1 == join_class) {
+      return *this;
+    } else if (c2 == join_class) {
+      return incoming_type;
+    } else {
+      return reg_types->FromClass(join_class);
+    }
+  }
+}
+
+static RegType::Type RegTypeFromPrimitiveType(Class::PrimitiveType prim_type) {
+  switch (prim_type) {
+    case Class::kPrimBoolean: return RegType::kRegTypeBoolean;
+    case Class::kPrimByte:    return RegType::kRegTypeByte;
+    case Class::kPrimShort:   return RegType::kRegTypeShort;
+    case Class::kPrimChar:    return RegType::kRegTypeChar;
+    case Class::kPrimInt:     return RegType::kRegTypeInteger;
+    case Class::kPrimLong:    return RegType::kRegTypeLongLo;
+    case Class::kPrimFloat:   return RegType::kRegTypeFloat;
+    case Class::kPrimDouble:  return RegType::kRegTypeDoubleLo;
+    case Class::kPrimVoid:
+    default:                  return RegType::kRegTypeUnknown;
+  }
+}
+
+static RegType::Type RegTypeFromDescriptor(const std::string& descriptor) {
+  if (descriptor.length() == 1) {
+    switch (descriptor[0]) {
+      case 'Z': return RegType::kRegTypeBoolean;
+      case 'B': return RegType::kRegTypeByte;
+      case 'S': return RegType::kRegTypeShort;
+      case 'C': return RegType::kRegTypeChar;
+      case 'I': return RegType::kRegTypeInteger;
+      case 'J': return RegType::kRegTypeLongLo;
+      case 'F': return RegType::kRegTypeFloat;
+      case 'D': return RegType::kRegTypeDoubleLo;
+      case 'V':
+      default:  return RegType::kRegTypeUnknown;
+    }
+  } else if(descriptor[0] == 'L' || descriptor[0] == '[') {
+    return RegType::kRegTypeReference;
+  } else {
+    return RegType::kRegTypeUnknown;
+  }
+}
+
+std::ostream& operator<<(std::ostream& os, const RegType& rhs) {
+  rhs.Dump(os);
+  return os;
+}
+
+const RegType& RegTypeCache::FromDescriptor(const ClassLoader* loader,
+                                            const std::string& descriptor) {
+  return From(RegTypeFromDescriptor(descriptor), loader, descriptor);
+}
+
+const RegType& RegTypeCache::From(RegType::Type type, const ClassLoader* loader,
+                                  const std::string& descriptor) {
+  if (type < RegType::kRegTypeReference) {
+    // entries should be sized greater than primitive types
+    DCHECK_GT(entries_.size(), static_cast<size_t>(type));
+    RegType* entry = entries_[type];
+    if (entry == NULL) {
+      Class *klass = NULL;
+      if (descriptor.size() != 0) {
+        klass = Runtime::Current()->GetClassLinker()->FindSystemClass(descriptor);
+      }
+      entry = new RegType(type, klass, RegType::kInitArgAddr, type);
+      entries_[type] = entry;
+    }
+    return *entry;
+  } else {
+    DCHECK (type == RegType::kRegTypeReference);
+    for (size_t i = RegType::kRegTypeReference; i < entries_.size(); i++) {
+      RegType* cur_entry = entries_[i];
+      if (cur_entry->IsInitialized() &&
+          cur_entry->GetClass()->GetDescriptor()->Equals(descriptor)) {
+        return *cur_entry;
+      }
+    }
+    Class* klass = Runtime::Current()->GetClassLinker()->FindClass(descriptor, loader);
+    RegType* entry = new RegType(type, klass, RegType::kInitArgAddr, entries_.size());
+    entries_.push_back(entry);
+    return *entry;
+  }
+}
+
+const RegType& RegTypeCache::FromClass(Class* klass) {
+  if (klass->IsPrimitive()) {
+    RegType::Type type = RegTypeFromPrimitiveType(klass->GetPrimitiveType());
+    // entries should be sized greater than primitive types
+    DCHECK_GT(entries_.size(), static_cast<size_t>(type));
+    RegType* entry = entries_[type];
+    if (entry == NULL) {
+      entry = new RegType(type, klass, RegType::kInitArgAddr, type);
+      entries_[type] = entry;
+    }
+    return *entry;
+  } else {
+    for (size_t i = RegType::kRegTypeReference; i < entries_.size(); i++) {
+      RegType* cur_entry = entries_[i];
+      if (cur_entry->IsInitialized() && cur_entry->GetClass() == klass) {
+        return *cur_entry;
+      }
+    }
+    RegType* entry = new RegType(RegType::kRegTypeReference, klass, RegType::kInitArgAddr,
+                                 entries_.size());
+    entries_.push_back(entry);
+    return *entry;
+  }
+}
+
+const RegType& RegTypeCache::Uninitialized(Class* klass, uint32_t allocation_pc) {
+  for (size_t i = RegType::kRegTypeReference; i < entries_.size(); i++) {
+    RegType* cur_entry = entries_[i];
+    if (cur_entry->allocation_pc_ == allocation_pc && cur_entry->GetClass() == klass) {
+      return *cur_entry;
+    }
+  }
+  RegType* entry = new RegType(RegType::kRegTypeReference, klass, allocation_pc, entries_.size());
+  entries_.push_back(entry);
+  return *entry;
+}
+
+const RegType& RegTypeCache::UninitializedThisArgument(Class* klass) {
+  for (size_t i = RegType::kRegTypeReference; i < entries_.size(); i++) {
+    RegType* cur_entry = entries_[i];
+    if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) {
+      return *cur_entry;
+    }
+  }
+  RegType* entry = new RegType(RegType::kRegTypeReference, klass, RegType::kUninitThisArgAddr,
+                               entries_.size());
+  entries_.push_back(entry);
+  return *entry;
+}
+
+const RegType& RegTypeCache::FromType(RegType::Type type) {
+  CHECK(type < RegType::kRegTypeReference);
+  switch (type) {
+    case RegType::kRegTypeBoolean:  return From(type, NULL, "Z");
+    case RegType::kRegTypeByte:     return From(type, NULL, "B");
+    case RegType::kRegTypeShort:    return From(type, NULL, "S");
+    case RegType::kRegTypeChar:     return From(type, NULL, "C");
+    case RegType::kRegTypeInteger:  return From(type, NULL, "I");
+    case RegType::kRegTypeFloat:    return From(type, NULL, "F");
+    case RegType::kRegTypeLongLo:
+    case RegType::kRegTypeLongHi:   return From(type, NULL, "J");
+    case RegType::kRegTypeDoubleLo:
+    case RegType::kRegTypeDoubleHi: return From(type, NULL, "D");
+    default:                        return From(type, NULL, "");
+  }
+}
+
+const RegType& RegTypeCache::FromCat1Const(int32_t value) {
+  if (value < -32768) {
+    return FromType(RegType::kRegTypeConstInteger);
+  } else if (value < -128) {
+    return FromType(RegType::kRegTypeConstShort);
+  } else if (value < 0) {
+    return FromType(RegType::kRegTypeConstByte);
+  } else if (value == 0) {
+    return FromType(RegType::kRegTypeZero);
+  } else if (value == 1) {
+    return FromType(RegType::kRegTypeOne);
+  } else if (value < 128) {
+    return FromType(RegType::kRegTypeConstPosByte);
+  } else if (value < 32768) {
+    return FromType(RegType::kRegTypeConstPosShort);
+  } else if (value < 65536) {
+    return FromType(RegType::kRegTypeConstChar);
+  } else {
+    return FromType(RegType::kRegTypeConstInteger);
+  }
+}
+
+bool RegisterLine::CheckConstructorReturn() const {
+  for (size_t i = 0; i < num_regs_; i++) {
+    if (GetRegisterType(i).IsUninitializedThisReference()) {
+      verifier_->Fail(VERIFY_ERROR_GENERIC)
+          << "Constructor returning without calling superclass constructor";
+      return false;
+    }
+  }
+  return true;
+}
+
+void RegisterLine::SetRegisterType(uint32_t vdst, const RegType& new_type) {
+  DCHECK(vdst < num_regs_);
+  if (new_type.IsLowHalf()) {
+    line_[vdst] = new_type.GetId();
+    line_[vdst + 1] = new_type.HighHalf(verifier_->GetRegTypeCache()).GetId();
+  } else if (new_type.IsHighHalf()) {
+    /* should never set these explicitly */
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "Explicit set of high register type";
+  } else if (new_type.IsConflict()) {  // should only be set during a merge
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "Set register to unknown type " << new_type;
+  } else {
+    line_[vdst] = new_type.GetId();
+  }
+  // Clear the monitor entry bits for this register.
+  ClearAllRegToLockDepths(vdst);
+}
+
+void RegisterLine::SetResultTypeToUnknown() {
+  uint16_t unknown_id = verifier_->GetRegTypeCache()->Unknown().GetId();
+  result_[0] = unknown_id;
+  result_[1] = unknown_id;
+}
+
+void RegisterLine::SetResultRegisterType(const RegType& new_type) {
+  result_[0] = new_type.GetId();
+  if(new_type.IsLowHalf()) {
+    DCHECK_EQ(new_type.HighHalf(verifier_->GetRegTypeCache()).GetId(), new_type.GetId() + 1);
+    result_[1] = new_type.GetId() + 1;
+  } else {
+    result_[1] = verifier_->GetRegTypeCache()->Unknown().GetId();
+  }
+}
+
+const RegType& RegisterLine::GetRegisterType(uint32_t vsrc) const {
+  // The register index was validated during the static pass, so we don't need to check it here.
+  DCHECK_LT(vsrc, num_regs_);
+  return verifier_->GetRegTypeCache()->GetFromId(line_[vsrc]);
+}
+
+const RegType& RegisterLine::GetInvocationThis(const Instruction::DecodedInstruction& dec_insn) {
+  if (dec_insn.vA_ < 1) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "invoke lacks 'this'";
+    return verifier_->GetRegTypeCache()->Unknown();
+  }
+  /* get the element type of the array held in vsrc */
+  const RegType& this_type = GetRegisterType(dec_insn.vC_);
+  if (!this_type.IsReferenceTypes()) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "tried to get class from non-reference register v"
+                                          << dec_insn.vC_ << " (type=" << this_type << ")";
+    return verifier_->GetRegTypeCache()->Unknown();
+  }
+  return this_type;
+}
+
+Class* RegisterLine::GetClassFromRegister(uint32_t vsrc) const {
+  /* get the element type of the array held in vsrc */
+  const RegType& type = GetRegisterType(vsrc);
+  /* if "always zero", we allow it to fail at runtime */
+  if (type.IsZero()) {
+    return NULL;
+  } else if (!type.IsReferenceTypes()) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "tried to get class from non-ref register v" << vsrc
+                                         << " (type=" << type << ")";
+    return NULL;
+  } else if (type.IsUninitializedReference()) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "register " << vsrc << " holds uninitialized reference";
+    return NULL;
+  } else {
+    return type.GetClass();
+  }
+}
+
+bool RegisterLine::VerifyRegisterType(uint32_t vsrc, const RegType& check_type) {
+  // Verify the src register type against the check type refining the type of the register
+  const RegType& src_type = GetRegisterType(vsrc);
+  const RegType& lub_type = src_type.VerifyAgainst(check_type, verifier_->GetRegTypeCache());
+  if (lub_type.IsConflict()) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "register v" << vsrc << " has type " << src_type
+                                          << " but expected " << check_type;
+    return false;
+  }
+  // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less
+  // precise than the subtype in vsrc so leave it for reference types. For primitive types
+  // if they are a defined type then they are as precise as we can get, however, for constant
+  // types we may wish to refine them. Unfortunately constant propagation has rendered this useless.
+  return true;
+}
+
+void RegisterLine::MarkRefsAsInitialized(const RegType& uninit_type) {
+  Class* klass = uninit_type.GetClass();
+  if (klass == NULL) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "Unable to find type=" << uninit_type;
+  } else {
+    const RegType& init_type = verifier_->GetRegTypeCache()->FromClass(klass);
+    size_t changed = 0;
+    for (size_t i = 0; i < num_regs_; i++) {
+      if (GetRegisterType(i).Equals(uninit_type)) {
+        line_[i] = init_type.GetId();
+        changed++;
+      }
+    }
+    DCHECK_GT(changed, 0u);
+  }
+}
+
+void RegisterLine::MarkUninitRefsAsInvalid(const RegType& uninit_type) {
+  for (size_t i = 0; i < num_regs_; i++) {
+    if (GetRegisterType(i).Equals(uninit_type)) {
+      line_[i] = verifier_->GetRegTypeCache()->Conflict().GetId();
+      ClearAllRegToLockDepths(i);
+    }
+  }
+}
+
+void RegisterLine::CopyRegister1(uint32_t vdst, uint32_t vsrc, TypeCategory cat) {
+  DCHECK(cat == kTypeCategory1nr || cat == kTypeCategoryRef);
+  const RegType& type = GetRegisterType(vsrc);
+  SetRegisterType(vdst, type);
+  if ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
+      (cat == kTypeCategoryRef && !type.IsReferenceTypes())) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "copy1 v" << vdst << "<-v" << vsrc << " type=" << type
+                                          << " cat=" << static_cast<int>(cat);
+  } else if (cat == kTypeCategoryRef) {
+    CopyRegToLockDepth(vdst, vsrc);
+  }
+}
+
+void RegisterLine::CopyRegister2(uint32_t vdst, uint32_t vsrc) {
+  const RegType& type_l = GetRegisterType(vsrc);
+  const RegType& type_h = GetRegisterType(vsrc + 1);
+
+  if (!type_l.CheckWidePair(type_h)) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "copy2 v" << vdst << "<-v" << vsrc
+                                         << " type=" << type_l << "/" << type_h;
+  } else {
+    SetRegisterType(vdst, type_l);  // implicitly sets the second half
+  }
+}
+
+void RegisterLine::CopyResultRegister1(uint32_t vdst, bool is_reference) {
+  const RegType& type = verifier_->GetRegTypeCache()->GetFromId(result_[0]);
+  if ((!is_reference && !type.IsCategory1Types()) ||
+      (is_reference && !type.IsReferenceTypes())) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC)
+        << "copyRes1 v" << vdst << "<- result0"  << " type=" << type;
+  } else {
+    DCHECK(verifier_->GetRegTypeCache()->GetFromId(result_[1]).IsUnknown());
+    SetRegisterType(vdst, type);
+    result_[0] = verifier_->GetRegTypeCache()->Unknown().GetId();
+  }
+}
+
+/*
+ * Implement "move-result-wide". Copy the category-2 value from the result
+ * register to another register, and reset the result register.
+ */
+void RegisterLine::CopyResultRegister2(uint32_t vdst) {
+  const RegType& type_l = verifier_->GetRegTypeCache()->GetFromId(result_[0]);
+  const RegType& type_h = verifier_->GetRegTypeCache()->GetFromId(result_[1]);
+  if (!type_l.IsCategory2Types()) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC)
+        << "copyRes2 v" << vdst << "<- result0"  << " type=" << type_l;
+  } else {
+    DCHECK(type_l.CheckWidePair(type_h));  // Set should never allow this case
+    SetRegisterType(vdst, type_l);  // also sets the high
+    result_[0] = verifier_->GetRegTypeCache()->Unknown().GetId();
+    result_[1] = verifier_->GetRegTypeCache()->Unknown().GetId();
+  }
+}
+
+void RegisterLine::CheckUnaryOp(const Instruction::DecodedInstruction& dec_insn,
+                                const RegType& dst_type, const RegType& src_type) {
+  if (VerifyRegisterType(dec_insn.vB_, src_type)) {
+    SetRegisterType(dec_insn.vA_, dst_type);
+  }
+}
+
+void RegisterLine::CheckBinaryOp(const Instruction::DecodedInstruction& dec_insn,
+                                 const RegType& dst_type,
+                                 const RegType& src_type1, const RegType& src_type2,
+                                 bool check_boolean_op) {
+  if (VerifyRegisterType(dec_insn.vB_, src_type1) &&
+      VerifyRegisterType(dec_insn.vC_, src_type2)) {
+    if (check_boolean_op) {
+      DCHECK(dst_type.IsInteger());
+      if (GetRegisterType(dec_insn.vB_).IsBooleanTypes() &&
+          GetRegisterType(dec_insn.vC_).IsBooleanTypes()) {
+        SetRegisterType(dec_insn.vA_, verifier_->GetRegTypeCache()->Boolean());
+        return;
+      }
+    }
+    SetRegisterType(dec_insn.vA_, dst_type);
+  }
+}
+
+void RegisterLine::CheckBinaryOp2addr(const Instruction::DecodedInstruction& dec_insn,
+                                      const RegType& dst_type, const RegType& src_type1,
+                                      const RegType& src_type2, bool check_boolean_op) {
+  if (VerifyRegisterType(dec_insn.vA_, src_type1) &&
+      VerifyRegisterType(dec_insn.vB_, src_type2)) {
+    if (check_boolean_op) {
+      DCHECK(dst_type.IsInteger());
+      if (GetRegisterType(dec_insn.vA_).IsBooleanTypes() &&
+          GetRegisterType(dec_insn.vB_).IsBooleanTypes()) {
+        SetRegisterType(dec_insn.vA_, verifier_->GetRegTypeCache()->Boolean());
+        return;
+      }
+    }
+    SetRegisterType(dec_insn.vA_, dst_type);
+  }
+}
+
+void RegisterLine::CheckLiteralOp(const Instruction::DecodedInstruction& dec_insn,
+                                  const RegType& dst_type, const RegType& src_type,
+                                  bool check_boolean_op) {
+  if (VerifyRegisterType(dec_insn.vB_, src_type)) {
+    if (check_boolean_op) {
+      DCHECK(dst_type.IsInteger());
+      /* check vB with the call, then check the constant manually */
+      if (GetRegisterType(dec_insn.vB_).IsBooleanTypes() &&
+          (dec_insn.vC_ == 0 || dec_insn.vC_ == 1)) {
+        SetRegisterType(dec_insn.vA_, verifier_->GetRegTypeCache()->Boolean());
+        return;
+      }
+    }
+    SetRegisterType(dec_insn.vA_, dst_type);
+  }
+}
+
+void RegisterLine::PushMonitor(uint32_t reg_idx, int32_t insn_idx) {
+  const RegType& reg_type = GetRegisterType(reg_idx);
+  if (!reg_type.IsReferenceTypes()) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "monitor-enter on non-object (" << reg_type << ")";
+  } else {
+    SetRegToLockDepth(reg_idx, monitors_.size());
+    monitors_.push(insn_idx);
+  }
+}
+
+void RegisterLine::PopMonitor(uint32_t reg_idx) {
+  const RegType& reg_type = GetRegisterType(reg_idx);
+  if (!reg_type.IsReferenceTypes()) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "monitor-exit on non-object (" << reg_type << ")";
+  } else if (monitors_.empty()) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "monitor-exit stack underflow";
+  } else {
+    monitors_.pop();
+    if(!IsSetLockDepth(reg_idx, monitors_.size())) {
+      // Bug 3215458: Locks and unlocks are on objects, if that object is a literal then before
+      // format "036" the constant collector may create unlocks on the same object but referenced
+      // via different registers.
+      ((verifier_->DexFileVersion() >= 36) ? verifier_->Fail(VERIFY_ERROR_GENERIC)
+                                           : verifier_->LogVerifyInfo())
+            << "monitor-exit not unlocking the top of the monitor stack";
+    } else {
+      // Record the register was unlocked
+      ClearRegToLockDepth(reg_idx, monitors_.size());
+    }
+  }
+}
+
+bool RegisterLine::VerifyMonitorStackEmpty() {
+  if (MonitorStackDepth() != 0) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "expected empty monitor stack";
+    return false;
+  } else {
+    return true;
+  }
+}
+
+bool RegisterLine::MergeRegisters(const RegisterLine* incoming_line) {
+  bool changed = false;
+  for (size_t idx = 0; idx < num_regs_; idx++) {
+    if (line_[idx] != incoming_line->line_[idx]) {
+      const RegType& incoming_reg_type = incoming_line->GetRegisterType(idx);
+      const RegType& cur_type = GetRegisterType(idx);
+      const RegType& new_type = cur_type.Merge(incoming_reg_type, verifier_->GetRegTypeCache());
+      changed = changed || !cur_type.Equals(new_type);
+      line_[idx] = new_type.GetId();
+    }
+  }
+  if(monitors_ != incoming_line->monitors_) {
+    verifier_->Fail(VERIFY_ERROR_GENERIC) << "mismatched stack depths (depth="
+        << MonitorStackDepth() << ", incoming depth=" << incoming_line->MonitorStackDepth() << ")";
+  } else if (reg_to_lock_depths_ != incoming_line->reg_to_lock_depths_) {
+    for (uint32_t idx = 0; idx < num_regs_; idx++) {
+      size_t depths = reg_to_lock_depths_.count(idx);
+      size_t incoming_depths = incoming_line->reg_to_lock_depths_.count(idx);
+      if (depths != incoming_depths) {
+        if (depths == 0 || incoming_depths == 0) {
+          reg_to_lock_depths_.erase(idx);
+        } else {
+          verifier_->Fail(VERIFY_ERROR_GENERIC) << "mismatched stack depths for register v" << idx
+                                                << ": " << depths  << " != " << incoming_depths;
+          break;
+        }
+      }
+    }
+  }
+  return changed;
+}
+
+void RegisterLine::WriteReferenceBitMap(int8_t* data, size_t max_bytes) {
+  for (size_t i = 0; i < num_regs_; i += 8) {
+    uint8_t val = 0;
+    for (size_t j = 0; j < 8 && (i + j) < num_regs_; j++) {
+      // Note: we write 1 for a Reference but not for Null
+      if (GetRegisterType(i + j).IsReference()) {
+        val |= 1 << j;
+      }
+    }
+    if (val != 0) {
+      DCHECK_LT(i / 8, max_bytes);
+      data[i / 8] = val;
+    }
+  }
+}
+
+std::ostream& operator<<(std::ostream& os, const RegisterLine& rhs) {
+  rhs.Dump(os);
+  return os;
+}
+
+
+void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InsnFlags* flags,
+                                 uint32_t insns_size, uint16_t registers_size,
+                                 DexVerifier* verifier) {
+  DCHECK_GT(insns_size, 0U);
+
+  for (uint32_t i = 0; i < insns_size; i++) {
+    bool interesting = false;
+    switch (mode) {
+      case kTrackRegsAll:
+        interesting = flags[i].IsOpcode();
+        break;
+      case kTrackRegsGcPoints:
+        interesting = flags[i].IsGcPoint() || flags[i].IsBranchTarget();
+        break;
+      case kTrackRegsBranches:
+        interesting = flags[i].IsBranchTarget();
+        break;
+      default:
+        break;
+    }
+    if (interesting) {
+      pc_to_register_line_[i] = new RegisterLine(registers_size, verifier);
+    }
+  }
+}
+
+bool DexVerifier::VerifyClass(const Class* klass) {
   if (klass->IsVerified()) {
     return true;
   }
+  Class* super = klass->GetSuperClass();
+  if (super == NULL && !klass->GetDescriptor()->Equals("Ljava/lang/Object;")) {
+    LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass) << " that has no super class";
+    return false;
+  }
+  if (super != NULL) {
+    if (!super->IsVerified() && !super->IsErroneous()) {
+      Runtime::Current()->GetClassLinker()->VerifyClass(super);
+    }
+    if (!super->IsVerified()) {
+      LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass)
+                 << " that attempts to sub-class corrupt class " << PrettyClass(super);
+      return false;
+    } else if (super->IsFinal()) {
+      LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass)
+                 << " that attempts to sub-class final class " << PrettyClass(super);
+      return false;
+    }
+  }
   for (size_t i = 0; i < klass->NumDirectMethods(); ++i) {
     Method* method = klass->GetDirectMethod(i);
     if (!VerifyMethod(method)) {
-      LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass);
+      LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass) << " due to bad method "
+                 << PrettyMethod(method, true);
       return false;
     }
   }
   for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
     Method* method = klass->GetVirtualMethod(i);
     if (!VerifyMethod(method)) {
-      LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass);
+      LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass) << " due to bad method "
+                 << PrettyMethod(method, true);
       return false;
     }
   }
@@ -120,361 +852,407 @@
 }
 
 bool DexVerifier::VerifyMethod(Method* method) {
+  DexVerifier verifier(method);
+  bool success = verifier.Verify();
+  // We expect either success and no verification error, or failure and a generic failure to
+  // reject the class.
+  if (success) {
+    if (verifier.failure_ != VERIFY_ERROR_NONE) {
+      LOG(FATAL) << "Unhandled failure in verification of " << PrettyMethod(method) << std::endl
+                 << verifier.fail_messages_;
+    }
+  } else {
+    LOG(INFO) << "Verification error in " << PrettyMethod(method) << " "
+               << verifier.fail_messages_.str() << std::endl << verifier.info_messages_.str();
+    verifier.Dump(std::cout);
+    DCHECK_EQ(verifier.failure_, VERIFY_ERROR_GENERIC);
+  }
+  return success;
+}
+
+DexVerifier::DexVerifier(Method* method) : java_lang_throwable_(NULL), work_insn_idx_(-1),
+                                           method_(method), failure_(VERIFY_ERROR_NONE),
+                                           new_instance_count_(0), monitor_enter_count_(0) {
   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->GetCodeItemOffset());
-
-  /*
-   * Construct the verifier state container object.
-   */
-  VerifierData vdata(method, &dex_file, code_item);
-
-  /*
-   * 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.
-   */
-  vdata.insn_flags_.reset(new InsnFlags[code_item->insns_size_]());
-
-  /*
-   * Run through the instructions and see if the width checks out.
-   */
-  if (!ComputeWidthsAndCountOps(&vdata)) {
-    return false;
-  }
-
-  /*
-   * Flag instructions guarded by a "try" block and check exception handlers.
-   */
-  if (!ScanTryCatchBlocks(&vdata)) {
-    return false;
-  }
-
-  /*
-   * Perform static instruction verification.
-   */
-  if (!VerifyInstructions(&vdata)) {
-    return false;
-  }
-
-  /*
-   * Perform code flow analysis.
-   */
-  if (!VerifyCodeFlow(&vdata)) {
-    return false;
-  }
-
-  return true;
+  dex_file_ = &class_linker->FindDexFile(dex_cache);
+  code_item_ = dex_file_->GetCodeItem(method->GetCodeItemOffset());
 }
 
-bool DexVerifier::VerifyInstructions(VerifierData* vdata) {
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  InsnFlags* insn_flags = vdata->insn_flags_.get();
-  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);
-
-  uint32_t width = 0;
-  uint32_t insns_size = code_item->insns_size_;
-
-  while (width < insns_size) {
-    if (!VerifyInstruction(vdata, inst, width)) {
-      LOG(ERROR) << "VFY: rejecting opcode 0x" << std::hex
-                 << (int) inst->Opcode() << " at 0x" << width << std::dec;
+bool DexVerifier::Verify() {
+  // If there aren't any instructions, make sure that's expected, then exit successfully.
+  if (code_item_ == NULL) {
+    if (!method_->IsNative() && !method_->IsAbstract()) {
+      Fail(VERIFY_ERROR_GENERIC) << "zero-length code in concrete non-native method";
       return false;
+    } else {
+      return true;
     }
-
-    /* Flag instructions that are garbage collection points */
-    if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow() ||
-        inst->IsReturn()) {
-      InsnSetGcPoint(insn_flags, width);
-    }
-
-    width += inst->Size();
-    inst = inst->Next();
   }
-  return true;
-}
-
-bool DexVerifier::VerifyInstruction(VerifierData* vdata,
-    const Instruction* inst, uint32_t code_offset) {
-  const DexFile* dex_file = vdata->dex_file_;
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  InsnFlags* insn_flags = vdata->insn_flags_.get();
-  Instruction::DecodedInstruction dec_insn(inst);
-  bool result = true;
-
-  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, dec_insn.vA_);
-      break;
-    case Instruction::kVerifyRegAWide:
-      result &= CheckWideRegisterIndex(code_item, dec_insn.vA_);
-      break;
+  // Sanity-check the register counts. ins + locals = registers, so make sure that ins <= registers.
+  if (code_item_->ins_size_ > code_item_->registers_size_) {
+    Fail(VERIFY_ERROR_GENERIC) << "bad register counts (ins=" << code_item_->ins_size_
+                               << " regs=" << code_item_->registers_size_;
+    return false;
   }
-
-  switch (argumentB) {
-    case Instruction::kVerifyRegB:
-      result &= CheckRegisterIndex(code_item, dec_insn.vB_);
-      break;
-    case Instruction::kVerifyRegBField:
-      result &= CheckFieldIndex(dex_file, dec_insn.vB_);
-      break;
-    case Instruction::kVerifyRegBMethod:
-      result &= CheckMethodIndex(dex_file, dec_insn.vB_);
-      break;
-    case Instruction::kVerifyRegBNewInstance:
-      result &= CheckNewInstance(dex_file, dec_insn.vB_);
-      break;
-    case Instruction::kVerifyRegBString:
-      result &= CheckStringIndex(dex_file, dec_insn.vB_);
-      break;
-    case Instruction::kVerifyRegBType:
-      result &= CheckTypeIndex(dex_file, dec_insn.vB_);
-      break;
-    case Instruction::kVerifyRegBWide:
-      result &= CheckWideRegisterIndex(code_item, dec_insn.vB_);
-      break;
-  }
-
-  switch (argumentC) {
-    case Instruction::kVerifyRegC:
-      result &= CheckRegisterIndex(code_item, dec_insn.vC_);
-      break;
-    case Instruction::kVerifyRegCField:
-      result &= CheckFieldIndex(dex_file, dec_insn.vC_);
-      break;
-    case Instruction::kVerifyRegCNewArray:
-      result &= CheckNewArray(dex_file, dec_insn.vC_);
-      break;
-    case Instruction::kVerifyRegCType:
-      result &= CheckTypeIndex(dex_file, dec_insn.vC_);
-      break;
-    case Instruction::kVerifyRegCWide:
-      result &= CheckWideRegisterIndex(code_item, dec_insn.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, dec_insn.vA_, dec_insn.arg_);
-      break;
-    case Instruction::kVerifyVarArgRange:
-      result &= CheckVarArgRangeRegs(code_item, dec_insn.vA_, dec_insn.vC_);
-      break;
-    case Instruction::kVerifyError:
-      LOG(ERROR) << "VFY: unexpected opcode " << std::hex
-                 << (int) dec_insn.opcode_ << std::dec;
-      result = false;
-      break;
-  }
-
+  // Allocate and initialize an array to hold instruction data.
+  insn_flags_.reset(new InsnFlags[code_item_->insns_size_in_code_units_]());
+  // Run through the instructions and see if the width checks out.
+  bool result = ComputeWidthsAndCountOps();
+  // Flag instructions guarded by a "try" block and check exception handlers.
+  result = result && ScanTryCatchBlocks();
+  // Perform static instruction verification.
+  result = result && VerifyInstructions();
+  // Perform code flow analysis.
+  result = result && VerifyCodeFlow();
   return result;
 }
 
-bool DexVerifier::VerifyCodeFlow(VerifierData* vdata) {
-  Method* method = vdata->method_;
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  uint16_t registers_size = code_item->registers_size_;
-  uint32_t insns_size = code_item->insns_size_;
-  RegisterTable reg_table;
-
-  if (registers_size * insns_size > 4*1024*1024) {
-    LOG(ERROR) << "VFY: warning: method is huge (regs=" << registers_size
-               << " insns_size=" << insns_size << ")";
-  }
-
-  /* Create and initialize register lists. */
-  if (!InitRegisterTable(vdata, &reg_table, kTrackRegsGcPoints)) {
-    return false;
-  }
-
-  vdata->register_lines_ = reg_table.register_lines_.get();
-
-  /* Allocate a map to hold the classes of uninitialized instances. */
-  vdata->uninit_map_.reset(CreateUninitInstanceMap(vdata));
-
-  /* Initialize register types of method arguments. */
-  if (!SetTypesFromSignature(vdata, reg_table.register_lines_[0].reg_types_.get())) {
-    LOG(ERROR) << "VFY: bad signature in " << PrettyMethod(method);
-    return false;
-  }
-
-  /* Perform code flow verification. */
-  if (!CodeFlowVerifyMethod(vdata, &reg_table)) {
-    return false;
-  }
-
-  /* Generate a register map and add it to the method. */
-  UniquePtr<RegisterMap> map(GenerateRegisterMapV(vdata));
-  SirtRef<ByteArray> header(ByteArray::Alloc(sizeof(RegisterMapHeader)));
-  if (header.get() == NULL) {
-    return false;
-  }
-  SirtRef<ByteArray> data(ByteArray::Alloc(ComputeRegisterMapSize(map.get())));
-  if (data.get() == NULL) {
-    return false;
-  }
-
-  memcpy(header->GetData(), map.get()->header_, sizeof(RegisterMapHeader));
-  memcpy(data->GetData(), map.get()->data_, ComputeRegisterMapSize(map.get()));
-
-  method->SetRegisterMapHeader(header.get());
-  method->SetRegisterMapData(data.get());
-
-  return true;
-}
-
-bool DexVerifier::ComputeWidthsAndCountOps(VerifierData* vdata) {
-  const uint16_t* insns = vdata->code_item_->insns_;
-  uint32_t insns_size = vdata->code_item_->insns_size_;
-  InsnFlags* insn_flags = vdata->insn_flags_.get();
-  const byte* ptr = reinterpret_cast<const byte*>(insns);
-  const Instruction* inst = Instruction::At(ptr);
+bool DexVerifier::ComputeWidthsAndCountOps() {
+  const uint16_t* insns = code_item_->insns_;
+  size_t insns_size = code_item_->insns_size_in_code_units_;
+  const Instruction* inst = Instruction::At(insns);
   size_t new_instance_count = 0;
   size_t monitor_enter_count = 0;
-  size_t width = 0;
+  size_t dex_pc = 0;
 
-  while (width < insns_size) {
+  while (dex_pc < insns_size) {
     Instruction::Code opcode = inst->Opcode();
     if (opcode == Instruction::NEW_INSTANCE) {
       new_instance_count++;
     } else if (opcode == Instruction::MONITOR_ENTER) {
       monitor_enter_count++;
     }
-
-    insn_flags[width] |= inst->Size();
-    width += inst->Size();
+    size_t inst_size = inst->SizeInCodeUnits();
+    insn_flags_[dex_pc].SetLengthInCodeUnits(inst_size);
+    dex_pc += inst_size;
     inst = inst->Next();
   }
 
-  if (width != insns_size) {
-    LOG(ERROR) << "VFY: code did not end where expected (" << width << " vs. "
-               << insns_size << ")";
+  if (dex_pc != insns_size) {
+    Fail(VERIFY_ERROR_GENERIC) << "code did not end where expected ("
+        << dex_pc << " vs. " << insns_size << ")";
     return false;
   }
 
-  vdata->new_instance_count_ = new_instance_count;
-  vdata->monitor_enter_count_ = monitor_enter_count;
+  new_instance_count_ = new_instance_count;
+  monitor_enter_count_ = monitor_enter_count;
   return true;
 }
 
-bool DexVerifier::ScanTryCatchBlocks(VerifierData* vdata) {
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  InsnFlags* insn_flags = vdata->insn_flags_.get();
-  uint32_t insns_size = code_item->insns_size_;
-  uint32_t tries_size = code_item->tries_size_;
-
+bool DexVerifier::ScanTryCatchBlocks() {
+  uint32_t tries_size = code_item_->tries_size_;
   if (tries_size == 0) {
     return true;
   }
-
-  const DexFile::TryItem* tries = DexFile::dexGetTryItems(*code_item, 0);
+  uint32_t insns_size = code_item_->insns_size_in_code_units_;
+  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 << ")";
+      Fail(VERIFY_ERROR_GENERIC) << "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 << ")";
+    if (!insn_flags_[start].IsOpcode()) {
+      Fail(VERIFY_ERROR_GENERIC) << "'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);
+    for (uint32_t dex_pc = start; dex_pc < end;
+        dex_pc += insn_flags_[dex_pc].GetLengthInCodeUnits()) {
+      insn_flags_[dex_pc].SetInTry();
     }
   }
-
   /* Iterate over each of the handlers to verify target addresses. */
-  const byte* handlers_ptr = DexFile::dexGetCatchHandlerData(*code_item, 0);
+  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 << ")";
+      uint32_t dex_pc= iterator.Get().address_;
+      if (!insn_flags_[dex_pc].IsOpcode()) {
+        Fail(VERIFY_ERROR_GENERIC) << "exception handler starts at bad address (" << dex_pc << ")";
         return false;
       }
-
-      InsnSetBranchTarget(insn_flags, addr);
+      insn_flags_[dex_pc].SetBranchTarget();
     }
-
     handlers_ptr = iterator.GetData();
   }
-
   return true;
 }
 
-bool DexVerifier::GetBranchOffset(const DexFile::CodeItem* code_item,
-    const InsnFlags insn_flags[], uint32_t cur_offset, int32_t* pOffset,
-    bool* pConditional, bool* selfOkay) {
-  const uint16_t* insns = code_item->insns_ + cur_offset;
+bool DexVerifier::VerifyInstructions() {
+  const Instruction* inst = Instruction::At(code_item_->insns_);
 
+  /* Flag the start of the method as a branch target. */
+  insn_flags_[0].SetBranchTarget();
+
+  uint32_t insns_size = code_item_->insns_size_in_code_units_;
+  for(uint32_t dex_pc = 0; dex_pc < insns_size;) {
+    if (!VerifyInstruction(inst, dex_pc)) {
+      Fail(VERIFY_ERROR_GENERIC) << "rejecting opcode " << inst->Name() << " at " << dex_pc;
+      return false;
+    }
+    /* Flag instructions that are garbage collection points */
+    if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow() || inst->IsReturn()) {
+      insn_flags_[dex_pc].SetGcPoint();
+    }
+    dex_pc += inst->SizeInCodeUnits();
+    inst = inst->Next();
+  }
+  return true;
+}
+
+bool DexVerifier::VerifyInstruction(const Instruction* inst, uint32_t code_offset) {
+  Instruction::DecodedInstruction dec_insn(inst);
+  bool result = true;
+  switch (inst->GetVerifyTypeArgumentA()) {
+    case Instruction::kVerifyRegA:
+      result = result && CheckRegisterIndex(dec_insn.vA_);
+      break;
+    case Instruction::kVerifyRegAWide:
+      result = result && CheckWideRegisterIndex(dec_insn.vA_);
+      break;
+  }
+  switch (inst->GetVerifyTypeArgumentB()) {
+    case Instruction::kVerifyRegB:
+      result = result && CheckRegisterIndex(dec_insn.vB_);
+      break;
+    case Instruction::kVerifyRegBField:
+      result = result && CheckFieldIndex(dec_insn.vB_);
+      break;
+    case Instruction::kVerifyRegBMethod:
+      result = result && CheckMethodIndex(dec_insn.vB_);
+      break;
+    case Instruction::kVerifyRegBNewInstance:
+      result = result && CheckNewInstance(dec_insn.vB_);
+      break;
+    case Instruction::kVerifyRegBString:
+      result = result && CheckStringIndex(dec_insn.vB_);
+      break;
+    case Instruction::kVerifyRegBType:
+      result = result && CheckTypeIndex(dec_insn.vB_);
+      break;
+    case Instruction::kVerifyRegBWide:
+      result = result && CheckWideRegisterIndex(dec_insn.vB_);
+      break;
+  }
+  switch (inst->GetVerifyTypeArgumentC()) {
+    case Instruction::kVerifyRegC:
+      result = result && CheckRegisterIndex(dec_insn.vC_);
+      break;
+    case Instruction::kVerifyRegCField:
+      result = result && CheckFieldIndex(dec_insn.vC_);
+      break;
+    case Instruction::kVerifyRegCNewArray:
+      result = result && CheckNewArray(dec_insn.vC_);
+      break;
+    case Instruction::kVerifyRegCType:
+      result = result && CheckTypeIndex(dec_insn.vC_);
+      break;
+    case Instruction::kVerifyRegCWide:
+      result = result && CheckWideRegisterIndex(dec_insn.vC_);
+      break;
+  }
+  switch (inst->GetVerifyExtraFlags()) {
+    case Instruction::kVerifyArrayData:
+      result = result && CheckArrayData(code_offset);
+      break;
+    case Instruction::kVerifyBranchTarget:
+      result = result && CheckBranchTarget(code_offset);
+      break;
+    case Instruction::kVerifySwitchTargets:
+      result = result && CheckSwitchTargets(code_offset);
+      break;
+    case Instruction::kVerifyVarArg:
+      result = result && CheckVarArgRegs(dec_insn.vA_, dec_insn.arg_);
+      break;
+    case Instruction::kVerifyVarArgRange:
+      result = result && CheckVarArgRangeRegs(dec_insn.vA_, dec_insn.vC_);
+      break;
+    case Instruction::kVerifyError:
+      Fail(VERIFY_ERROR_GENERIC) << "unexpected opcode " << inst->Name();
+      result = false;
+      break;
+  }
+  return result;
+}
+
+bool DexVerifier::CheckRegisterIndex(uint32_t idx) {
+  if (idx >= code_item_->registers_size_) {
+    Fail(VERIFY_ERROR_GENERIC) << "register index out of range (" << idx << " >= "
+                               << code_item_->registers_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+bool DexVerifier::CheckWideRegisterIndex(uint32_t idx) {
+  if (idx + 1 >= code_item_->registers_size_) {
+    Fail(VERIFY_ERROR_GENERIC) << "wide register index out of range (" << idx
+                               << "+1 >= " << code_item_->registers_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+bool DexVerifier::CheckFieldIndex(uint32_t idx) {
+  if (idx >= dex_file_->GetHeader().field_ids_size_) {
+    Fail(VERIFY_ERROR_GENERIC) << "bad field index " << idx << " (max "
+                               << dex_file_->GetHeader().field_ids_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+bool DexVerifier::CheckMethodIndex(uint32_t idx) {
+  if (idx >= dex_file_->GetHeader().method_ids_size_) {
+    Fail(VERIFY_ERROR_GENERIC) << "bad method index " << idx << " (max "
+                               << dex_file_->GetHeader().method_ids_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+bool DexVerifier::CheckNewInstance(uint32_t idx) {
+  if (idx >= dex_file_->GetHeader().type_ids_size_) {
+    Fail(VERIFY_ERROR_GENERIC) << "bad type index " << idx << " (max "
+                               << dex_file_->GetHeader().type_ids_size_ << ")";
+    return false;
+  }
+  // We don't need the actual class, just a pointer to the class name.
+  const char* descriptor = dex_file_->dexStringByTypeIdx(idx);
+  if (descriptor[0] != 'L') {
+    Fail(VERIFY_ERROR_GENERIC) << "can't call new-instance on type '" << descriptor << "'";
+    return false;
+  }
+  return true;
+}
+
+bool DexVerifier::CheckStringIndex(uint32_t idx) {
+  if (idx >= dex_file_->GetHeader().string_ids_size_) {
+    Fail(VERIFY_ERROR_GENERIC) << "bad string index " << idx << " (max "
+                               << dex_file_->GetHeader().string_ids_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+bool DexVerifier::CheckTypeIndex(uint32_t idx) {
+  if (idx >= dex_file_->GetHeader().type_ids_size_) {
+    Fail(VERIFY_ERROR_GENERIC) << "bad type index " << idx << " (max "
+                               << dex_file_->GetHeader().type_ids_size_ << ")";
+    return false;
+  }
+  return true;
+}
+
+bool DexVerifier::CheckNewArray(uint32_t idx) {
+  if (idx >= dex_file_->GetHeader().type_ids_size_) {
+    Fail(VERIFY_ERROR_GENERIC) << "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. */
+    Fail(VERIFY_ERROR_GENERIC) << "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. */
+    Fail(VERIFY_ERROR_GENERIC) << "can't new-array class '" << descriptor << "' (exceeds limit)";
+    return false;
+  }
+  return true;
+}
+
+bool DexVerifier::CheckArrayData(uint32_t cur_offset) {
+  const uint32_t insn_count = code_item_->insns_size_in_code_units_;
+  const uint16_t* insns = code_item_->insns_ + cur_offset;
+  const uint16_t* array_data;
+  int32_t array_data_offset;
+
+  DCHECK_LT(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) {
+    Fail(VERIFY_ERROR_GENERIC) << "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) {
+    Fail(VERIFY_ERROR_GENERIC) << "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) {
+    Fail(VERIFY_ERROR_GENERIC) << "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;
+}
+
+bool DexVerifier::CheckBranchTarget(uint32_t cur_offset) {
+  int32_t offset;
+  bool isConditional, selfOkay;
+  if (!GetBranchOffset(cur_offset, &offset, &isConditional, &selfOkay)) {
+    return false;
+  }
+  if (!selfOkay && offset == 0) {
+    Fail(VERIFY_ERROR_GENERIC) << "branch offset of zero not allowed at" << (void*) 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)) {
+    Fail(VERIFY_ERROR_GENERIC) << "branch target overflow " << (void*) cur_offset << " +" << offset;
+    return false;
+  }
+  const uint32_t insn_count = code_item_->insns_size_in_code_units_;
+  int32_t abs_offset = cur_offset + offset;
+  if (abs_offset < 0 || (uint32_t) abs_offset >= insn_count || !insn_flags_[abs_offset].IsOpcode()) {
+    Fail(VERIFY_ERROR_GENERIC) << "invalid branch target " << offset << " (-> "
+                               << (void*) abs_offset << ") at " << (void*) cur_offset;
+    return false;
+  }
+  insn_flags_[abs_offset].SetBranchTarget();
+  return true;
+}
+
+bool DexVerifier::GetBranchOffset(uint32_t cur_offset, int32_t* pOffset, bool* pConditional,
+                                  bool* selfOkay) {
+  const uint16_t* insns = code_item_->insns_ + cur_offset;
+  *pConditional = false;
+  *selfOkay = false;
   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:
@@ -490,234 +1268,36 @@
     case Instruction::IF_LEZ:
       *pOffset = (int16_t) insns[1];
       *pConditional = true;
-      *selfOkay = false;
       break;
     default:
       return false;
       break;
   }
-
   return true;
 }
 
-bool DexVerifier::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;
-
+bool DexVerifier::CheckSwitchTargets(uint32_t cur_offset) {
+  const uint32_t insn_count = code_item_->insns_size_in_code_units_;
   DCHECK_LT(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;
-}
-
-bool DexVerifier::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;
-}
-
-bool DexVerifier::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;
-}
-
-bool DexVerifier::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;
-}
-
-bool DexVerifier::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;
-}
-
-bool DexVerifier::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;
-}
-
-bool DexVerifier::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;
-}
-
-bool DexVerifier::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;
-}
-
-bool DexVerifier::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;
-}
-
-bool DexVerifier::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;
-}
-
-bool DexVerifier::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;
-}
-
-bool DexVerifier::CheckSwitchTargets(const DexFile::CodeItem* code_item,
-    InsnFlags 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;
-
+  const uint16_t* insns = code_item_->insns_ + cur_offset;
   /* 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;
+  int32_t switch_offset = insns[1] | ((int32_t) insns[2]) << 16;
+  if ((int32_t) cur_offset + switch_offset < 0 || cur_offset + switch_offset + 2 >= insn_count) {
+    Fail(VERIFY_ERROR_GENERIC) << "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;
-
+  const uint16_t* 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;
+    Fail(VERIFY_ERROR_GENERIC) << "unaligned switch table: at " << cur_offset
+                               << ", switch offset " << switch_offset;
     return false;
   }
-
-  switch_count = switch_insns[1];
-
+  uint32_t switch_count = switch_insns[1];
+  int32_t keys_offset, targets_offset;
+  uint16_t expected_signature;
   if ((*insns & 0xff) == Instruction::PACKED_SWITCH) {
     /* 0=sig, 1=count, 2/3=firstKey */
     targets_offset = 4;
@@ -729,543 +1309,301 @@
     targets_offset = 2 + 2 * switch_count;
     expected_signature = Instruction::kSparseSwitchSignature;
   }
-  table_size = targets_offset + switch_count * 2;
-
+  uint32_t table_size = targets_offset + switch_count * 2;
   if (switch_insns[0] != expected_signature) {
-    LOG(ERROR) << "VFY: wrong signature for switch table (0x" << std::hex
-               << switch_insns[0] << ", wanted 0x" << expected_signature << ")"
-               << std::dec;
+    Fail(VERIFY_ERROR_GENERIC) << "wrong signature for switch table (" << (void*) switch_insns[0]
+                               << ", wanted " << (void*) 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;
+    Fail(VERIFY_ERROR_GENERIC) << "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 last_key = switch_insns[keys_offset] | (switch_insns[keys_offset + 1] << 16);
+    for (uint32_t 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;
+        Fail(VERIFY_ERROR_GENERIC) << "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 << " (-> "
-                 << std::hex << abs_offset << ") at " << cur_offset << std::dec
-                 << "[" << targ << "]";
+  for (uint32_t targ = 0; targ < switch_count; targ++) {
+    int32_t offset = (int32_t) switch_insns[targets_offset + targ * 2] |
+                     (int32_t) (switch_insns[targets_offset + targ * 2 + 1] << 16);
+    int32_t abs_offset = cur_offset + offset;
+    if (abs_offset < 0 || abs_offset >= (int32_t) insn_count || !insn_flags_[abs_offset].IsOpcode()) {
+      Fail(VERIFY_ERROR_GENERIC) << "invalid switch target " << offset << " (-> "
+                                 << (void*) abs_offset << ") at "
+                                 << (void*) cur_offset << "[" << targ << "]";
       return false;
     }
-    InsnSetBranchTarget(insn_flags, abs_offset);
+    insn_flags_[abs_offset].SetBranchTarget();
+  }
+  return true;
+}
+
+bool DexVerifier::CheckVarArgRegs(uint32_t vA, uint32_t arg[]) {
+  if (vA > 5) {
+    Fail(VERIFY_ERROR_GENERIC) << "invalid arg count (" << vA << ") in non-range invoke)";
+    return false;
+  }
+  uint16_t registers_size = code_item_->registers_size_;
+  for (uint32_t idx = 0; idx < vA; idx++) {
+    if (arg[idx] > registers_size) {
+      Fail(VERIFY_ERROR_GENERIC) << "invalid reg index (" << arg[idx]
+                                 << ") in non-range invoke (> " << registers_size << ")";
+      return false;
+    }
   }
 
   return true;
 }
 
-bool DexVerifier::CheckBranchTarget(const DexFile::CodeItem* code_item,
-    InsnFlags insn_flags[], uint32_t cur_offset) {
-  const uint32_t 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" << std::hex
-               << cur_offset << std::dec;
+bool DexVerifier::CheckVarArgRangeRegs(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) {
+    Fail(VERIFY_ERROR_GENERIC) << "invalid reg index " << vA << "+" << vC << " in range invoke (> "
+                               << registers_size << ")";
     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 " << std::hex << cur_offset
-               << std::dec << " +" << offset;
-    return false;
-  }
-  abs_offset = cur_offset + offset;
-  if (abs_offset < 0 || (uint32_t) abs_offset >= insn_count ||
-      !InsnIsOpcode(insn_flags, abs_offset))
-  {
-    LOG(ERROR) << "VFY: invalid branch target " << offset << " (-> "
-               << std::hex << abs_offset << ") at " << cur_offset << std::dec;
-    return false;
-  }
-  InsnSetBranchTarget(insn_flags, abs_offset);
-
   return true;
 }
 
-bool DexVerifier::InitRegisterTable(VerifierData* vdata,
-    RegisterTable* reg_table, RegisterTrackingMode track_regs_for) {
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  InsnFlags* insn_flags = vdata->insn_flags_.get();
-  uint16_t registers_size = code_item->registers_size_;
-  uint32_t insns_size = code_item->insns_size_;
-  uint32_t i;
+bool DexVerifier::VerifyCodeFlow() {
+  uint16_t registers_size = code_item_->registers_size_;
+  uint32_t insns_size = code_item_->insns_size_in_code_units_;
 
-  /*
-   * Every address gets a RegisterLine struct. This is wasteful, but
-   * not so much that it's worth chasing through an extra level of
-   * indirection.
-   */
-  reg_table->insn_reg_count_plus_ = registers_size + kExtraRegs;
-  reg_table->register_lines_.reset(new RegisterLine[insns_size]());
+  if (registers_size * insns_size > 4*1024*1024) {
+    Fail(VERIFY_ERROR_GENERIC) << "warning: method is huge (regs=" << registers_size
+                               << " insns_size=" << insns_size << ")";
+  }
+  /* Create and initialize table holding register status */
+  reg_table_.Init(PcToRegisterLineTable::kTrackRegsGcPoints, insn_flags_.get(), insns_size,
+                  registers_size, this);
 
-  DCHECK_GT(insns_size, 0U);
+  work_line_.reset(new RegisterLine(registers_size, this));
+  saved_line_.reset(new RegisterLine(registers_size, this));
 
-  bool track_monitors;
-  //if (gDvm.monitorVerification) {
-    //track_monitors = (vdata->monitor_enter_count_ != 0);
-  //} else {
-    track_monitors = false;
-  //}
-
-  /*
-   * Allocate entries in the sparse register line table.
-   *
-   * There is a RegisterLine associated with every address, but not
-   * every RegisterLine has non-NULL pointers to storage for its fields.
-   */
-  for (i = 0; i < insns_size; i++) {
-    bool interesting;
-
-    switch (track_regs_for) {
-      case kTrackRegsAll:
-        interesting = InsnIsOpcode(insn_flags, i);
-        break;
-      case kTrackRegsGcPoints:
-        interesting = InsnIsGcPoint(insn_flags, i) ||
-                      InsnIsBranchTarget(insn_flags, i);
-        break;
-      case kTrackRegsBranches:
-        interesting = InsnIsBranchTarget(insn_flags, i);
-        break;
-      default:
-        return false;
-    }
-
-    if (interesting) {
-      reg_table->register_lines_[i].Alloc(reg_table->insn_reg_count_plus_,
-          track_monitors);
-    }
+  /* Initialize register types of method arguments. */
+  if (!SetTypesFromSignature()) {
+    Fail(VERIFY_ERROR_GENERIC) << "bad signature in " << PrettyMethod(method_);
+    return false;
+  }
+  /* Perform code flow verification. */
+  if (!CodeFlowVerifyMethod()) {
+    return false;
   }
 
-  /*
-   * Allocate space for our "temporary" register lines.
-   */
-  reg_table->work_line_.Alloc(reg_table->insn_reg_count_plus_, track_monitors);
-  reg_table->saved_line_.Alloc(reg_table->insn_reg_count_plus_, track_monitors);
-
+  /* Generate a register map and add it to the method. */
+  ByteArray* map = GenerateGcMap();
+  if (map == NULL) {
+    return false;  // Not a real failure, but a failure to encode
+  }
+  method_->SetGcMap(map);
+#ifndef NDEBUG
+  VerifyGcMap();
+#endif
   return true;
 }
 
-DexVerifier::UninitInstanceMap* DexVerifier::CreateUninitInstanceMap(
-    VerifierData* vdata) {
-  Method* method = vdata->method_;
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  size_t new_instance_count = vdata->new_instance_count_;
-
-  if (IsInitMethod(method)) {
-    new_instance_count++;
+void DexVerifier::Dump(std::ostream& os) {
+  if (method_->IsNative()) {
+    os << "Native method" << std::endl;
+    return;
   }
-
-  /*
-   * Allocate the header and map as a single unit.
-   *
-   * TODO: consider having a static instance so we can avoid allocations.
-   * I don't think the verifier is guaranteed to be single-threaded when
-   * running in the VM (rather than dexopt), so that must be taken into
-   * account.
-   */
-  UninitInstanceMap* uninit_map = new UninitInstanceMap(new_instance_count);
-
-  size_t idx = 0;
-  if (IsInitMethod(method)) {
-    uninit_map->map_[idx++].addr_ = kUninitThisArgAddr;
-  }
-
-  /*
-   * Run through and find the new-instance instructions.
-   */
-  uint32_t addr = 0;
-  uint32_t insns_size = code_item->insns_size_;
-  const byte* ptr = reinterpret_cast<const byte*>(code_item->insns_);
-  const Instruction* inst = Instruction::At(ptr);
-  while (addr < insns_size) {
-    Instruction::Code opcode = inst->Opcode();
-    if (opcode == Instruction::NEW_INSTANCE) {
-      uninit_map->map_[idx++].addr_ = addr;
+  DCHECK(code_item_ != NULL);
+  const Instruction* inst = Instruction::At(code_item_->insns_);
+  for (size_t dex_pc = 0; dex_pc < code_item_->insns_size_in_code_units_;
+      dex_pc += insn_flags_[dex_pc].GetLengthInCodeUnits()) {
+    std::ios::fmtflags saved_flags(os.flags());
+    os << std::hex << std::showbase << std::setfill('0') << std::setw(4) << dex_pc << ": ";
+    os.flags(saved_flags);
+    insn_flags_[dex_pc].Dump(os);
+    os << " ";
+    inst->DumpHex(os, 5);
+    os << " ";
+    inst->Dump(os, dex_file_);
+    os << std::endl;
+    RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
+    if (reg_line != NULL) {
+      reg_line->Dump(os);
+      os << std::endl;
     }
-
-    addr += inst->Size();
     inst = inst->Next();
   }
-
-  CHECK_EQ(idx, new_instance_count);
-  return uninit_map;
 }
 
-bool DexVerifier::IsInitMethod(const Method* method) {
-  return (method->GetName()->Equals("<init>"));
-}
-
-Class* DexVerifier::LookupClassByDescriptor(const Method* method,
-    const char* descriptor, VerifyError* failure) {
-  /*
-   * The compiler occasionally puts references to nonexistent classes in
-   * signatures. For example, if you have a non-static inner class with no
-   * constructor, the compiler provides a private <init> for you.
-   * Constructing the class requires <init>(parent), but the outer class can't
-   * call that because the method is private. So the compiler generates a
-   * package-scope <init>(parent,bogus) method that just calls the regular
-   * <init> (the "bogus" part being necessary to distinguish the signature of
-   * the synthetic method). Treating the bogus class as an instance of
-   * java.lang.Object allows the verifier to process the class successfully.
-   */
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  const ClassLoader* class_loader =
-      method->GetDeclaringClass()->GetClassLoader();
-  Class* klass = class_linker->FindClass(descriptor, class_loader);
-
-  if (klass == NULL) {
-    Thread::Current()->ClearException();
-    if (strchr(descriptor, '$') != NULL) {
-      LOG(INFO) << "VFY: unable to find class referenced in signature ("
-                << descriptor << ")";
-    } else {
-      LOG(ERROR) << "VFY: unable to find class referenced in signature ("
-                 << descriptor << ")";
-    }
-
-    /* Check if the descriptor is an array. */
-    if (descriptor[0] == '[' && descriptor[1] != '\0') {
-      /*
-       * There should never be a problem loading primitive arrays.
-       */
-      if (descriptor[1] != 'L' && descriptor[1] != '[') {
-        LOG(ERROR) << "VFY: invalid char in signature in '" << descriptor
-                   << "'";
-        *failure = VERIFY_ERROR_GENERIC;
-      }
-
-      /*
-       * Try to continue with base array type. This will let us pass basic
-       * stuff (e.g. get array len) that wouldn't fly with an Object. This
-       * is NOT correct if the missing type is a primitive array, but we
-       * should never have a problem loading those. (I'm not convinced this
-       * is correct or even useful. Just use Object here?)
-       */
-      klass = class_linker->FindClass("[Ljava/lang/Object;", class_loader);
-    } else if (descriptor[0] == 'L') {
-      /*
-       * We are looking at a non-array reference descriptor;
-       * try to continue with base reference type.
-       */
-      klass = class_linker->FindSystemClass("Ljava/lang/Object;");
-    } else {
-      /* We are looking at a primitive type. */
-      LOG(ERROR) << "VFY: invalid char in signature in '" << descriptor << "'";
-      *failure = VERIFY_ERROR_GENERIC;
-    }
-
-    if (klass == NULL) {
-      *failure = VERIFY_ERROR_GENERIC;
-    }
-  }
-
-  if (klass->IsPrimitive()) {
-    LOG(ERROR) << "VFY: invalid use of primitive type '" << descriptor << "'";
-    *failure = VERIFY_ERROR_GENERIC;
-    klass = NULL;
-  }
-
-  return klass;
-}
-
-Class* DexVerifier::LookupSignatureClass(const Method* method, std::string sig,
-    VerifyError* failure) {
-  DCHECK_EQ(sig[0], 'L');
-  size_t end = sig.find(';');
-
-  if (end == std::string::npos) {
-    LOG(ERROR) << "VFY: bad signature component '" << sig << "' (missing ';')";
-    *failure = VERIFY_ERROR_GENERIC;
-    return NULL;
-  }
-
-  return LookupClassByDescriptor(method, sig.substr(0, end + 1).c_str(),
-      failure);
-}
-
-Class* DexVerifier::LookupSignatureArrayClass(const Method* method,
-    std::string sig, VerifyError* failure) {
-  DCHECK_EQ(sig[0], '[');
-  size_t end = 0;
-
-  while (sig[end] == '[')
-    end++;
-
-  if (sig[end] == 'L') {
-    end = sig.find(';');
-    if (end == std::string::npos) {
-      LOG(ERROR) << "VFY: bad signature component '" << sig
-                 << "' (missing ';')";
-      *failure = VERIFY_ERROR_GENERIC;
-      return NULL;
-    }
-  }
-
-  return LookupClassByDescriptor(method, sig.substr(0, end + 1).c_str(),
-      failure);
-}
-
-bool DexVerifier::SetTypesFromSignature(VerifierData* vdata, RegType* reg_types)
-{
-  Method* method = vdata->method_;
-  const DexFile* dex_file = vdata->dex_file_;
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  UninitInstanceMap* uninit_map = vdata->uninit_map_.get();
-
-  int arg_start = code_item->registers_size_ - code_item->ins_size_;
-  int expected_args = code_item->ins_size_;   /* long/double count as two */
-  int actual_args = 0;
-
-  DCHECK_GE(arg_start, 0);      /* should have been verified earlier */
-
-  /*
-   * Include the "this" pointer.
-   */
-  if (!method->IsStatic()) {
-    /*
-     * If this is a constructor for a class other than java.lang.Object,
-     * mark the first ("this") argument as uninitialized. This restricts
-     * field access until the superclass constructor is called.
-     */
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    Class* klass_object = class_linker->FindSystemClass("Ljava/lang/Object;");
-    if (IsInitMethod(method) && method->GetDeclaringClass() != klass_object) {
-      int idx = SetUninitInstance(uninit_map, kUninitThisArgAddr,
-          method->GetDeclaringClass());
-      DCHECK_EQ(idx, 0);
-      reg_types[arg_start + actual_args] = RegTypeFromUninitIndex(idx);
-    } else {
-      reg_types[arg_start + actual_args] =
-          RegTypeFromClass(method->GetDeclaringClass());
-    }
-    actual_args++;
-  }
-
-  const DexFile::ProtoId& proto_id =
-      dex_file->GetProtoId(method->GetProtoIdx());
-  DexFile::ParameterIterator iterator(*dex_file, proto_id);
-  VerifyError failure = VERIFY_ERROR_NONE;
-
-  for (; iterator.HasNext(); iterator.Next()) {
-    const char* descriptor = iterator.GetDescriptor();
-
-    if (descriptor == NULL) {
-      break;
-    }
-
-    if (actual_args >= expected_args) {
-      LOG(ERROR) << "VFY: expected " << expected_args << " args, found more ("
-                 << descriptor << ")";
-      return false;
-    }
-
-    switch (*descriptor) {
-      case 'L':
-      case '[':
-        /*
-         * We assume that reference arguments are initialized. The only way
-         * it could be otherwise (assuming the caller was verified) is if
-         * the current method is <init>, but in that case it's effectively
-         * considered initialized the instant we reach here (in the sense
-         * that we can return without doing anything or call virtual methods).
-         */
-        {
-          Class* klass =
-              LookupClassByDescriptor(method, descriptor, &failure);
-          if (failure != VERIFY_ERROR_NONE)
-            return false;
-          reg_types[arg_start + actual_args] = RegTypeFromClass(klass);
-        }
-        actual_args++;
-        break;
-      case 'Z':
-        reg_types[arg_start + actual_args] = kRegTypeBoolean;
-        actual_args++;
-        break;
-      case 'C':
-        reg_types[arg_start + actual_args] = kRegTypeChar;
-        actual_args++;
-        break;
-      case 'B':
-        reg_types[arg_start + actual_args] = kRegTypeByte;
-        actual_args++;
-        break;
-      case 'I':
-        reg_types[arg_start + actual_args] = kRegTypeInteger;
-        actual_args++;
-        break;
-      case 'S':
-        reg_types[arg_start + actual_args] = kRegTypeShort;
-        actual_args++;
-        break;
-      case 'F':
-        reg_types[arg_start + actual_args] = kRegTypeFloat;
-        actual_args++;
-        break;
-      case 'D':
-        reg_types[arg_start + actual_args] = kRegTypeDoubleLo;
-        reg_types[arg_start + actual_args +1] = kRegTypeDoubleHi;
-        actual_args += 2;
-        break;
-      case 'J':
-        reg_types[arg_start + actual_args] = kRegTypeLongLo;
-        reg_types[arg_start + actual_args +1] = kRegTypeLongHi;
-        actual_args += 2;
-        break;
-      default:
-        LOG(ERROR) << "VFY: unexpected signature type char '" << descriptor
-                   << "'";
-        return false;
-    }
-  }
-
-  if (actual_args != expected_args) {
-    LOG(ERROR) << "VFY: expected " << expected_args << " args, found "
-               << actual_args;
-    return false;
-  }
-
-  const char* descriptor = dex_file->GetReturnTypeDescriptor(proto_id);
-
-  /*
-   * Validate return type. We don't do the type lookup; just want to make
-   * sure that it has the right format. Only major difference from the
-   * method argument format is that 'V' is supported.
-   */
-  switch (*descriptor) {
+static bool IsPrimitiveDescriptor(char descriptor) {
+  switch (descriptor) {
     case 'I':
     case 'C':
     case 'S':
     case 'B':
     case 'Z':
-    case 'V':
     case 'F':
     case 'D':
     case 'J':
-      if (*(descriptor + 1) != '\0')
-        return false;
-      break;
-    case '[':
-      /* single/multi, object/primitive */
-      while (*++descriptor == '[')
-        ;
-      if (*descriptor == 'L') {
-        while (*++descriptor != ';' && *descriptor != '\0')
-          ;
-        if (*descriptor != ';')
-          return false;
-      } else {
-        if (*(descriptor+1) != '\0')
-          return false;
-      }
-      break;
-    case 'L':
-      /* could be more thorough here, but shouldn't be required */
-      while (*++descriptor != ';' && *descriptor != '\0')
-        ;
-      if (*descriptor != ';')
-        return false;
-      break;
+      return true;
     default:
       return false;
   }
-
-  return true;
 }
 
-int DexVerifier::SetUninitInstance(UninitInstanceMap* uninit_map, int addr,
-    Class* klass) {
-  int idx;
-  DCHECK(klass != NULL);
+bool DexVerifier::SetTypesFromSignature() {
+  RegisterLine* reg_line = reg_table_.GetLine(0);
+  int arg_start = code_item_->registers_size_ - code_item_->ins_size_;
+  size_t expected_args = code_item_->ins_size_;   /* long/double count as two */
 
-  /* TODO: binary search when num_entries > 8 */
-  for (idx = uninit_map->num_entries_ - 1; idx >= 0; idx--) {
-    if (uninit_map->map_[idx].addr_ == addr) {
-      if (uninit_map->map_[idx].klass_ != NULL &&
-          uninit_map->map_[idx].klass_ != klass) {
-        LOG(ERROR) << "VFY: addr " << addr << " already set to "
-                   << (int) uninit_map->map_[idx].klass_ << ", not setting to "
-                   << (int) klass;
-        return -1;          // already set to something else??
-      }
-      uninit_map->map_[idx].klass_ = klass;
-      return idx;
+  DCHECK_GE(arg_start, 0);      /* should have been verified earlier */
+  //Include the "this" pointer.
+  size_t cur_arg = 0;
+  if (!method_->IsStatic()) {
+    // If this is a constructor for a class other than java.lang.Object, mark the first ("this")
+    // argument as uninitialized. This restricts field access until the superclass constructor is
+    // called.
+    Class* declaring_class = method_->GetDeclaringClass();
+    if (method_->IsConstructor() && !declaring_class->IsObjectClass()) {
+      reg_line->SetRegisterType(arg_start + cur_arg,
+                                reg_types_.UninitializedThisArgument(declaring_class));
+    } else {
+      reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.FromClass(declaring_class));
     }
+    cur_arg++;
   }
 
-  LOG(FATAL) << "VFY: addr " << addr << " not found in uninit map";
-  return -1;
+  const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_->GetProtoIdx());
+  DexFile::ParameterIterator iterator(*dex_file_, proto_id);
+
+  for (; iterator.HasNext(); iterator.Next()) {
+    const char* descriptor = iterator.GetDescriptor();
+    if (descriptor == NULL) {
+      LOG(FATAL) << "Null descriptor";
+    }
+    if (cur_arg >= expected_args) {
+      Fail(VERIFY_ERROR_GENERIC) << "expected " << expected_args
+                                 << " args, found more (" << descriptor << ")";
+      return false;
+    }
+    switch (descriptor[0]) {
+      case 'L':
+      case '[':
+        // We assume that reference arguments are initialized. The only way it could be otherwise
+        // (assuming the caller was verified) is if the current method is <init>, but in that case
+        // it's effectively considered initialized the instant we reach here (in the sense that we
+        // can return without doing anything or call virtual methods).
+        {
+          const RegType& reg_type =
+              reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(), descriptor);
+          if (reg_type.IsUnknown()) {
+            DCHECK(Thread::Current()->IsExceptionPending());
+            Thread::Current()->ClearException();
+            Fail(VERIFY_ERROR_GENERIC)
+                << "Unable to resolve descriptor in signature " << descriptor;
+            return false;
+          }
+          reg_line->SetRegisterType(arg_start + cur_arg, reg_type);
+        }
+        break;
+      case 'Z':
+        reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Boolean());
+        break;
+      case 'C':
+        reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Char());
+        break;
+      case 'B':
+        reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Byte());
+        break;
+      case 'I':
+        reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Integer());
+        break;
+      case 'S':
+        reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Short());
+        break;
+      case 'F':
+        reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Float());
+        break;
+      case 'J':
+      case 'D': {
+        const RegType& low_half = descriptor[0] == 'J' ? reg_types_.Long() : reg_types_.Double();
+        reg_line->SetRegisterType(arg_start + cur_arg, low_half);  // implicitly sets high-register
+        cur_arg++;
+        break;
+      }
+      default:
+        Fail(VERIFY_ERROR_GENERIC) << "unexpected signature type char '" << descriptor << "'";
+        return false;
+    }
+    cur_arg++;
+  }
+  if (cur_arg != expected_args) {
+    Fail(VERIFY_ERROR_GENERIC) << "expected " << expected_args << " arguments, found " << cur_arg;
+    return false;
+  }
+  const char* descriptor = dex_file_->GetReturnTypeDescriptor(proto_id);
+  // Validate return type. We don't do the type lookup; just want to make sure that it has the right
+  // format. Only major difference from the method argument format is that 'V' is supported.
+  bool result;
+  if (IsPrimitiveDescriptor(descriptor[0]) || descriptor[0] == 'V') {
+    result = descriptor[1] == '\0';
+  } else if (descriptor[0] == '[') { // single/multi-dimensional array of object/primitive
+    size_t i = 0;
+    do {
+      i++;
+    } while (descriptor[i] == '[');  // process leading [
+    if (descriptor[i] == 'L') {  // object array
+      do {
+        i++;  // find closing ;
+      } while (descriptor[i] != ';' && descriptor[i] != '\0');
+      result = descriptor[i] == ';';
+    } else {  // primitive array
+      result = IsPrimitiveDescriptor(descriptor[i]) && descriptor[i + 1] == '\0';
+    }
+  } else if (descriptor[0] == 'L') {
+    // could be more thorough here, but shouldn't be required
+    size_t i = 0;
+    do {
+      i++;
+    } while (descriptor[i] != ';' && descriptor[i] != '\0');
+    result = descriptor[i] == ';';
+  } else {
+    result = false;
+  }
+  if (!result) {
+    Fail(VERIFY_ERROR_GENERIC) << "unexpected char in return type descriptor '"
+                               << descriptor << "'";
+  }
+  return result;
 }
 
-bool DexVerifier::CodeFlowVerifyMethod(VerifierData* vdata,
-    RegisterTable* reg_table) {
-  const Method* method = vdata->method_;
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  InsnFlags* insn_flags = vdata->insn_flags_.get();
-  const uint16_t* insns = code_item->insns_;
-  uint32_t insns_size = code_item->insns_size_;
-  size_t insn_idx, start_guess;
+bool DexVerifier::CodeFlowVerifyMethod() {
+  const uint16_t* insns = code_item_->insns_;
+  const uint32_t insns_size = code_item_->insns_size_in_code_units_;
 
   /* Begin by marking the first instruction as "changed". */
-  InsnSetChanged(insn_flags, 0, true);
-
-  start_guess = 0;
+  insn_flags_[0].SetChanged();
+  uint32_t start_guess = 0;
 
   /* Continue until no instructions are marked "changed". */
   while (true) {
-    /*
-     * Find the first marked one. Use "start_guess" as a way to find
-     * one quickly.
-     */
-    for (insn_idx = start_guess; insn_idx < insns_size; insn_idx++) {
-      if (InsnIsChanged(insn_flags, insn_idx))
+    // Find the first marked one. Use "start_guess" as a way to find one quickly.
+    uint32_t insn_idx = start_guess;
+    for (; insn_idx < insns_size; insn_idx++) {
+      if (insn_flags_[insn_idx].IsChanged())
         break;
     }
-
     if (insn_idx == insns_size) {
       if (start_guess != 0) {
         /* try again, starting from the top */
@@ -1276,45 +1614,44 @@
         break;
       }
     }
-
-    /*
-     * We carry the working set of registers from instruction to instruction.
-     * If this address can be the target of a branch (or throw) instruction,
-     * or if we're skipping around chasing "changed" flags, we need to load
-     * the set of registers from the table.
-     *
-     * Because we always prefer to continue on to the next instruction, we
-     * should never have a situation where we have a stray "changed" flag set
-     * on an instruction that isn't a branch target.
-     */
-    if (InsnIsBranchTarget(insn_flags, insn_idx)) {
-      RegisterLine* work_line = &reg_table->work_line_;
-      CopyLineFromTable(work_line, reg_table, insn_idx);
+    // We carry the working set of registers from instruction to instruction. If this address can
+    // be the target of a branch (or throw) instruction, or if we're skipping around chasing
+    // "changed" flags, we need to load the set of registers from the table.
+    // Because we always prefer to continue on to the next instruction, we should never have a
+    // situation where we have a stray "changed" flag set on an instruction that isn't a branch
+    // target.
+    work_insn_idx_ = insn_idx;
+    if (insn_flags_[insn_idx].IsBranchTarget()) {
+      work_line_->CopyFromLine(reg_table_.GetLine(insn_idx));
     } else {
 #ifndef NDEBUG
       /*
        * Sanity check: retrieve the stored register line (assuming
        * a full table) and make sure it actually matches.
        */
-      RegisterLine* register_line = GetRegisterLine(reg_table, insn_idx);
-      if (register_line->reg_types_.get() != NULL && CompareLineToTable(reg_table,
-          insn_idx, &reg_table->work_line_) != 0) {
-        LOG(ERROR) << "HUH? work_line diverged in " << PrettyMethod(method);
+      RegisterLine* register_line = reg_table_.GetLine(insn_idx);
+      if (register_line != NULL) {
+        if (work_line_->CompareLine(register_line) != 0) {
+          Dump(std::cout);
+          std::cout << info_messages_.str();
+          LOG(FATAL) << "work_line diverged in " << PrettyMethod(method_)
+              << "@" << (void*)work_insn_idx_ << std::endl
+              << " work_line=" << *work_line_ << std::endl
+              << "  expected=" << *register_line;
+        }
       }
 #endif
     }
-
-    if (!CodeFlowVerifyInstruction(vdata, reg_table, insn_idx, &start_guess)) {
-      LOG(ERROR) << "VFY: failure to verify " << PrettyMethod(method);
+    if (!CodeFlowVerifyInstruction(&start_guess)) {
+      fail_messages_ << std::endl << PrettyMethod(method_) << " failed to verify";
       return false;
     }
-
     /* Clear "changed" and mark as visited. */
-    InsnSetVisited(insn_flags, insn_idx, true);
-    InsnSetChanged(insn_flags, insn_idx, false);
+    insn_flags_[insn_idx].SetVisited();
+    insn_flags_[insn_idx].ClearChanged();
   }
 
-  if (DEAD_CODE_SCAN && ((method->GetAccessFlags() & kAccWritable) == 0)) {
+  if (DEAD_CODE_SCAN && ((method_->GetAccessFlags() & kAccWritable) == 0)) {
     /*
      * Scan for dead code. There's nothing "evil" about dead code
      * (besides the wasted space), but it indicates a flaw somewhere
@@ -1324,8 +1661,8 @@
      * we are almost certainly going to have some dead code.
      */
     int dead_start = -1;
-    for (insn_idx = 0; insn_idx < insns_size;
-         insn_idx += InsnGetWidth(insn_flags, insn_idx)) {
+    uint32_t insn_idx = 0;
+    for (; insn_idx < insns_size; insn_idx += insn_flags_[insn_idx].GetLengthInCodeUnits()) {
       /*
        * Switch-statement data doesn't get "visited" by scanner. It
        * may or may not be preceded by a padding NOP (for alignment).
@@ -1337,41 +1674,27 @@
            (insns[insn_idx + 1] == Instruction::kPackedSwitchSignature ||
             insns[insn_idx + 1] == Instruction::kSparseSwitchSignature ||
             insns[insn_idx + 1] == Instruction::kArrayDataSignature))) {
-        InsnSetVisited(insn_flags, insn_idx, true);
+        insn_flags_[insn_idx].SetVisited();
       }
 
-      if (!InsnIsVisited(insn_flags, insn_idx)) {
+      if (!insn_flags_[insn_idx].IsVisited()) {
         if (dead_start < 0)
           dead_start = insn_idx;
       } else if (dead_start >= 0) {
-        LOG(INFO) << "VFY: dead code 0x" << std::hex << dead_start << "-"
-                  << insn_idx - 1 << std::dec << " in " << PrettyMethod(method);
+        LogVerifyInfo() << "dead code " << (void*) dead_start << "-" << (void*) (insn_idx - 1);
         dead_start = -1;
       }
     }
     if (dead_start >= 0) {
-      LOG(INFO) << "VFY: dead code 0x" << std::hex << dead_start << "-"
-                << insn_idx - 1 << std::dec << " in " << PrettyMethod(method);
+      LogVerifyInfo() << "dead code " << (void*) dead_start << "-" << (void*) (insn_idx - 1);
     }
   }
-
   return true;
 }
 
-bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
-    RegisterTable* reg_table, uint32_t insn_idx, size_t* start_guess) {
-  const Method* method = vdata->method_;
-  Class* klass = method->GetDeclaringClass();
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  InsnFlags* insn_flags = vdata->insn_flags_.get();
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  UninitInstanceMap* uninit_map = vdata->uninit_map_.get();
-  const uint16_t* insns = code_item->insns_ + insn_idx;
-  uint32_t insns_size = code_item->insns_size_;
-  uint32_t registers_size = code_item->registers_size_;
-
+bool DexVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
 #ifdef VERIFIER_STATS
-  if (InsnIsVisited(insn_flags, insn_idx)) {
+  if (CurrentInsnFlags().IsVisited()) {
     gDvm.verifierStats.instrsReexamined++;
   } else {
     gDvm.verifierStats.instrsExamined++;
@@ -1396,18 +1719,17 @@
    *
    * The behavior can be determined from the OpcodeFlags.
    */
-  RegisterLine* work_line = &reg_table->work_line_;
-  const DexFile* dex_file = vdata->dex_file_;
-  const byte* ptr = reinterpret_cast<const byte*>(insns);
-  const Instruction* inst = Instruction::At(ptr);
+  const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
+  const Instruction* inst = Instruction::At(insns);
   Instruction::DecodedInstruction dec_insn(inst);
   int opcode_flag = inst->Flag();
 
-  Class* res_class;
   int32_t branch_target = 0;
-  RegType tmp_type;
   bool just_set_result = false;
-  VerifyError failure = VERIFY_ERROR_NONE;
+  if (false) {
+    // Generate processing back trace to debug verifier
+    LogVerifyInfo() << "Processing " << *inst << std::endl << *work_line_.get();
+  }
 
   /*
    * Make a copy of the previous register state. If the instruction
@@ -1416,14 +1738,11 @@
    * from the "successful" code path (e.g. a check-cast that "improves"
    * a type) to be visible to the exception handler.
    */
-  if ((opcode_flag & Instruction::kThrow) != 0 &&
-      InsnIsInTry(insn_flags, insn_idx)) {
-    CopyRegisterLine(&reg_table->saved_line_, work_line,
-        reg_table->insn_reg_count_plus_);
+  if ((opcode_flag & Instruction::kThrow) != 0 && CurrentInsnFlags().IsInTry()) {
+    saved_line_->CopyFromLine(work_line_.get());
   } else {
 #ifndef NDEBUG
-    memset(reg_table->saved_line_.reg_types_.get(), 0xdd,
-        reg_table->insn_reg_count_plus_ * sizeof(RegType));
+    saved_line_->FillWithGarbage();
 #endif
   }
 
@@ -1435,27 +1754,24 @@
        * the course of executing code then we have a problem.
        */
       if (dec_insn.vA_ != 0) {
-        LOG(ERROR) << "VFY: encountered data table in instruction stream";
-        failure = VERIFY_ERROR_GENERIC;
+        Fail(VERIFY_ERROR_GENERIC) << "encountered data table in instruction stream";
       }
       break;
 
     case Instruction::MOVE:
     case Instruction::MOVE_FROM16:
     case Instruction::MOVE_16:
-      CopyRegister1(work_line, dec_insn.vA_, dec_insn.vB_, kTypeCategory1nr,
-          &failure);
+      work_line_->CopyRegister1(dec_insn.vA_, dec_insn.vB_, kTypeCategory1nr);
       break;
     case Instruction::MOVE_WIDE:
     case Instruction::MOVE_WIDE_FROM16:
     case Instruction::MOVE_WIDE_16:
-      CopyRegister2(work_line, dec_insn.vA_, dec_insn.vB_, &failure);
+      work_line_->CopyRegister2(dec_insn.vA_, dec_insn.vB_);
       break;
     case Instruction::MOVE_OBJECT:
     case Instruction::MOVE_OBJECT_FROM16:
     case Instruction::MOVE_OBJECT_16:
-      CopyRegister1(work_line, dec_insn.vA_, dec_insn.vB_, kTypeCategoryRef,
-          &failure);
+      work_line_->CopyRegister1(dec_insn.vA_, dec_insn.vB_, kTypeCategoryRef);
       break;
 
     /*
@@ -1470,133 +1786,94 @@
      * easier to read in some cases.)
      */
     case Instruction::MOVE_RESULT:
-      CopyResultRegister1(work_line, registers_size, dec_insn.vA_,
-          kTypeCategory1nr, &failure);
+      work_line_->CopyResultRegister1(dec_insn.vA_, false);
       break;
     case Instruction::MOVE_RESULT_WIDE:
-      CopyResultRegister2(work_line, registers_size, dec_insn.vA_, &failure);
+      work_line_->CopyResultRegister2(dec_insn.vA_);
       break;
     case Instruction::MOVE_RESULT_OBJECT:
-      CopyResultRegister1(work_line, registers_size, dec_insn.vA_,
-          kTypeCategoryRef, &failure);
+      work_line_->CopyResultRegister1(dec_insn.vA_, true);
       break;
 
-    case Instruction::MOVE_EXCEPTION:
+    case Instruction::MOVE_EXCEPTION: {
       /*
-       * This statement can only appear as the first instruction in an
-       * exception handler (though not all exception handlers need to
-       * have one of these). We verify that as part of extracting the
+       * This statement can only appear as the first instruction in an exception handler (though not
+       * all exception handlers need to have one of these). We verify that as part of extracting the
        * exception type from the catch block list.
-       *
-       * "res_class" will hold the closest common superclass of all
-       * exceptions that can be handled here.
        */
-      res_class = GetCaughtExceptionType(vdata, insn_idx, &failure);
+      Class* res_class = GetCaughtExceptionType();
       if (res_class == NULL) {
-        DCHECK(failure != VERIFY_ERROR_NONE);
+        DCHECK(failure_ != VERIFY_ERROR_NONE);
       } else {
-        SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(res_class));
+        work_line_->SetRegisterType(dec_insn.vA_, reg_types_.FromClass(res_class));
       }
       break;
-
+    }
     case Instruction::RETURN_VOID:
-      if (!CheckConstructorReturn(method, work_line, registers_size)) {
-        failure = VERIFY_ERROR_GENERIC;
-      } else if (GetMethodReturnType(dex_file, method) != kRegTypeUnknown) {
-        LOG(ERROR) << "VFY: return-void not expected";
-        failure = VERIFY_ERROR_GENERIC;
+      if (!method_->IsConstructor() || work_line_->CheckConstructorReturn()) {
+        if (!GetMethodReturnType().IsUnknown()) {
+          Fail(VERIFY_ERROR_GENERIC) << "return-void not expected";
+        }
       }
       break;
     case Instruction::RETURN:
-      if (!CheckConstructorReturn(method, work_line, registers_size)) {
-        failure = VERIFY_ERROR_GENERIC;
-      } else {
+      if (!method_->IsConstructor() || work_line_->CheckConstructorReturn()) {
         /* check the method signature */
-        RegType return_type = GetMethodReturnType(dex_file, method);
-        CheckTypeCategory(return_type, kTypeCategory1nr, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          LOG(ERROR) << "VFY: return-1nr not expected";
-
-        /*
-         * compiler may generate synthetic functions that write byte
-         * values into boolean fields. Also, it may use integer values
-         * for boolean, byte, short, and character return types.
-         */
-        RegType src_type = GetRegisterType(work_line, dec_insn.vA_);
-        if ((return_type == kRegTypeBoolean && src_type == kRegTypeByte) ||
-           ((return_type == kRegTypeBoolean || return_type == kRegTypeByte ||
-             return_type == kRegTypeShort || return_type == kRegTypeChar) &&
-             src_type == kRegTypeInteger))
-          return_type = src_type;
-
-        /* check the register contents */
-        VerifyRegisterType(work_line, dec_insn.vA_, return_type, &failure);
-        if (failure != VERIFY_ERROR_NONE) {
-          LOG(ERROR) << "VFY: return-1nr on invalid register v" << dec_insn.vA_;
+        const RegType& return_type = GetMethodReturnType();
+        if (!return_type.IsCategory1Types()) {
+          Fail(VERIFY_ERROR_GENERIC) << "unexpected non-category 1 return type " << return_type;
+        } else {
+          // Compilers may generate synthetic functions that write byte values into boolean fields.
+          // Also, it may use integer values for boolean, byte, short, and character return types.
+          const RegType& src_type = work_line_->GetRegisterType(dec_insn.vA_);
+          bool use_src = ((return_type.IsBoolean() && src_type.IsByte()) ||
+                          ((return_type.IsBoolean() || return_type.IsByte() ||
+                           return_type.IsShort() || return_type.IsChar()) &&
+                           src_type.IsInteger()));
+          /* check the register contents */
+          work_line_->VerifyRegisterType(dec_insn.vA_, use_src ? src_type : return_type);
+          if (failure_ != VERIFY_ERROR_NONE) {
+            Fail(VERIFY_ERROR_GENERIC) << "return-1nr on invalid register v" << dec_insn.vA_;
+          }
         }
       }
       break;
     case Instruction::RETURN_WIDE:
-      if (!CheckConstructorReturn(method, work_line, registers_size)) {
-        failure = VERIFY_ERROR_GENERIC;
-      } else {
-        RegType return_type;
-
+      if (!method_->IsConstructor() || work_line_->CheckConstructorReturn()) {
         /* check the method signature */
-        return_type = GetMethodReturnType(dex_file, method);
-        CheckTypeCategory(return_type, kTypeCategory2, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          LOG(ERROR) << "VFY: return-wide not expected";
-
-        /* check the register contents */
-        VerifyRegisterType(work_line, dec_insn.vA_, return_type, &failure);
-        if (failure != VERIFY_ERROR_NONE) {
-          LOG(ERROR) << "VFY: return-wide on invalid register pair v"
-                     << dec_insn.vA_;
+        const RegType& return_type = GetMethodReturnType();
+        if (!return_type.IsCategory2Types()) {
+          Fail(VERIFY_ERROR_GENERIC) << "return-wide not expected";
+        } else {
+          /* check the register contents */
+          work_line_->VerifyRegisterType(dec_insn.vA_, return_type);
+          if (failure_ != VERIFY_ERROR_NONE) {
+            Fail(failure_) << "return-wide on invalid register pair v" << dec_insn.vA_;
+          }
         }
       }
       break;
     case Instruction::RETURN_OBJECT:
-      if (!CheckConstructorReturn(method, work_line, registers_size)) {
-        failure = VERIFY_ERROR_GENERIC;
-      } else {
-        RegType return_type = GetMethodReturnType(dex_file, method);
-        CheckTypeCategory(return_type, kTypeCategoryRef, &failure);
-        if (failure != VERIFY_ERROR_NONE) {
-          LOG(ERROR) << "VFY: return-object not expected";
-          break;
-        }
-
-        /* return_type is the *expected* return type, not register value */
-        DCHECK(return_type != kRegTypeZero);
-        DCHECK(!RegTypeIsUninitReference(return_type));
-
-        /*
-         * Verify that the reference in vAA is an instance of the type
-         * in "return_type". The Zero type is allowed here. If the
-         * method is declared to return an interface, then any
-         * initialized reference is acceptable.
-         *
-         * Note GetClassFromRegister fails if the register holds an
-         * uninitialized reference, so we do not allow them to be
-         * returned.
-         */
-        Class* decl_class = RegTypeInitializedReferenceToClass(return_type);
-        res_class = GetClassFromRegister(work_line, dec_insn.vA_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        if (res_class != NULL) {
-          if (!decl_class->IsInterface() &&
-              !decl_class->IsAssignableFrom(res_class)) {
-            LOG(ERROR) << "VFY: returning " << std::hex
-                       << res_class->GetDescriptor()->ToModifiedUtf8()
-                       << " (cl=0x" << (int) res_class->GetClassLoader()
-                       << "), declared "
-                       << decl_class->GetDescriptor()->ToModifiedUtf8()
-                       << " (cl=0x" << (int) decl_class->GetClassLoader()
-                       << ")" << std::dec;
-            failure = VERIFY_ERROR_GENERIC;
-            break;
+      if (!method_->IsConstructor() || work_line_->CheckConstructorReturn()) {
+        const RegType& return_type = GetMethodReturnType();
+        if (!return_type.IsReferenceTypes()) {
+          Fail(VERIFY_ERROR_GENERIC) << "return-object not expected";
+        } else {
+          /* return_type is the *expected* return type, not register value */
+          DCHECK(!return_type.IsZero());
+          DCHECK(!return_type.IsUninitializedReference());
+          // Verify that the reference in vAA is an instance of the type in "return_type". The Zero
+          // type is allowed here. If the method is declared to return an interface, then any
+          // initialized reference is acceptable.
+          // Note GetClassFromRegister fails if the register holds an uninitialized reference, so
+          // we do not allow them to be returned.
+          Class* decl_class = return_type.GetClass();
+          Class* res_class = work_line_->GetClassFromRegister(dec_insn.vA_);
+          if (res_class != NULL && failure_ == VERIFY_ERROR_NONE) {
+            if (!decl_class->IsInterface() && !decl_class->IsAssignableFrom(res_class)) {
+              Fail(VERIFY_ERROR_GENERIC) << "returning " << PrettyClassAndClassLoader(res_class)
+                                         << ", declared " << PrettyClassAndClassLoader(res_class);
+            }
           }
         }
       }
@@ -1606,43 +1883,40 @@
     case Instruction::CONST_16:
     case Instruction::CONST:
       /* could be boolean, int, float, or a null reference */
-      SetRegisterType(work_line, dec_insn.vA_,
-          DetermineCat1Const((int32_t) dec_insn.vB_));
+      work_line_->SetRegisterType(dec_insn.vA_, reg_types_.FromCat1Const((int32_t) dec_insn.vB_));
       break;
     case Instruction::CONST_HIGH16:
       /* could be boolean, int, float, or a null reference */
-      SetRegisterType(work_line, dec_insn.vA_,
-          DetermineCat1Const((int32_t) dec_insn.vB_ << 16));
+      work_line_->SetRegisterType(dec_insn.vA_,
+                                  reg_types_.FromCat1Const((int32_t) dec_insn.vB_ << 16));
       break;
     case Instruction::CONST_WIDE_16:
     case Instruction::CONST_WIDE_32:
     case Instruction::CONST_WIDE:
     case Instruction::CONST_WIDE_HIGH16:
       /* could be long or double; resolved upon use */
-      SetRegisterType(work_line, dec_insn.vA_, kRegTypeConstLo);
+      work_line_->SetRegisterType(dec_insn.vA_, reg_types_.ConstLo());
       break;
     case Instruction::CONST_STRING:
     case Instruction::CONST_STRING_JUMBO:
-      SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(
-          class_linker->FindSystemClass("Ljava/lang/String;")));
+      work_line_->SetRegisterType(dec_insn.vA_, reg_types_.JavaLangString());
       break;
-    case Instruction::CONST_CLASS:
+    case Instruction::CONST_CLASS: {
       /* make sure we can resolve the class; access check is important */
-      res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vB_, klass, &failure);
+      Class* res_class = ResolveClassAndCheckAccess(dec_insn.vB_);
       if (res_class == NULL) {
-        const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vB_);
-        LOG(ERROR) << "VFY: unable to resolve const-class " << dec_insn.vB_
-                   << " (" << bad_class_desc << ") in "
-                   << klass->GetDescriptor()->ToModifiedUtf8();
-        DCHECK(failure != VERIFY_ERROR_GENERIC);
+        const char* bad_class_desc = dex_file_->dexStringByTypeIdx(dec_insn.vB_);
+        Fail(failure_) << "unable to resolve const-class " << dec_insn.vB_
+                       << " (" << bad_class_desc << ") in "
+                       << PrettyDescriptor(method_->GetDeclaringClass()->GetDescriptor());
+        DCHECK(failure_ != VERIFY_ERROR_GENERIC);
       } else {
-        SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(
-            class_linker->FindSystemClass("Ljava/lang/Class;")));
+        work_line_->SetRegisterType(dec_insn.vA_, reg_types_.JavaLangClass());
       }
       break;
-
+    }
     case Instruction::MONITOR_ENTER:
-      HandleMonitorEnter(work_line, dec_insn.vA_, insn_idx, &failure);
+      work_line_->PushMonitor(dec_insn.vA_, work_insn_idx_);
       break;
     case Instruction::MONITOR_EXIT:
       /*
@@ -1665,12 +1939,11 @@
        * we skip them here); if we can't, then the code path could be
        * "live" so we still need to check it.
        */
-      if (work_line->monitor_entries_.get() != NULL)
-        opcode_flag &= ~Instruction::kThrow;
-      HandleMonitorExit(work_line, dec_insn.vA_, insn_idx, &failure);
+      opcode_flag &= ~Instruction::kThrow;
+      work_line_->PopMonitor(dec_insn.vA_);
       break;
 
-    case Instruction::CHECK_CAST:
+    case Instruction::CHECK_CAST: {
       /*
        * If this instruction succeeds, we will promote register vA to
        * the type in vB. (This could be a demotion -- not expected, so
@@ -1679,168 +1952,147 @@
        * If it fails, an exception is thrown, which we deal with later
        * by ignoring the update to dec_insn.vA_ when branching to a handler.
        */
-      res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vB_, klass, &failure);
+      Class* res_class = ResolveClassAndCheckAccess(dec_insn.vB_);
       if (res_class == NULL) {
-        const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vB_);
-        LOG(ERROR) << "VFY: unable to resolve check-cast " << dec_insn.vB_
-                   << " (" << bad_class_desc << ") in "
-                   << klass->GetDescriptor()->ToModifiedUtf8();
-        DCHECK(failure != VERIFY_ERROR_GENERIC);
+        const char* bad_class_desc = dex_file_->dexStringByTypeIdx(dec_insn.vB_);
+        Fail(failure_) << "unable to resolve check-cast " << dec_insn.vB_
+                       << " (" << bad_class_desc << ") in "
+                       << PrettyDescriptor(method_->GetDeclaringClass()->GetDescriptor());
+        DCHECK(failure_ != VERIFY_ERROR_GENERIC);
       } else {
-        RegType orig_type = GetRegisterType(work_line, dec_insn.vA_);
-        if (!RegTypeIsReference(orig_type)) {
-          LOG(ERROR) << "VFY: check-cast on non-reference in v" << dec_insn.vA_;
-          failure = VERIFY_ERROR_GENERIC;
-          break;
+        const RegType& orig_type = work_line_->GetRegisterType(dec_insn.vA_);
+        if (!orig_type.IsReferenceTypes()) {
+          Fail(VERIFY_ERROR_GENERIC) << "check-cast on non-reference in v" << dec_insn.vA_;
+        } else {
+          work_line_->SetRegisterType(dec_insn.vA_, reg_types_.FromClass(res_class));
         }
-        SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(res_class));
       }
       break;
-    case Instruction::INSTANCE_OF:
+    }
+    case Instruction::INSTANCE_OF: {
       /* make sure we're checking a reference type */
-      tmp_type = GetRegisterType(work_line, dec_insn.vB_);
-      if (!RegTypeIsReference(tmp_type)) {
-        LOG(ERROR) << "VFY: vB not a reference (" << tmp_type << ")";
-        failure = VERIFY_ERROR_GENERIC;
-        break;
-      }
-
-      /* make sure we can resolve the class; access check is important */
-      res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vC_, klass, &failure);
-      if (res_class == NULL) {
-        const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vC_);
-        LOG(ERROR) << "VFY: unable to resolve instanceof " << dec_insn.vC_
-                   << " (" << bad_class_desc << ") in "
-                   << klass->GetDescriptor()->ToModifiedUtf8();
-        DCHECK(failure != VERIFY_ERROR_GENERIC);
+      const RegType& tmp_type = work_line_->GetRegisterType(dec_insn.vB_);
+      if (!tmp_type.IsReferenceTypes()) {
+        Fail(VERIFY_ERROR_GENERIC) << "vB not a reference (" << tmp_type << ")";
       } else {
-        /* result is boolean */
-        SetRegisterType(work_line, dec_insn.vA_, kRegTypeBoolean);
-      }
-      break;
-
-    case Instruction::ARRAY_LENGTH:
-      res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
-      if (failure != VERIFY_ERROR_NONE)
-        break;
-      if (res_class != NULL && !res_class->IsArrayClass()) {
-        LOG(ERROR) << "VFY: array-length on non-array";
-        failure = VERIFY_ERROR_GENERIC;
-        break;
-      }
-      SetRegisterType(work_line, dec_insn.vA_, kRegTypeInteger);
-      break;
-
-    case Instruction::NEW_INSTANCE:
-      res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vB_, klass, &failure);
-      if (res_class == NULL) {
-        const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vB_);
-        LOG(ERROR) << "VFY: unable to resolve new-instance " << dec_insn.vB_
-                   << " (" << bad_class_desc << ") in "
-                   << klass->GetDescriptor()->ToModifiedUtf8();
-        DCHECK(failure != VERIFY_ERROR_GENERIC);
-      } else {
-        RegType uninit_type;
-
-        /* can't create an instance of an interface or abstract class */
-        if (res_class->IsAbstract() || res_class->IsInterface()) {
-          LOG(ERROR) << "VFY: new-instance on interface or abstract class"
-                     << res_class->GetDescriptor()->ToModifiedUtf8();
-          failure = VERIFY_ERROR_INSTANTIATION;
-          break;
+        /* make sure we can resolve the class; access check is important */
+        Class* res_class = ResolveClassAndCheckAccess(dec_insn.vC_);
+        if (res_class == NULL) {
+          const char* bad_class_desc = dex_file_->dexStringByTypeIdx(dec_insn.vC_);
+          Fail(failure_) << "unable to resolve instance of " << dec_insn.vC_
+                         << " (" << bad_class_desc << ") in "
+                         << PrettyDescriptor(method_->GetDeclaringClass()->GetDescriptor());
+          DCHECK(failure_ != VERIFY_ERROR_GENERIC);
+        } else {
+          /* result is boolean */
+          work_line_->SetRegisterType(dec_insn.vA_, reg_types_.Boolean());
         }
-
-        /* add resolved class to uninit map if not already there */
-        int uidx = SetUninitInstance(uninit_map, insn_idx, res_class);
-        DCHECK_GE(uidx, 0);
-        uninit_type = RegTypeFromUninitIndex(uidx);
-
-        /*
-         * Any registers holding previous allocations from this address
-         * that have not yet been initialized must be marked invalid.
-         */
-        MarkUninitRefsAsInvalid(work_line, registers_size, uninit_map,
-            uninit_type);
-
-        /* add the new uninitialized reference to the register ste */
-        SetRegisterType(work_line, dec_insn.vA_, uninit_type);
       }
       break;
-    case Instruction::NEW_ARRAY:
-      res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vC_, klass, &failure);
+    }
+    case Instruction::ARRAY_LENGTH: {
+      Class* res_class = work_line_->GetClassFromRegister(dec_insn.vB_);
+      if (failure_ == VERIFY_ERROR_NONE) {
+        if (res_class != NULL && !res_class->IsArrayClass()) {
+          Fail(VERIFY_ERROR_GENERIC) << "array-length on non-array";
+        } else {
+          work_line_->SetRegisterType(dec_insn.vA_, reg_types_.Integer());
+        }
+      }
+      break;
+    }
+    case Instruction::NEW_INSTANCE: {
+      Class* res_class = ResolveClassAndCheckAccess(dec_insn.vB_);
       if (res_class == NULL) {
-        const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vC_);
-        LOG(ERROR) << "VFY: unable to resolve new-array " << dec_insn.vC_
-                   << " (" << bad_class_desc << ") in "
-                   << klass->GetDescriptor()->ToModifiedUtf8();
-        DCHECK(failure != VERIFY_ERROR_GENERIC);
+        const char* bad_class_desc = dex_file_->dexStringByTypeIdx(dec_insn.vB_);
+        Fail(failure_) << "unable to resolve new-instance " << dec_insn.vB_
+                       << " (" << bad_class_desc << ") in "
+                       << PrettyDescriptor(method_->GetDeclaringClass()->GetDescriptor());
+        DCHECK(failure_ != VERIFY_ERROR_GENERIC);
+      } else {
+        /* can't create an instance of an interface or abstract class */
+        if (res_class->IsPrimitive() || res_class->IsAbstract() || res_class->IsInterface()) {
+          Fail(VERIFY_ERROR_INSTANTIATION)
+              << "new-instance on primitive, interface or abstract class"
+              << PrettyDescriptor(res_class->GetDescriptor());
+        } else {
+          const RegType& uninit_type = reg_types_.Uninitialized(res_class, work_insn_idx_);
+          // Any registers holding previous allocations from this address that have not yet been
+          // initialized must be marked invalid.
+          work_line_->MarkUninitRefsAsInvalid(uninit_type);
+
+          /* add the new uninitialized reference to the register state */
+          work_line_->SetRegisterType(dec_insn.vA_, uninit_type);
+        }
+      }
+      break;
+    }
+    case Instruction::NEW_ARRAY: {
+      Class* res_class = ResolveClassAndCheckAccess(dec_insn.vC_);
+      if (res_class == NULL) {
+        const char* bad_class_desc = dex_file_->dexStringByTypeIdx(dec_insn.vC_);
+        Fail(failure_) << "unable to resolve new-array " << dec_insn.vC_
+                       << " (" << bad_class_desc << ") in "
+                       << PrettyDescriptor(method_->GetDeclaringClass()->GetDescriptor());
+        DCHECK(failure_ != VERIFY_ERROR_GENERIC);
       } else if (!res_class->IsArrayClass()) {
-        LOG(ERROR) << "VFY: new-array on non-array class";
-        failure = VERIFY_ERROR_GENERIC;
+        Fail(VERIFY_ERROR_GENERIC) << "new-array on non-array class";
       } else {
         /* make sure "size" register is valid type */
-        VerifyRegisterType(work_line, dec_insn.vB_, kRegTypeInteger, &failure);
+        work_line_->VerifyRegisterType(dec_insn.vB_, reg_types_.Integer());
         /* set register type to array class */
-        SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(res_class));
+        work_line_->SetRegisterType(dec_insn.vA_, reg_types_.FromClass(res_class));
       }
       break;
+    }
     case Instruction::FILLED_NEW_ARRAY:
-    case Instruction::FILLED_NEW_ARRAY_RANGE:
-      res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vB_, klass, &failure);
+    case Instruction::FILLED_NEW_ARRAY_RANGE: {
+      Class* res_class = ResolveClassAndCheckAccess(dec_insn.vB_);
       if (res_class == NULL) {
-        const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vB_);
-        LOG(ERROR) << "VFY: unable to resolve filled-array " << dec_insn.vB_
-                   << " (" << bad_class_desc << ") in "
-                   << klass->GetDescriptor()->ToModifiedUtf8();
-        DCHECK(failure != VERIFY_ERROR_GENERIC);
+        const char* bad_class_desc = dex_file_->dexStringByTypeIdx(dec_insn.vB_);
+        Fail(failure_) << "unable to resolve filled-array " << dec_insn.vB_
+                       << " (" << bad_class_desc << ") in "
+                       << PrettyDescriptor(method_->GetDeclaringClass()->GetDescriptor());
+        DCHECK(failure_ != VERIFY_ERROR_GENERIC);
       } else if (!res_class->IsArrayClass()) {
-        LOG(ERROR) << "VFY: filled-new-array on non-array class";
-        failure = VERIFY_ERROR_GENERIC;
+        Fail(VERIFY_ERROR_GENERIC) << "filled-new-array on non-array class";
       } else {
         bool is_range = (dec_insn.opcode_ == Instruction::FILLED_NEW_ARRAY_RANGE);
-
         /* check the arguments to the instruction */
-        VerifyFilledNewArrayRegs(method, work_line, &dec_insn, res_class,
-            is_range, &failure);
+        VerifyFilledNewArrayRegs(dec_insn, res_class, is_range);
         /* filled-array result goes into "result" register */
-        SetResultRegisterType(work_line, registers_size,
-            RegTypeFromClass(res_class));
+        work_line_->SetResultRegisterType(reg_types_.FromClass(res_class));
         just_set_result = true;
       }
       break;
-
+    }
     case Instruction::CMPL_FLOAT:
     case Instruction::CMPG_FLOAT:
-      VerifyRegisterType(work_line, dec_insn.vB_, kRegTypeFloat, &failure);
-      VerifyRegisterType(work_line, dec_insn.vC_, kRegTypeFloat, &failure);
-      SetRegisterType(work_line, dec_insn.vA_, kRegTypeBoolean);
+      work_line_->VerifyRegisterType(dec_insn.vB_, reg_types_.Float());
+      work_line_->VerifyRegisterType(dec_insn.vC_, reg_types_.Float());
+      work_line_->SetRegisterType(dec_insn.vA_, reg_types_.Integer());
       break;
     case Instruction::CMPL_DOUBLE:
     case Instruction::CMPG_DOUBLE:
-      VerifyRegisterType(work_line, dec_insn.vB_, kRegTypeDoubleLo, &failure);
-      VerifyRegisterType(work_line, dec_insn.vC_, kRegTypeDoubleLo, &failure);
-      SetRegisterType(work_line, dec_insn.vA_, kRegTypeBoolean);
+      work_line_->VerifyRegisterType(dec_insn.vB_, reg_types_.Double());
+      work_line_->VerifyRegisterType(dec_insn.vC_, reg_types_.Double());
+      work_line_->SetRegisterType(dec_insn.vA_, reg_types_.Integer());
       break;
     case Instruction::CMP_LONG:
-      VerifyRegisterType(work_line, dec_insn.vB_, kRegTypeLongLo, &failure);
-      VerifyRegisterType(work_line, dec_insn.vC_, kRegTypeLongLo, &failure);
-      SetRegisterType(work_line, dec_insn.vA_, kRegTypeBoolean);
+      work_line_->VerifyRegisterType(dec_insn.vB_, reg_types_.Long());
+      work_line_->VerifyRegisterType(dec_insn.vC_, reg_types_.Long());
+      work_line_->SetRegisterType(dec_insn.vA_, reg_types_.Integer());
       break;
-
-    case Instruction::THROW:
-      res_class = GetClassFromRegister(work_line, dec_insn.vA_, &failure);
-      if (failure == VERIFY_ERROR_NONE && res_class != NULL) {
-        Class* throwable_class =
-            class_linker->FindSystemClass("Ljava/lang/Throwable;");
-        if (!throwable_class->IsAssignableFrom(res_class)) {
-          LOG(ERROR) << "VFY: thrown class "
-                     << res_class->GetDescriptor()->ToModifiedUtf8()
-                     << " not instanceof Throwable",
-          failure = VERIFY_ERROR_GENERIC;
+    case Instruction::THROW: {
+      Class* res_class = work_line_->GetClassFromRegister(dec_insn.vA_);
+      if (failure_ == VERIFY_ERROR_NONE && res_class != NULL) {
+        if (!JavaLangThrowable()->IsAssignableFrom(res_class)) {
+          Fail(VERIFY_ERROR_GENERIC) << "thrown class "
+              << PrettyDescriptor(res_class->GetDescriptor()) << " not instanceof Throwable";
         }
       }
       break;
-
+    }
     case Instruction::GOTO:
     case Instruction::GOTO_16:
     case Instruction::GOTO_32:
@@ -1850,1013 +2102,280 @@
     case Instruction::PACKED_SWITCH:
     case Instruction::SPARSE_SWITCH:
       /* verify that vAA is an integer, or can be converted to one */
-      VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeInteger, &failure);
+      work_line_->VerifyRegisterType(dec_insn.vA_, reg_types_.Integer());
       break;
 
-    case Instruction::FILL_ARRAY_DATA:
-      {
-        RegType value_type;
-        const uint16_t *array_data;
-        uint16_t elem_width;
-
-        /* Similar to the verification done for APUT */
-        res_class = GetClassFromRegister(work_line, dec_insn.vA_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
+    case Instruction::FILL_ARRAY_DATA: {
+      /* Similar to the verification done for APUT */
+      Class* res_class = work_line_->GetClassFromRegister(dec_insn.vA_);
+      if (failure_ == VERIFY_ERROR_NONE) {
         /* res_class can be null if the reg type is Zero */
-        if (res_class == NULL)
-          break;
-
-        Class::PrimitiveType prim_type =
-            res_class->GetComponentType()->GetPrimitiveType();
-        if (!res_class->IsArrayClass() ||
-            prim_type == Class::kPrimNot || prim_type == Class::kPrimVoid) {
-          LOG(ERROR) << "VFY: invalid fill-array-data on " <<
-                res_class->GetDescriptor()->ToModifiedUtf8();
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        value_type = PrimitiveTypeToRegType(prim_type);
-        DCHECK(value_type != kRegTypeUnknown);
-
-        /*
-         * Now verify if the element width in the table matches the element
-         * width declared in the array
-         */
-        array_data = insns + (insns[1] | (((int32_t) insns[2]) << 16));
-        if (array_data[0] != Instruction::kArrayDataSignature) {
-          LOG(ERROR) << "VFY: invalid magic for array-data";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        switch (prim_type) {
-          case Class::kPrimBoolean:
-          case Class::kPrimByte:
-            elem_width = 1;
-            break;
-          case Class::kPrimChar:
-          case Class::kPrimShort:
-            elem_width = 2;
-            break;
-          case Class::kPrimFloat:
-          case Class::kPrimInt:
-            elem_width = 4;
-            break;
-          case Class::kPrimDouble:
-          case Class::kPrimLong:
-            elem_width = 8;
-            break;
-          default:
-            elem_width = 0;
-            break;
-        }
-
-        /*
-         * Since we don't compress the data in Dex, expect to see equal
-         * width of data stored in the table and expected from the array
-         * class.
-         */
-        if (array_data[1] != elem_width) {
-          LOG(ERROR) << "VFY: array-data size mismatch (" << array_data[1]
-                     << " vs " << elem_width << ")";
-          failure = VERIFY_ERROR_GENERIC;
+        if (res_class != NULL) {
+          Class* component_type = res_class->GetComponentType();
+          if (!res_class->IsArrayClass() || !component_type->IsPrimitive()  ||
+              component_type->IsPrimitiveVoid()) {
+            Fail(VERIFY_ERROR_GENERIC) << "invalid fill-array-data on "
+                                       << PrettyDescriptor(res_class->GetDescriptor());
+          } else {
+            const RegType& value_type = reg_types_.FromClass(component_type);
+            DCHECK(!value_type.IsUnknown());
+            // Now verify if the element width in the table matches the element width declared in
+            // the array
+            const uint16_t* array_data = insns + (insns[1] | (((int32_t) insns[2]) << 16));
+            if (array_data[0] != Instruction::kArrayDataSignature) {
+              Fail(VERIFY_ERROR_GENERIC) << "invalid magic for array-data";
+            } else {
+              size_t elem_width = component_type->PrimitiveSize();
+              // Since we don't compress the data in Dex, expect to see equal width of data stored
+              // in the table and expected from the array class.
+              if (array_data[1] != elem_width) {
+                Fail(VERIFY_ERROR_GENERIC) << "array-data size mismatch (" << array_data[1]
+                                           << " vs " << elem_width << ")";
+              }
+            }
+          }
         }
       }
       break;
-
+    }
     case Instruction::IF_EQ:
-    case Instruction::IF_NE:
-      {
-        RegType type1, type2;
-
-        type1 = GetRegisterType(work_line, dec_insn.vA_);
-        type2 = GetRegisterType(work_line, dec_insn.vB_);
-
-        /* both references? */
-        if (RegTypeIsReference(type1) && RegTypeIsReference(type2))
-          break;
-
-        /* both category-1nr? */
-        CheckTypeCategory(type1, kTypeCategory1nr, &failure);
-        CheckTypeCategory(type2, kTypeCategory1nr, &failure);
-        if (failure != VERIFY_ERROR_NONE) {
-          LOG(ERROR) << "VFY: args to if-eq/if-ne must both be refs or cat1";
-          break;
-        }
+    case Instruction::IF_NE: {
+      const RegType& reg_type1 = work_line_->GetRegisterType(dec_insn.vA_);
+      const RegType& reg_type2 = work_line_->GetRegisterType(dec_insn.vB_);
+      bool mismatch = false;
+      if (reg_type1.IsZero()) {  // zero then integral or reference expected
+        mismatch = !reg_type2.IsReferenceTypes() && !reg_type2.IsIntegralTypes();
+      } else if (reg_type1.IsReferenceTypes()) {  // both references?
+        mismatch = !reg_type2.IsReferenceTypes();
+      } else {  // both integral?
+        mismatch = !reg_type1.IsIntegralTypes() || !reg_type2.IsIntegralTypes();
+      }
+      if (mismatch) {
+        Fail(VERIFY_ERROR_GENERIC) << "args to if-eq/if-ne (" << reg_type1 << "," << reg_type2
+                                   << ") must both be references or integral";
       }
       break;
+    }
     case Instruction::IF_LT:
     case Instruction::IF_GE:
     case Instruction::IF_GT:
-    case Instruction::IF_LE:
-      tmp_type = GetRegisterType(work_line, dec_insn.vA_);
-      CheckTypeCategory(tmp_type, kTypeCategory1nr, &failure);
-      if (failure != VERIFY_ERROR_NONE) {
-        LOG(ERROR) << "VFY: args to 'if' must be cat-1nr";
-        break;
-      }
-      tmp_type = GetRegisterType(work_line, dec_insn.vB_);
-      CheckTypeCategory(tmp_type, kTypeCategory1nr, &failure);
-      if (failure != VERIFY_ERROR_NONE) {
-        LOG(ERROR) << "VFY: args to 'if' must be cat-1nr";
-        break;
+    case Instruction::IF_LE: {
+      const RegType& reg_type1 = work_line_->GetRegisterType(dec_insn.vA_);
+      const RegType& reg_type2 = work_line_->GetRegisterType(dec_insn.vB_);
+      if (!reg_type1.IsIntegralTypes() || !reg_type2.IsIntegralTypes()) {
+        Fail(VERIFY_ERROR_GENERIC) << "args to 'if' (" << reg_type1 << ","
+                                   << reg_type2 << ") must be integral";
       }
       break;
+    }
     case Instruction::IF_EQZ:
-    case Instruction::IF_NEZ:
-      tmp_type = GetRegisterType(work_line, dec_insn.vA_);
-      if (RegTypeIsReference(tmp_type))
-        break;
-      CheckTypeCategory(tmp_type, kTypeCategory1nr, &failure);
-      if (failure != VERIFY_ERROR_NONE)
-        LOG(ERROR) << "VFY: expected cat-1 arg to if";
+    case Instruction::IF_NEZ: {
+      const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA_);
+      if (!reg_type.IsReferenceTypes() && !reg_type.IsIntegralTypes()) {
+        Fail(VERIFY_ERROR_GENERIC) << "type " << reg_type << " unexpected as arg to if-eqz/if-nez";
+      }
       break;
+    }
     case Instruction::IF_LTZ:
     case Instruction::IF_GEZ:
     case Instruction::IF_GTZ:
-    case Instruction::IF_LEZ:
-      tmp_type = GetRegisterType(work_line, dec_insn.vA_);
-      CheckTypeCategory(tmp_type, kTypeCategory1nr, &failure);
-      if (failure != VERIFY_ERROR_NONE)
-        LOG(ERROR) << "VFY: expected cat-1 arg to if";
+    case Instruction::IF_LEZ: {
+      const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA_);
+      if (!reg_type.IsIntegralTypes()) {
+        Fail(VERIFY_ERROR_GENERIC) << "type " << reg_type
+                                   << " unexpected as arg to if-ltz/if-gez/if-gtz/if-lez";
+      }
       break;
-
-    case Instruction::AGET:
-      tmp_type = kRegTypeConstInteger;
-      goto aget_1nr_common;
+    }
     case Instruction::AGET_BOOLEAN:
-      tmp_type = kRegTypeBoolean;
-      goto aget_1nr_common;
+      VerifyAGet(dec_insn, reg_types_.Boolean(), true);
+      break;
     case Instruction::AGET_BYTE:
-      tmp_type = kRegTypeByte;
-      goto aget_1nr_common;
+      VerifyAGet(dec_insn, reg_types_.Byte(), true);
+      break;
     case Instruction::AGET_CHAR:
-      tmp_type = kRegTypeChar;
-      goto aget_1nr_common;
+      VerifyAGet(dec_insn, reg_types_.Char(), true);
+      break;
     case Instruction::AGET_SHORT:
-      tmp_type = kRegTypeShort;
-      goto aget_1nr_common;
-aget_1nr_common:
-      {
-        RegType src_type, index_type;
-
-        index_type = GetRegisterType(work_line, dec_insn.vC_);
-        CheckArrayIndexType(method, index_type, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        if (res_class != NULL) {
-          /* verify the class */
-          Class::PrimitiveType prim_type =
-              res_class->GetComponentType()->GetPrimitiveType();
-          if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot) {
-            LOG(ERROR) << "VFY: invalid aget-1nr target "
-                       << res_class->GetDescriptor()->ToModifiedUtf8();
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-
-          /* make sure array type matches instruction */
-          src_type = PrimitiveTypeToRegType(prim_type);
-
-          /* differentiate between float and int */
-          if (src_type == kRegTypeFloat || src_type == kRegTypeInteger)
-            tmp_type = src_type;
-
-          if (tmp_type != src_type) {
-            LOG(ERROR) << "VFY: invalid aget-1nr, array type=" << src_type
-                       << " with inst type=" << tmp_type << " (on "
-                       << res_class->GetDescriptor()->ToModifiedUtf8() << ")";
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-        }
-        SetRegisterType(work_line, dec_insn.vA_, tmp_type);
-      }
+      VerifyAGet(dec_insn, reg_types_.Short(), true);
       break;
-
+    case Instruction::AGET:
+      VerifyAGet(dec_insn, reg_types_.Integer(), true);
+      break;
     case Instruction::AGET_WIDE:
-      {
-        RegType dst_type, index_type;
-
-        index_type = GetRegisterType(work_line, dec_insn.vC_);
-        CheckArrayIndexType(method, index_type, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        if (res_class != NULL) {
-          /* verify the class */
-          Class::PrimitiveType prim_type =
-              res_class->GetComponentType()->GetPrimitiveType();
-          if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot) {
-            LOG(ERROR) << "VFY: invalid aget-wide target "
-                       << res_class->GetDescriptor()->ToModifiedUtf8();
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-
-          /* try to refine "dst_type" */
-          switch (prim_type) {
-            case Class::kPrimLong:
-              dst_type = kRegTypeLongLo;
-              break;
-            case Class::kPrimDouble:
-              dst_type = kRegTypeDoubleLo;
-              break;
-            default:
-              LOG(ERROR) << "VFY: invalid aget-wide on "
-                         << res_class->GetDescriptor()->ToModifiedUtf8();
-              dst_type = kRegTypeUnknown;
-              failure = VERIFY_ERROR_GENERIC;
-              break;
-          }
-        } else {
-          /*
-           * Null array ref; this code path will fail at runtime. We
-           * know this is either long or double, so label it const.
-           */
-          dst_type = kRegTypeConstLo;
-        }
-        SetRegisterType(work_line, dec_insn.vA_, dst_type);
-      }
+      VerifyAGet(dec_insn, reg_types_.Long(), true);
+      break;
+    case Instruction::AGET_OBJECT:
+      VerifyAGet(dec_insn, reg_types_.JavaLangObject(), false);
       break;
 
-    case Instruction::AGET_OBJECT:
-      {
-        RegType dst_type, index_type;
-
-        index_type = GetRegisterType(work_line, dec_insn.vC_);
-        CheckArrayIndexType(method, index_type, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        /* get the class of the array we're pulling an object from */
-        res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        if (res_class != NULL) {
-          Class* element_class;
-
-          DCHECK(res_class != NULL);
-          if (!res_class->IsArrayClass()) {
-            LOG(ERROR) << "VFY: aget-object on non-array class";
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-          DCHECK(res_class->GetComponentType() != NULL);
-
-          /*
-           * Find the element class.
-           */
-          element_class = res_class->GetComponentType();
-          if (element_class->IsPrimitive()) {
-            LOG(ERROR) << "VFY: aget-object on non-ref array class ("
-                       << res_class->GetDescriptor()->ToModifiedUtf8() << ")";
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-
-          dst_type = RegTypeFromClass(element_class);
-        } else {
-          /*
-           * The array reference is NULL, so the current code path will
-           * throw an exception. For proper merging with later code
-           * paths, and correct handling of "if-eqz" tests on the
-           * result of the array get, we want to treat this as a null
-           * reference.
-           */
-          dst_type = kRegTypeZero;
-        }
-      SetRegisterType(work_line, dec_insn.vA_, dst_type);
-      }
+    case Instruction::APUT_BOOLEAN:
+      VerifyAPut(dec_insn, reg_types_.Boolean(), true);
+      break;
+    case Instruction::APUT_BYTE:
+      VerifyAPut(dec_insn, reg_types_.Byte(), true);
+      break;
+    case Instruction::APUT_CHAR:
+      VerifyAPut(dec_insn, reg_types_.Char(), true);
+      break;
+    case Instruction::APUT_SHORT:
+      VerifyAPut(dec_insn, reg_types_.Short(), true);
       break;
     case Instruction::APUT:
-      tmp_type = kRegTypeInteger;
-      goto aput_1nr_common;
-    case Instruction::APUT_BOOLEAN:
-      tmp_type = kRegTypeBoolean;
-      goto aput_1nr_common;
-    case Instruction::APUT_BYTE:
-      tmp_type = kRegTypeByte;
-      goto aput_1nr_common;
-    case Instruction::APUT_CHAR:
-      tmp_type = kRegTypeChar;
-      goto aput_1nr_common;
-    case Instruction::APUT_SHORT:
-      tmp_type = kRegTypeShort;
-      goto aput_1nr_common;
-aput_1nr_common:
-      {
-        RegType src_type, dst_type, index_type;
-
-        index_type = GetRegisterType(work_line, dec_insn.vC_);
-        CheckArrayIndexType(method, index_type, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        /* res_class can be null if the reg type is Zero */
-        if (res_class == NULL)
-          break;
-
-        Class::PrimitiveType prim_type =
-            res_class->GetComponentType()->GetPrimitiveType();
-        if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot) {
-          LOG(ERROR) << "VFY: invalid aput-1nr on "
-                     << res_class->GetDescriptor()->ToModifiedUtf8();
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        /* verify that instruction matches array */
-        dst_type = PrimitiveTypeToRegType(prim_type);
-
-        /* correct if float */
-        if (dst_type == kRegTypeFloat)
-          tmp_type = kRegTypeFloat;
-
-        /* make sure the source register has the correct type */
-        src_type = GetRegisterType(work_line, dec_insn.vA_);
-        if (!CanConvertTo1nr(src_type, tmp_type)) {
-          LOG(ERROR) << "VFY: invalid reg type " << src_type
-                     << " on aput instr (need " << tmp_type << ")";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        VerifyRegisterType(work_line, dec_insn.vA_, dst_type, &failure);
-
-        if (failure != VERIFY_ERROR_NONE || dst_type == kRegTypeUnknown ||
-          tmp_type != dst_type) {
-          LOG(ERROR) << "VFY: invalid aput-1nr on "
-                     << res_class->GetDescriptor()->ToModifiedUtf8()
-                     << " (inst=" << tmp_type << " dst=" << dst_type << ")";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-      }
+      VerifyAPut(dec_insn, reg_types_.Integer(), true);
       break;
     case Instruction::APUT_WIDE:
-      tmp_type = GetRegisterType(work_line, dec_insn.vC_);
-      CheckArrayIndexType(method, tmp_type, &failure);
-      if (failure != VERIFY_ERROR_NONE)
-        break;
-
-      res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
-      if (failure != VERIFY_ERROR_NONE)
-        break;
-      if (res_class != NULL) {
-        Class::PrimitiveType prim_type =
-            res_class->GetComponentType()->GetPrimitiveType();
-        /* verify the class and try to refine "dst_type" */
-        if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot)
-        {
-          LOG(ERROR) << "VFY: invalid aput-wide on "
-                     << res_class->GetDescriptor()->ToModifiedUtf8();
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        switch (prim_type) {
-          case Class::kPrimLong:
-            VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeLongLo,
-                &failure);
-            break;
-          case Class::kPrimDouble:
-            VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeDoubleLo,
-                &failure);
-            break;
-          default:
-            LOG(ERROR) << "VFY: invalid aput-wide on "
-                       << res_class->GetDescriptor()->ToModifiedUtf8();
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-        }
-      }
+      VerifyAPut(dec_insn, reg_types_.Long(), true);
       break;
     case Instruction::APUT_OBJECT:
-      tmp_type = GetRegisterType(work_line, dec_insn.vC_);
-      CheckArrayIndexType(method, tmp_type, &failure);
-      if (failure != VERIFY_ERROR_NONE)
-        break;
-
-      /* get the ref we're storing; Zero is okay, Uninit is not */
-      res_class = GetClassFromRegister(work_line, dec_insn.vA_, &failure);
-      if (failure != VERIFY_ERROR_NONE)
-        break;
-      if (res_class != NULL) {
-        Class* array_class;
-        Class* element_class;
-
-        /*
-         * Get the array class. If the array ref is null, we won't
-         * have type information (and we'll crash at runtime with a
-         * null pointer exception).
-         */
-        array_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
-
-        if (array_class != NULL) {
-          /* see if the array holds a compatible type */
-          if (!array_class->IsArrayClass()) {
-            LOG(ERROR) << "VFY: invalid aput-object on "
-                       << array_class->GetDescriptor()->ToModifiedUtf8();
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-
-          /*
-           * Find the element class.
-           *
-           * All we want to check here is that the element type is a
-           * reference class. We *don't* check instanceof here, because
-           * you can still put a String into a String[] after the latter
-           * has been cast to an Object[].
-           */
-          element_class = array_class->GetComponentType();
-          if (element_class->IsPrimitive()) {
-            LOG(ERROR) << "VFY: invalid aput-object of "
-                       << res_class->GetDescriptor()->ToModifiedUtf8()
-                       << " into "
-                       << array_class->GetDescriptor()->ToModifiedUtf8();
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-        }
-      }
+      VerifyAPut(dec_insn, reg_types_.JavaLangObject(), false);
       break;
 
-    case Instruction::IGET:
-      tmp_type = kRegTypeInteger;
-      goto iget_1nr_common;
     case Instruction::IGET_BOOLEAN:
-      tmp_type = kRegTypeBoolean;
-      goto iget_1nr_common;
+      VerifyIGet(dec_insn, reg_types_.Boolean(), true);
+      break;
     case Instruction::IGET_BYTE:
-      tmp_type = kRegTypeByte;
-      goto iget_1nr_common;
+      VerifyIGet(dec_insn, reg_types_.Byte(), true);
+      break;
     case Instruction::IGET_CHAR:
-      tmp_type = kRegTypeChar;
-      goto iget_1nr_common;
+      VerifyIGet(dec_insn, reg_types_.Char(), true);
+      break;
     case Instruction::IGET_SHORT:
-      tmp_type = kRegTypeShort;
-      goto iget_1nr_common;
-iget_1nr_common:
-      {
-        Field* inst_field;
-        RegType obj_type, field_type;
-
-        obj_type = GetRegisterType(work_line, dec_insn.vB_);
-        inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        /* make sure the field's type is compatible with expectation */
-        field_type = PrimitiveTypeToRegType(inst_field->GetType()->GetPrimitiveType());
-
-        /* correct if float */
-        if (field_type == kRegTypeFloat)
-          tmp_type = kRegTypeFloat;
-
-        if (field_type == kRegTypeUnknown || tmp_type != field_type) {
-          LOG(ERROR) << "VFY: invalid iget-1nr of " << PrettyField(inst_field)
-                     << " (inst=" << tmp_type << " field=" << field_type << ")";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        SetRegisterType(work_line, dec_insn.vA_, tmp_type);
-      }
+      VerifyIGet(dec_insn, reg_types_.Short(), true);
+      break;
+    case Instruction::IGET:
+      VerifyIGet(dec_insn, reg_types_.Integer(), true);
       break;
     case Instruction::IGET_WIDE:
-      {
-        Field* inst_field;
-        RegType obj_type;
-
-        obj_type = GetRegisterType(work_line, dec_insn.vB_);
-        inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        /* check the type, which should be prim */
-        switch (inst_field->GetType()->GetPrimitiveType()) {
-          case Class::kPrimDouble:
-            SetRegisterType(work_line, dec_insn.vA_, kRegTypeDoubleLo);
-            break;
-          case Class::kPrimLong:
-            SetRegisterType(work_line, dec_insn.vA_, kRegTypeLongLo);
-            break;
-          default:
-            LOG(ERROR) << "VFY: invalid iget-wide of " << PrettyField(inst_field);
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-        }
-      }
+      VerifyIGet(dec_insn, reg_types_.Long(), true);
       break;
     case Instruction::IGET_OBJECT:
-      {
-        Class* field_class;
-        Field* inst_field;
-        RegType obj_type;
+      VerifyIGet(dec_insn, reg_types_.JavaLangObject(), false);
+      break;
 
-        obj_type = GetRegisterType(work_line, dec_insn.vB_);
-        inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        field_class = inst_field->GetType();
-        if (field_class == NULL) {
-          /* class not found or primitive type */
-          LOG(ERROR) << "VFY: unable to recover field class from "
-                     << inst_field->GetName()->ToModifiedUtf8();
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-        DCHECK(!field_class->IsPrimitive()) << PrettyClass(field_class);
-        SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(field_class));
-      }
+    case Instruction::IPUT_BOOLEAN:
+      VerifyIPut(dec_insn, reg_types_.Boolean(), true);
+      break;
+    case Instruction::IPUT_BYTE:
+      VerifyIPut(dec_insn, reg_types_.Byte(), true);
+      break;
+    case Instruction::IPUT_CHAR:
+      VerifyIPut(dec_insn, reg_types_.Char(), true);
+      break;
+    case Instruction::IPUT_SHORT:
+      VerifyIPut(dec_insn, reg_types_.Short(), true);
       break;
     case Instruction::IPUT:
-      tmp_type = kRegTypeInteger;
-      goto iput_1nr_common;
-    case Instruction::IPUT_BOOLEAN:
-      tmp_type = kRegTypeBoolean;
-      goto iput_1nr_common;
-    case Instruction::IPUT_BYTE:
-      tmp_type = kRegTypeByte;
-      goto iput_1nr_common;
-    case Instruction::IPUT_CHAR:
-      tmp_type = kRegTypeChar;
-      goto iput_1nr_common;
-    case Instruction::IPUT_SHORT:
-      tmp_type = kRegTypeShort;
-      goto iput_1nr_common;
-iput_1nr_common:
-      {
-        RegType src_type, field_type, obj_type;
-        Field* inst_field;
-
-        obj_type = GetRegisterType(work_line, dec_insn.vB_);
-        inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        CheckFinalFieldAccess(method, inst_field, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        /* get type of field we're storing into */
-        field_type = PrimitiveTypeToRegType(inst_field->GetType()->GetPrimitiveType());
-        src_type = GetRegisterType(work_line, dec_insn.vA_);
-
-        /* correct if float */
-        if (field_type == kRegTypeFloat)
-          tmp_type = kRegTypeFloat;
-
-        /*
-         * compiler can generate synthetic functions that write byte values
-         * into boolean fields.
-         */
-        if (tmp_type == kRegTypeBoolean && src_type == kRegTypeByte)
-          tmp_type = kRegTypeByte;
-        if (field_type == kRegTypeBoolean && src_type == kRegTypeByte)
-          field_type = kRegTypeByte;
-
-        /* make sure the source register has the correct type */
-        if (!CanConvertTo1nr(src_type, tmp_type)) {
-          LOG(ERROR) << "VFY: invalid reg type " << src_type
-                     << " on iput instr (need " << tmp_type << ")",
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        VerifyRegisterType(work_line, dec_insn.vA_, field_type, &failure);
-
-        if (failure != VERIFY_ERROR_NONE || field_type == kRegTypeUnknown ||
-            tmp_type != field_type) {
-          LOG(ERROR) << "VFY: invalid iput-1nr of " << PrettyField(inst_field)
-                     << " (inst=" << tmp_type << " field=" << field_type << ")";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-      }
+      VerifyIPut(dec_insn, reg_types_.Integer(), true);
       break;
     case Instruction::IPUT_WIDE:
-      {
-        Field* inst_field;
-        RegType obj_type;
-
-        obj_type = GetRegisterType(work_line, dec_insn.vB_);
-        inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        CheckFinalFieldAccess(method, inst_field, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        /* check the type, which should be prim */
-        switch (inst_field->GetType()->GetPrimitiveType()) {
-          case Class::kPrimDouble:
-            VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeDoubleLo,
-                &failure);
-            break;
-          case Class::kPrimLong:
-            VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeLongLo, &failure);
-            break;
-          default:
-            LOG(ERROR) << "VFY: invalid iput-wide of " << PrettyField(inst_field);
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-        }
-        break;
-      }
+      VerifyIPut(dec_insn, reg_types_.Long(), true);
+      break;
     case Instruction::IPUT_OBJECT:
-      {
-        Class* field_class;
-        Class* value_class;
-        Field* inst_field;
-        RegType obj_type, value_type;
-
-        obj_type = GetRegisterType(work_line, dec_insn.vB_);
-        inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        DCHECK(inst_field != NULL);
-        CheckFinalFieldAccess(method, inst_field, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        field_class = inst_field->GetType();
-        if (field_class == NULL) {
-          LOG(ERROR) << "VFY: unable to recover field class from '"
-                     << inst_field->GetName()->ToModifiedUtf8() << "'";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        value_type = GetRegisterType(work_line, dec_insn.vA_);
-        if (!RegTypeIsReference(value_type)) {
-          LOG(ERROR) << "VFY: storing non-ref v" << dec_insn.vA_
-                     << " into ref field '"
-                     << inst_field->GetName()->ToModifiedUtf8() << "' ("
-                     << field_class->GetDescriptor()->ToModifiedUtf8() << ")";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-        if (value_type != kRegTypeZero) {
-          value_class = RegTypeInitializedReferenceToClass(value_type);
-          if (value_class == NULL) {
-            LOG(ERROR) << "VFY: storing uninit ref v" << dec_insn.vA_
-                       << " into ref field";
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-          /* allow if field is any interface or field is base class */
-          if (!field_class->IsInterface() &&
-              !field_class->IsAssignableFrom(value_class)) {
-            LOG(ERROR) << "VFY: storing type '"
-                       << value_class->GetDescriptor()->ToModifiedUtf8()
-                       << "' into field type '"
-                       << field_class->GetDescriptor()->ToModifiedUtf8()
-                       << "' (" << PrettyField(inst_field) << ")";
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-        }
-      }
+      VerifyIPut(dec_insn, reg_types_.JavaLangObject(), false);
       break;
 
-    case Instruction::SGET:
-      tmp_type = kRegTypeInteger;
-      goto sget_1nr_common;
     case Instruction::SGET_BOOLEAN:
-      tmp_type = kRegTypeBoolean;
-      goto sget_1nr_common;
+      VerifySGet(dec_insn, reg_types_.Boolean(), true);
+      break;
     case Instruction::SGET_BYTE:
-      tmp_type = kRegTypeByte;
-      goto sget_1nr_common;
+      VerifySGet(dec_insn, reg_types_.Byte(), true);
+      break;
     case Instruction::SGET_CHAR:
-      tmp_type = kRegTypeChar;
-      goto sget_1nr_common;
+      VerifySGet(dec_insn, reg_types_.Char(), true);
+      break;
     case Instruction::SGET_SHORT:
-      tmp_type = kRegTypeShort;
-      goto sget_1nr_common;
-sget_1nr_common:
-      {
-        Field* static_field;
-        RegType field_type;
-
-        static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        /*
-         * Make sure the field's type is compatible with expectation.
-         * We can get ourselves into trouble if we mix & match loads
-         * and stores with different widths, so rather than just checking
-         * "CanConvertTo1nr" we require that the field types have equal
-         * widths.
-         */
-        field_type =
-            PrimitiveTypeToRegType(static_field->GetType()->GetPrimitiveType());
-
-        /* correct if float */
-        if (field_type == kRegTypeFloat)
-          tmp_type = kRegTypeFloat;
-
-        if (tmp_type != field_type) {
-          LOG(ERROR) << "VFY: invalid sget-1nr of " << PrettyField(static_field)
-                     << " (inst=" << tmp_type << " actual=" << field_type
-                     << ")";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        SetRegisterType(work_line, dec_insn.vA_, tmp_type);
-      }
+      VerifySGet(dec_insn, reg_types_.Short(), true);
+      break;
+    case Instruction::SGET:
+      VerifySGet(dec_insn, reg_types_.Integer(), true);
       break;
     case Instruction::SGET_WIDE:
-      {
-        Field* static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        /* check the type, which should be prim */
-        switch (static_field->GetType()->GetPrimitiveType()) {
-          case Class::kPrimDouble:
-            SetRegisterType(work_line, dec_insn.vA_, kRegTypeDoubleLo);
-            break;
-          case Class::kPrimLong:
-            SetRegisterType(work_line, dec_insn.vA_, kRegTypeLongLo);
-            break;
-          default:
-            LOG(ERROR) << "VFY: invalid sget-wide of " << PrettyField(static_field);
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-        }
-      }
+      VerifySGet(dec_insn, reg_types_.Long(), true);
       break;
     case Instruction::SGET_OBJECT:
-      {
-        Field* static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        Class* field_class = static_field->GetType();
-        if (field_class == NULL) {
-          LOG(ERROR) << "VFY: unable to recover field class from '"
-                     << static_field->GetName()->ToModifiedUtf8() << "'";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-        if (field_class->IsPrimitive()) {
-          LOG(ERROR) << "VFY: attempt to get prim field with sget-object";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-      SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(field_class));
-      }
+      VerifySGet(dec_insn, reg_types_.JavaLangObject(), false);
+      break;
+
+    case Instruction::SPUT_BOOLEAN:
+      VerifySPut(dec_insn, reg_types_.Boolean(), true);
+      break;
+    case Instruction::SPUT_BYTE:
+      VerifySPut(dec_insn, reg_types_.Byte(), true);
+      break;
+    case Instruction::SPUT_CHAR:
+      VerifySPut(dec_insn, reg_types_.Char(), true);
+      break;
+    case Instruction::SPUT_SHORT:
+      VerifySPut(dec_insn, reg_types_.Short(), true);
       break;
     case Instruction::SPUT:
-      tmp_type = kRegTypeInteger;
-      goto sput_1nr_common;
-    case Instruction::SPUT_BOOLEAN:
-      tmp_type = kRegTypeBoolean;
-      goto sput_1nr_common;
-    case Instruction::SPUT_BYTE:
-      tmp_type = kRegTypeByte;
-      goto sput_1nr_common;
-    case Instruction::SPUT_CHAR:
-      tmp_type = kRegTypeChar;
-      goto sput_1nr_common;
-    case Instruction::SPUT_SHORT:
-      tmp_type = kRegTypeShort;
-      goto sput_1nr_common;
-sput_1nr_common:
-      {
-        RegType src_type, field_type;
-        Field* static_field;
-
-        static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        CheckFinalFieldAccess(method, static_field, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        /*
-         * Get type of field we're storing into. We know that the
-         * contents of the register match the instruction, but we also
-         * need to ensure that the instruction matches the field type.
-         * Using e.g. sput-short to write into a 32-bit integer field
-         * can lead to trouble if we do 16-bit writes.
-         */
-        field_type =
-            PrimitiveTypeToRegType(static_field->GetType()->GetPrimitiveType());
-        src_type = GetRegisterType(work_line, dec_insn.vA_);
-
-        /* correct if float */
-        if (field_type == kRegTypeFloat)
-          tmp_type = kRegTypeFloat;
-
-        /*
-         * compiler can generate synthetic functions that write byte values
-         * into boolean fields.
-         */
-        if (tmp_type == kRegTypeBoolean && src_type == kRegTypeByte)
-          tmp_type = kRegTypeByte;
-        if (field_type == kRegTypeBoolean && src_type == kRegTypeByte)
-          field_type = kRegTypeByte;
-
-        /* make sure the source register has the correct type */
-        if (!CanConvertTo1nr(src_type, tmp_type)) {
-          LOG(ERROR) << "VFY: invalid reg type " << src_type
-                     << " on sput instr (need " << tmp_type << ")";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        VerifyRegisterType(work_line, dec_insn.vA_, field_type, &failure);
-
-        if (failure != VERIFY_ERROR_NONE || field_type == kRegTypeUnknown ||
-            tmp_type != field_type) {
-          LOG(ERROR) << "VFY: invalid sput-1nr of " << PrettyField(static_field)
-                     << " (inst=" << tmp_type << " actual=" << field_type
-                     << ")";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-      }
+      VerifySPut(dec_insn, reg_types_.Integer(), true);
       break;
     case Instruction::SPUT_WIDE:
-      Field* static_field;
-
-      static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
-      if (failure != VERIFY_ERROR_NONE)
-        break;
-      CheckFinalFieldAccess(method, static_field, &failure);
-      if (failure != VERIFY_ERROR_NONE)
-        break;
-
-      /* check the type, which should be prim */
-      switch (static_field->GetType()->GetPrimitiveType()) {
-        case Class::kPrimDouble:
-          VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeDoubleLo,
-              &failure);
-          break;
-        case Class::kPrimLong:
-          VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeLongLo, &failure);
-          break;
-        default:
-          LOG(ERROR) << "VFY: invalid sput-wide of " << PrettyField(static_field);
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-      }
+      VerifySPut(dec_insn, reg_types_.Long(), true);
       break;
     case Instruction::SPUT_OBJECT:
-      {
-        Class* field_class;
-        Class* value_class;
-        Field* static_field;
-        RegType value_type;
-
-        static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-        CheckFinalFieldAccess(method, static_field, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        field_class = static_field->GetType();
-        if (field_class == NULL) {
-          LOG(ERROR) << "VFY: unable to recover field class from '"
-                     << static_field->GetName()->ToModifiedUtf8() << "'";
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-
-        value_type = GetRegisterType(work_line, dec_insn.vA_);
-        if (!RegTypeIsReference(value_type)) {
-          LOG(ERROR) << "VFY: storing non-ref v" << dec_insn.vA_
-                     << " into ref field '"
-                     << static_field->GetName()->ToModifiedUtf8() << "' ("
-                     << field_class->GetDescriptor()->ToModifiedUtf8() << ")",
-          failure = VERIFY_ERROR_GENERIC;
-          break;
-        }
-        if (value_type != kRegTypeZero) {
-          value_class = RegTypeInitializedReferenceToClass(value_type);
-          if (value_class == NULL) {
-            LOG(ERROR) << "VFY: storing uninit ref v" << dec_insn.vA_
-                       << " into ref field";
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-          /* allow if field is any interface or field is base class */
-          if (!field_class->IsInterface() &&
-              !field_class->IsAssignableFrom(value_class)) {
-            LOG(ERROR) << "VFY: storing type '"
-                       << value_class->GetDescriptor()->ToModifiedUtf8()
-                       << "' into field type '"
-                       << field_class->GetDescriptor()->ToModifiedUtf8()
-                       << "' (" << PrettyField(static_field) << ")";
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-        }
-      }
+      VerifySPut(dec_insn, reg_types_.JavaLangObject(), false);
       break;
 
     case Instruction::INVOKE_VIRTUAL:
     case Instruction::INVOKE_VIRTUAL_RANGE:
     case Instruction::INVOKE_SUPER:
-    case Instruction::INVOKE_SUPER_RANGE:
-      {
-        Method* called_method;
-        RegType return_type;
-        bool is_range;
-        bool is_super;
-
-        is_range =  (dec_insn.opcode_ == Instruction::INVOKE_VIRTUAL_RANGE ||
-                     dec_insn.opcode_ == Instruction::INVOKE_SUPER_RANGE);
-        is_super =  (dec_insn.opcode_ == Instruction::INVOKE_SUPER ||
-                     dec_insn.opcode_ == Instruction::INVOKE_SUPER_RANGE);
-
-        called_method = VerifyInvocationArgs(vdata, work_line, registers_size,
-            &dec_insn, METHOD_VIRTUAL, is_range, is_super, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-            break;
-        return_type = GetMethodReturnType(dex_file, called_method);
-        SetResultRegisterType(work_line, registers_size, return_type);
+    case Instruction::INVOKE_SUPER_RANGE: {
+      bool is_range = (dec_insn.opcode_ == Instruction::INVOKE_VIRTUAL_RANGE ||
+                       dec_insn.opcode_ == Instruction::INVOKE_SUPER_RANGE);
+      bool is_super =  (dec_insn.opcode_ == Instruction::INVOKE_SUPER ||
+                        dec_insn.opcode_ == Instruction::INVOKE_SUPER_RANGE);
+      Method* called_method = VerifyInvocationArgs(dec_insn, METHOD_VIRTUAL, is_range, is_super);
+      if (failure_ == VERIFY_ERROR_NONE) {
+        const RegType& return_type = reg_types_.FromClass(called_method->GetReturnType());
+        work_line_->SetResultRegisterType(return_type);
         just_set_result = true;
       }
       break;
+    }
     case Instruction::INVOKE_DIRECT:
-    case Instruction::INVOKE_DIRECT_RANGE:
-      {
-        RegType return_type;
-        Method* called_method;
-        bool is_range;
-
-        is_range = (dec_insn.opcode_ == Instruction::INVOKE_DIRECT_RANGE);
-        called_method = VerifyInvocationArgs(vdata, work_line, registers_size,
-            &dec_insn, METHOD_DIRECT, is_range, false, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
+    case Instruction::INVOKE_DIRECT_RANGE: {
+      bool is_range = (dec_insn.opcode_ == Instruction::INVOKE_DIRECT_RANGE);
+      Method* called_method = VerifyInvocationArgs(dec_insn, METHOD_DIRECT, is_range, false);
+      if (failure_ == VERIFY_ERROR_NONE) {
         /*
-         * Some additional checks when calling <init>. We know from
-         * the invocation arg check that the "this" argument is an
-         * instance of called_method->klass. Now we further restrict
-         * that to require that called_method->klass is the same as
-         * this->klass or this->super, allowing the latter only if
-         * the "this" argument is the same as the "this" argument to
-         * this method (which implies that we're in <init> ourselves).
+         * Some additional checks when calling a constructor. We know from the invocation arg check
+         * that the "this" argument is an instance of called_method->klass. Now we further restrict
+         * that to require that called_method->klass is the same as this->klass or this->super,
+         * allowing the latter only if the "this" argument is the same as the "this" argument to
+         * this method (which implies that we're in a constructor ourselves).
          */
-        if (IsInitMethod(called_method)) {
-          RegType this_type;
-          this_type = GetInvocationThis(work_line, &dec_insn, &failure);
-          if (failure != VERIFY_ERROR_NONE)
+        if (called_method->IsConstructor()) {
+          const RegType& this_type = work_line_->GetInvocationThis(dec_insn);
+          if (failure_ != VERIFY_ERROR_NONE)
             break;
 
           /* no null refs allowed (?) */
-          if (this_type == kRegTypeZero) {
-            LOG(ERROR) << "VFY: unable to initialize null ref";
-            failure = VERIFY_ERROR_GENERIC;
+          if (this_type.IsZero()) {
+            Fail(VERIFY_ERROR_GENERIC) << "unable to initialize null ref";
             break;
           }
-
-          Class* this_class;
-
-          this_class = RegTypeReferenceToClass(this_type, uninit_map);
+          Class* this_class = this_type.GetClass();
           DCHECK(this_class != NULL);
 
           /* must be in same class or in superclass */
-          if (called_method->GetDeclaringClass() == this_class->GetSuperClass())
-          {
-            if (this_class != method->GetDeclaringClass()) {
-              LOG(ERROR) << "VFY: invoke-direct <init> on super only "
-                         << "allowed for 'this' in <init>";
-              failure = VERIFY_ERROR_GENERIC;
+          if (called_method->GetDeclaringClass() == this_class->GetSuperClass()) {
+            if (this_class != method_->GetDeclaringClass()) {
+              Fail(VERIFY_ERROR_GENERIC)
+                  << "invoke-direct <init> on super only allowed for 'this' in <init>";
               break;
             }
           }  else if (called_method->GetDeclaringClass() != this_class) {
-            LOG(ERROR) << "VFY: invoke-direct <init> must be on current "
-                       << "class or super";
-            failure = VERIFY_ERROR_GENERIC;
+            Fail(VERIFY_ERROR_GENERIC) << "invoke-direct <init> must be on current class or super";
             break;
           }
 
           /* arg must be an uninitialized reference */
-          if (!RegTypeIsUninitReference(this_type)) {
-            LOG(ERROR) << "VFY: can only initialize the uninitialized";
-            failure = VERIFY_ERROR_GENERIC;
+          if (this_type.IsInitialized()) {
+            Fail(VERIFY_ERROR_GENERIC) << "Expected initialization on uninitialized reference "
+                << this_type;
             break;
           }
 
@@ -2866,167 +2385,129 @@
            * do this for all registers that have the same object
            * instance in them, not just the "this" register.
            */
-          MarkRefsAsInitialized(work_line, registers_size, uninit_map,
-              this_type, &failure);
-          if (failure != VERIFY_ERROR_NONE)
+          work_line_->MarkRefsAsInitialized(this_type);
+          if (failure_ != VERIFY_ERROR_NONE)
             break;
         }
-        return_type = GetMethodReturnType(dex_file, called_method);
-        SetResultRegisterType(work_line, registers_size, return_type);
+        const RegType& return_type = reg_types_.FromClass(called_method->GetReturnType());
+        work_line_->SetResultRegisterType(return_type);
         just_set_result = true;
       }
       break;
+    }
     case Instruction::INVOKE_STATIC:
-    case Instruction::INVOKE_STATIC_RANGE:
-      {
-        RegType return_type;
-        Method* called_method;
-        bool is_range;
-
-        is_range = (dec_insn.opcode_ == Instruction::INVOKE_STATIC_RANGE);
-        called_method = VerifyInvocationArgs(vdata, work_line, registers_size,
-            &dec_insn, METHOD_STATIC, is_range, false, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        return_type = GetMethodReturnType(dex_file, called_method);
-        SetResultRegisterType(work_line, registers_size, return_type);
-        just_set_result = true;
+    case Instruction::INVOKE_STATIC_RANGE: {
+        bool is_range = (dec_insn.opcode_ == Instruction::INVOKE_STATIC_RANGE);
+        Method* called_method = VerifyInvocationArgs(dec_insn, METHOD_STATIC, is_range, false);
+        if (failure_ == VERIFY_ERROR_NONE) {
+          const RegType& return_type =  reg_types_.FromClass(called_method->GetReturnType());
+          work_line_->SetResultRegisterType(return_type);
+          just_set_result = true;
+        }
       }
       break;
     case Instruction::INVOKE_INTERFACE:
-    case Instruction::INVOKE_INTERFACE_RANGE:
-      {
-        RegType /*this_type,*/ return_type;
-        Method* abs_method;
-        bool is_range;
-
-        is_range =  (dec_insn.opcode_ == Instruction::INVOKE_INTERFACE_RANGE);
-        abs_method = VerifyInvocationArgs(vdata, work_line, registers_size,
-            &dec_insn, METHOD_INTERFACE, is_range, false, &failure);
-        if (failure != VERIFY_ERROR_NONE)
+    case Instruction::INVOKE_INTERFACE_RANGE: {
+      bool is_range =  (dec_insn.opcode_ == Instruction::INVOKE_INTERFACE_RANGE);
+      Method* abs_method = VerifyInvocationArgs(dec_insn, METHOD_INTERFACE, is_range, false);
+      if (failure_ == VERIFY_ERROR_NONE) {
+        Class* called_interface = abs_method->GetDeclaringClass();
+        if (!called_interface->IsInterface()) {
+          Fail(VERIFY_ERROR_CLASS_CHANGE) << "expected interface class in invoke-interface '"
+                                          << PrettyMethod(abs_method) << "'";
           break;
-
-#if 0   /* can't do this here, fails on dalvik test 052-verifier-fun */
-        /*
-         * Get the type of the "this" arg, which should always be an
-         * interface class. Because we don't do a full merge on
-         * interface classes, this might have reduced to Object.
-         */
-        this_type = GetInvocationThis(work_line, &dec_insn, &failure);
-        if (failure != VERIFY_ERROR_NONE)
-          break;
-
-        if (this_type == kRegTypeZero) {
-          /* null pointer always passes (and always fails at runtime) */
         } else {
-          Class* this_class;
-
-          this_class = RegTypeInitializedReferenceToClass(this_type);
-          if (this_class == NULL) {
-            LOG(ERROR) << "VFY: interface call on uninitialized";
-            failure = VERIFY_ERROR_GENERIC;
-            break;
-          }
-
-          /*
-           * Either "this_class" needs to be the interface class that
-           * defined abs_method, or abs_method's class needs to be one
-           * of the interfaces implemented by "this_class". (Or, if
-           * we couldn't complete the merge, this will be Object.)
+          /* Get the type of the "this" arg, which should either be a sub-interface of called
+           * interface or Object (see comments in RegType::JoinClass).
            */
-          if (this_class != abs_method->GetDeclaringClass() &&
-              this_class != class_linker->FindSystemClass("Ljava/lang/Object;") &&
-              !this_class->Implements(abs_method->GetDeclaringClass())) {
-            LOG(ERROR) << "VFY: unable to match abs_method '"
-                       << abs_method->GetName()->ToModifiedUtf8() << "' with "
-                       << this_class->GetDescriptor()->ToModifiedUtf8()
-                       << " interfaces";
-            failure = VERIFY_ERROR_GENERIC;
-            break;
+          const RegType& this_type = work_line_->GetInvocationThis(dec_insn);
+          if (failure_ == VERIFY_ERROR_NONE) {
+            if (this_type.IsZero()) {
+              /* null pointer always passes (and always fails at runtime) */
+            } else {
+              Class* this_class = this_type.GetClass();
+              if (this_type.IsUninitializedReference() || this_class == NULL) {
+                Fail(VERIFY_ERROR_GENERIC) << "interface call on uninitialized";
+                break;
+              }
+              if (!this_class->IsObjectClass() && !called_interface->IsAssignableFrom(this_class)) {
+                Fail(VERIFY_ERROR_GENERIC) << "unable to match abstract method '"
+                                           << PrettyMethod(abs_method) << "' with "
+                                           << PrettyDescriptor(this_class->GetDescriptor())
+                                           << " interfaces";
+                break;
+              }
+            }
           }
         }
-#endif
-
         /*
-         * We don't have an object instance, so we can't find the
-         * concrete method. However, all of the type information is
-         * in the abstract method, so we're good.
+         * We don't have an object instance, so we can't find the concrete method. However, all of
+         * the type information is in the abstract method, so we're good.
          */
-        return_type = GetMethodReturnType(dex_file, abs_method);
-        SetResultRegisterType(work_line, registers_size, return_type);
+        const RegType& return_type = reg_types_.FromClass(abs_method->GetReturnType());
+        work_line_->SetResultRegisterType(return_type);
         just_set_result = true;
       }
       break;
-
+    }
     case Instruction::NEG_INT:
     case Instruction::NOT_INT:
-      CheckUnop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
-          &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer());
       break;
     case Instruction::NEG_LONG:
     case Instruction::NOT_LONG:
-      CheckUnop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeLongLo, &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Long());
       break;
     case Instruction::NEG_FLOAT:
-      CheckUnop(work_line, &dec_insn, kRegTypeFloat, kRegTypeFloat, &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Float());
       break;
     case Instruction::NEG_DOUBLE:
-      CheckUnop(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeDoubleLo,
-          &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Double());
       break;
     case Instruction::INT_TO_LONG:
-      CheckUnop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeInteger,
-          &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_FLOAT:
-      CheckUnop(work_line, &dec_insn, kRegTypeFloat, kRegTypeInteger, &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_DOUBLE:
-      CheckUnop(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeInteger,
-          &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Integer());
       break;
     case Instruction::LONG_TO_INT:
-      CheckUnop(work_line, &dec_insn, kRegTypeInteger, kRegTypeLongLo,
-          &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Long());
       break;
     case Instruction::LONG_TO_FLOAT:
-      CheckUnop(work_line, &dec_insn, kRegTypeFloat, kRegTypeLongLo, &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Long());
       break;
     case Instruction::LONG_TO_DOUBLE:
-      CheckUnop(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeLongLo,
-          &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Long());
       break;
     case Instruction::FLOAT_TO_INT:
-      CheckUnop(work_line, &dec_insn, kRegTypeInteger, kRegTypeFloat, &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Float());
       break;
     case Instruction::FLOAT_TO_LONG:
-      CheckUnop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeFloat, &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Float());
       break;
     case Instruction::FLOAT_TO_DOUBLE:
-      CheckUnop(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeFloat,
-          &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Float());
       break;
     case Instruction::DOUBLE_TO_INT:
-      CheckUnop(work_line, &dec_insn, kRegTypeInteger, kRegTypeDoubleLo,
-          &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Double());
       break;
     case Instruction::DOUBLE_TO_LONG:
-      CheckUnop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeDoubleLo,
-          &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Double());
       break;
     case Instruction::DOUBLE_TO_FLOAT:
-      CheckUnop(work_line, &dec_insn, kRegTypeFloat, kRegTypeDoubleLo,
-          &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Double());
       break;
     case Instruction::INT_TO_BYTE:
-      CheckUnop(work_line, &dec_insn, kRegTypeByte, kRegTypeInteger, &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Byte(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_CHAR:
-      CheckUnop(work_line, &dec_insn, kRegTypeChar, kRegTypeInteger, &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Char(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_SHORT:
-      CheckUnop(work_line, &dec_insn, kRegTypeShort, kRegTypeInteger, &failure);
+      work_line_->CheckUnaryOp(dec_insn, reg_types_.Short(), reg_types_.Integer());
       break;
 
     case Instruction::ADD_INT:
@@ -3037,14 +2518,12 @@
     case Instruction::SHL_INT:
     case Instruction::SHR_INT:
     case Instruction::USHR_INT:
-      CheckBinop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
-          kRegTypeInteger, false, &failure);
+      work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
       break;
     case Instruction::AND_INT:
     case Instruction::OR_INT:
     case Instruction::XOR_INT:
-      CheckBinop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
-          kRegTypeInteger, true, &failure);
+      work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true);
       break;
     case Instruction::ADD_LONG:
     case Instruction::SUB_LONG:
@@ -3054,31 +2533,27 @@
     case Instruction::AND_LONG:
     case Instruction::OR_LONG:
     case Instruction::XOR_LONG:
-      CheckBinop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeLongLo,
-          kRegTypeLongLo, false, &failure);
+      work_line_->CheckBinaryOp(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Long(), false);
       break;
     case Instruction::SHL_LONG:
     case Instruction::SHR_LONG:
     case Instruction::USHR_LONG:
-      /* shift distance is Int, making these different from other binops */
-      CheckBinop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeLongLo,
-          kRegTypeInteger, false, &failure);
+      /* shift distance is Int, making these different from other binary operations */
+      work_line_->CheckBinaryOp(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Integer(), false);
       break;
     case Instruction::ADD_FLOAT:
     case Instruction::SUB_FLOAT:
     case Instruction::MUL_FLOAT:
     case Instruction::DIV_FLOAT:
     case Instruction::REM_FLOAT:
-      CheckBinop(work_line, &dec_insn, kRegTypeFloat, kRegTypeFloat,
-          kRegTypeFloat, false, &failure);
+      work_line_->CheckBinaryOp(dec_insn, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
       break;
     case Instruction::ADD_DOUBLE:
     case Instruction::SUB_DOUBLE:
     case Instruction::MUL_DOUBLE:
     case Instruction::DIV_DOUBLE:
     case Instruction::REM_DOUBLE:
-      CheckBinop(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeDoubleLo,
-          kRegTypeDoubleLo, false, &failure);
+      work_line_->CheckBinaryOp(dec_insn, reg_types_.Double(), reg_types_.Double(), reg_types_.Double(), false);
       break;
     case Instruction::ADD_INT_2ADDR:
     case Instruction::SUB_INT_2ADDR:
@@ -3087,18 +2562,15 @@
     case Instruction::SHL_INT_2ADDR:
     case Instruction::SHR_INT_2ADDR:
     case Instruction::USHR_INT_2ADDR:
-      CheckBinop2addr(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
-          kRegTypeInteger, false, &failure);
+      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
       break;
     case Instruction::AND_INT_2ADDR:
     case Instruction::OR_INT_2ADDR:
     case Instruction::XOR_INT_2ADDR:
-      CheckBinop2addr(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
-          kRegTypeInteger, true, &failure);
+      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true);
       break;
     case Instruction::DIV_INT_2ADDR:
-      CheckBinop2addr(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
-          kRegTypeInteger, false, &failure);
+      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
       break;
     case Instruction::ADD_LONG_2ADDR:
     case Instruction::SUB_LONG_2ADDR:
@@ -3108,44 +2580,38 @@
     case Instruction::AND_LONG_2ADDR:
     case Instruction::OR_LONG_2ADDR:
     case Instruction::XOR_LONG_2ADDR:
-      CheckBinop2addr(work_line, &dec_insn, kRegTypeLongLo, kRegTypeLongLo,
-          kRegTypeLongLo, false, &failure);
+      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Long(), false);
       break;
     case Instruction::SHL_LONG_2ADDR:
     case Instruction::SHR_LONG_2ADDR:
     case Instruction::USHR_LONG_2ADDR:
-      CheckBinop2addr(work_line, &dec_insn, kRegTypeLongLo, kRegTypeLongLo,
-          kRegTypeInteger, false, &failure);
+      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Integer(), false);
       break;
     case Instruction::ADD_FLOAT_2ADDR:
     case Instruction::SUB_FLOAT_2ADDR:
     case Instruction::MUL_FLOAT_2ADDR:
     case Instruction::DIV_FLOAT_2ADDR:
     case Instruction::REM_FLOAT_2ADDR:
-      CheckBinop2addr(work_line, &dec_insn, kRegTypeFloat, kRegTypeFloat,
-          kRegTypeFloat, false, &failure);
+      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
       break;
     case Instruction::ADD_DOUBLE_2ADDR:
     case Instruction::SUB_DOUBLE_2ADDR:
     case Instruction::MUL_DOUBLE_2ADDR:
     case Instruction::DIV_DOUBLE_2ADDR:
     case Instruction::REM_DOUBLE_2ADDR:
-      CheckBinop2addr(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeDoubleLo,
-          kRegTypeDoubleLo, false, &failure);
+      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Double(), reg_types_.Double(),  reg_types_.Double(), false);
       break;
     case Instruction::ADD_INT_LIT16:
     case Instruction::RSUB_INT:
     case Instruction::MUL_INT_LIT16:
     case Instruction::DIV_INT_LIT16:
     case Instruction::REM_INT_LIT16:
-      CheckLitop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger, false,
-          &failure);
+      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), false);
       break;
     case Instruction::AND_INT_LIT16:
     case Instruction::OR_INT_LIT16:
     case Instruction::XOR_INT_LIT16:
-      CheckLitop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger, true,
-          &failure);
+      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), true);
       break;
     case Instruction::ADD_INT_LIT8:
     case Instruction::RSUB_INT_LIT8:
@@ -3153,26 +2619,14 @@
     case Instruction::DIV_INT_LIT8:
     case Instruction::REM_INT_LIT8:
     case Instruction::SHL_INT_LIT8:
-      CheckLitop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger, false,
-          &failure);
-      break;
     case Instruction::SHR_INT_LIT8:
-      tmp_type = AdjustForRightShift(work_line, dec_insn.vB_, dec_insn.vC_,
-          false);
-      CheckLitop(work_line, &dec_insn, tmp_type, kRegTypeInteger, false,
-          &failure);
-      break;
     case Instruction::USHR_INT_LIT8:
-      tmp_type = AdjustForRightShift(work_line, dec_insn.vB_, dec_insn.vC_,
-          true);
-      CheckLitop(work_line, &dec_insn, tmp_type, kRegTypeInteger, false,
-          &failure);
+      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), false);
       break;
     case Instruction::AND_INT_LIT8:
     case Instruction::OR_INT_LIT8:
     case Instruction::XOR_INT_LIT8:
-      CheckLitop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger, true,
-          &failure);
+      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), true);
       break;
 
     /*
@@ -3183,38 +2637,7 @@
     case Instruction::THROW_VERIFICATION_ERROR:
       break;
 
-    /*
-     * Verifying "quickened" instructions is tricky, because we have
-     * discarded the original field/method information. The byte offsets
-     * and vtable indices only have meaning in the context of an object
-     * instance.
-     *
-     * If a piece of code declares a local reference variable, assigns
-     * null to it, and then issues a virtual method call on it, we
-     * cannot evaluate the method call during verification. This situation
-     * isn't hard to handle, since we know the call will always result in an
-     * NPE, and the arguments and return value don't matter. Any code that
-     * depends on the result of the method call is inaccessible, so the
-     * fact that we can't fully verify anything that comes after the bad
-     * call is not a problem.
-     *
-     * We must also consider the case of multiple code paths, only some of
-     * which involve a null reference. We can completely verify the method
-     * if we sidestep the results of executing with a null reference.
-     * For example, if on the first pass through the code we try to do a
-     * virtual method invocation through a null ref, we have to skip the
-     * method checks and have the method return a "wildcard" type (which
-     * merges with anything to become that other thing). The move-result
-     * will tell us if it's a reference, single-word numeric, or double-word
-     * value. We continue to perform the verification, and at the end of
-     * the function any invocations that were never fully exercised are
-     * marked as null-only.
-     *
-     * We would do something similar for the field accesses. The field's
-     * type, once known, can be used to recover the width of short integers.
-     * If the object reference was null, the field-get returns the "wildcard"
-     * type, which is acceptable for any operation.
-     */
+    /* These should never appear during verification. */
     case Instruction::UNUSED_EE:
     case Instruction::UNUSED_EF:
     case Instruction::UNUSED_F2:
@@ -3227,27 +2650,6 @@
     case Instruction::UNUSED_F9:
     case Instruction::UNUSED_FA:
     case Instruction::UNUSED_FB:
-    //case Instruction::EXECUTE_INLINE:
-    //case Instruction::EXECUTE_INLINE_RANGE:
-    //case Instruction::IGET_QUICK:
-    //case Instruction::IGET_WIDE_QUICK:
-    //case Instruction::IGET_OBJECT_QUICK:
-    //case Instruction::IPUT_QUICK:
-    //case Instruction::IPUT_WIDE_QUICK:
-    //case Instruction::IPUT_OBJECT_QUICK:
-    //case Instruction::INVOKE_VIRTUAL_QUICK:
-    //case Instruction::INVOKE_VIRTUAL_QUICK_RANGE:
-    //case Instruction::INVOKE_SUPER_QUICK:
-    //case Instruction::INVOKE_SUPER_QUICK_RANGE:
-      /* fall through to failure */
-
-    /*
-     * These instructions are equivalent (from the verifier's point of view)
-     * to the original form. The change was made for correctness rather
-     * than improved performance (except for invoke-object-init, which
-     * provides both). The substitution takes place after verification
-     * completes, though, so we don't expect to see them here.
-     */
     case Instruction::UNUSED_F0:
     case Instruction::UNUSED_F1:
     case Instruction::UNUSED_E3:
@@ -3262,23 +2664,6 @@
     case Instruction::UNUSED_E6:
     case Instruction::UNUSED_EB:
     case Instruction::UNUSED_FE:
-    //case Instruction::INVOKE_OBJECT_INIT_RANGE:
-    //case Instruction::RETURN_VOID_BARRIER:
-    //case Instruction::IGET_VOLATILE:
-    //case Instruction::IGET_WIDE_VOLATILE:
-    //case Instruction::IGET_OBJECT_VOLATILE:
-    //case Instruction::IPUT_VOLATILE:
-    //case Instruction::IPUT_WIDE_VOLATILE:
-    //case Instruction::IPUT_OBJECT_VOLATILE:
-    //case Instruction::SGET_VOLATILE:
-    //case Instruction::SGET_WIDE_VOLATILE:
-    //case Instruction::SGET_OBJECT_VOLATILE:
-    //case Instruction::SPUT_VOLATILE:
-    //case Instruction::SPUT_WIDE_VOLATILE:
-    //case Instruction::SPUT_OBJECT_VOLATILE:
-      /* fall through to failure */
-
-    /* These should never appear during verification. */
     case Instruction::UNUSED_3E:
     case Instruction::UNUSED_3F:
     case Instruction::UNUSED_40:
@@ -3290,85 +2675,65 @@
     case Instruction::UNUSED_7A:
     case Instruction::UNUSED_EC:
     case Instruction::UNUSED_FF:
-    //case Instruction::BREAKPOINT:
-    //case Instruction::DISPATCH_FF:
-      failure = VERIFY_ERROR_GENERIC;
+      Fail(VERIFY_ERROR_GENERIC) << "Unexpected opcode " << *inst;
       break;
 
     /*
      * DO NOT add a "default" clause here. Without it the compiler will
      * complain if an instruction is missing (which is desirable).
      */
-    }
+  }  // end - switch (dec_insn.opcode_)
 
-  if (failure != VERIFY_ERROR_NONE) {
-    if (failure == VERIFY_ERROR_GENERIC) {
+  if (failure_ != VERIFY_ERROR_NONE) {
+    if (failure_ == VERIFY_ERROR_GENERIC) {
       /* immediate failure, reject class */
-      LOG(ERROR) << "VFY:  rejecting opcode 0x" << std::hex
-                 << (int) dec_insn.opcode_ << " at 0x" << insn_idx << std::dec;
+      fail_messages_ << std::endl << "Rejecting opcode " << *inst;
       return false;
     } else {
       /* replace opcode and continue on */
-      LOG(ERROR) << "VFY: replacing opcode 0x" << std::hex
-                 << (int) dec_insn.opcode_ << " at 0x" << insn_idx << std::dec;
-      if (!ReplaceFailingInstruction(code_item, insn_idx, failure)) {
-        LOG(ERROR) << "VFY:  rejecting opcode 0x" << std::hex
-                   << (int) dec_insn.opcode_ << " at 0x" << insn_idx
-                   << std::dec;
-        return false;
-      }
+      fail_messages_ << std::endl << "Replacing opcode " << *inst;
+      ReplaceFailingInstruction();
       /* IMPORTANT: method->insns may have been changed */
-      insns = code_item->insns_ + insn_idx;
-
+      insns = code_item_->insns_ + work_insn_idx_;
       /* continue on as if we just handled a throw-verification-error */
-      failure = VERIFY_ERROR_NONE;
+      failure_ = VERIFY_ERROR_NONE;
       opcode_flag = Instruction::kThrow;
     }
   }
-
   /*
-   * If we didn't just set the result register, clear it out. This
-   * ensures that you can only use "move-result" immediately after the
-   * result is set. (We could check this statically, but it's not
-   * expensive and it makes our debugging output cleaner.)
+   * If we didn't just set the result register, clear it out. This ensures that you can only use
+   * "move-result" immediately after the result is set. (We could check this statically, but it's
+   * not expensive and it makes our debugging output cleaner.)
    */
   if (!just_set_result) {
-    int reg = RESULT_REGISTER(registers_size);
-    SetRegisterType(work_line, reg, kRegTypeUnknown);
-    SetRegisterType(work_line, reg + 1, kRegTypeUnknown);
+    work_line_->SetResultTypeToUnknown();
   }
 
   /* Handle "continue". Tag the next consecutive instruction. */
   if ((opcode_flag & Instruction::kContinue) != 0) {
-    size_t insn_width = InsnGetWidth(insn_flags, insn_idx);
-    if (insn_idx + insn_width >= insns_size) {
-      LOG(ERROR) << "VFY: execution can walk off end of code area (from 0x"
-                 << std::hex << insn_idx << std::dec << ")";
+    uint32_t next_insn_idx = work_insn_idx_ + CurrentInsnFlags().GetLengthInCodeUnits();
+    if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
+      Fail(VERIFY_ERROR_GENERIC) << "Execution can walk off end of code area";
       return false;
     }
-
-    /*
-     * The only way to get to a move-exception instruction is to get
-     * thrown there. Make sure the next instruction isn't one.
-     */
-    if (!CheckMoveException(code_item->insns_, insn_idx + insn_width))
+    // The only way to get to a move-exception instruction is to get thrown there. Make sure the
+    // next instruction isn't one.
+    if (!CheckMoveException(code_item_->insns_, next_insn_idx)) {
       return false;
-
-    if (GetRegisterLine(reg_table, insn_idx + insn_width)->reg_types_.get() != NULL) {
-      /*
-       * Merge registers into what we have for the next instruction,
-       * and set the "changed" flag if needed.
-       */
-      if (!UpdateRegisters(insn_flags, reg_table, insn_idx + insn_width,
-          work_line))
+    }
+    RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
+    if (next_line != NULL) {
+      // Merge registers into what we have for the next instruction, and set the "changed" flag if
+      // needed.
+      if (!UpdateRegisters(next_insn_idx, work_line_.get())) {
         return false;
+      }
     } else {
       /*
-       * We're not recording register data for the next instruction,
-       * so we don't know what the prior state was. We have to
-       * assume that something has changed and re-evaluate it.
+       * We're not recording register data for the next instruction, so we don't know what the prior
+       * state was. We have to assume that something has changed and re-evaluate it.
        */
-      InsnSetChanged(insn_flags, insn_idx + insn_width, true);
+      insn_flags_[next_insn_idx].SetChanged();
     }
   }
 
@@ -3386,22 +2751,19 @@
    */
   if ((opcode_flag & Instruction::kBranch) != 0) {
     bool isConditional, selfOkay;
-
-    if (!GetBranchOffset(code_item, insn_flags, insn_idx, &branch_target,
-        &isConditional, &selfOkay)) {
+    if (!GetBranchOffset(work_insn_idx_, &branch_target, &isConditional, &selfOkay)) {
       /* should never happen after static verification */
-      LOG(ERROR) << "VFY: bad branch at 0x" << std::hex << insn_idx << std::dec;
+      Fail(VERIFY_ERROR_GENERIC) << "bad branch";
       return false;
     }
     DCHECK_EQ(isConditional, (opcode_flag & Instruction::kContinue) != 0);
-
-    if (!CheckMoveException(code_item->insns_, insn_idx + branch_target))
+    if (!CheckMoveException(code_item_->insns_, work_insn_idx_ + branch_target)) {
       return false;
-
+    }
     /* update branch target, set "changed" if appropriate */
-    if (!UpdateRegisters(insn_flags, reg_table, insn_idx + branch_target,
-        work_line))
+    if (!UpdateRegisters(work_insn_idx_ + branch_target, work_line_.get())) {
       return false;
+    }
   }
 
   /*
@@ -3433,73 +2795,62 @@
       /* offsets are 32-bit, and only partly endian-swapped */
       offset = switch_insns[offset_to_targets + targ * 2] |
          (((int32_t) switch_insns[offset_to_targets + targ * 2 + 1]) << 16);
-      abs_offset = insn_idx + offset;
-
-      DCHECK_LT(abs_offset, insns_size);
-
-      if (!CheckMoveException(code_item->insns_, abs_offset))
+      abs_offset = work_insn_idx_ + offset;
+      DCHECK_LT(abs_offset, code_item_->insns_size_in_code_units_);
+      if (!CheckMoveException(code_item_->insns_, abs_offset)) {
         return false;
-
-      if (!UpdateRegisters(insn_flags, reg_table, abs_offset, work_line))
+      }
+      if (!UpdateRegisters(abs_offset, work_line_.get()))
         return false;
     }
   }
 
   /*
-   * Handle instructions that can throw and that are sitting in a
-   * "try" block. (If they're not in a "try" block when they throw,
-   * control transfers out of the method.)
+   * Handle instructions that can throw and that are sitting in a "try" block. (If they're not in a
+   * "try" block when they throw, control transfers out of the method.)
    */
-  if ((opcode_flag & Instruction::kThrow) != 0 &&
-      InsnIsInTry(insn_flags, insn_idx)) {
-    bool has_catch_all = false;
-    DexFile::CatchHandlerIterator iterator = DexFile::dexFindCatchHandler(
-        *code_item, insn_idx);
+  if ((opcode_flag & Instruction::kThrow) != 0 && insn_flags_[work_insn_idx_].IsInTry()) {
+    bool within_catch_all = false;
+    DexFile::CatchHandlerIterator iterator =
+        DexFile::dexFindCatchHandler(*code_item_, work_insn_idx_);
 
     for (; !iterator.HasNext(); iterator.Next()) {
-      if (iterator.Get().type_idx_ == DexFile::kDexNoIndex)
-        has_catch_all = true;
-
+      if (iterator.Get().type_idx_ == DexFile::kDexNoIndex) {
+        within_catch_all = true;
+      }
       /*
-       * Merge registers into the "catch" block. We want to use the
-       * "savedRegs" rather than "work_regs", because at runtime the
-       * exception will be thrown before the instruction modifies any
-       * registers.
+       * Merge registers into the "catch" block. We want to use the "savedRegs" rather than
+       * "work_regs", because at runtime the exception will be thrown before the instruction
+       * modifies any registers.
        */
-      if (!UpdateRegisters(insn_flags, reg_table, iterator.Get().address_,
-          &reg_table->saved_line_))
+      if (!UpdateRegisters(iterator.Get().address_, saved_line_.get())) {
         return false;
+      }
     }
 
     /*
-     * If the monitor stack depth is nonzero, there must be a "catch all"
-     * handler for this instruction. This does apply to monitor-exit
-     * because of async exception handling.
+     * If the monitor stack depth is nonzero, there must be a "catch all" handler for this
+     * instruction. This does apply to monitor-exit because of async exception handling.
      */
-    if (work_line->monitor_stack_top_ != 0 && !has_catch_all) {
+    if (work_line_->MonitorStackDepth() > 0 && !within_catch_all) {
       /*
-       * The state in work_line reflects the post-execution state.
-       * If the current instruction is a monitor-enter and the monitor
-       * stack was empty, we don't need a catch-all (if it throws,
+       * The state in work_line reflects the post-execution state. If the current instruction is a
+       * monitor-enter and the monitor stack was empty, we don't need a catch-all (if it throws,
        * it will do so before grabbing the lock).
        */
-      if (!(dec_insn.opcode_ == Instruction::MONITOR_ENTER &&
-          work_line->monitor_stack_top_ == 1))
-      {
-        LOG(ERROR) << "VFY: no catch-all for instruction at 0x" << std::hex
-                   << insn_idx << std::dec;
+      if (dec_insn.opcode_ != Instruction::MONITOR_ENTER || work_line_->MonitorStackDepth() != 1) {
+        Fail(VERIFY_ERROR_GENERIC)
+            << "expected to be within a catch-all for an instruction where a monitor is held";
         return false;
       }
     }
   }
 
   /* If we're returning from the method, make sure monitor stack is empty. */
-  if ((opcode_flag & Instruction::kReturn) != 0 &&
-      work_line->monitor_stack_top_ != 0) {
-    LOG(ERROR) << "VFY: return with stack depth="
-               << work_line->monitor_stack_top_ << " at 0x" << std::hex
-               << insn_idx << std::dec;
-    return false;
+  if ((opcode_flag & Instruction::kReturn) != 0) {
+    if(!work_line_->VerifyMonitorStackEmpty()) {
+      return false;
+    }
   }
 
   /*
@@ -3509,43 +2860,629 @@
    * alone and let the caller sort it out.
    */
   if ((opcode_flag & Instruction::kContinue) != 0) {
-    *start_guess = insn_idx + InsnGetWidth(insn_flags, insn_idx);
+    *start_guess = work_insn_idx_ + insn_flags_[work_insn_idx_].GetLengthInCodeUnits();
   } else if ((opcode_flag & Instruction::kBranch) != 0) {
     /* we're still okay if branch_target is zero */
-    *start_guess = insn_idx + branch_target;
+    *start_guess = work_insn_idx_ + branch_target;
   }
 
-  DCHECK_LT(*start_guess, insns_size);
-  DCHECK_NE(InsnGetWidth(insn_flags, *start_guess), 0);
+  DCHECK_LT(*start_guess, code_item_->insns_size_in_code_units_);
+  DCHECK(insn_flags_[*start_guess].IsOpcode());
 
   return true;
 }
 
-bool DexVerifier::ReplaceFailingInstruction(const DexFile::CodeItem* code_item,
-    int insn_idx, VerifyError failure) {
-  const uint16_t* insns = code_item->insns_ + insn_idx;
-  const byte* ptr = reinterpret_cast<const byte*>(insns);
-  const Instruction* inst = Instruction::At(ptr);
-  Instruction::Code opcode = inst->Opcode();
-  VerifyErrorRefType ref_type;
+Class* DexVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) {
+  const Class* referrer = method_->GetDeclaringClass();
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Class* res_class = class_linker->ResolveType(*dex_file_, class_idx, referrer);
 
+  if (res_class == NULL) {
+    Thread::Current()->ClearException();
+    Fail(VERIFY_ERROR_NO_CLASS) << "can't find class with index " << (void*) class_idx;
+  } else if (!referrer->CanAccess(res_class)) {   /* Check if access is allowed. */
+    Fail(VERIFY_ERROR_ACCESS_CLASS) << "illegal class access: "
+                                    << referrer->GetDescriptor()->ToModifiedUtf8() << " -> "
+                                    << res_class->GetDescriptor()->ToModifiedUtf8();
+  }
+  return res_class;
+}
+
+Class* DexVerifier::GetCaughtExceptionType() {
+  Class* common_super = NULL;
+  if (code_item_->tries_size_ != 0) {
+    const byte* handlers_ptr = DexFile::dexGetCatchHandlerData(*code_item_, 0);
+    uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+    for (uint32_t i = 0; i < handlers_size; i++) {
+      DexFile::CatchHandlerIterator iterator(handlers_ptr);
+      for (; !iterator.HasNext(); iterator.Next()) {
+        DexFile::CatchHandlerItem handler = iterator.Get();
+        if (handler.address_ == (uint32_t) work_insn_idx_) {
+          if (handler.type_idx_ == DexFile::kDexNoIndex) {
+            common_super = JavaLangThrowable();
+          } else {
+            Class* klass = ResolveClassAndCheckAccess(handler.type_idx_);
+            /* TODO: on error do we want to keep going?  If we don't fail this we run the risk of
+             * having a non-Throwable introduced at runtime. However, that won't pass an instanceof
+             * test, so is essentially harmless.
+             */
+            if (klass == NULL) {
+              Fail(VERIFY_ERROR_GENERIC) << "unable to resolve exception class "
+                                         << handler.type_idx_ << " ("
+                                         << dex_file_->dexStringByTypeIdx(handler.type_idx_) << ")";
+              return NULL;
+            } else if(!JavaLangThrowable()->IsAssignableFrom(klass)) {
+              Fail(VERIFY_ERROR_GENERIC) << "unexpected non-exception class " << PrettyClass(klass);
+              return NULL;
+            } else if (common_super == NULL) {
+              common_super = klass;
+            } else {
+              common_super = RegType::ClassJoin(common_super, klass);
+            }
+          }
+        }
+      }
+      handlers_ptr = iterator.GetData();
+    }
+  }
+  if (common_super == NULL) {
+    /* no catch blocks, or no catches with classes we can find */
+    Fail(VERIFY_ERROR_GENERIC) << "unable to find exception handler";
+  }
+  return common_super;
+}
+
+Method* DexVerifier::ResolveMethodAndCheckAccess(uint32_t method_idx, bool is_direct) {
+  Class* referrer = method_->GetDeclaringClass();
+  DexCache* dex_cache = referrer->GetDexCache();
+  Method* res_method = dex_cache->GetResolvedMethod(method_idx);
+  if (res_method == NULL) {
+    const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
+    Class* klass = ResolveClassAndCheckAccess(method_id.class_idx_);
+    if (klass == NULL) {
+      DCHECK(failure_ != VERIFY_ERROR_NONE);
+      return NULL;
+    }
+    const char* name = dex_file_->dexStringById(method_id.name_idx_);
+    std::string signature(dex_file_->CreateMethodDescriptor(method_id.proto_idx_, NULL));
+    if (is_direct) {
+      res_method = klass->FindDirectMethod(name, signature);
+    } else if (klass->IsInterface()) {
+      res_method = klass->FindInterfaceMethod(name, signature);
+    } else {
+      res_method = klass->FindVirtualMethod(name, signature);
+    }
+    if (res_method != NULL) {
+      dex_cache->SetResolvedMethod(method_idx, res_method);
+    } else {
+      Fail(VERIFY_ERROR_NO_METHOD) << "couldn't find method "
+                                   << PrettyDescriptor(klass->GetDescriptor()) << "." << name
+                                   << " " << signature;
+      return NULL;
+    }
+  }
+  /* Check if access is allowed. */
+  if (!referrer->CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
+    Fail(VERIFY_ERROR_ACCESS_METHOD) << "illegal method access (call " << PrettyMethod(res_method)
+                                  << " from " << PrettyDescriptor(referrer->GetDescriptor()) << ")";
+    return NULL;
+  }
+  return res_method;
+}
+
+Method* DexVerifier::VerifyInvocationArgs(const Instruction::DecodedInstruction& dec_insn,
+                                          MethodType method_type, bool is_range, bool is_super) {
+  // Resolve the method. This could be an abstract or concrete method depending on what sort of call
+  // we're making.
+  Method* res_method = ResolveMethodAndCheckAccess(dec_insn.vB_,
+                           (method_type == METHOD_DIRECT || method_type == METHOD_STATIC));
+  if (res_method == NULL) {
+    const DexFile::MethodId& method_id = dex_file_->GetMethodId(dec_insn.vB_);
+    const char* method_name = dex_file_->GetMethodName(method_id);
+    std::string method_signature = dex_file_->GetMethodSignature(method_id);
+    const char* class_descriptor = dex_file_->GetMethodClassDescriptor(method_id);
+    Fail(VERIFY_ERROR_GENERIC) << "unable to resolve method " << dec_insn.vB_ << ": "
+                               << class_descriptor << "." << method_name << " " << method_signature;
+    return NULL;
+  }
+  // Make sure calls to constructors are "direct". There are additional restrictions but we don't
+  // enforce them here.
+  if (res_method->IsConstructor() && method_type != METHOD_DIRECT) {
+    Fail(VERIFY_ERROR_GENERIC) << "rejecting non-direct call to constructor "
+                               << PrettyMethod(res_method);
+    return NULL;
+  }
+  // See if the method type implied by the invoke instruction matches the access flags for the
+  // target method.
+  if ((method_type == METHOD_DIRECT && !res_method->IsDirect()) ||
+      (method_type == METHOD_STATIC && !res_method->IsStatic()) ||
+      ((method_type == METHOD_VIRTUAL || method_type == METHOD_INTERFACE) && res_method->IsDirect())
+      ) {
+    Fail(VERIFY_ERROR_GENERIC) << "invoke type does not match method type of "
+                               << PrettyMethod(res_method);
+    return NULL;
+  }
+  // If we're using invoke-super(method), make sure that the executing method's class' superclass
+  // has a vtable entry for the target method.
+  if (is_super) {
+    DCHECK(method_type == METHOD_VIRTUAL);
+    Class* super = method_->GetDeclaringClass()->GetSuperClass();
+    if (super == NULL || res_method->GetMethodIndex() > super->GetVTable()->GetLength()) {
+      if (super == NULL) {  // Only Object has no super class
+        Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from " << PrettyMethod(method_)
+                                     << " to super " << PrettyMethod(res_method);
+      } else {
+        Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from " << PrettyMethod(method_)
+                                     << " to super " << PrettyDescriptor(super->GetDescriptor())
+                                     << "." << res_method->GetName()->ToModifiedUtf8()
+                                     << " " << res_method->GetSignature()->ToModifiedUtf8();
+
+      }
+      return NULL;
+    }
+  }
+  // We use vAA as our expected arg count, rather than res_method->insSize, because we need to
+  // match the call to the signature. Also, we might might be calling through an abstract method
+  // definition (which doesn't have register count values).
+  int expected_args = dec_insn.vA_;
+  /* caught by static verifier */
+  DCHECK(is_range || expected_args <= 5);
+  if (expected_args > code_item_->outs_size_) {
+    Fail(VERIFY_ERROR_GENERIC) << "invalid arg count (" << expected_args
+        << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
+    return NULL;
+  }
+  std::string sig = res_method->GetSignature()->ToModifiedUtf8();
+  if (sig[0] != '(') {
+    Fail(VERIFY_ERROR_GENERIC) << "rejecting call to " << res_method
+        << " as descriptor doesn't start with '(': " << sig;
+    return NULL;
+  }
   /*
-   * Generate the new instruction out of the old.
-   *
-   * First, make sure this is an instruction we're expecting to stomp on.
+   * Check the "this" argument, which must be an instance of the class
+   * that declared the method. For an interface class, we don't do the
+   * full interface merge, so we can't do a rigorous check here (which
+   * is okay since we have to do it at runtime).
    */
-  switch (opcode) {
-    case Instruction::CONST_CLASS:            // insn[1] == class ref, 2 bytes
+  int actual_args = 0;
+  if (!res_method->IsStatic()) {
+    const RegType& actual_arg_type = work_line_->GetInvocationThis(dec_insn);
+    if (failure_ != VERIFY_ERROR_NONE) {
+      return NULL;
+    }
+    if (actual_arg_type.IsUninitializedReference() && !res_method->IsConstructor()) {
+      Fail(VERIFY_ERROR_GENERIC) << "'this' arg must be initialized";
+      return NULL;
+    }
+    if (method_type != METHOD_INTERFACE && !actual_arg_type.IsZero()) {
+      Class* actual_this_ref = actual_arg_type.GetClass();
+      if (!res_method->GetDeclaringClass()->IsAssignableFrom(actual_this_ref)) {
+        Fail(VERIFY_ERROR_GENERIC) << "'this' arg '"
+            << PrettyDescriptor(actual_this_ref->GetDescriptor()) << "' not instance of '"
+            << PrettyDescriptor(res_method->GetDeclaringClass()->GetDescriptor()) << "'";
+        return NULL;
+      }
+    }
+    actual_args++;
+  }
+  /*
+   * Process the target method's signature. This signature may or may not
+   * have been verified, so we can't assume it's properly formed.
+   */
+  size_t sig_offset = 0;
+  for (sig_offset = 1; sig_offset < sig.size() && sig[sig_offset] != ')'; sig_offset++) {
+    if (actual_args >= expected_args) {
+      Fail(VERIFY_ERROR_GENERIC) << "Rejecting invalid call to '" << PrettyMethod(res_method)
+          << "'. Expected " << expected_args << " args, found more ("
+          << sig.substr(sig_offset) << ")";
+      return NULL;
+    }
+    std::string descriptor;
+    if ((sig[sig_offset] == 'L') || (sig[sig_offset] == '[')) {
+      size_t end;
+      if (sig[sig_offset] == 'L') {
+        end = sig.find(';', sig_offset);
+      } else {
+        for(end = sig_offset + 1; sig[end] == '['; end++) ;
+        if (sig[end] == 'L') {
+          end = sig.find(';', end);
+        }
+      }
+      if (end == std::string::npos) {
+        Fail(VERIFY_ERROR_GENERIC) << "Rejecting invocation of " << PrettyMethod(res_method)
+            << "bad signature component '" << sig << "' (missing ';')";
+        return NULL;
+      }
+      descriptor = sig.substr(sig_offset, end - sig_offset + 1);
+      sig_offset = end;
+    } else {
+      descriptor = sig[sig_offset];
+    }
+    const RegType& reg_type =
+        reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(), descriptor);
+    if (reg_type.IsUnknown()) {
+      DCHECK(Thread::Current()->IsExceptionPending());
+      Thread::Current()->ClearException();
+      Fail(VERIFY_ERROR_GENERIC) << "Rejecting invocation of " << PrettyMethod(res_method)
+         << " bad descriptor '" << descriptor << "' in signature " << sig;
+      return NULL;
+    } else {
+      uint32_t get_reg = is_range ? dec_insn.vC_ + actual_args : dec_insn.arg_[actual_args];
+      if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
+        return NULL;
+      }
+    }
+    actual_args = reg_type.IsLongOrDoubleTypes() ? actual_args + 2 : actual_args + 1;
+  }
+  if (sig[sig_offset] != ')') {
+    Fail(VERIFY_ERROR_GENERIC) << "invocation target: bad signature" << PrettyMethod(res_method);
+    return NULL;
+  }
+  if (actual_args != expected_args) {
+    Fail(VERIFY_ERROR_GENERIC) << "Rejecting invocation of " << PrettyMethod(res_method)
+        << " expected " << expected_args << " args, found " << actual_args;
+    return NULL;
+  } else {
+    return res_method;
+  }
+}
+
+void DexVerifier::VerifyAGet(const Instruction::DecodedInstruction& dec_insn,
+                             const RegType& insn_type, bool is_primitive) {
+  const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC_);
+  if (!index_type.IsArrayIndexTypes()) {
+    Fail(VERIFY_ERROR_GENERIC) << "Invalid reg type for array index (" << index_type << ")";
+  } else {
+    Class* array_class = work_line_->GetClassFromRegister(dec_insn.vB_);
+    if (failure_ == VERIFY_ERROR_NONE) {
+      if (array_class == NULL) {
+        // Null array class; this code path will fail at runtime. Infer a merge-able type from the
+        // instruction type. TODO: have a proper notion of bottom here.
+        if (!is_primitive || insn_type.IsCategory1Types()) {
+          // Reference or category 1
+          work_line_->SetRegisterType(dec_insn.vA_, reg_types_.Zero());
+        } else {
+          // Category 2
+          work_line_->SetRegisterType(dec_insn.vA_, reg_types_.ConstLo());
+        }
+      } else {
+        /* verify the class */
+        Class* component_class = array_class->GetComponentType();
+        const RegType& component_type = reg_types_.FromClass(component_class);
+        if (!array_class->IsArrayClass()) {
+          Fail(VERIFY_ERROR_GENERIC) << "not array type "
+              << PrettyDescriptor(array_class->GetDescriptor()) << " with aget";
+        } else if (component_class->IsPrimitive() && !is_primitive) {
+          Fail(VERIFY_ERROR_GENERIC) << "primitive array type "
+                                     << PrettyDescriptor(array_class->GetDescriptor())
+                                     << " source for aget-object";
+        } else if (!component_class->IsPrimitive() && is_primitive) {
+          Fail(VERIFY_ERROR_GENERIC) << "reference array type "
+                                     << PrettyDescriptor(array_class->GetDescriptor())
+                                     << " source for category 1 aget";
+        } else if (is_primitive && !insn_type.Equals(component_type) &&
+                   !((insn_type.IsInteger() && component_type.IsFloat()) ||
+                     (insn_type.IsLong() && component_type.IsDouble()))) {
+          Fail(VERIFY_ERROR_GENERIC) << "array type "
+              << PrettyDescriptor(array_class->GetDescriptor())
+              << " incompatible with aget of type " << insn_type;
+        } else {
+          // Use knowledge of the field type which is stronger than the type inferred from the
+          // instruction, which can't differentiate object types and ints from floats, longs from
+          // doubles.
+          work_line_->SetRegisterType(dec_insn.vA_, component_type);
+        }
+      }
+    }
+  }
+}
+
+void DexVerifier::VerifyAPut(const Instruction::DecodedInstruction& dec_insn,
+                             const RegType& insn_type, bool is_primitive) {
+  const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC_);
+  if (!index_type.IsArrayIndexTypes()) {
+    Fail(VERIFY_ERROR_GENERIC) << "Invalid reg type for array index (" << index_type << ")";
+  } else {
+    Class* array_class = work_line_->GetClassFromRegister(dec_insn.vB_);
+    if (failure_ == VERIFY_ERROR_NONE) {
+      if (array_class == NULL) {
+        // Null array class; this code path will fail at runtime. Infer a merge-able type from the
+        // instruction type.
+      } else {
+        /* verify the class */
+        Class* component_class = array_class->GetComponentType();
+        const RegType& component_type = reg_types_.FromClass(component_class);
+        if (!array_class->IsArrayClass()) {
+          Fail(VERIFY_ERROR_GENERIC) << "not array type "
+              << PrettyDescriptor(array_class->GetDescriptor()) << " with aput";
+        } else if (component_class->IsPrimitive() && !is_primitive) {
+          Fail(VERIFY_ERROR_GENERIC) << "primitive array type "
+                                     << PrettyDescriptor(array_class->GetDescriptor())
+                                     << " source for aput-object";
+        } else if (!component_class->IsPrimitive() && is_primitive) {
+          Fail(VERIFY_ERROR_GENERIC) << "reference array type "
+                                     << PrettyDescriptor(array_class->GetDescriptor())
+                                     << " source for category 1 aput";
+        } else if (is_primitive && !insn_type.Equals(component_type) &&
+                   !((insn_type.IsInteger() && component_type.IsFloat()) ||
+                     (insn_type.IsLong() && component_type.IsDouble()))) {
+          Fail(VERIFY_ERROR_GENERIC) << "array type "
+              << PrettyDescriptor(array_class->GetDescriptor())
+              << " incompatible with aput of type " << insn_type;
+        } else {
+          // The instruction agrees with the type of array, confirm the value to be stored does too
+          work_line_->VerifyRegisterType(dec_insn.vA_, component_type);
+        }
+      }
+    }
+  }
+}
+
+Field* DexVerifier::GetStaticField(int field_idx) {
+  Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, method_, true);
+  if (field == NULL) {
+    const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
+    Fail(VERIFY_ERROR_NO_FIELD) << "unable to resolve static field " << field_idx << " ("
+                                << dex_file_->GetFieldName(field_id) << ") in "
+                                << dex_file_->GetFieldClassDescriptor(field_id);
+    DCHECK(Thread::Current()->IsExceptionPending());
+    Thread::Current()->ClearException();
+    return NULL;
+  } else if (!method_->GetDeclaringClass()->CanAccessMember(field->GetDeclaringClass(),
+                                                            field->GetAccessFlags())) {
+    Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot access static field " << PrettyField(field)
+                                   << " from " << PrettyClass(method_->GetDeclaringClass());
+    return NULL;
+  } else if (!field->IsStatic()) {
+    Fail(VERIFY_ERROR_CLASS_CHANGE) << "expected field " << PrettyField(field) << " to be static";
+    return NULL;
+  } else {
+    return field;
+  }
+}
+
+void DexVerifier::VerifySGet(const Instruction::DecodedInstruction& dec_insn,
+                             const RegType& insn_type, bool is_primitive) {
+  Field* field = GetStaticField(dec_insn.vB_);
+  if (field != NULL) {
+    DCHECK(field->GetDeclaringClass()->IsResolved());
+    Class* field_class = field->GetType();
+    Class* insn_class = insn_type.GetClass();
+    if (is_primitive) {
+      if (field_class == insn_class ||
+          (field_class->IsPrimitiveFloat() && insn_class->IsPrimitiveInt()) ||
+          (field_class->IsPrimitiveDouble() && insn_class->IsPrimitiveLong())) {
+        // expected that read is of the correct primitive type or that int reads are reading
+        // floats or long reads are reading doubles
+      } else {
+        // This is a global failure rather than a class change failure as the instructions and
+        // the descriptors for the type should have been consistent within the same file at
+        // compile time
+        Fail(VERIFY_ERROR_GENERIC) << "expected field " << PrettyField(field)
+                                   << " to be of type " << PrettyClass(insn_class)
+                                   << " but found type " << PrettyClass(field_class) << " in sget";
+        return;
+      }
+    } else {
+      if (!insn_class->IsAssignableFrom(field_class)) {
+        Fail(VERIFY_ERROR_GENERIC) << "expected field " << PrettyField(field)
+                                   << " to be of type " << PrettyClass(insn_class)
+                                   << " but found type " << PrettyClass(field_class)
+                                   << " in sget-object";
+        return;
+      }
+    }
+    work_line_->SetRegisterType(dec_insn.vA_, reg_types_.FromClass(field_class));
+  }
+}
+
+void DexVerifier::VerifySPut(const Instruction::DecodedInstruction& dec_insn,
+                             const RegType& insn_type, bool is_primitive) {
+  Field* field = GetStaticField(dec_insn.vB_);
+  if (field != NULL) {
+    DCHECK(field->GetDeclaringClass()->IsResolved());
+    if (field->IsFinal() && field->GetDeclaringClass() != method_->GetDeclaringClass()) {
+      Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final static field " << PrettyField(field)
+                               << " from other class " << PrettyClass(method_->GetDeclaringClass());
+      return;
+    }
+    Class* field_class = field->GetType();
+    Class* insn_class = insn_type.GetClass();
+    if (is_primitive) {
+      if (field_class == insn_class ||
+          (field_class->IsPrimitiveFloat() && insn_class->IsPrimitiveInt()) ||
+          (field_class->IsPrimitiveDouble() && insn_class->IsPrimitiveLong())) {
+        // expected that read is of the correct primitive type or that int reads are reading
+        // floats or long reads are reading doubles
+      } else {
+        // This is a global failure rather than a class change failure as the instructions and
+        // the descriptors for the type should have been consistent within the same file at
+        // compile time
+        Fail(VERIFY_ERROR_GENERIC) << "expected field " << PrettyField(field)
+                                   << " to be of type " << PrettyClass(insn_class)
+                                   << " but found type " << PrettyClass(field_class) << " in sput";
+        return;
+      }
+    } else {
+      if (!insn_class->IsAssignableFrom(field_class)) {
+        Fail(VERIFY_ERROR_GENERIC) << "expected field " << PrettyField(field)
+                                  << " to be compatible with type " << insn_type
+                                  << " but found type " << PrettyClass(field_class)
+                                  << " in sput-object";
+        return;
+      }
+    }
+    work_line_->VerifyRegisterType(dec_insn.vA_, reg_types_.FromClass(field_class));
+  }
+}
+
+Field* DexVerifier::GetInstanceField(const RegType& obj_type, int field_idx) {
+  Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, method_, false);
+  if (field == NULL) {
+    const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
+    Fail(VERIFY_ERROR_NO_FIELD) << "unable to resolve instance field " << field_idx << " ("
+                                << dex_file_->GetFieldName(field_id) << ") in "
+                                << dex_file_->GetFieldClassDescriptor(field_id);
+    DCHECK(Thread::Current()->IsExceptionPending());
+    Thread::Current()->ClearException();
+    return NULL;
+  } else if (!method_->GetDeclaringClass()->CanAccessMember(field->GetDeclaringClass(),
+                                                            field->GetAccessFlags())) {
+    Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot access instance field " << PrettyField(field)
+                                    << " from " << PrettyClass(method_->GetDeclaringClass());
+    return NULL;
+  } else if (field->IsStatic()) {
+    Fail(VERIFY_ERROR_CLASS_CHANGE) << "expected field " << PrettyField(field)
+                                    << " to not be static";
+    return NULL;
+  } else if (obj_type.IsZero()) {
+    // Cannot infer and check type, however, access will cause null pointer exception
+    return field;
+  } else if(obj_type.IsUninitializedReference() &&
+            (!method_->IsConstructor() || method_->GetDeclaringClass() != obj_type.GetClass() ||
+             field->GetDeclaringClass() != method_->GetDeclaringClass())) {
+    // Field accesses through uninitialized references are only allowable for constructors where
+    // the field is declared in this class
+    Fail(VERIFY_ERROR_GENERIC) << "cannot access instance field " << PrettyField(field)
+                               << " of a not fully initialized object within the context of "
+                               << PrettyMethod(method_);
+    return NULL;
+  } else if(!field->GetDeclaringClass()->IsAssignableFrom(obj_type.GetClass())) {
+    // Trying to access C1.field1 using reference of type C2, which is neither C1 or a sub-class
+    // of C1. For resolution to occur the declared class of the field must be compatible with
+    // obj_type, we've discovered this wasn't so, so report the field didn't exist.
+    Fail(VERIFY_ERROR_NO_FIELD) << "cannot access instance field " << PrettyField(field)
+                                << " from object of type " << PrettyClass(obj_type.GetClass());
+    return NULL;
+  } else {
+    return field;
+  }
+}
+
+void DexVerifier::VerifyIGet(const Instruction::DecodedInstruction& dec_insn,
+                             const RegType& insn_type, bool is_primitive) {
+  const RegType& object_type = work_line_->GetRegisterType(dec_insn.vB_);
+  Field* field = GetInstanceField(object_type, dec_insn.vC_);
+  if (field != NULL) {
+    DCHECK(field->GetDeclaringClass()->IsResolved());
+    Class* field_class = field->GetType();
+    Class* insn_class = insn_type.GetClass();
+    if (is_primitive) {
+      if (field_class == insn_class ||
+          (field_class->IsPrimitiveFloat() && insn_class->IsPrimitiveInt()) ||
+          (field_class->IsPrimitiveDouble() && insn_class->IsPrimitiveLong())) {
+        // expected that read is of the correct primitive type or that int reads are reading
+        // floats or long reads are reading doubles
+      } else {
+        // This is a global failure rather than a class change failure as the instructions and
+        // the descriptors for the type should have been consistent within the same file at
+        // compile time
+        Fail(VERIFY_ERROR_GENERIC) << "expected field " << PrettyField(field)
+                                   << " to be of type " << PrettyClass(insn_class)
+                                   << " but found type " << PrettyClass(field_class) << " in iget";
+        return;
+      }
+    } else {
+      if (!insn_class->IsAssignableFrom(field_class)) {
+        Fail(VERIFY_ERROR_GENERIC) << "expected field " << PrettyField(field)
+                                   << " to be compatible with type " << PrettyClass(insn_class)
+                                   << " but found type " << PrettyClass(field_class) << " in iget-object";
+        return;
+      }
+    }
+    work_line_->SetRegisterType(dec_insn.vA_, reg_types_.FromClass(field_class));
+  }
+}
+
+void DexVerifier::VerifyIPut(const Instruction::DecodedInstruction& dec_insn,
+                             const RegType& insn_type, bool is_primitive) {
+  const RegType& object_type = work_line_->GetRegisterType(dec_insn.vB_);
+  Field* field = GetInstanceField(object_type, dec_insn.vC_);
+  if (field != NULL) {
+    DCHECK(field->GetDeclaringClass()->IsResolved());
+    if (field->IsFinal() && field->GetDeclaringClass() != method_->GetDeclaringClass()) {
+      Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
+                               << " from other class " << PrettyClass(method_->GetDeclaringClass());
+      return;
+    }
+    Class* field_class = field->GetType();
+    Class* insn_class = insn_type.GetClass();
+    if (is_primitive) {
+      if (field_class == insn_class ||
+          (field_class->IsPrimitiveFloat() && insn_class->IsPrimitiveInt()) ||
+          (field_class->IsPrimitiveDouble() && insn_class->IsPrimitiveLong())) {
+        // expected that read is of the correct primitive type or that int reads are reading
+        // floats or long reads are reading doubles
+      } else {
+        // This is a global failure rather than a class change failure as the instructions and
+        // the descriptors for the type should have been consistent within the same file at
+        // compile time
+        Fail(VERIFY_ERROR_GENERIC) << "expected field " << PrettyField(field)
+                                   << " to be of type " << PrettyClass(insn_class)
+                                   << " but found type " << PrettyClass(field_class) << " in iput";
+        return;
+      }
+    } else {
+      if (!insn_class->IsAssignableFrom(field_class)) {
+        Fail(VERIFY_ERROR_GENERIC) << "expected field " << PrettyField(field)
+                                   << " to be compatible with type " << PrettyClass(insn_class)
+                                   << " but found type " << PrettyClass(field_class)
+                                   << " in iput-object";
+        return;
+      }
+    }
+    work_line_->VerifyRegisterType(dec_insn.vA_, reg_types_.FromClass(field_class));
+  }
+}
+
+bool DexVerifier::CheckMoveException(const uint16_t* insns, int insn_idx) {
+  if ((insns[insn_idx] & 0xff) == Instruction::MOVE_EXCEPTION) {
+    Fail(VERIFY_ERROR_GENERIC) << "invalid use of move-exception";
+    return false;
+  }
+  return true;
+}
+
+void DexVerifier::VerifyFilledNewArrayRegs(const Instruction::DecodedInstruction& dec_insn,
+                                           Class* res_class, bool is_range) {
+  DCHECK(res_class->IsArrayClass()) << PrettyClass(res_class);  // Checked before calling.
+  /*
+   * Verify each register. If "arg_count" is bad, VerifyRegisterType() will run off the end of the
+   * list and fail. It's legal, if silly, for arg_count to be zero.
+   */
+  const RegType& expected_type = reg_types_.FromClass(res_class->GetComponentType());
+  uint32_t arg_count = dec_insn.vA_;
+  for (size_t ui = 0; ui < arg_count; ui++) {
+    uint32_t get_reg;
+
+    if (is_range)
+      get_reg = dec_insn.vC_ + ui;
+    else
+      get_reg = dec_insn.arg_[ui];
+
+    if (!work_line_->VerifyRegisterType(get_reg, expected_type)) {
+      Fail(VERIFY_ERROR_GENERIC) << "filled-new-array arg " << ui << "(" << get_reg
+                                 << ") not valid";
+      return;
+    }
+  }
+}
+
+void DexVerifier::ReplaceFailingInstruction() {
+  const Instruction* inst = Instruction::At(code_item_->insns_ + work_insn_idx_);
+  DCHECK(inst->IsThrow()) << "Expected instruction that will throw " << inst->Name();
+  VerifyErrorRefType ref_type;
+  switch (inst->Opcode()) {
+    case Instruction::CONST_CLASS:            // insn[1] == class ref, 2 code units (4 bytes)
     case Instruction::CHECK_CAST:
     case Instruction::INSTANCE_OF:
     case Instruction::NEW_INSTANCE:
     case Instruction::NEW_ARRAY:
-    case Instruction::FILLED_NEW_ARRAY:       // insn[1] == class ref, 3 bytes
+    case Instruction::FILLED_NEW_ARRAY:       // insn[1] == class ref, 3 code units (6 bytes)
     case Instruction::FILLED_NEW_ARRAY_RANGE:
       ref_type = VERIFY_ERROR_REF_CLASS;
       break;
-
-    case Instruction::IGET:                   // insn[1] == field ref, 2 bytes
+    case Instruction::IGET:                   // insn[1] == field ref, 2 code units (4 bytes)
     case Instruction::IGET_BOOLEAN:
     case Instruction::IGET_BYTE:
     case Instruction::IGET_CHAR:
@@ -3575,8 +3512,7 @@
     case Instruction::SPUT_OBJECT:
       ref_type = VERIFY_ERROR_REF_FIELD;
       break;
-
-    case Instruction::INVOKE_VIRTUAL:         // insn[1] == method ref, 3 bytes
+    case Instruction::INVOKE_VIRTUAL:         // insn[1] == method ref, 3 code units (6 bytes)
     case Instruction::INVOKE_VIRTUAL_RANGE:
     case Instruction::INVOKE_SUPER:
     case Instruction::INVOKE_SUPER_RANGE:
@@ -3588,2394 +3524,212 @@
     case Instruction::INVOKE_INTERFACE_RANGE:
       ref_type = VERIFY_ERROR_REF_METHOD;
       break;
-
     default:
-      /* could handle this in a generic way, but this is probably safer */
-      LOG(ERROR) << "GLITCH: verifier asked to replace opcode 0x" << std::hex
-                 << (int) opcode << std::dec;
-      return false;
-  }
-
-  DCHECK(inst->IsThrow());
-
-  /* write a NOP over the third code unit, if necessary */
-  int width = inst->Size();
-  switch (width) {
-    case 2:
-      /* nothing to do */
-      break;
-    case 3:
-      UpdateCodeUnit(insns + 2, Instruction::NOP);
-      break;
-    default:
-      /* whoops */
-      LOG(FATAL) << "ERROR: stomped a " << width
-                 << "-unit instruction with a verifier error";
-  }
-
-  /* encode the opcode, with the failure code in the high byte */
-  DCHECK(width == 2 || width == 3);
-  uint16_t new_val = Instruction::THROW_VERIFICATION_ERROR |
-      (failure << 8) | (ref_type << (8 + kVerifyErrorRefTypeShift));
-  UpdateCodeUnit(insns, new_val);
-
-  return true;
-}
-
-void DexVerifier::UpdateCodeUnit(const uint16_t* ptr, uint16_t new_val) {
-  *(uint16_t*) ptr = new_val;
-}
-
-void DexVerifier::HandleMonitorEnter(RegisterLine* work_line, uint32_t reg_idx,
-    uint32_t insn_idx, VerifyError* failure) {
-  if (!RegTypeIsReference(GetRegisterType(work_line, reg_idx))) {
-    LOG(ERROR) << "VFY: monitor-enter on non-object";
-    *failure = VERIFY_ERROR_GENERIC;
-    return;
-  }
-
-  if (work_line->monitor_entries_.get() == NULL) {
-    return;
-  }
-
-  if (work_line->monitor_stack_top_ == kMaxMonitorStackDepth) {
-    LOG(ERROR) << "VFY: monitor-enter stack overflow (" << kMaxMonitorStackDepth
-               << ")";
-    *failure = VERIFY_ERROR_GENERIC;
-    return;
-  }
-
-  /*
-   * Push an entry on the stack, and set a bit in the register flags to
-   * indicate that it's associated with this register.
-   */
-  work_line->monitor_entries_[reg_idx] |= 1 << work_line->monitor_stack_top_;
-  work_line->monitor_stack_[work_line->monitor_stack_top_++] = insn_idx;
-}
-
-void DexVerifier::HandleMonitorExit(RegisterLine* work_line, uint32_t reg_idx,
-    uint32_t insn_idx, VerifyError* failure) {
-  if (!RegTypeIsReference(GetRegisterType(work_line, reg_idx))) {
-    LOG(ERROR) << "VFY: monitor-exit on non-object";
-    *failure = VERIFY_ERROR_GENERIC;
-    return;
-  }
-
-  if (work_line->monitor_entries_.get() == NULL) {
-    return;
-  }
-
-  if (work_line->monitor_stack_top_ == 0) {
-    LOG(ERROR) << "VFY: monitor-exit stack underflow";
-    *failure = VERIFY_ERROR_GENERIC;
-    return;
-  }
-
-  /*
-   * Confirm that the entry at the top of the stack is associated with
-   * the register. Pop the top entry off.
-   */
-  work_line->monitor_stack_top_--;
-#ifdef BUG_3215458_FIXED
-  /*
-   * TODO: This code can safely be enabled if know we are working on
-   * a dex file of format version 036 or later. (That is, we'll need to
-   * add a check for the version number.)
-   */
-  if ((work_line->monitor_entries_[reg_idx] &
-      (1 << work_line->monitor_stack_top_)) == 0) {
-    LOG(ERROR) << "VFY: monitor-exit bit " << work_line->monitor_stack_top_
-               << " not set: addr=0x" << std::hex << insn_idx << std::dec
-               << " (bits[" << reg_idx << "]=" << std::hex
-               << work_line->monitor_entries_[reg_idx] << std::dec << ")";
-    *failure = VERIFY_ERROR_GENERIC;
-    return;
-  }
-#endif
-  work_line->monitor_stack_[work_line->monitor_stack_top_] = 0;
-
-  /* Clear the bit from the register flags. */
-  work_line->monitor_entries_[reg_idx] &= ~(1 << work_line->monitor_stack_top_);
-}
-
-Field* DexVerifier::GetInstField(VerifierData* vdata, RegType obj_type,
-    int field_idx, VerifyError* failure) {
-  Method* method = vdata->method_;
-  const DexFile* dex_file = vdata->dex_file_;
-  UninitInstanceMap* uninit_map = vdata->uninit_map_.get();
-  bool must_be_local = false;
-
-  if (!RegTypeIsReference(obj_type)) {
-    LOG(ERROR) << "VFY: attempt to access field in non-reference type "
-               << obj_type;
-    *failure = VERIFY_ERROR_GENERIC;
-    return NULL;
-  }
-
-  Field* field = ResolveFieldAndCheckAccess(dex_file, field_idx,
-      method->GetDeclaringClass(), failure, false);
-  if (field == NULL) {
-    LOG(ERROR) << "VFY: unable to resolve instance field " << field_idx;
-    return NULL;
-  }
-
-  if (obj_type == kRegTypeZero)
-    return field;
-
-  /*
-   * Access to fields in uninitialized objects is allowed if this is
-   * the <init> method for the object and the field in question is
-   * declared by this class.
-   */
-  Class* obj_class = RegTypeReferenceToClass(obj_type, uninit_map);
-  DCHECK(obj_class != NULL);
-  if (RegTypeIsUninitReference(obj_type)) {
-    if (!IsInitMethod(method) || method->GetDeclaringClass() != obj_class) {
-      LOG(ERROR) << "VFY: attempt to access field via uninitialized ref";
-      *failure = VERIFY_ERROR_GENERIC;
-      return field;
-    }
-    must_be_local = true;
-  }
-
-  if (!field->GetDeclaringClass()->IsAssignableFrom(obj_class)) {
-    LOG(ERROR) << "VFY: invalid field access (field " << PrettyField(field)
-               << ", through " << obj_class->GetDescriptor()->ToModifiedUtf8()
-               << " ref)";
-    *failure = VERIFY_ERROR_NO_FIELD;
-    return field;
-  }
-
-  if (must_be_local) {
-    bool found = false;
-    /* for uninit ref, make sure it's defined by this class, not super */
-    for (uint32_t i = 0; i < obj_class->NumInstanceFields(); i++) {
-      found |= (field == obj_class->GetInstanceField(i));
-    }
-    if (!found) {
-      LOG(ERROR) << "VFY: invalid constructor field access (field "
-                 << field->GetName()->ToModifiedUtf8() << " in "
-                 << obj_class->GetDescriptor()->ToModifiedUtf8() << ")";
-      *failure = VERIFY_ERROR_GENERIC;
-      return field;
-    }
-  }
-
-  return field;
-}
-
-Field* DexVerifier::GetStaticField(VerifierData* vdata, int field_idx,
-    VerifyError* failure) {
-  Method* method = vdata->method_;
-  const DexFile* dex_file = vdata->dex_file_;
-  Field* field = ResolveFieldAndCheckAccess(dex_file, field_idx,
-      method->GetDeclaringClass(), failure, true);
-  if (field == NULL) {
-    const DexFile::FieldId& field_id = dex_file->GetFieldId(field_idx);
-    LOG(ERROR) << "VFY: unable to resolve static field " << field_idx << " ("
-               << dex_file->GetFieldName(field_id) << ") in "
-               << dex_file->GetFieldClassDescriptor(field_id);
-    *failure = VERIFY_ERROR_NO_FIELD;
-  }
-
-  return field;
-}
-
-Class* DexVerifier::GetCaughtExceptionType(VerifierData* vdata, int insn_idx,
-    VerifyError* failure) {
-  const DexFile* dex_file = vdata->dex_file_;
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  Method* method = vdata->method_;
-  Class* common_super = NULL;
-  uint32_t handlers_size;
-  const byte* handlers_ptr = DexFile::dexGetCatchHandlerData(*code_item, 0);
-  VerifyError local_failure;
-
-  if (code_item->tries_size_ != 0) {
-    handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
-  } else {
-    handlers_size = 0;
-  }
-
-  for (uint32_t i = 0; i < handlers_size; i++) {
-    DexFile::CatchHandlerIterator iterator(handlers_ptr);
-
-    for (; !iterator.HasNext(); iterator.Next()) {
-      DexFile::CatchHandlerItem handler = iterator.Get();
-      if (handler.address_ == (uint32_t) insn_idx) {
-        ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-        Class* klass;
-
-        if (handler.type_idx_ == DexFile::kDexNoIndex) {
-          klass = class_linker->FindSystemClass("Ljava/lang/Throwable;");
-        } else {
-          klass = ResolveClassAndCheckAccess(dex_file, handler.type_idx_,
-              method->GetDeclaringClass(), &local_failure);
-        }
-
-        if (klass == NULL) {
-          LOG(ERROR) << "VFY: unable to resolve exception class "
-                     << handler.type_idx_ << " ("
-                     << dex_file->dexStringByTypeIdx(handler.type_idx_) << ")";
-          /* TODO: do we want to keep going?  If we don't fail this we run
-           * the risk of having a non-Throwable introduced at runtime.
-           * However, that won't pass an instanceof test, so is essentially
-           * harmless.
-           */
-        } else {
-          if (common_super == NULL)
-            common_super = klass;
-          else
-            common_super = FindCommonSuperclass(klass, common_super);
-        }
-      }
-    }
-
-    handlers_ptr = iterator.GetData();
-  }
-
-  if (common_super == NULL) {
-    /* no catch blocks, or no catches with classes we can find */
-    LOG(ERROR) << "VFY: unable to find exception handler at addr 0x" << std::hex
-               << insn_idx << std::dec;
-    *failure = VERIFY_ERROR_GENERIC;
-  }
-
-  return common_super;
-}
-
-DexVerifier::RegType DexVerifier::GetMethodReturnType(const DexFile* dex_file,
-    const Method* method) {
-  Class* klass = method->GetReturnType();
-  if (klass->IsPrimitive())
-    return PrimitiveTypeToRegType(klass->GetPrimitiveType());
-  else
-    return RegTypeFromClass(klass);
-}
-
-Class* DexVerifier::GetClassFromRegister(const RegisterLine* register_line,
-    uint32_t vsrc, VerifyError* failure) {
-  /* get the element type of the array held in vsrc */
-  RegType type = GetRegisterType(register_line, vsrc);
-
-  /* if "always zero", we allow it to fail at runtime */
-  if (type == kRegTypeZero)
-    return NULL;
-
-  if (!RegTypeIsReference(type)) {
-    LOG(ERROR) << "VFY: tried to get class from non-ref register v" << vsrc
-               << " (type=" << type << ")",
-    *failure = VERIFY_ERROR_GENERIC;
-    return NULL;
-  }
-  if (RegTypeIsUninitReference(type)) {
-    LOG(ERROR) << "VFY: register " << vsrc << " holds uninitialized reference";
-    *failure = VERIFY_ERROR_GENERIC;
-    return NULL;
-  }
-
-  return RegTypeInitializedReferenceToClass(type);
-}
-
-DexVerifier::RegType DexVerifier::GetInvocationThis(
-    const RegisterLine* register_line,
-    const Instruction::DecodedInstruction* dec_insn, VerifyError* failure) {
-  if (dec_insn->vA_ < 1) {
-    LOG(ERROR) << "VFY: invoke lacks 'this'";
-    *failure = VERIFY_ERROR_GENERIC;
-    return kRegTypeUnknown;
-  }
-
-  /* get the element type of the array held in vsrc */
-  RegType this_type = GetRegisterType(register_line, dec_insn->vC_);
-  if (!RegTypeIsReference(this_type)) {
-    LOG(ERROR) << "VFY: tried to get class from non-ref register v"
-               << dec_insn->vC_ << " (type=" << this_type << ")";
-    *failure = VERIFY_ERROR_GENERIC;
-    return kRegTypeUnknown;
-  }
-
-  return this_type;
-}
-
-void DexVerifier::SetRegisterType(RegisterLine* register_line, uint32_t vdst,
-    RegType new_type) {
-  RegType* insn_regs = register_line->reg_types_.get();
-
-  switch (new_type) {
-    case kRegTypeUnknown:
-    case kRegTypeBoolean:
-    case kRegTypeOne:
-    case kRegTypeConstByte:
-    case kRegTypeConstPosByte:
-    case kRegTypeConstShort:
-    case kRegTypeConstPosShort:
-    case kRegTypeConstChar:
-    case kRegTypeConstInteger:
-    case kRegTypeByte:
-    case kRegTypePosByte:
-    case kRegTypeShort:
-    case kRegTypePosShort:
-    case kRegTypeChar:
-    case kRegTypeInteger:
-    case kRegTypeFloat:
-    case kRegTypeZero:
-    case kRegTypeUninit:
-      insn_regs[vdst] = new_type;
-      break;
-    case kRegTypeConstLo:
-    case kRegTypeLongLo:
-    case kRegTypeDoubleLo:
-      insn_regs[vdst] = new_type;
-      insn_regs[vdst + 1] = new_type + 1;
-      break;
-    case kRegTypeConstHi:
-    case kRegTypeLongHi:
-    case kRegTypeDoubleHi:
-      /* should never set these explicitly */
-      LOG(FATAL) << "BUG: explicit set of high register type";
-      break;
-
-    default:
-      /* can't switch for ref types, so we check explicitly */
-      if (RegTypeIsReference(new_type)) {
-        insn_regs[vdst] = new_type;
-
-        /*
-         * In most circumstances we won't see a reference to a primitive
-         * class here (e.g. "D"), since that would mean the object in the
-         * register is actually a primitive type. It can happen as the
-         * result of an assumed-successful check-cast instruction in
-         * which the second argument refers to a primitive class. (In
-         * practice, such an instruction will always throw an exception.)
-         *
-         * This is not an issue for instructions like const-class, where
-         * the object in the register is a java.lang.Class instance.
-         */
-        break;
-      }
-      /* bad type - fall through */
-
-    case kRegTypeConflict:      // should only be set during a merge
-      LOG(FATAL) << "BUG: set register to unknown type " << new_type;
-      break;
-  }
-
-  /*
-   * Clear the monitor entry bits for this register.
-   */
-  if (register_line->monitor_entries_.get() != NULL)
-    register_line->monitor_entries_[vdst] = 0;
-}
-
-void DexVerifier::VerifyRegisterType(RegisterLine* register_line, uint32_t vsrc,
-    RegType check_type, VerifyError* failure) {
-  const RegType* insn_regs = register_line->reg_types_.get();
-  RegType src_type = insn_regs[vsrc];
-
-  switch (check_type) {
-    case kRegTypeFloat:
-    case kRegTypeBoolean:
-    case kRegTypePosByte:
-    case kRegTypeByte:
-    case kRegTypePosShort:
-    case kRegTypeShort:
-    case kRegTypeChar:
-    case kRegTypeInteger:
-      if (!CanConvertTo1nr(src_type, check_type)) {
-        LOG(ERROR) << "VFY: register1 v" << vsrc << " type " << src_type
-                   << ", wanted " << check_type;
-        *failure = VERIFY_ERROR_GENERIC;
-      }
-      /* Update type if result is float */
-      if (check_type == kRegTypeFloat) {
-        SetRegisterType(register_line, vsrc, check_type);
-      } else {
-        /* Update const type to actual type after use */
-        SetRegisterType(register_line, vsrc, ConstTypeToRegType(src_type));
-      }
-      break;
-    case kRegTypeLongLo:
-    case kRegTypeDoubleLo:
-      if (insn_regs[vsrc + 1] != src_type + 1) {
-        LOG(ERROR) << "VFY: register2 v" << vsrc << "-" << vsrc + 1
-                   << " values " << insn_regs[vsrc] << ","
-                   << insn_regs[vsrc + 1];
-        *failure = VERIFY_ERROR_GENERIC;
-      } else if (!CanConvertTo2(src_type, check_type)) {
-        LOG(ERROR) << "VFY: register2 v" << vsrc << " type " << src_type
-                   << ", wanted " << check_type;
-        *failure = VERIFY_ERROR_GENERIC;
-      }
-      /* Update type if source is from const */
-      if (src_type == kRegTypeConstLo) {
-        SetRegisterType(register_line, vsrc, check_type);
-      }
-      break;
-    case kRegTypeConstLo:
-    case kRegTypeConstHi:
-    case kRegTypeLongHi:
-    case kRegTypeDoubleHi:
-    case kRegTypeZero:
-    case kRegTypeOne:
-    case kRegTypeUnknown:
-    case kRegTypeConflict:
-      /* should never be checking for these explicitly */
-      DCHECK(false);
-      *failure = VERIFY_ERROR_GENERIC;
+      LOG(FATAL) << "Error: verifier asked to replace instruction " << *inst;
       return;
-    case kRegTypeUninit:
-    default:
-      /* make sure check_type is initialized reference */
-      if (!RegTypeIsReference(check_type)) {
-        LOG(FATAL) << "VFY: unexpected check type " << check_type;
-        *failure = VERIFY_ERROR_GENERIC;
-        break;
-      }
-      if (RegTypeIsUninitReference(check_type)) {
-        LOG(ERROR) << "VFY: uninitialized ref not expected as reg check";
-        *failure = VERIFY_ERROR_GENERIC;
-        break;
-      }
-      /* make sure src_type is initialized reference or always-NULL */
-      if (!RegTypeIsReference(src_type)) {
-        LOG(ERROR) << "VFY: register1 v" << vsrc << " type " << src_type
-                   << ", wanted ref";
-        *failure = VERIFY_ERROR_GENERIC;
-        break;
-      }
-      if (RegTypeIsUninitReference(src_type)) {
-        LOG(ERROR) << "VFY: register1 v" << vsrc << " holds uninitialized ref";
-        *failure = VERIFY_ERROR_GENERIC;
-        break;
-      }
-      /* if the register isn't Zero, make sure it's an instance of check */
-      if (src_type != kRegTypeZero) {
-        Class* src_class = RegTypeInitializedReferenceToClass(src_type);
-        Class* check_class = RegTypeInitializedReferenceToClass(check_type);
-        DCHECK(src_class != NULL);
-        DCHECK(check_class != NULL);
-
-        if (check_class->IsInterface()) {
-          /*
-           * All objects implement all interfaces as far as the verifier is
-           * concerned. The runtime has to sort it out. See coments above
-           * FindCommonSuperclass.
-           */
-        } else {
-          if (!check_class->IsAssignableFrom(src_class)) {
-            LOG(ERROR) << "VFY: " << src_class->GetDescriptor()->ToModifiedUtf8()
-                       << " is not instance of "
-                       << check_class->GetDescriptor()->ToModifiedUtf8();
-            *failure = VERIFY_ERROR_GENERIC;
-          }
-        }
-      }
-      break;
   }
+  uint16_t* insns = const_cast<uint16_t*>(code_item_->insns_);
+  // THROW_VERIFICATION_ERROR is a 2 code unit instruction. We shouldn't be rewriting a 1 code unit
+  // instruction, so assert it.
+  size_t width = inst->SizeInCodeUnits();
+  CHECK_GT(width, 1u);
+  // If the instruction is larger than 2 code units, rewrite subqeuent code unit sized chunks with
+  // NOPs
+  for (size_t i = 2; i < width; i++) {
+    insns[work_insn_idx_ + i] = Instruction::NOP;
+  }
+  // Encode the opcode, with the failure code in the high byte
+  uint16_t new_instruction = Instruction::THROW_VERIFICATION_ERROR |
+                             (failure_ << 8) |  // AA - component
+                             (ref_type << (8 + kVerifyErrorRefTypeShift));
+  insns[work_insn_idx_] = new_instruction;
+  // The 2nd code unit (higher in memory) with the reference in, comes from the instruction we
+  // rewrote, so nothing to do here.
 }
 
-void DexVerifier::SetResultRegisterType(RegisterLine* register_line,
-    const int insn_reg_count, RegType new_type) {
-  SetRegisterType(register_line, RESULT_REGISTER(insn_reg_count), new_type);
-}
-
-void DexVerifier::MarkRefsAsInitialized(RegisterLine* register_line,
-    int insn_reg_count, UninitInstanceMap* uninit_map, RegType uninit_type,
-    VerifyError* failure) {
-  RegType* insn_regs = register_line->reg_types_.get();
-  Class* klass = GetUninitInstance(uninit_map,
-      RegTypeToUninitIndex(uninit_type));
-
-  if (klass == NULL) {
-    LOG(ERROR) << "VFY: unable to find type=" << std::hex << uninit_type
-               << std::dec << " (idx=" << RegTypeToUninitIndex(uninit_type)
-               << ")";
-    *failure = VERIFY_ERROR_GENERIC;
-    return;
-  }
-
-  RegType init_type = RegTypeFromClass(klass);
-  int changed = 0;
-  for (int i = 0; i < insn_reg_count; i++) {
-    if (insn_regs[i] == uninit_type) {
-      insn_regs[i] = init_type;
-      changed++;
-    }
-  }
-  DCHECK_GT(changed, 0);
-
-  return;
-}
-
-void DexVerifier::MarkUninitRefsAsInvalid(RegisterLine* register_line,
-    int insn_reg_count, UninitInstanceMap* uninit_map, RegType uninit_type) {
-  RegType* insn_regs = register_line->reg_types_.get();
-
-  for (int i = 0; i < insn_reg_count; i++) {
-    if (insn_regs[i] == uninit_type) {
-      insn_regs[i] = kRegTypeConflict;
-      if (register_line->monitor_entries_.get() != NULL)
-        register_line->monitor_entries_[i] = 0;
-    }
-  }
-}
-
-void DexVerifier::CopyRegister1(RegisterLine* register_line, uint32_t vdst,
-    uint32_t vsrc, TypeCategory cat, VerifyError* failure) {
-  DCHECK(cat == kTypeCategory1nr || cat == kTypeCategoryRef);
-  RegType type = GetRegisterType(register_line, vsrc);
-  CheckTypeCategory(type, cat, failure);
-  if (*failure != VERIFY_ERROR_NONE) {
-    LOG(ERROR) << "VFY: copy1 v" << vdst << "<-v" << vsrc << " type=" << type
-               << " cat=" << (int) cat;
-  } else {
-    SetRegisterType(register_line, vdst, type);
-    if (cat == kTypeCategoryRef && register_line->monitor_entries_.get() != NULL) {
-      register_line->monitor_entries_[vdst] =
-          register_line->monitor_entries_[vsrc];
-    }
-  }
-}
-
-void DexVerifier::CopyRegister2(RegisterLine* register_line, uint32_t vdst,
-    uint32_t vsrc, VerifyError* failure) {
-  RegType type_l = GetRegisterType(register_line, vsrc);
-  RegType type_h = GetRegisterType(register_line, vsrc + 1);
-
-  CheckTypeCategory(type_l, kTypeCategory2, failure);
-  CheckWidePair(type_l, type_h, failure);
-  if (*failure != VERIFY_ERROR_NONE) {
-    LOG(ERROR) << "VFY: copy2 v" << vdst << "<-v" << vsrc << " type=" << type_l
-               << "/" << type_h;
-  } else {
-    SetRegisterType(register_line, vdst, type_l);
-  }
-}
-
-void DexVerifier::CopyResultRegister1(RegisterLine* register_line,
-    const int insn_reg_count, uint32_t vdst, TypeCategory cat,
-    VerifyError* failure) {
-  DCHECK_LT(vdst, static_cast<uint32_t>(insn_reg_count));
-
-  uint32_t vsrc = RESULT_REGISTER(insn_reg_count);
-  RegType type = GetRegisterType(register_line, vsrc);
-  CheckTypeCategory(type, cat, failure);
-  if (*failure != VERIFY_ERROR_NONE) {
-    LOG(ERROR) << "VFY: copyRes1 v" << vdst << "<-v" << vsrc << " cat="
-               << (int) cat << " type=" << type;
-  } else {
-    SetRegisterType(register_line, vdst, type);
-    SetRegisterType(register_line, vsrc, kRegTypeUnknown);
-  }
-}
-
-/*
- * Implement "move-result-wide". Copy the category-2 value from the result
- * register to another register, and reset the result register.
- */
-void DexVerifier::CopyResultRegister2(RegisterLine* register_line,
-    const int insn_reg_count, uint32_t vdst, VerifyError* failure) {
-  DCHECK_LT(vdst, static_cast<uint32_t>(insn_reg_count));
-
-  uint32_t vsrc = RESULT_REGISTER(insn_reg_count);
-  RegType type_l = GetRegisterType(register_line, vsrc);
-  RegType type_h = GetRegisterType(register_line, vsrc + 1);
-  CheckTypeCategory(type_l, kTypeCategory2, failure);
-  CheckWidePair(type_l, type_h, failure);
-  if (*failure != VERIFY_ERROR_NONE) {
-    LOG(ERROR) << "VFY: copyRes2 v" << vdst << "<-v" << vsrc << " type="
-               << type_l << "/" << type_h;
-  } else {
-    SetRegisterType(register_line, vdst, type_l);
-    SetRegisterType(register_line, vsrc, kRegTypeUnknown);
-    SetRegisterType(register_line, vsrc + 1, kRegTypeUnknown);
-  }
-}
-
-int DexVerifier::GetClassDepth(Class* klass) {
-  int depth = 0;
-  while (klass->GetSuperClass() != NULL) {
-    klass = klass->GetSuperClass();
-    depth++;
-  }
-  return depth;
-}
-
-Class* DexVerifier::DigForSuperclass(Class* c1, Class* c2) {
-  int depth1, depth2;
-
-  depth1 = GetClassDepth(c1);
-  depth2 = GetClassDepth(c2);
-
-  /* pull the deepest one up */
-  if (depth1 > depth2) {
-    while (depth1 > depth2) {
-      c1 = c1->GetSuperClass();
-      depth1--;
-    }
-  } else {
-    while (depth2 > depth1) {
-      c2 = c2->GetSuperClass();
-      depth2--;
-    }
-  }
-
-  /* walk up in lock-step */
-  while (c1 != c2) {
-    c1 = c1->GetSuperClass();
-    c2 = c2->GetSuperClass();
-    DCHECK(c1 != NULL);
-    DCHECK(c2 != NULL);
-  }
-
-  return c1;
-}
-
-Class* DexVerifier::FindCommonArraySuperclass(Class* c1, Class* c2) {
-  DCHECK(c1->IsArrayClass());
-  DCHECK(c2->IsArrayClass());
-  Class* e1 = c1->GetComponentType();
-  Class* e2 = c2->GetComponentType();
-  if (e1->IsPrimitive() || e2->IsPrimitive()) {
-    return c1->GetSuperClass();  // == java.lang.Object
-  }
-  Class* common_elem = FindCommonSuperclass(c1->GetComponentType(), c2->GetComponentType());
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  const ClassLoader* class_loader = c1->GetClassLoader();
-  std::string descriptor = "[" + common_elem->GetDescriptor()->ToModifiedUtf8();
-  Class* array_class = class_linker->FindClass(descriptor.c_str(), class_loader);
-  DCHECK(array_class != NULL);
-  return array_class;
-}
-
-Class* DexVerifier::FindCommonSuperclass(Class* c1, Class* c2) {
-  DCHECK(!c1->IsPrimitive()) << PrettyClass(c1);
-  DCHECK(!c2->IsPrimitive()) << PrettyClass(c2);
-
-  if (c1 == c2)
-    return c1;
-
-  if (c1->IsInterface() && c1->IsAssignableFrom(c2)) {
-    return c1;
-  }
-  if (c2->IsInterface() && c2->IsAssignableFrom(c1)) {
-    return c2;
-  }
-  if (c1->IsArrayClass() && c2->IsArrayClass()) {
-    return FindCommonArraySuperclass(c1, c2);
-  }
-
-  return DigForSuperclass(c1, c2);
-}
-
-Class* DexVerifier::ResolveClassAndCheckAccess(const DexFile* dex_file,
-    uint32_t class_idx, const Class* referrer, VerifyError* failure) {
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Class* res_class = class_linker->ResolveType(*dex_file, class_idx, referrer);
-
-  if (res_class == NULL) {
-    Thread::Current()->ClearException();
-    LOG(ERROR) << "VFY: can't find class with index 0x" << std::hex << class_idx << std::dec;
-    *failure = VERIFY_ERROR_NO_CLASS;
-    return NULL;
-  }
-
-  /* Check if access is allowed. */
-  if (!referrer->CanAccess(res_class)) {
-    LOG(ERROR) << "VFY: illegal class access: "
-               << referrer->GetDescriptor()->ToModifiedUtf8() << " -> "
-               << res_class->GetDescriptor()->ToModifiedUtf8();
-    *failure = VERIFY_ERROR_ACCESS_CLASS;
-    return NULL;
-  }
-
-  return res_class;
-}
-
-Method* DexVerifier::ResolveMethodAndCheckAccess(const DexFile* dex_file,
-    uint32_t method_idx, const Class* referrer, VerifyError* failure,
-    bool is_direct) {
-  DexCache* dex_cache = referrer->GetDexCache();
-  Method* res_method = dex_cache->GetResolvedMethod(method_idx);
-
-  if (res_method == NULL) {
-    const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx);
-    Class* klass = ResolveClassAndCheckAccess(dex_file, method_id.class_idx_, referrer, failure);
-    if (klass == NULL) {
-      DCHECK(*failure != VERIFY_ERROR_NONE);
-      return NULL;
-    }
-
-    const char* name = dex_file->dexStringById(method_id.name_idx_);
-    std::string signature(dex_file->CreateMethodDescriptor(method_id.proto_idx_, NULL));
-    if (is_direct) {
-      res_method = klass->FindDirectMethod(name, signature);
-    } else if (klass->IsInterface()) {
-      res_method = klass->FindInterfaceMethod(name, signature);
-    } else {
-      res_method = klass->FindVirtualMethod(name, signature);
-    }
-    if (res_method != NULL) {
-      dex_cache->SetResolvedMethod(method_idx, res_method);
-    } else {
-      LOG(ERROR) << "VFY: couldn't find method "
-                 << klass->GetDescriptor()->ToModifiedUtf8() << "." << name
-                 << " " << signature;
-      *failure = VERIFY_ERROR_NO_METHOD;
-      return NULL;
-    }
-  }
-
-  /* Check if access is allowed. */
-  if (!referrer->CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
-    LOG(ERROR) << "VFY: illegal method access (call " << PrettyMethod(res_method)
-               << " from " << referrer->GetDescriptor()->ToModifiedUtf8() << ")";
-    *failure = VERIFY_ERROR_ACCESS_METHOD;
-    return NULL;
-  }
-
-  return res_method;
-}
-
-Field* DexVerifier::ResolveFieldAndCheckAccess(const DexFile* dex_file,
-    uint32_t field_idx, const Class* referrer, VerifyError* failure,
-    bool is_static) {
-  DexCache* dex_cache = referrer->GetDexCache();
-  Field* res_field = dex_cache->GetResolvedField(field_idx);
-
-  if (res_field == NULL) {
-    const DexFile::FieldId& field_id = dex_file->GetFieldId(field_idx);
-    Class* klass = ResolveClassAndCheckAccess(dex_file, field_id.class_idx_, referrer, failure);
-    if (klass == NULL) {
-      DCHECK(*failure != VERIFY_ERROR_NONE) << PrettyClass(referrer);
-      return NULL;
-    }
-
-    Class* field_type = ResolveClassAndCheckAccess(dex_file, field_id.type_idx_, referrer, failure);
-    if (field_type == NULL) {
-      DCHECK(*failure != VERIFY_ERROR_NONE) << PrettyClass(referrer) << " " << PrettyClass(klass);
-      return NULL;
-    }
-
-    const char* name = dex_file->dexStringById(field_id.name_idx_);
-    if (is_static) {
-      res_field = klass->FindStaticField(name, field_type);
-    } else {
-      res_field = klass->FindInstanceField(name, field_type);
-    }
-    if (res_field != NULL) {
-      dex_cache->SetResolvedField(field_idx, res_field);
-    } else {
-      LOG(ERROR) << "VFY: couldn't find field "
-                 << klass->GetDescriptor()->ToModifiedUtf8() << "." << name;
-      *failure = VERIFY_ERROR_NO_FIELD;
-      return NULL;
-    }
-  }
-
-  /* Check if access is allowed. */
-  if (!referrer->CanAccessMember(res_field->GetDeclaringClass(), res_field->GetAccessFlags())) {
-    LOG(ERROR) << "VFY: access denied from "
-               << referrer->GetDescriptor()->ToModifiedUtf8() << " to field "
-               << PrettyField(res_field);
-    *failure = VERIFY_ERROR_ACCESS_FIELD;
-    return NULL;
-  }
-
-  return res_field;
-}
-
-DexVerifier::RegType DexVerifier::MergeTypes(RegType type1, RegType type2,
-    bool* changed) {
-  RegType result;
-
-  /* Check for trivial case so we don't have to hit memory. */
-  if (type1 == type2)
-    return type1;
-
-  /*
-   * Use the table if we can, and reject any attempts to merge something
-   * from the table with a reference type.
-   *
-   * Uninitialized references are composed of the enum ORed with an
-   * index value. The uninitialized table entry at index zero *will*
-   * show up as a simple kRegTypeUninit value. Since this cannot be
-   * merged with anything but itself, the rules do the right thing.
-   */
-  if (type1 < kRegTypeMAX) {
-    if (type2 < kRegTypeMAX) {
-      result = merge_table_[type1][type2];
-    } else {
-      /* simple + reference == conflict, usually */
-      if (type1 == kRegTypeZero)
-        result = type2;
-      else
-        result = kRegTypeConflict;
-    }
-  } else {
-    if (type2 < kRegTypeMAX) {
-      /* reference + simple == conflict, usually */
-      if (type2 == kRegTypeZero)
-        result = type1;
-      else
-        result = kRegTypeConflict;
-    } else {
-      /* merging two references */
-      if (RegTypeIsUninitReference(type1) ||
-          RegTypeIsUninitReference(type2))
-      {
-        /* can't merge uninit with anything but self */
-        result = kRegTypeConflict;
-      } else {
-        Class* klass1 = RegTypeInitializedReferenceToClass(type1);
-        Class* klass2 = RegTypeInitializedReferenceToClass(type2);
-        Class* merged_class = FindCommonSuperclass(klass1, klass2);
-        DCHECK(merged_class != NULL);
-        result = RegTypeFromClass(merged_class);
-      }
-    }
-  }
-
-  if (result != type1)
-    *changed = true;
-  return result;
-}
-
-DexVerifier::MonitorEntries DexVerifier::MergeMonitorEntries(
-    MonitorEntries ents1, MonitorEntries ents2, bool* changed) {
-  MonitorEntries result = ents1 & ents2;
-  if (result != ents1)
-    *changed = true;
-  return result;
-}
-
-bool DexVerifier::UpdateRegisters(InsnFlags* insn_flags,
-    RegisterTable* reg_table, int next_insn, const RegisterLine* work_line) {
-  const size_t insn_reg_count_plus = reg_table->insn_reg_count_plus_;
-  DCHECK(work_line != NULL);
-  const RegType* work_regs = work_line->reg_types_.get();
-
-  if (!InsnIsVisitedOrChanged(insn_flags, next_insn)) {
+bool DexVerifier::UpdateRegisters(uint32_t next_insn, const RegisterLine* merge_line) {
+  const bool merge_debug = true;
+  bool changed = true;
+  RegisterLine* target_line = reg_table_.GetLine(next_insn);
+  if (!insn_flags_[next_insn].IsVisitedOrChanged()) {
     /*
-     * We haven't processed this instruction before, and we haven't
-     * touched the registers here, so there's nothing to "merge". Copy
-     * the registers over and mark it as changed. (This is the only
-     * way a register can transition out of "unknown", so this is not
-     * just an optimization.)
+     * We haven't processed this instruction before, and we haven't touched the registers here, so
+     * there's nothing to "merge". Copy the registers over and mark it as changed. (This is the
+     * only way a register can transition out of "unknown", so this is not just an optimization.)
      */
-    CopyLineToTable(reg_table, next_insn, work_line);
-    InsnSetChanged(insn_flags, next_insn, true);
+    target_line->CopyFromLine(merge_line);
   } else {
-    /* Merge registers, set Changed only if different */
-    RegisterLine* target_line = GetRegisterLine(reg_table, next_insn);
-    RegType* target_regs = target_line->reg_types_.get();
-    MonitorEntries* work_mon_ents = work_line->monitor_entries_.get();
-    MonitorEntries* target_mon_ents = target_line->monitor_entries_.get();
-    bool changed = false;
-    unsigned int idx;
-
-    DCHECK(target_regs != NULL);
-    if (target_mon_ents != NULL) {
-      /* Monitor stacks must be identical. */
-      if (target_line->monitor_stack_top_ != work_line->monitor_stack_top_) {
-        LOG(ERROR) << "VFY: mismatched stack depth "
-                   << target_line->monitor_stack_top_ << " vs. "
-                   << work_line->monitor_stack_top_ << " at 0x"
-                   << std::hex << next_insn << std::dec;
-        return false;
-      }
-      if (memcmp(target_line->monitor_stack_.get(), work_line->monitor_stack_.get(),
-                 target_line->monitor_stack_top_ * sizeof(uint32_t)) != 0) {
-         LOG(ERROR) << "VFY: mismatched monitor stacks at 0x" << std::hex
-                    << next_insn << std::dec;
-         return false;
-      }
+    UniquePtr<RegisterLine> copy(merge_debug ? new RegisterLine(target_line->NumRegs(), this) : NULL);
+    copy->CopyFromLine(target_line);
+    changed = target_line->MergeRegisters(merge_line);
+    if (failure_ != VERIFY_ERROR_NONE) {
+      return false;
     }
-
-    for (idx = 0; idx < insn_reg_count_plus; idx++) {
-      target_regs[idx] = MergeTypes(target_regs[idx], work_regs[idx], &changed);
-
-      if (target_mon_ents != NULL) {
-        target_mon_ents[idx] = MergeMonitorEntries(target_mon_ents[idx],
-             work_mon_ents[idx], &changed);
-      }
-    }
-
     if (changed) {
-      InsnSetChanged(insn_flags, next_insn, true);
+      LogVerifyInfo() << "Merging at [" << (void*)work_insn_idx_ << "] to [" <<(void*)next_insn << "]: " << std::endl
+                      << *copy.get() << "  MERGE" << std::endl
+                      << *merge_line << "  ==" << std::endl
+                      << *target_line << std::endl;
     }
   }
-
-  return true;
-}
-
-bool DexVerifier::CanConvertTo1nr(RegType src_type, RegType check_type) {
-  static const char conv_tab[kRegType1nrEND - kRegType1nrSTART + 1]
-                            [kRegType1nrEND - kRegType1nrSTART + 1] =
-  {
-    /* chk: 0  1  Z  y  Y  h  H  c  i  b  B  s  S  C  I  F */
-    { /*0*/ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
-    { /*1*/ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
-    { /*Z*/ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
-    { /*y*/ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
-    { /*Y*/ 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1 },
-    { /*h*/ 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1 },
-    { /*H*/ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1 },
-    { /*c*/ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1 },
-    { /*i*/ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1 },
-    { /*b*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 },
-    { /*B*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0 },
-    { /*s*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 },
-    { /*S*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0 },
-    { /*C*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0 },
-    { /*I*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 },
-    { /*F*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
-  };
-
-  DCHECK(check_type >= kRegType1nrSTART);
-  DCHECK(check_type <= kRegType1nrEND);
-
-  if (src_type >= kRegType1nrSTART && src_type <= kRegType1nrEND)
-    return (bool) conv_tab[src_type - kRegType1nrSTART]
-                          [check_type - kRegType1nrSTART];
-
-  return false;
-}
-
-bool DexVerifier::CanConvertTo2(RegType src_type, RegType check_type) {
-  return ((src_type == kRegTypeConstLo || src_type == check_type) &&
-          (check_type == kRegTypeLongLo || check_type == kRegTypeDoubleLo));
-}
-
-DexVerifier::RegType DexVerifier::PrimitiveTypeToRegType(
-    Class::PrimitiveType prim_type) {
-  switch (prim_type) {
-    case Class::kPrimBoolean: return kRegTypeBoolean;
-    case Class::kPrimByte:    return kRegTypeByte;
-    case Class::kPrimShort:   return kRegTypeShort;
-    case Class::kPrimChar:    return kRegTypeChar;
-    case Class::kPrimInt:     return kRegTypeInteger;
-    case Class::kPrimLong:    return kRegTypeLongLo;
-    case Class::kPrimFloat:   return kRegTypeFloat;
-    case Class::kPrimDouble:  return kRegTypeDoubleLo;
-    case Class::kPrimVoid:
-    default: {
-      return kRegTypeUnknown;
-    }
-  }
-}
-
-DexVerifier::RegType DexVerifier::ConstTypeToRegType(RegType const_type) {
-  switch (const_type) {
-    case kRegTypeConstPosByte: return kRegTypePosByte;
-    case kRegTypeConstByte: return kRegTypeByte;
-    case kRegTypeConstPosShort: return kRegTypePosShort;
-    case kRegTypeConstShort: return kRegTypeShort;
-    case kRegTypeConstChar: return kRegTypeChar;
-    case kRegTypeConstInteger: return kRegTypeInteger;
-    default: {
-      return const_type;
-    }
-  }
-}
-
-char DexVerifier::DetermineCat1Const(int32_t value) {
-  if (value < -32768)
-    return kRegTypeConstInteger;
-  else if (value < -128)
-    return kRegTypeConstShort;
-  else if (value < 0)
-    return kRegTypeConstByte;
-  else if (value == 0)
-    return kRegTypeZero;
-  else if (value == 1)
-    return kRegTypeOne;
-  else if (value < 128)
-    return kRegTypeConstPosByte;
-  else if (value < 32768)
-    return kRegTypeConstPosShort;
-  else if (value < 65536)
-    return kRegTypeConstChar;
-  else
-    return kRegTypeConstInteger;
-}
-
-void DexVerifier::CheckFinalFieldAccess(const Method* method,
-    const Field* field, VerifyError* failure) {
-  DCHECK(field != NULL);
-  if (!field->IsFinal()) {
-    return;
-  }
-
-  /* make sure we're in the same class */
-  if (method->GetDeclaringClass() != field->GetDeclaringClass()) {
-    LOG(ERROR) << "VFY: can't modify final field " << PrettyField(field);
-    *failure = VERIFY_ERROR_ACCESS_FIELD;
-    return;
-  }
-}
-
-void DexVerifier::CheckArrayIndexType(const Method* method, RegType reg_type,
-    VerifyError* failure) {
-  if (*failure == VERIFY_ERROR_NONE) {
-    /*
-     * The 1nr types are interchangeable at this level. We could
-     * do something special if we can definitively identify it as a
-     * float, but there's no real value in doing so.
-     */
-    CheckTypeCategory(reg_type, kTypeCategory1nr, failure);
-    if (*failure != VERIFY_ERROR_NONE) {
-      LOG(ERROR) << "Invalid reg type for array index (" << reg_type << ")";
-    }
-  }
-}
-
-bool DexVerifier::CheckConstructorReturn(const Method* method,
-    const RegisterLine* register_line, const int insn_reg_count) {
-  const RegType* insn_regs = register_line->reg_types_.get();
-
-  if (!IsInitMethod(method))
-    return true;
-
-  RegType uninit_this = RegTypeFromUninitIndex(kUninitThisArgSlot);
-
-  for (int i = 0; i < insn_reg_count; i++) {
-    if (insn_regs[i] == uninit_this) {
-      LOG(ERROR) << "VFY: <init> returning without calling superclass init";
-      return false;
-    }
+  if (changed) {
+    insn_flags_[next_insn].SetChanged();
   }
   return true;
 }
 
-bool DexVerifier::CheckMoveException(const uint16_t* insns, int insn_idx) {
-  if ((insns[insn_idx] & 0xff) == Instruction::MOVE_EXCEPTION) {
-    LOG(ERROR) << "VFY: invalid use of move-exception";
-    return false;
-  }
-  return true;
-}
-
-void DexVerifier::CheckTypeCategory(RegType type, TypeCategory cat,
-    VerifyError* failure) {
-  switch (cat) {
-    case kTypeCategory1nr:
-      switch (type) {
-        case kRegTypeZero:
-        case kRegTypeOne:
-        case kRegTypeBoolean:
-        case kRegTypeConstPosByte:
-        case kRegTypeConstByte:
-        case kRegTypeConstPosShort:
-        case kRegTypeConstShort:
-        case kRegTypeConstChar:
-        case kRegTypeConstInteger:
-        case kRegTypePosByte:
-        case kRegTypeByte:
-        case kRegTypePosShort:
-        case kRegTypeShort:
-        case kRegTypeChar:
-        case kRegTypeInteger:
-        case kRegTypeFloat:
-          break;
-        default:
-          *failure = VERIFY_ERROR_GENERIC;
-          break;
-      }
-      break;
-    case kTypeCategory2:
-      switch (type) {
-        case kRegTypeConstLo:
-        case kRegTypeLongLo:
-        case kRegTypeDoubleLo:
-          break;
-        default:
-          *failure = VERIFY_ERROR_GENERIC;
-         break;
-      }
-      break;
-    case kTypeCategoryRef:
-      if (type != kRegTypeZero && !RegTypeIsReference(type))
-        *failure = VERIFY_ERROR_GENERIC;
-      break;
-    default:
-      DCHECK(false);
-      *failure = VERIFY_ERROR_GENERIC;
-      break;
-  }
-}
-
-void DexVerifier::CheckWidePair(RegType type_l, RegType type_h,
-    VerifyError* failure) {
-  if ((type_h != type_l + 1))
-    *failure = VERIFY_ERROR_GENERIC;
-}
-
-void DexVerifier::CheckUnop(RegisterLine* register_line,
-    Instruction::DecodedInstruction* dec_insn, RegType dst_type,
-    RegType src_type, VerifyError* failure) {
-  VerifyRegisterType(register_line, dec_insn->vB_, src_type, failure);
-  SetRegisterType(register_line, dec_insn->vA_, dst_type);
-}
-
-bool DexVerifier::UpcastBooleanOp(RegisterLine* register_line, uint32_t reg1,
-    uint32_t reg2) {
-  RegType type1, type2;
-
-  type1 = GetRegisterType(register_line, reg1);
-  type2 = GetRegisterType(register_line, reg2);
-
-  if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero || type1 == kRegTypeOne) &&
-      (type2 == kRegTypeBoolean || type2 == kRegTypeZero || type2 == kRegTypeOne)) {
-    return true;
-  }
-  return false;
-}
-
-void DexVerifier::CheckLitop(RegisterLine* register_line,
-    Instruction::DecodedInstruction* dec_insn, RegType dst_type,
-    RegType src_type, bool check_boolean_op, VerifyError* failure) {
-  VerifyRegisterType(register_line, dec_insn->vB_, src_type, failure);
-
-  if ((*failure == VERIFY_ERROR_NONE) && check_boolean_op) {
-    DCHECK(dst_type == kRegTypeInteger);
-
-    /* check vB with the call, then check the constant manually */
-    if (UpcastBooleanOp(register_line, dec_insn->vB_, dec_insn->vB_)
-        && (dec_insn->vC_ == 0 || dec_insn->vC_ == 1)) {
-      dst_type = kRegTypeBoolean;
+void DexVerifier::ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits,
+                                    size_t* log2_max_gc_pc) {
+  size_t local_gc_points = 0;
+  size_t max_insn = 0;
+  size_t max_ref_reg = -1;
+  for (size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
+    if (insn_flags_[i].IsGcPoint()) {
+      local_gc_points++;
+      max_insn = i;
+      RegisterLine* line = reg_table_.GetLine(i);
+      max_ref_reg = line->GetMaxReferenceReg(max_ref_reg);
     }
   }
-
-  SetRegisterType(register_line, dec_insn->vA_, dst_type);
+  *gc_points = local_gc_points;
+  *ref_bitmap_bits = max_ref_reg + 1;  // if max register is 0 we need 1 bit to encode (ie +1)
+  size_t i = 0;
+  while ((1U << i) < max_insn) {
+    i++;
+  }
+  *log2_max_gc_pc = i;
 }
 
-void DexVerifier::CheckBinop(RegisterLine* register_line,
-    Instruction::DecodedInstruction* dec_insn, RegType dst_type,
-    RegType src_type1, RegType src_type2, bool check_boolean_op,
-    VerifyError* failure) {
-  VerifyRegisterType(register_line, dec_insn->vB_, src_type1, failure);
-  VerifyRegisterType(register_line, dec_insn->vC_, src_type2, failure);
-
-  if ((*failure == VERIFY_ERROR_NONE) && check_boolean_op) {
-    DCHECK(dst_type == kRegTypeInteger);
-    if (UpcastBooleanOp(register_line, dec_insn->vB_, dec_insn->vC_))
-      dst_type = kRegTypeBoolean;
-  }
-
-  SetRegisterType(register_line, dec_insn->vA_, dst_type);
-}
-
-void DexVerifier::CheckBinop2addr(RegisterLine* register_line,
-    Instruction::DecodedInstruction* dec_insn, RegType dst_type,
-    RegType src_type1, RegType src_type2, bool check_boolean_op,
-    VerifyError* failure) {
-  VerifyRegisterType(register_line, dec_insn->vA_, src_type1, failure);
-  VerifyRegisterType(register_line, dec_insn->vB_, src_type2, failure);
-
-  if ((*failure == VERIFY_ERROR_NONE) && check_boolean_op) {
-    DCHECK(dst_type == kRegTypeInteger);
-    if (UpcastBooleanOp(register_line, dec_insn->vA_, dec_insn->vB_))
-      dst_type = kRegTypeBoolean;
-  }
-
-  SetRegisterType(register_line, dec_insn->vA_, dst_type);
-}
-
-DexVerifier::RegType DexVerifier::AdjustForRightShift(
-    RegisterLine* register_line, int reg, unsigned int shift_count,
-    bool is_unsigned_shift) {
-  RegType src_type = GetRegisterType(register_line, reg);
-  RegType new_type;
-
-  /* convert const derived types to their actual types */
-  src_type = ConstTypeToRegType(src_type);
-
-  /* no-op */
-  if (shift_count == 0)
-    return src_type;
-
-  /* safe defaults */
-  if (is_unsigned_shift)
-    new_type = kRegTypeInteger;
-  else
-    new_type = src_type;
-
-  if (shift_count >= 32) {
-    LOG(ERROR) << "Got unexpectedly large shift count " << shift_count;
-    /* fail? */
-    return new_type;
-  }
-
-  switch (src_type) {
-    case kRegTypeInteger:               /* 32-bit signed value */
-      if (is_unsigned_shift) {
-        if (shift_count > 24)
-          new_type = kRegTypePosByte;
-        else if (shift_count >= 16)
-          new_type = kRegTypeChar;
-      } else {
-        if (shift_count >= 24)
-          new_type = kRegTypeByte;
-        else if (shift_count >= 16)
-          new_type = kRegTypeShort;
-      }
-      break;
-    case kRegTypeShort:                 /* 16-bit signed value */
-      if (is_unsigned_shift) {
-        /* default (kRegTypeInteger) is correct */
-      } else {
-        if (shift_count >= 8)
-          new_type = kRegTypeByte;
-      }
-      break;
-    case kRegTypePosShort:              /* 15-bit unsigned value */
-      if (shift_count >= 8)
-        new_type = kRegTypePosByte;
-      break;
-    case kRegTypeChar:                  /* 16-bit unsigned value */
-      if (shift_count > 8)
-        new_type = kRegTypePosByte;
-      break;
-    case kRegTypeByte:                  /* 8-bit signed value */
-      /* defaults (u=kRegTypeInteger / s=src_type) are correct */
-      break;
-    case kRegTypePosByte:               /* 7-bit unsigned value */
-      /* always use new_type=src_type */
-      new_type = src_type;
-      break;
-    case kRegTypeZero:                  /* 1-bit unsigned value */
-    case kRegTypeOne:
-    case kRegTypeBoolean:
-      /* unnecessary? */
-      new_type = kRegTypeZero;
-      break;
-    default:
-      /* long, double, references; shouldn't be here! */
-      DCHECK(false);
-      break;
-  }
-
-  return new_type;
-}
-
-void DexVerifier::VerifyFilledNewArrayRegs(const Method* method,
-    RegisterLine* register_line,
-    const Instruction::DecodedInstruction* dec_insn, Class* res_class,
-    bool is_range, VerifyError* failure) {
-  uint32_t arg_count = dec_insn->vA_;
-  RegType expected_type;
-  Class::PrimitiveType elem_type;
-  unsigned int ui;
-
-  DCHECK(res_class->IsArrayClass()) << PrettyClass(res_class);
-  elem_type = res_class->GetComponentType()->GetPrimitiveType();
-  if (elem_type == Class::kPrimNot) {
-    expected_type = RegTypeFromClass(res_class->GetComponentType());
-  } else {
-    expected_type = PrimitiveTypeToRegType(elem_type);
-  }
-
-  /*
-   * Verify each register. If "arg_count" is bad, VerifyRegisterType()
-   * will run off the end of the list and fail. It's legal, if silly,
-   * for arg_count to be zero.
-   */
-  for (ui = 0; ui < arg_count; ui++) {
-    uint32_t get_reg;
-
-    if (is_range)
-      get_reg = dec_insn->vC_ + ui;
-    else
-      get_reg = dec_insn->arg_[ui];
-
-    VerifyRegisterType(register_line, get_reg, expected_type, failure);
-    if (*failure != VERIFY_ERROR_NONE) {
-      LOG(ERROR) << "VFY: filled-new-array arg " << ui << "(" << get_reg
-                 << ") not valid";
-      return;
-    }
-  }
-}
-
-bool DexVerifier::IsCorrectInvokeKind(MethodType method_type,
-    Method* res_method) {
-  switch (method_type) {
-    case METHOD_DIRECT:
-      return res_method->IsDirect();
-    case METHOD_STATIC:
-      return res_method->IsStatic();
-    case METHOD_VIRTUAL:
-    case METHOD_INTERFACE:
-      return !res_method->IsDirect();
-    default:
-      return false;
-  }
-}
-
-Method* DexVerifier::VerifyInvocationArgs(VerifierData* vdata,
-    RegisterLine* register_line, const int insn_reg_count,
-    const Instruction::DecodedInstruction* dec_insn, MethodType method_type,
-    bool is_range, bool is_super, VerifyError* failure) {
-  Method* method = vdata->method_;
-  const DexFile* dex_file = vdata->dex_file_;
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  UninitInstanceMap* uninit_map = vdata->uninit_map_.get();
-
-  Method* res_method;
-  std::string sig;
-  size_t sig_offset;
-  int expected_args;
-  int actual_args;
-
-  /*
-   * Resolve the method. This could be an abstract or concrete method
-   * depending on what sort of call we're making.
-   */
-  res_method = ResolveMethodAndCheckAccess(dex_file, dec_insn->vB_, method->GetDeclaringClass(),
-      failure, (method_type == METHOD_DIRECT || method_type == METHOD_STATIC));
-
-  if (res_method == NULL) {
-    const DexFile::MethodId& method_id = dex_file->GetMethodId(dec_insn->vB_);
-    const char* method_name = dex_file->GetMethodName(method_id);
-    std::string method_signature = dex_file->GetMethodSignature(method_id);
-    const char* class_descriptor = dex_file->GetMethodClassDescriptor(method_id);
-
-    LOG(ERROR) << "VFY: unable to resolve method " << dec_insn->vB_ << ": "
-               << class_descriptor << "." << method_name << " " << method_signature;
+ByteArray* DexVerifier::GenerateGcMap() {
+  size_t num_entries, ref_bitmap_bits, pc_bits;
+  ComputeGcMapSizes(&num_entries, &ref_bitmap_bits, &pc_bits);
+  // There's a single byte to encode the size of each bitmap
+  if (ref_bitmap_bits >= (8 /* bits per byte */ * 256 /* max unsigned byte + 1 */ )) {
+    // TODO: either a better GC map format or per method failures
+    Fail(VERIFY_ERROR_GENERIC) << "Cannot encode GC map for method with "
+       << ref_bitmap_bits << " registers";
     return NULL;
   }
-
-  /*
-   * Make sure calls to "<init>" are "direct". There are additional restrictions
-   * but we don't enfore them here.
-   */
-  if (res_method->GetName()->Equals("<init>") && method_type != METHOD_DIRECT) {
-    LOG(ERROR) << "VFY: invalid call to " << PrettyMethod(res_method);
-    goto bad_sig;
-  }
-
-  /*
-   * See if the method type implied by the invoke instruction matches the
-   * access flags for the target method.
-   */
-  if (!IsCorrectInvokeKind(method_type, res_method)) {
-    LOG(ERROR) << "VFY: invoke type does not match method type of "
-               << PrettyMethod(res_method);
-    *failure = VERIFY_ERROR_GENERIC;
+  size_t ref_bitmap_bytes = (ref_bitmap_bits + 7) / 8;
+  // There are 2 bytes to encode the number of entries
+  if (num_entries >= 65536) {
+    // TODO: either a better GC map format or per method failures
+    Fail(VERIFY_ERROR_GENERIC) << "Cannot encode GC map for method with "
+       << num_entries << " entries";
     return NULL;
   }
-
-  /*
-   * If we're using invoke-super(method), make sure that the executing
-   * method's class' superclass has a vtable entry for the target method.
-   */
-  if (is_super) {
-    DCHECK(method_type == METHOD_VIRTUAL);
-    Class* super = method->GetDeclaringClass()->GetSuperClass();
-    if (super == NULL || res_method->GetMethodIndex() > super->GetVTable()->GetLength()) {
-      if (super == NULL) {
-        LOG(ERROR) << "VFY: invalid invoke-super from " << PrettyMethod(method)
-                   << " to super -." << res_method->GetName()->ToModifiedUtf8()
-                   << " " << res_method->GetSignature()->ToModifiedUtf8();
-      } else {
-        LOG(ERROR) << "VFY: invalid invoke-super from " << PrettyMethod(method)
-                   << " to super " << super->GetDescriptor()->ToModifiedUtf8()
-                   << "." << res_method->GetName()->ToModifiedUtf8()
-                   << " " << res_method->GetSignature()->ToModifiedUtf8();
-      }
-      *failure = VERIFY_ERROR_NO_METHOD;
-      return NULL;
-    }
-  }
-
-  /*
-   * We use vAA as our expected arg count, rather than res_method->insSize,
-   * because we need to match the call to the signature. Also, we might
-   * might be calling through an abstract method definition (which doesn't
-   * have register count values).
-   */
-  expected_args = dec_insn->vA_;
-  actual_args = 0;
-
-  /* caught by static verifier */
-  DCHECK(is_range || expected_args <= 5);
-
-  if (expected_args > code_item->outs_size_) {
-    LOG(ERROR) << "VFY: invalid arg count (" << expected_args
-               << ") exceeds outsSize (" << code_item->outs_size_ << ")";
-    *failure = VERIFY_ERROR_GENERIC;
-    return NULL;
-  }
-
-  sig = res_method->GetSignature()->ToModifiedUtf8();
-  if (sig[0] != '(') {
-    LOG(ERROR) << "VFY: descriptor doesn't start with '(': " << sig;
-    goto bad_sig;
-  }
-
-  /*
-   * Check the "this" argument, which must be an instance of the class
-   * that declared the method. For an interface class, we don't do the
-   * full interface merge, so we can't do a rigorous check here (which
-   * is okay since we have to do it at runtime).
-   */
-  if (!res_method->IsStatic()) {
-    Class* actual_this_ref;
-    RegType actual_arg_type;
-
-    actual_arg_type = GetInvocationThis(register_line, dec_insn, failure);
-    if (*failure != VERIFY_ERROR_NONE)
-      return NULL;
-
-    if (RegTypeIsUninitReference(actual_arg_type) &&
-        !res_method->GetName()->Equals("<init>")) {
-      LOG(ERROR) << "VFY: 'this' arg must be initialized";
-      *failure = VERIFY_ERROR_GENERIC;
-      return NULL;
-    }
-    if (method_type != METHOD_INTERFACE && actual_arg_type != kRegTypeZero) {
-      actual_this_ref = RegTypeReferenceToClass(actual_arg_type, uninit_map);
-      if (!res_method->GetDeclaringClass()->IsAssignableFrom(actual_this_ref)) {
-        LOG(ERROR) << "VFY: 'this' arg '"
-                   << actual_this_ref->GetDescriptor()->ToModifiedUtf8()
-                   << "' not instance of '"
-                   << res_method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
-                   << "'";
-        *failure = VERIFY_ERROR_GENERIC;
-        return NULL;
-      }
-    }
-    actual_args++;
-  }
-
-  /*
-   * Process the target method's signature. This signature may or may not
-   * have been verified, so we can't assume it's properly formed.
-   */
-  for (sig_offset = 1; sig_offset < sig.size(); sig_offset++) {
-    if (sig[sig_offset] == ')')
-      break;
-
-    if (actual_args >= expected_args) {
-      LOG(ERROR) << "VFY: expected " << expected_args << " args, found more ("
-                 << sig.substr(sig_offset) << ")";
-      goto bad_sig;
-    }
-
-    uint32_t get_reg;
-    if (is_range)
-      get_reg = dec_insn->vC_ + actual_args;
-    else
-      get_reg = dec_insn->arg_[actual_args];
-
-    switch (sig[sig_offset]) {
-      case 'L':
-        {
-          Class* klass = LookupSignatureClass(method, sig.substr(sig_offset),
-              failure);
-          if (*failure != VERIFY_ERROR_NONE)
-            goto bad_sig;
-          VerifyRegisterType(register_line, get_reg, RegTypeFromClass(klass),
-              failure);
-          if (*failure != VERIFY_ERROR_NONE) {
-            LOG(ERROR) << "VFY: bad arg " << actual_args << " (into "
-                       << klass->GetDescriptor()->ToModifiedUtf8() << ")";
-            goto bad_sig;
-          }
-          sig_offset += sig.substr(sig_offset).find(';');
-        }
-        actual_args++;
-        break;
-      case '[':
-        {
-          Class* klass = LookupSignatureArrayClass(method,
-              sig.substr(sig_offset), failure);
-          if (*failure != VERIFY_ERROR_NONE)
-            goto bad_sig;
-          VerifyRegisterType(register_line, get_reg, RegTypeFromClass(klass),
-              failure);
-          if (*failure != VERIFY_ERROR_NONE) {
-            LOG(ERROR) << "VFY: bad arg " << actual_args << " (into "
-                       << klass->GetDescriptor()->ToModifiedUtf8() << ")";
-            goto bad_sig;
-          }
-          while (sig[sig_offset] == '[')
-            sig_offset++;
-          if (sig[sig_offset] == 'L')
-            sig_offset += sig.substr(sig_offset).find(';');
-        }
-        actual_args++;
-        break;
-      case 'Z':
-        VerifyRegisterType(register_line, get_reg, kRegTypeBoolean, failure);
-        actual_args++;
-        break;
-      case 'C':
-        VerifyRegisterType(register_line, get_reg, kRegTypeChar, failure);
-        actual_args++;
-        break;
-      case 'B':
-        VerifyRegisterType(register_line, get_reg, kRegTypeByte, failure);
-        actual_args++;
-        break;
-      case 'I':
-        VerifyRegisterType(register_line, get_reg, kRegTypeInteger, failure);
-        actual_args++;
-        break;
-      case 'S':
-        VerifyRegisterType(register_line, get_reg, kRegTypeShort, failure);
-        actual_args++;
-        break;
-      case 'F':
-        VerifyRegisterType(register_line, get_reg, kRegTypeFloat, failure);
-        actual_args++;
-        break;
-      case 'D':
-        VerifyRegisterType(register_line, get_reg, kRegTypeDoubleLo, failure);
-        actual_args += 2;
-        break;
-      case 'J':
-        VerifyRegisterType(register_line, get_reg, kRegTypeLongLo, failure);
-        actual_args += 2;
-        break;
-      default:
-        LOG(ERROR) << "VFY: invocation target: bad signature type char '"
-                   << sig << "'";
-        goto bad_sig;
-    }
-  }
-  if (sig[sig_offset] != ')') {
-    LOG(ERROR) << "VFY: invocation target: bad signature '"
-               << res_method->GetSignature()->ToModifiedUtf8() << "'";
-    goto bad_sig;
-  }
-
-  if (actual_args != expected_args) {
-    LOG(ERROR) << "VFY: expected " << expected_args << " args, found "
-               << actual_args;
-    goto bad_sig;
-  }
-
-  return res_method;
-
-bad_sig:
-  LOG(ERROR) << "VFY:  rejecting call to " << PrettyMethod(res_method);
-  if (*failure == VERIFY_ERROR_NONE)
-    *failure = VERIFY_ERROR_GENERIC;
-  return NULL;
-}
-
-DexVerifier::RegisterMap* DexVerifier::GenerateRegisterMapV(VerifierData* vdata)
-{
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  int i, bytes_for_addr, gc_point_count;
-
-  if (code_item->registers_size_ >= 2048) {
-    LOG(ERROR) << "ERROR: register map can't handle "
-               << code_item->registers_size_ << " registers";
-    return NULL;
-  }
-  uint8_t reg_width = (code_item->registers_size_ + 7) / 8;
-
-  /*
-   * Decide if we need 8 or 16 bits to hold the address. Strictly speaking
-   * we only need 16 bits if we actually encode an address >= 256 -- if
-   * the method has a section at the end without GC points (e.g. array
-   * data) we don't need to count it. The situation is unusual, and
-   * detecting it requires scanning the entire method, so we don't bother.
-   */
+  size_t pc_bytes;
   RegisterMapFormat format;
-  if (code_item->insns_size_ < 256) {
+  if (pc_bits < 8) {
     format = kRegMapFormatCompact8;
-    bytes_for_addr = 1;
-  } else {
+    pc_bytes = 1;
+  } else if (pc_bits < 16) {
     format = kRegMapFormatCompact16;
-    bytes_for_addr = 2;
-  }
-
-  /*
-   * Count up the number of GC point instructions.
-   *
-   * NOTE: this does not automatically include the first instruction,
-   * since we don't count method entry as a GC point.
-   */
-  gc_point_count = 0;
-  for (i = 0; i < (int) code_item->insns_size_; i++) {
-    if (InsnIsGcPoint(vdata->insn_flags_.get(), i))
-      gc_point_count++;
-  }
-  if (gc_point_count >= 65536) {
-    /* We could handle this, but in practice we don't get near this. */
-    LOG(ERROR) << "ERROR: register map can't handle " << gc_point_count
-               << " gc points in one method";
-    return NULL;
-  }
-
-  /* Calculate size of buffer to hold the map data. */
-  uint32_t data_size = gc_point_count * (bytes_for_addr + reg_width);
-
-  RegisterMap* map = new RegisterMap(format, reg_width, gc_point_count,
-      data_size);
-
-  /* Populate it. */
-  uint8_t* map_data = map->data_;
-  for (i = 0; i < (int) vdata->code_item_->insns_size_; i++) {
-    if (InsnIsGcPoint(vdata->insn_flags_.get(), i)) {
-      DCHECK(vdata->register_lines_[i].reg_types_.get() != NULL);
-      if (format == kRegMapFormatCompact8) {
-        *map_data++ = i;
-      } else /*kRegMapFormatCompact16*/ {
-        *map_data++ = i & 0xff;
-        *map_data++ = i >> 8;
-      }
-      OutputTypeVector(vdata->register_lines_[i].reg_types_.get(),
-          code_item->registers_size_, map_data);
-      map_data += reg_width;
-    }
-  }
-
-  DCHECK_EQ((uint32_t) map_data - (uint32_t) map->data_, data_size);
-
-  // TODO: Remove this check when it's really running...
-#if 1
-  if (!VerifyMap(vdata, map)) {
-    LOG(ERROR) << "Map failed to verify";
-    return NULL;
-  }
-#endif
-
-  /* Try to compress the map. */
-#if 0
-  RegisterMap* compress_map = CompressMapDifferential(map);
-  if (compress_map != NULL) {
-    // TODO: Remove this check when it's really running...
-#if 1
-    /*
-     * Expand the compressed map we just created, and compare it
-     * to the original. Abort the VM if it doesn't match up.
-     */
-    UniquePtr<RegisterMap> uncompressed_map(UncompressMapDifferential(compress_map));
-    if (uncompressed_map.get() == NULL) {
-      LOG(ERROR) << "Map failed to uncompress - " << PrettyMethod(vdata->method_);
-      delete map;
-      delete compress_map;
-      /* bad - compression is broken or we're out of memory */
-      return NULL;
-    } else {
-      if (!CompareMaps(map, uncompressed_map.get())) {
-        LOG(ERROR) << "Map comparison failed - " << PrettyMethod(vdata->method_);
-        delete map;
-        delete compress_map;
-        /* bad - compression is broken */
-        return NULL;
-      }
-    }
-#endif
-    delete map;
-    map = compress_map;
-  }
-#endif
-  return map;
-}
-
-DexVerifier::RegisterMap* DexVerifier::GetExpandedRegisterMapHelper(
-    Method* method, RegisterMap* map) {
-  RegisterMap* new_map;
-
-  if (map == NULL)
-    return NULL;
-
-  /* TODO: sanity check to ensure this isn't called w/o external locking */
-
-  uint8_t format = map->header_->format_;
-  switch (format) {
-    case kRegMapFormatCompact8:
-    case kRegMapFormatCompact16:
-      /* already expanded */
-      return map;
-    case kRegMapFormatDifferential:
-      new_map = UncompressMapDifferential(map);
-      break;
-    default:
-      LOG(ERROR) << "Unknown format " << format
-                 << " in dvmGetExpandedRegisterMap";
-      return NULL;
-  }
-
-  if (new_map == NULL) {
-    LOG(ERROR) << "Map failed to uncompress (fmt=" << format << ") "
-               << PrettyMethod(method);
-    return NULL;
-  }
-
-  /* Update method, and free compressed map if it was sitting on the heap. */
-  //SirtRef<ByteArray> header(ByteArray::Alloc(sizeof(RegisterMapHeader)));
-  //if (header.get() == NULL) {
-  //  return NULL;
-  //}
-  //SirtRef<ByteArray> data(ByteArray::Alloc(ComputeRegisterMapSize(map)));
-  //if (data.get() == NULL) {
-  //  return NULL;
-  //}
-
-  //memcpy(header->GetData(), map->header_, sizeof(RegisterMapHeader));
-  //memcpy(data->GetData(), map->data_, ComputeRegisterMapSize(map));
-
-  //method->SetRegisterMapHeader(header);
-  //method->SetRegisterMapData(data);
-
-  delete map;
-  return new_map;
-}
-
-const uint8_t* DexVerifier::RegisterMapGetLine(const RegisterMap* map, int addr) {
-  int addr_width, line_width;
-  uint8_t format = map->header_->format_;
-  uint16_t num_entries = map->header_->num_entries_;
-
-  DCHECK_GT(num_entries, 0);
-
-  switch (format) {
-    case kRegMapFormatNone:
-      return NULL;
-    case kRegMapFormatCompact8:
-      addr_width = 1;
-      break;
-    case kRegMapFormatCompact16:
-      addr_width = 2;
-      break;
-    default:
-      LOG(ERROR) << "Unknown format " << format;
-      return NULL;
-  }
-
-  line_width = addr_width + map->header_->reg_width_;
-
-  /*
-   * Find the appropriate entry. Many maps are very small, some are very large.
-   */
-  static const int kSearchThreshold = 8;
-  const uint8_t* data = NULL;
-  int line_addr;
-
-  if (num_entries < kSearchThreshold) {
-    int i;
-    data = map->data_;
-    for (i = num_entries; i > 0; i--) {
-      line_addr = data[0];
-      if (addr_width > 1)
-        line_addr |= data[1] << 8;
-      if (line_addr == addr)
-        return data + addr_width;
-
-      data += line_width;
-    }
-    DCHECK_EQ(data, map->data_ + line_width * num_entries);
+    pc_bytes = 2;
   } else {
-    int hi, lo, mid;
+    // TODO: either a better GC map format or per method failures
+    Fail(VERIFY_ERROR_GENERIC) << "Cannot encode GC map for method with "
+       << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2)";
+    return NULL;
+  }
+  size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries ) + 4;
+  ByteArray* table = ByteArray::Alloc(table_size);
+  if (table == NULL) {
+    Fail(VERIFY_ERROR_GENERIC) << "Failed to encode GC map (size=" << table_size << ")";
+    return NULL;
+  }
+  // Write table header
+  table->Set(0, format);
+  table->Set(1, ref_bitmap_bytes);
+  table->Set(2, num_entries & 0xFF);
+  table->Set(3, (num_entries >> 8) & 0xFF);
+  // Write table data
+  size_t offset = 4;
+  for (size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
+    if (insn_flags_[i].IsGcPoint()) {
+      table->Set(offset, i & 0xFF);
+      offset++;
+      if (pc_bytes == 2) {
+        table->Set(offset, (i >> 8) & 0xFF);
+        offset++;
+      }
+      RegisterLine* line = reg_table_.GetLine(i);
+      line->WriteReferenceBitMap(table->GetData() + offset, ref_bitmap_bytes);
+      offset += ref_bitmap_bytes;
+    }
+  }
+  DCHECK(offset == table_size);
+  return table;
+}
 
-    lo = 0;
-    hi = num_entries -1;
+void DexVerifier::VerifyGcMap() {
+  // Check that for every GC point there is a map entry, there aren't entries for non-GC points,
+  // that the table data is well formed and all references are marked (or not) in the bitmap
+  PcToReferenceMap map(method_);
+  size_t map_index = 0;
+  for(size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
+    const uint8_t* reg_bitmap = map.FindBitMap(i, false);
+    if (insn_flags_[i].IsGcPoint()) {
+      CHECK_LT(map_index, map.NumEntries());
+      CHECK_EQ(map.GetPC(map_index), i);
+      CHECK_EQ(map.GetBitMap(map_index), reg_bitmap);
+      map_index++;
+      RegisterLine* line = reg_table_.GetLine(i);
+      for(size_t j = 0; j < code_item_->registers_size_; j++) {
+        if (line->GetRegisterType(j).IsReference()) {
+          CHECK_LT(j / 8, map.RegWidth());
+          CHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1);
+        } else if ((j / 8) < map.RegWidth()) {
+          CHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 0);
+        } else {
+          // If a register doesn't contain a reference then the bitmap may be shorter than the line
+        }
+      }
+    } else {
+      CHECK(reg_bitmap == NULL);
+    }
+  }
+}
 
+Class* DexVerifier::JavaLangThrowable() {
+  if (java_lang_throwable_ == NULL) {
+    java_lang_throwable_ =
+        Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/Throwable;");
+   DCHECK(java_lang_throwable_ != NULL);
+  }
+  return java_lang_throwable_;
+}
+
+const uint8_t* PcToReferenceMap::FindBitMap(uint16_t dex_pc, bool error_if_not_present) const {
+  size_t num_entries = NumEntries();
+  // Do linear or binary search?
+  static const size_t kSearchThreshold = 8;
+  if (num_entries < kSearchThreshold) {
+    for (size_t i = 0; i < num_entries; i++)  {
+      if (GetPC(i) == dex_pc) {
+        return GetBitMap(i);
+      }
+    }
+  } else {
+    int lo = 0;
+    int hi = num_entries -1;
     while (hi >= lo) {
-      mid = (hi + lo) / 2;
-      data = map->data_ + line_width * mid;
-
-      line_addr = data[0];
-      if (addr_width > 1)
-        line_addr |= data[1] << 8;
-
-      if (addr > line_addr) {
+      int mid = (hi + lo) / 2;
+      int mid_pc = GetPC(mid);
+      if (dex_pc > mid_pc) {
         lo = mid + 1;
-      } else if (addr < line_addr) {
+      } else if (dex_pc < mid_pc) {
         hi = mid - 1;
       } else {
-        return data + addr_width;
+        return GetBitMap(mid);
       }
     }
   }
-
+  if (error_if_not_present) {
+    LOG(ERROR) << "Didn't find reference bit map for dex_pc " << dex_pc;
+  }
   return NULL;
 }
 
-void DexVerifier::OutputTypeVector(const RegType* regs, int insn_reg_count,
-    uint8_t* data) {
-  uint8_t val = 0;
-  int i;
-
-  for (i = 0; i < insn_reg_count; i++) {
-    RegType type = *regs++;
-    val >>= 1;
-    if (IsReferenceType(type))
-      val |= 0x80;        /* set hi bit */
-
-    if ((i & 0x07) == 7)
-      *data++ = val;
-  }
-  if ((i & 0x07) != 0) {
-    /* Flush bits from last byte. */
-    val >>= 8 - (i & 0x07);
-    *data++ = val;
-  }
-}
-
-bool DexVerifier::VerifyMap(VerifierData* vdata, const RegisterMap* map) {
-  const uint8_t* raw_map = map->data_;
-  uint8_t format = map->header_->format_;
-  const int num_entries = map->header_->num_entries_;
-  int ent;
-
-  if ((vdata->code_item_->registers_size_ + 7) / 8 != map->header_->reg_width_) {
-    LOG(ERROR) << "GLITCH: registersSize=" << vdata->code_item_->registers_size_
-               << ", reg_width=" << map->header_->reg_width_;
-    return false;
-  }
-
-  for (ent = 0; ent < num_entries; ent++) {
-    int addr;
-
-    switch (format) {
-      case kRegMapFormatCompact8:
-        addr = *raw_map++;
-        break;
-      case kRegMapFormatCompact16:
-        addr = *raw_map++;
-        addr |= (*raw_map++) << 8;
-        break;
-      default:
-        LOG(FATAL) << "GLITCH: bad format (" << format << ")";
-        return false;
-    }
-
-    const RegType* regs = vdata->register_lines_[addr].reg_types_.get();
-    if (regs == NULL) {
-      LOG(ERROR) << "GLITCH: addr " << addr << " has no data";
-      return false;
-    }
-
-    uint8_t val = 0;
-    int i;
-
-    for (i = 0; i < vdata->code_item_->registers_size_; i++) {
-      bool bit_is_ref, reg_is_ref;
-
-      val >>= 1;
-      if ((i & 0x07) == 0) {
-        /* Load next byte of data. */
-        val = *raw_map++;
-      }
-
-      bit_is_ref = val & 0x01;
-
-      RegType type = regs[i];
-      reg_is_ref = IsReferenceType(type);
-
-      if (bit_is_ref != reg_is_ref) {
-        LOG(ERROR) << "GLITCH: addr " << addr << " reg " << i << ": bit="
-                   << bit_is_ref << " reg=" << reg_is_ref << "(" << type << ")";
-        return false;
-      }
-    }
-    /* Raw_map now points to the address field of the next entry. */
-  }
-
-  return true;
-}
-
-bool DexVerifier::CompareMaps(const RegisterMap* map1, const RegisterMap* map2)
-{
-  size_t size1, size2;
-
-  size1 = ComputeRegisterMapSize(map1);
-  size2 = ComputeRegisterMapSize(map2);
-  if (size1 != size2) {
-    LOG(ERROR) << "CompareMaps: size mismatch (" << size1 << " vs " << size2
-               << ")";
-    return false;
-  }
-
-  if (map1->header_->format_ != map2->header_->format_ ||
-      map1->header_->reg_width_ != map2->header_->reg_width_ ||
-      map1->header_->num_entries_ != map2->header_->num_entries_) {
-    LOG(ERROR) << "CompareMaps: fields mismatch";
-  }
-  if (memcmp(map1->data_, map2->data_, size1) != 0) {
-    LOG(ERROR) << "CompareMaps: data mismatch";
-    return false;
-  }
-
-  return true;
-}
-
-size_t DexVerifier::ComputeRegisterMapSize(const RegisterMap* map) {
-  uint8_t format = map->header_->format_;
-  uint16_t num_entries = map->header_->num_entries_;
-
-  DCHECK(map != NULL);
-
-  switch (format) {
-    case kRegMapFormatNone:
-      return 1;
-    case kRegMapFormatCompact8:
-      return (1 + map->header_->reg_width_) * num_entries;
-    case kRegMapFormatCompact16:
-      return (2 + map->header_->reg_width_) * num_entries;
-    case kRegMapFormatDifferential:
-      {
-        /* Decoded ULEB128 length. */
-        const uint8_t* ptr = map->data_;
-        return DecodeUnsignedLeb128(&ptr);
-      }
-    default:
-      LOG(FATAL) << "Bad register map format " << format;
-      return 0;
-  }
-}
-
-int DexVerifier::ComputeBitDiff(const uint8_t* bits1, const uint8_t* bits2,
-    int byte_width, int* first_bit_changed_ptr, int* num_bits_changed_ptr,
-    uint8_t* leb_out_buf) {
-  int num_bits_changed = 0;
-  int first_bit_changed = -1;
-  int leb_size = 0;
-  int byte_num;
-
-  /*
-   * Run through the vectors, first comparing them at the byte level. This
-   * will yield a fairly quick result if nothing has changed between them.
-   */
-  for (byte_num = 0; byte_num < byte_width; byte_num++) {
-    uint8_t byte1 = *bits1++;
-    uint8_t byte2 = *bits2++;
-    if (byte1 != byte2) {
-      /* Walk through the byte, identifying the changed bits. */
-      int bit_num;
-      for (bit_num = 0; bit_num < 8; bit_num++) {
-        if (((byte1 >> bit_num) & 0x01) != ((byte2 >> bit_num) & 0x01)) {
-          int bit_offset = (byte_num << 3) + bit_num;
-
-          if (first_bit_changed < 0)
-            first_bit_changed = bit_offset;
-          num_bits_changed++;
-
-          if (leb_out_buf == NULL) {
-            leb_size += UnsignedLeb128Size(bit_offset);
-          } else {
-            uint8_t* cur_buf = leb_out_buf;
-            leb_out_buf = WriteUnsignedLeb128(leb_out_buf, bit_offset);
-            leb_size += leb_out_buf - cur_buf;
-          }
-        }
-      }
-    }
-  }
-
-  if (num_bits_changed > 0) {
-    DCHECK_GE(first_bit_changed, 0);
-  }
-
-  if (first_bit_changed_ptr != NULL) {
-    *first_bit_changed_ptr = first_bit_changed;
-  }
-
-  if (num_bits_changed_ptr != NULL) {
-    *num_bits_changed_ptr = num_bits_changed;
-  }
-
-  return leb_size;
-}
-
-DexVerifier::RegisterMap* DexVerifier::CompressMapDifferential(
-    const RegisterMap* map) {
-  int orig_size = ComputeRegisterMapSize(map);
-  uint8_t* tmp_ptr;
-  int addr_width;
-
-  uint8_t format = map->header_->format_;
-  switch (format) {
-    case kRegMapFormatCompact8:
-      addr_width = 1;
-      break;
-    case kRegMapFormatCompact16:
-      addr_width = 2;
-      break;
-    default:
-      LOG(ERROR) << "ERROR: can't compress map with format=" << format;
-      return NULL;
-  }
-
-  int reg_width = map->header_->reg_width_;
-  int num_entries = map->header_->num_entries_;
-
-  if (num_entries <= 1) {
-    return NULL;
-  }
-
-  /*
-   * We don't know how large the compressed data will be. It's possible
-   * for it to expand and become larger than the original. The header
-   * itself is variable-sized, so we generate everything into a temporary
-   * buffer and then copy it to form-fitting storage once we know how big
-   * it will be (and that it's smaller than the original).
-   *
-   * If we use a size that is equal to the size of the input map plus
-   * a value longer than a single entry can possibly expand to, we need
-   * only check for overflow at the end of each entry. The worst case
-   * for a single line is (1 + <ULEB8 address> + <full copy of vector>).
-   * Addresses are 16 bits, so that's (1 + 3 + reg_width).
-   *
-   * The initial address offset and bit vector will take up less than
-   * or equal to the amount of space required when uncompressed -- large
-   * initial offsets are rejected.
-   */
-  UniquePtr<uint8_t[]> tmp_buf(new uint8_t[orig_size + (1 + 3 + reg_width)]);
-
-  tmp_ptr = tmp_buf.get();
-
-  const uint8_t* map_data = map->data_;
-  const uint8_t* prev_bits;
-  uint16_t addr, prev_addr;
-
-  addr = *map_data++;
-  if (addr_width > 1)
-    addr |= (*map_data++) << 8;
-
-  if (addr >= 128) {
-    LOG(ERROR) << "Can't compress map with starting address >= 128";
-    return NULL;
-  }
-
-  /*
-   * Start by writing the initial address and bit vector data. The high
-   * bit of the initial address is used to indicate the required address
-   * width (which the decoder can't otherwise determine without parsing
-   * the compressed data).
-   */
-  *tmp_ptr++ = addr | (addr_width > 1 ? 0x80 : 0x00);
-  memcpy(tmp_ptr, map_data, reg_width);
-
-  prev_bits = map_data;
-  prev_addr = addr;
-
-  tmp_ptr += reg_width;
-  map_data += reg_width;
-
-  /* Loop over all following entries. */
-  for (int entry = 1; entry < num_entries; entry++) {
-    int addr_diff;
-    uint8_t key;
-
-    /* Pull out the address and figure out how to encode it. */
-    addr = *map_data++;
-    if (addr_width > 1)
-      addr |= (*map_data++) << 8;
-
-    addr_diff = addr - prev_addr;
-    DCHECK_GT(addr_diff, 0);
-    if (addr_diff < 8) {
-      /* Small difference, encode in 3 bits. */
-      key = addr_diff -1;          /* set 00000AAA */
-    } else {
-      /* Large difference, output escape code. */
-      key = 0x07;                 /* escape code for AAA */
-    }
-
-    int num_bits_changed, first_bit_changed, leb_size;
-
-    leb_size = ComputeBitDiff(prev_bits, map_data, reg_width,
-        &first_bit_changed, &num_bits_changed, NULL);
-
-    if (num_bits_changed == 0) {
-      /* set B to 1 and CCCC to zero to indicate no bits were changed */
-      key |= 0x08;
-    } else if (num_bits_changed == 1 && first_bit_changed < 16) {
-      /* set B to 0 and CCCC to the index of the changed bit */
-      key |= first_bit_changed << 4;
-    } else if (num_bits_changed < 15 && leb_size < reg_width) {
-      /* set B to 1 and CCCC to the number of bits */
-      key |= 0x08 | (num_bits_changed << 4);
-    } else {
-      /* set B to 1 and CCCC to 0x0f so we store the entire vector */
-      key |= 0x08 | 0xf0;
-    }
-
-    /*
-     * Encode output. Start with the key, follow with the address
-     * diff (if it didn't fit in 3 bits), then the changed bit info.
-     */
-    *tmp_ptr++ = key;
-    if ((key & 0x07) == 0x07)
-      tmp_ptr = WriteUnsignedLeb128(tmp_ptr, addr_diff);
-
-    if ((key & 0x08) != 0) {
-      int bit_count = key >> 4;
-      if (bit_count == 0) {
-        /* nothing changed, no additional output required */
-      } else if (bit_count == 15) {
-        /* full vector is most compact representation */
-        memcpy(tmp_ptr, map_data, reg_width);
-        tmp_ptr += reg_width;
-      } else {
-        /* write bit indices in ULEB128 format */
-        (void) ComputeBitDiff(prev_bits, map_data, reg_width,
-               NULL, NULL, tmp_ptr);
-        tmp_ptr += leb_size;
-      }
-    } else {
-      /* single-bit changed, value encoded in key byte */
-    }
-
-    prev_bits = map_data;
-    prev_addr = addr;
-    map_data += reg_width;
-
-    /* See if we've run past the original size. */
-    if (tmp_ptr - tmp_buf.get() >= orig_size) {
-      return NULL;
-    }
-  }
-
-  /*
-   * Create a RegisterMap with the contents.
-   *
-   * TODO: consider using a threshold other than merely ">=". We would
-   * get poorer compression but potentially use less native heap space.
-   */
-  int new_data_size = tmp_ptr - tmp_buf.get();
-  int new_map_size = new_data_size + UnsignedLeb128Size(new_data_size);
-
-  if (new_map_size >= orig_size) {
-    return NULL;
-  }
-
-  RegisterMap* new_map = new RegisterMap(kRegMapFormatDifferential, reg_width,
-      num_entries, new_map_size);
-
-  tmp_ptr = new_map->data_;
-  tmp_ptr = WriteUnsignedLeb128(tmp_ptr, new_data_size);
-  memcpy(tmp_ptr, tmp_buf.get(), new_data_size);
-
-  return new_map;
-}
-
-DexVerifier::RegisterMap* DexVerifier::UncompressMapDifferential(
-    const RegisterMap* map) {
-  uint8_t format = map->header_->format_;
-  RegisterMapFormat new_format;
-  int reg_width, num_entries, new_addr_width, new_data_size;
-
-  if (format != kRegMapFormatDifferential) {
-    LOG(ERROR) << "Not differential (" << format << ")";
-    return NULL;
-  }
-
-  reg_width = map->header_->reg_width_;
-  num_entries = map->header_->num_entries_;
-
-  /* Get the data size; we can check this at the end. */
-  const uint8_t* src_ptr = map->data_;
-  int expected_src_len = DecodeUnsignedLeb128(&src_ptr);
-  const uint8_t* src_start = src_ptr;
-
-  /* Get the initial address and the 16-bit address flag. */
-  int addr = *src_ptr & 0x7f;
-  if ((*src_ptr & 0x80) == 0) {
-    new_format = kRegMapFormatCompact8;
-    new_addr_width = 1;
-  } else {
-    new_format = kRegMapFormatCompact16;
-    new_addr_width = 2;
-  }
-  src_ptr++;
-
-  /* Now we know enough to allocate the new map. */
-  new_data_size = (new_addr_width + reg_width) * num_entries;
-  RegisterMap* new_map = new RegisterMap(new_format, reg_width, num_entries,
-      new_data_size);
-
-  /* Write the start address and initial bits to the new map. */
-  uint8_t* dst_ptr = new_map->data_;
-
-  *dst_ptr++ = addr & 0xff;
-  if (new_addr_width > 1)
-    *dst_ptr++ = (uint8_t) (addr >> 8);
-
-  memcpy(dst_ptr, src_ptr, reg_width);
-
-  int prev_addr = addr;
-  const uint8_t* prev_bits = dst_ptr;    /* point at uncompressed data */
-
-  dst_ptr += reg_width;
-  src_ptr += reg_width;
-
-  /* Walk through, uncompressing one line at a time. */
-  int entry;
-  for (entry = 1; entry < num_entries; entry++) {
-    int addr_diff;
-    uint8_t key;
-
-    key = *src_ptr++;
-
-    /* Get the address. */
-    if ((key & 0x07) == 7) {
-      /* Address diff follows in ULEB128. */
-      addr_diff = DecodeUnsignedLeb128(&src_ptr);
-    } else {
-      addr_diff = (key & 0x07) +1;
-    }
-
-    addr = prev_addr + addr_diff;
-    *dst_ptr++ = addr & 0xff;
-    if (new_addr_width > 1)
-      *dst_ptr++ = (uint8_t) (addr >> 8);
-
-    /* Unpack the bits. */
-    if ((key & 0x08) != 0) {
-      int bit_count = (key >> 4);
-      if (bit_count == 0) {
-        /* No bits changed, just copy previous. */
-        memcpy(dst_ptr, prev_bits, reg_width);
-      } else if (bit_count == 15) {
-        /* Full copy of bit vector is present; ignore prev_bits. */
-        memcpy(dst_ptr, src_ptr, reg_width);
-        src_ptr += reg_width;
-      } else {
-        /* Copy previous bits and modify listed indices. */
-        memcpy(dst_ptr, prev_bits, reg_width);
-        while (bit_count--) {
-          int bit_index = DecodeUnsignedLeb128(&src_ptr);
-          ToggleBit(dst_ptr, bit_index);
-        }
-      }
-    } else {
-      /* Copy previous bits and modify the specified one. */
-      memcpy(dst_ptr, prev_bits, reg_width);
-
-      /* One bit, from 0-15 inclusive, was changed. */
-      ToggleBit(dst_ptr, key >> 4);
-    }
-
-    prev_addr = addr;
-    prev_bits = dst_ptr;
-    dst_ptr += reg_width;
-  }
-
-  if (dst_ptr - new_map->data_ != new_data_size) {
-    LOG(ERROR) << "ERROR: output " << dst_ptr - new_map->data_
-               << " bytes, expected " << new_data_size;
-    free(new_map);
-    return NULL;
-  }
-
-  if (src_ptr - src_start != expected_src_len) {
-    LOG(ERROR) << "ERROR: consumed " << src_ptr - src_start
-               << " bytes, expected " << expected_src_len;
-    free(new_map);
-    return NULL;
-  }
-
-  return new_map;
-}
-
-/* Dump the register types for the specifed address to the log file. */
-void DexVerifier::DumpRegTypes(const VerifierData* vdata,
-    const RegisterLine* register_line, int addr, const char* addr_name,
-    const UninitInstanceMap* uninit_map) {
-  const DexFile::CodeItem* code_item = vdata->code_item_;
-  uint16_t reg_count = code_item->registers_size_;
-  uint32_t insns_size = code_item->insns_size_;
-  const InsnFlags* insn_flags = vdata->insn_flags_.get();
-  const RegType* addr_regs = register_line->reg_types_.get();
-  int full_reg_count = reg_count + kExtraRegs;
-  bool branch_target = InsnIsBranchTarget(insn_flags, addr);
-  int i;
-
-  CHECK(addr >= 0 && addr < (int) insns_size);
-
-  int reg_char_size = full_reg_count + (full_reg_count - 1) / 4 + 2 + 1;
-  char reg_chars[reg_char_size + 1];
-  memset(reg_chars, ' ', reg_char_size);
-  reg_chars[0] = '[';
-  if (reg_count == 0) {
-    reg_chars[1] = ']';
-  } else {
-    reg_chars[1 + (reg_count - 1) + (reg_count - 1) / 4 + 1] = ']';
-  }
-  reg_chars[reg_char_size] = '\0';
-
-  for (i = 0; i < reg_count + kExtraRegs; i++) {
-    char tch;
-
-    switch (addr_regs[i]) {
-      case kRegTypeUnknown:       tch = '.';  break;
-      case kRegTypeConflict:      tch = 'X';  break;
-      case kRegTypeZero:          tch = '0';  break;
-      case kRegTypeOne:           tch = '1';  break;
-      case kRegTypeBoolean:       tch = 'Z';  break;
-      case kRegTypeConstPosByte:  tch = 'y';  break;
-      case kRegTypeConstByte:     tch = 'Y';  break;
-      case kRegTypeConstPosShort: tch = 'h';  break;
-      case kRegTypeConstShort:    tch = 'H';  break;
-      case kRegTypeConstChar:     tch = 'c';  break;
-      case kRegTypeConstInteger:  tch = 'i';  break;
-      case kRegTypePosByte:       tch = 'b';  break;
-      case kRegTypeByte:          tch = 'B';  break;
-      case kRegTypePosShort:      tch = 's';  break;
-      case kRegTypeShort:         tch = 'S';  break;
-      case kRegTypeChar:          tch = 'C';  break;
-      case kRegTypeInteger:       tch = 'I';  break;
-      case kRegTypeFloat:         tch = 'F';  break;
-      case kRegTypeConstLo:       tch = 'N';  break;
-      case kRegTypeConstHi:       tch = 'n';  break;
-      case kRegTypeLongLo:        tch = 'J';  break;
-      case kRegTypeLongHi:        tch = 'j';  break;
-      case kRegTypeDoubleLo:      tch = 'D';  break;
-      case kRegTypeDoubleHi:      tch = 'd';  break;
-      default:
-        if (RegTypeIsReference(addr_regs[i])) {
-          if (RegTypeIsUninitReference(addr_regs[i]))
-            tch = 'U';
-          else
-            tch = 'L';
-        } else {
-          tch = '*';
-          CHECK(false);
-        }
-        break;
-    }
-
-    if (i < reg_count)
-      reg_chars[1 + i + (i / 4)] = tch;
-    else
-      reg_chars[1 + i + (i / 4) + 2] = tch;
-  }
-
-  if (addr == 0 && addr_name != NULL) {
-    char start = branch_target ? '>' : ' ';
-    LOG(INFO) << start << addr_name << " " << reg_chars << " mst="
-              << register_line->monitor_stack_top_;
-  } else {
-    char start = branch_target ? '>' : ' ';
-    LOG(INFO) << start << "0x" << std::hex << addr << std::dec << " "
-              << reg_chars << " mst=" << register_line->monitor_stack_top_;
-  }
-
-  for (i = 0; i < reg_count + kExtraRegs; i++) {
-    if (RegTypeIsReference(addr_regs[i]) && addr_regs[i] != kRegTypeZero) {
-      Class* klass = RegTypeReferenceToClass(addr_regs[i], uninit_map);
-      if (i < reg_count) {
-        const char* undef = RegTypeIsUninitReference(addr_regs[i]) ? "[U]" : "";
-        LOG(INFO) << "        " << i << ": 0x" << std::hex << addr_regs[i] << std::dec
-                  << " " << undef << klass->GetDescriptor()->ToModifiedUtf8();
-      } else {
-        const char* undef = RegTypeIsUninitReference(addr_regs[i]) ? "[U]" : "";
-        LOG(INFO) << "        RS: 0x" << std::hex << addr_regs[i] << std::dec
-                  << " " << undef << klass->GetDescriptor()->ToModifiedUtf8();
-      }
-    }
-  }
-}
-
+}  // namespace verifier
 }  // namespace art
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index 6012231..1f28204 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -3,21 +3,29 @@
 #ifndef ART_SRC_DEX_VERIFY_H_
 #define ART_SRC_DEX_VERIFY_H_
 
+#include "casts.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
 #include "macros.h"
 #include "object.h"
+#include "stl_util.h"
 #include "UniquePtr.h"
 
-namespace art {
+#include <map>
+#include <stack>
+#include <vector>
 
-#define kMaxMonitorStackDepth   (sizeof(MonitorEntries) * 8)
+namespace art {
+namespace verifier {
+
+class DexVerifier;
+class PcToReferenceMap;
+class RegTypeCache;
 
 /*
- * Set this to enable dead code scanning. This is not required, but it's
- * very useful when testing changes to the verifier (to make sure we're not
- * skipping over stuff). The only reason not to do it is that it slightly
- * increases the time required to perform verification.
+ * Set this to enable dead code scanning. This is not required, but it's very useful when testing
+ * changes to the verifier (to make sure we're not skipping over stuff). The only reason not to do
+ * it is that it slightly increases the time required to perform verification.
  */
 #ifndef NDEBUG
 # define DEAD_CODE_SCAN  true
@@ -26,81 +34,15 @@
 #endif
 
 /*
- * We need an extra "pseudo register" to hold the return type briefly. It
- * can be category 1 or 2, so we need two slots.
+ * RegType holds information about the type of data held in a register. For most types it's a simple
+ * enum. For reference types it holds a pointer to the ClassObject, and for uninitialized references
+ * it holds an index into the UninitInstanceMap.
  */
-#define kExtraRegs  2
-#define RESULT_REGISTER(_insnRegCount)  (_insnRegCount)
-
-class DexVerifier {
+class RegType {
  public:
   /*
-   * RegType holds information about the type of data held in a register.
-   * For most types it's a simple enum. For reference types it holds a
-   * pointer to the ClassObject, and for uninitialized references it holds
-   * an index into the UninitInstanceMap.
-   */
-  typedef uint32_t RegType;
-
-  /*
-   * A bit vector indicating which entries in the monitor stack are
-   * associated with this register. The low bit corresponds to the stack's
-   * bottom-most entry.
-   */
-  typedef uint32_t MonitorEntries;
-
-  /*
-   * InsnFlags is a 32-bit integer with the following layout:
-   *   0-15  instruction length (or 0 if this address doesn't hold an opcode)
-   *  16-31  single bit flags:
-   *    InTry: in "try" block; exceptions thrown here may be caught locally
-   *    BranchTarget: other instructions can branch to this instruction
-   *    GcPoint: this instruction is a GC safe point
-   *    Visited: verifier has examined this instruction at least once
-   *    Changed: set/cleared as bytecode verifier runs
-   */
-  typedef uint32_t InsnFlags;
-
-  enum InsnFlag {
-    kInsnFlagWidthMask    = 0x0000ffff,
-    kInsnFlagInTry        = (1 << 16),
-    kInsnFlagBranchTarget = (1 << 17),
-    kInsnFlagGcPoint      = (1 << 18),
-    kInsnFlagVisited      = (1 << 30),
-    kInsnFlagChanged      = (1 << 31),
-  };
-
-  /*
-   * "Direct" and "virtual" methods are stored independently. The type of call
-   * used to invoke the method determines which list we search, and whether
-   * we travel up into superclasses.
-   *
-   * (<clinit>, <init>, and methods declared "private" or "static" are stored
-   * in the "direct" list. All others are stored in the "virtual" list.)
-   */
-  enum MethodType {
-    METHOD_UNKNOWN  = 0,
-    METHOD_DIRECT,      // <init>, private
-    METHOD_STATIC,      // static
-    METHOD_VIRTUAL,     // virtual, super
-    METHOD_INTERFACE    // interface
-  };
-
-  /*
-   * We don't need to store the register data for many instructions, because
-   * we either only need it at branch points (for verification) or GC points
-   * and branches (for verification + type-precise register analysis).
-   */
-  enum RegisterTrackingMode {
-    kTrackRegsBranches,
-    kTrackRegsGcPoints,
-    kTrackRegsAll,
-  };
-
-  /*
-   * Enumeration for register type values. The "hi" piece of a 64-bit value
-   * MUST immediately follow the "lo" piece in the enumeration, so we can check
-   * that hi==lo+1.
+   * Enumeration for register type values. The "hi" piece of a 64-bit value MUST immediately follow
+   * the "lo" piece in the enumeration, so we can check that hi==lo+1.
    *
    * Assignment of constants:
    *   [-MAXINT,-32768)   : integer
@@ -125,572 +67,746 @@
    *
    * In addition, all of the above can convert to "float".
    *
-   * We're more careful with integer values than the spec requires. The
-   * motivation is to restrict byte/char/short to the correct range of values.
-   * For example, if a method takes a byte argument, we don't want to allow
-   * the code to load the constant "1024" and pass it in.
+   * We're more careful with integer values than the spec requires. The motivation is to restrict
+   * byte/char/short to the correct range of values. For example, if a method takes a byte argument,
+   * we don't want to allow the code to load the constant "1024" and pass it in.
    */
-  enum {
-    kRegTypeUnknown = 0,    /* initial state; use value=0 so calloc works */
-    kRegTypeUninit = 1,     /* MUST be odd to distinguish from pointer */
+  enum Type {
+    kRegTypeUnknown = 0,    /* initial state */
     kRegTypeConflict,       /* merge clash makes this reg's type unknowable */
 
     /*
-     * Category-1nr types. The order of these is chiseled into a couple
-     * of tables, so don't add, remove, or reorder if you can avoid it.
+     * Category-1nr types. The order of these is chiseled into a couple of tables, so don't add,
+     * remove, or reorder if you can avoid it.
      */
-#define kRegType1nrSTART    kRegTypeZero
-    kRegTypeZero,           /* 32-bit 0, could be Boolean, Int, Float, or Ref */
-    kRegTypeOne,            /* 32-bit 1, could be Boolean, Int, Float */
-    kRegTypeBoolean,        /* must be 0 or 1 */
-    kRegTypeConstPosByte,   /* const derived byte, known positive */
-    kRegTypeConstByte,      /* const derived byte */
-    kRegTypeConstPosShort,  /* const derived short, known positive */
-    kRegTypeConstShort,     /* const derived short */
-    kRegTypeConstChar,      /* const derived char */
-    kRegTypeConstInteger,   /* const derived integer */
-    kRegTypePosByte,        /* byte, known positive (can become char) */
-    kRegTypeByte,
-    kRegTypePosShort,       /* short, known positive (can become char) */
-    kRegTypeShort,
-    kRegTypeChar,
-    kRegTypeInteger,
-    kRegTypeFloat,
-#define kRegType1nrEND      kRegTypeFloat
-    kRegTypeConstLo,        /* const derived wide, lower half */
-    kRegTypeConstHi,        /* const derived wide, upper half */
+    kRegTypeZero,           /* 0 - 32-bit 0, could be Boolean, Int, Float, or Ref */
+    kRegType1nrSTART = kRegTypeZero,
+    kRegTypeIntegralSTART = kRegTypeZero,
+    kRegTypeOne,            /* 1 - 32-bit 1, could be Boolean, Int, Float */
+    kRegTypeBoolean,        /* Z - must be 0 or 1 */
+    kRegTypeConstPosByte,   /* y - const derived byte, known positive */
+    kRegTypeConstByte,      /* Y - const derived byte */
+    kRegTypeConstPosShort,  /* h - const derived short, known positive */
+    kRegTypeConstShort,     /* H - const derived short */
+    kRegTypeConstChar,      /* c - const derived char */
+    kRegTypeConstInteger,   /* i - const derived integer */
+    kRegTypePosByte,        /* b - byte, known positive (can become char) */
+    kRegTypeByte,           /* B */
+    kRegTypePosShort,       /* s - short, known positive (can become char) */
+    kRegTypeShort,          /* S */
+    kRegTypeChar,           /* C */
+    kRegTypeInteger,        /* I */
+    kRegTypeIntegralEND = kRegTypeInteger,
+    kRegTypeFloat,          /* F */
+    kRegType1nrEND = kRegTypeFloat,
+    kRegTypeConstLo,        /* const derived wide, lower half - could be long or double */
+    kRegTypeConstHi,        /* const derived wide, upper half - could be long or double */
     kRegTypeLongLo,         /* lower-numbered register; endian-independent */
     kRegTypeLongHi,
     kRegTypeDoubleLo,
     kRegTypeDoubleHi,
-
-    /*
-     * Enumeration max; this is used with "full" (32-bit) RegType values.
-     *
-     * Anything larger than this is a ClassObject or uninit ref. Mask off
-     * all but the low 8 bits; if you're left with kRegTypeUninit, pull
-     * the uninit index out of the high 24. Because kRegTypeUninit has an
-     * odd value, there is no risk of a particular ClassObject pointer bit
-     * pattern being confused for it (assuming our class object allocator
-     * uses word alignment).
-     */
-    kRegTypeMAX
-  };
-#define kRegTypeUninitMask  0xff
-#define kRegTypeUninitShift 8
-
-  /*
-   * Register type categories, for type checking.
-   *
-   * The spec says category 1 includes boolean, byte, char, short, int, float,
-   * reference, and returnAddress. Category 2 includes long and double.
-   *
-   * We treat object references separately, so we have "category1nr". We
-   * don't support jsr/ret, so there is no "returnAddress" type.
-   */
-  enum TypeCategory {
-    kTypeCategoryUnknown = 0,
-    kTypeCategory1nr = 1,         // boolean, byte, char, short, int, float
-    kTypeCategory2 = 2,           // long, double
-    kTypeCategoryRef = 3,         // object reference
+    kRegTypeReference,      // Reference type
+    kRegTypeMAX = kRegTypeReference + 1,
   };
 
-  /* An enumeration of problems that can turn up during verification. */
-  enum VerifyError {
-    VERIFY_ERROR_NONE = 0,      /* no error; must be zero */
-    VERIFY_ERROR_GENERIC,       /* VerifyError */
-
-    VERIFY_ERROR_NO_CLASS,      /* NoClassDefFoundError */
-    VERIFY_ERROR_NO_FIELD,      /* NoSuchFieldError */
-    VERIFY_ERROR_NO_METHOD,     /* NoSuchMethodError */
-    VERIFY_ERROR_ACCESS_CLASS,  /* IllegalAccessError */
-    VERIFY_ERROR_ACCESS_FIELD,  /* IllegalAccessError */
-    VERIFY_ERROR_ACCESS_METHOD, /* IllegalAccessError */
-    VERIFY_ERROR_CLASS_CHANGE,  /* IncompatibleClassChangeError */
-    VERIFY_ERROR_INSTANTIATION, /* InstantiationError */
-  };
-
-  /*
-   * Identifies the type of reference in the instruction that generated the
-   * verify error (e.g. VERIFY_ERROR_ACCESS_CLASS could come from a method,
-   * field, or class reference).
-   *
-   * This must fit in two bits.
-   */
-  enum VerifyErrorRefType {
-    VERIFY_ERROR_REF_CLASS  = 0,
-    VERIFY_ERROR_REF_FIELD  = 1,
-    VERIFY_ERROR_REF_METHOD = 2,
-  };
-#define kVerifyErrorRefTypeShift 6
-
-  /*
-   * Format enumeration for RegisterMap data area.
-   */
-  enum RegisterMapFormat {
-    kRegMapFormatUnknown = 0,
-    kRegMapFormatNone,          /* indicates no map data follows */
-    kRegMapFormatCompact8,      /* compact layout, 8-bit addresses */
-    kRegMapFormatCompact16,     /* compact layout, 16-bit addresses */
-    kRegMapFormatDifferential,  /* compressed, differential encoding */
-  };
-
-  /*
-   * During verification, we associate one of these with every "interesting"
-   * instruction. We track the status of all registers, and (if the method
-   * has any monitor-enter instructions) maintain a stack of entered monitors
-   * (identified by code unit offset).
-   *
-   * If live-precise register maps are enabled, the "liveRegs" vector will
-   * be populated. Unlike the other lists of registers here, we do not
-   * track the liveness of the method result register (which is not visible
-   * to the GC).
-   */
-  struct RegisterLine {
-    UniquePtr<RegType[]> reg_types_;
-    UniquePtr<MonitorEntries[]> monitor_entries_;
-    UniquePtr<uint32_t[]> monitor_stack_;
-    uint32_t monitor_stack_top_;
-
-    RegisterLine()
-        : reg_types_(NULL), monitor_entries_(NULL), monitor_stack_(NULL),
-          monitor_stack_top_(0) {
-    }
-
-    /* Allocate space for the fields. */
-    void Alloc(size_t size, bool track_monitors) {
-      reg_types_.reset(new RegType[size]());
-      if (track_monitors) {
-        monitor_entries_.reset(new MonitorEntries[size]);
-        monitor_stack_.reset(new uint32_t[kMaxMonitorStackDepth]);
-      }
-    }
-  };
-
-  /* Big fat collection of register data. */
-  struct RegisterTable {
-    /*
-     * Array of RegisterLine structs, one per address in the method. We only
-     * set the pointers for certain addresses, based on instruction widths
-     * and what we're trying to accomplish.
-     */
-    UniquePtr<RegisterLine[]> register_lines_;
-
-    /*
-     * Number of registers we track for each instruction. This is equal
-     * to the method's declared "registersSize" plus kExtraRegs (2).
-     */
-    size_t      insn_reg_count_plus_;
-
-    /* Storage for a register line we're currently working on. */
-    RegisterLine work_line_;
-
-    /* Storage for a register line we're saving for later. */
-    RegisterLine saved_line_;
-
-    RegisterTable() : register_lines_(NULL), insn_reg_count_plus_(0) {
-    }
-  };
-
-  /* Entries in the UninitInstanceMap. */
-  struct UninitInstanceMapEntry {
-    /* Code offset, or -1 for method arg ("this"). */
-    int addr_;
-
-    /* Class created at this address. */
-    Class* klass_;
-  };
-
-  /*
-   * Table that maps uninitialized instances to classes, based on the
-   * address of the new-instance instruction. One per method.
-   */
-  struct UninitInstanceMap {
-    int num_entries_;
-    UniquePtr<UninitInstanceMapEntry[]> map_;
-
-    explicit UninitInstanceMap(int num_entries)
-        : num_entries_(num_entries),
-          map_(new UninitInstanceMapEntry[num_entries]()) {
-    }
-  };
-  #define kUninitThisArgAddr  (-1)
-  #define kUninitThisArgSlot  0
-
-  /* Various bits of data used by the verifier and register map generator. */
-  struct VerifierData {
-    /* The method we're working on. */
-    Method* method_;
-
-    /* The dex file containing the method. */
-    const DexFile* dex_file_;
-
-    /* The code item containing the code for the method. */
-    const DexFile::CodeItem* code_item_;
-
-    /* Instruction widths and flags, one entry per code unit. */
-    UniquePtr<InsnFlags[]> insn_flags_;
-
-    /*
-     * Uninitialized instance map, used for tracking the movement of
-     * objects that have been allocated but not initialized.
-     */
-    UniquePtr<UninitInstanceMap> uninit_map_;
-
-    /*
-     * Array of RegisterLine structs, one entry per code unit. We only need
-     * entries for code units that hold the start of an "interesting"
-     * instruction. For register map generation, we're only interested
-     * in GC points.
-     */
-    RegisterLine* register_lines_;
-
-    /* The number of occurrences of specific opcodes. */
-    size_t new_instance_count_;
-    size_t monitor_enter_count_;
-
-    VerifierData(Method* method, const DexFile* dex_file,
-        const DexFile::CodeItem* code_item)
-        : method_(method), dex_file_(dex_file), code_item_(code_item),
-          insn_flags_(NULL), uninit_map_(NULL), register_lines_(NULL),
-          new_instance_count_(0), monitor_enter_count_(0) {
-    }
-  };
-
-  /* Header for RegisterMap */
-  struct RegisterMapHeader {
-    uint8_t format_;          /* enum RegisterMapFormat; MUST be first entry */
-    uint8_t reg_width_;       /* bytes per register line, 1+ */
-    uint16_t num_entries_;    /* number of entries */
-
-    RegisterMapHeader(uint8_t format, uint8_t reg_width, uint16_t num_entries)
-        : format_(format), reg_width_(reg_width), num_entries_(num_entries) {
-    }
-  };
-
-  /*
-   * This is a single variable-size structure. It may be allocated on the
-   * heap or mapped out of a (post-dexopt) DEX file.
-   *
-   * 32-bit alignment of the structure is NOT guaranteed. This makes it a
-   * little awkward to deal with as a structure; to avoid accidents we use
-   * only byte types. Multi-byte values are little-endian.
-   *
-   * Size of (format==FormatNone): 1 byte
-   * Size of (format==FormatCompact8): 4 + (1 + reg_width) * num_entries
-   * Size of (format==FormatCompact16): 4 + (2 + reg_width) * num_entries
-   */
-  struct RegisterMap {
-    RegisterMapHeader* header_;
-    uint8_t* data_;
-    bool needs_free_;
-
-    RegisterMap(ByteArray* header, ByteArray* data) {
-      header_ = (RegisterMapHeader*) header->GetData();
-      data_ = (uint8_t*) data->GetData();
-      needs_free_ = false;
-    }
-
-    RegisterMap(uint8_t format, uint8_t reg_width, uint16_t num_entries,
-        uint32_t data_size) {
-      header_ = new RegisterMapHeader(format, reg_width, num_entries);
-      data_ = new uint8_t[data_size]();
-      needs_free_ = true;
-    }
-
-    ~RegisterMap() {
-      if (needs_free_) {
-        delete header_;
-        delete [] data_;
-      }
-    }
-  };
-
-  /*
-   * Merge result table for primitive values. The table is symmetric along
-   * the diagonal.
-   *
-   * Note that 32-bit int/float do not merge into 64-bit long/double. This
-   * is a register merge, not a widening conversion. Only the "implicit"
-   * widening within a category, e.g. byte to short, is allowed.
-   *
-   * Dalvik does not draw a distinction between int and float, but we enforce
-   * that once a value is used as int, it can't be used as float, and vice
-   * versa. We do not allow free exchange between 32-bit int/float and 64-bit
-   * long/double.
-   *
-   * Note that Uninit+Uninit=Uninit. This holds true because we only
-   * use this when the RegType value is exactly equal to kRegTypeUninit, which
-   * can only happen for the zeroeth entry in the table.
-   *
-   * "Unknown" never merges with anything known. The only time a register
-   * transitions from "unknown" to "known" is when we're executing code
-   * for the first time, and we handle that with a simple copy.
-   */
-  static const char merge_table_[kRegTypeMAX][kRegTypeMAX];
-
-  /*
-   * Returns "true" if the flags indicate that this address holds the start
-   * of an instruction.
-   */
-  static inline bool InsnIsOpcode(const InsnFlags insn_flags[], int addr) {
-    return (insn_flags[addr] & kInsnFlagWidthMask) != 0;
+  bool IsUninitializedThisReference() const {
+    return allocation_pc_ == kUninitThisArgAddr;
   }
 
-  /* Extract the unsigned 16-bit instruction width from "flags". */
-  static inline int InsnGetWidth(const InsnFlags insn_flags[], int addr) {
-    return insn_flags[addr] & kInsnFlagWidthMask;
+  Type GetType() const {
+    return type_;
   }
 
-  /* Utilities to check and set kInsnFlagChanged. */
-  static inline bool InsnIsChanged(const InsnFlags insn_flags[], int addr) {
-    return (insn_flags[addr] & kInsnFlagChanged) != 0;
-  }
-  static inline void InsnSetChanged(InsnFlags insn_flags[], int addr,
-      bool changed) {
-    if (changed)
-      insn_flags[addr] |= kInsnFlagChanged;
-    else
-      insn_flags[addr] &= ~kInsnFlagChanged;
+  void Dump(std::ostream& os) const;
+
+  Class* GetClass() const {
+    DCHECK(klass_ != NULL);
+    return klass_;
   }
 
-  /* Utilities to check and set kInsnFlagVisited. */
-  static inline bool InsnIsVisited(const InsnFlags insn_flags[], int addr) {
-      return (insn_flags[addr] & kInsnFlagVisited) != 0;
-  }
-  static inline void InsnSetVisited(InsnFlags insn_flags[], int addr,
-      bool visited) {
-    if (visited)
-      insn_flags[addr] |= kInsnFlagVisited;
-    else
-      insn_flags[addr] &= ~kInsnFlagVisited;
+  bool IsInitialized() const { return allocation_pc_ == kInitArgAddr; }
+  bool IsUninitializedReference() const { return allocation_pc_ != kInitArgAddr; }
+
+  bool IsUnknown() const { return type_ == kRegTypeUnknown; }
+  bool IsConflict() const { return type_ == kRegTypeConflict; }
+  bool IsZero()    const { return type_ == kRegTypeZero; }
+  bool IsOne()     const { return type_ == kRegTypeOne; }
+  bool IsConstLo() const { return type_ == kRegTypeConstLo; }
+  bool IsBoolean() const { return type_ == kRegTypeBoolean; }
+  bool IsByte()    const { return type_ == kRegTypeByte; }
+  bool IsChar()    const { return type_ == kRegTypeChar; }
+  bool IsShort()   const { return type_ == kRegTypeShort; }
+  bool IsInteger() const { return type_ == kRegTypeInteger; }
+  bool IsLong()    const { return type_ == kRegTypeLongLo; }
+  bool IsFloat()   const { return type_ == kRegTypeFloat; }
+  bool IsDouble()  const { return type_ == kRegTypeDoubleLo; }
+  bool IsReference() const { return type_ == kRegTypeReference; }
+
+  bool IsLowHalf() const { return type_ == kRegTypeLongLo ||
+                                  type_ == kRegTypeDoubleLo ||
+                                  type_ == kRegTypeConstLo; }
+  bool IsHighHalf() const { return type_ == kRegTypeLongHi ||
+                                   type_ == kRegTypeDoubleHi ||
+                                   type_ == kRegTypeConstHi; }
+
+  const RegType& HighHalf(RegTypeCache* cache) const;
+
+  bool CheckWidePair(const RegType& type_h) const {
+    return IsLowHalf() && (type_h.type_ == type_ + 1);
   }
 
-  static inline bool InsnIsVisitedOrChanged(const InsnFlags insn_flags[],
-      int addr) {
-    return (insn_flags[addr] & (kInsnFlagVisited |
-                                kInsnFlagChanged)) != 0;
+  uint16_t GetId() const {
+    return cache_id_;
   }
 
-  /* Utilities to check and set kInsnFlagInTry. */
-  static inline bool InsnIsInTry(const InsnFlags insn_flags[], int addr) {
-    return (insn_flags[addr] & kInsnFlagInTry) != 0;
-  }
-  static inline void InsnSetInTry(InsnFlags insn_flags[], int addr) {
-    insn_flags[addr] |= kInsnFlagInTry;
+  bool IsLongOrDoubleTypes() const { return IsLowHalf(); }
+
+  bool IsReferenceTypes() const {
+    return type_ == kRegTypeReference || type_ == kRegTypeZero;
   }
 
-  /* Utilities to check and set kInsnFlagBranchTarget. */
-  static inline bool InsnIsBranchTarget(const InsnFlags insn_flags[], int addr)
-  {
-    return (insn_flags[addr] & kInsnFlagBranchTarget) != 0;
-  }
-  static inline void InsnSetBranchTarget(InsnFlags insn_flags[], int addr) {
-    insn_flags[addr] |= kInsnFlagBranchTarget;
+  bool IsCategory1Types() const {
+    return type_ >= kRegType1nrSTART && type_ <= kRegType1nrEND;
   }
 
-  /* Utilities to check and set kInsnFlagGcPoint. */
-  static inline bool InsnIsGcPoint(const InsnFlags insn_flags[], int addr) {
-    return (insn_flags[addr] & kInsnFlagGcPoint) != 0;
-  }
-  static inline void InsnSetGcPoint(InsnFlags insn_flags[], int addr) {
-    insn_flags[addr] |= kInsnFlagGcPoint;
+  bool IsCategory2Types() const {
+    return IsLowHalf();  // Don't expect explicit testing of high halves
   }
 
-  /* Get the class object at the specified index. */
-  static inline Class* GetUninitInstance(const UninitInstanceMap* uninit_map, int idx) {
-    DCHECK_GE(idx, 0);
-    DCHECK_LT(idx, uninit_map->num_entries_);
-    return uninit_map->map_[idx].klass_;
+  bool IsBooleanTypes() const { return IsBoolean() || IsZero() || IsOne(); }
+
+  bool IsByteTypes() const {
+    return IsByte() || IsBooleanTypes() || type_ == kRegTypeConstPosByte ||
+        type_ == kRegTypeConstByte || type_ == kRegTypePosByte;
   }
 
-  /* Determine if "type" is actually an object reference (init/uninit/zero) */
-  static inline bool RegTypeIsReference(RegType type) {
-    return (type > kRegTypeMAX || type == kRegTypeUninit ||
-            type == kRegTypeZero);
+  bool IsShortTypes() const {
+    return IsShort() || IsByteTypes() || type_ == kRegTypeConstPosShort ||
+        type_ == kRegTypeConstShort || type_ == kRegTypePosShort;
   }
 
-  /* Determine if "type" is an uninitialized object reference */
-  static inline bool RegTypeIsUninitReference(RegType type) {
-    return ((type & kRegTypeUninitMask) == kRegTypeUninit);
+  bool IsCharTypes() const {
+    return IsChar() || IsBooleanTypes() || type_ == kRegTypeConstPosByte ||
+        type_ == kRegTypePosByte || type_ == kRegTypeConstPosShort || type_ == kRegTypePosShort ||
+        type_ == kRegTypeConstChar;
+  }
+
+  bool IsIntegralTypes() const {
+    return type_ >= kRegTypeIntegralSTART && type_ <= kRegTypeIntegralEND;
+  }
+
+  bool IsArrayIndexTypes() const {
+    return IsIntegralTypes();
+  }
+
+  // Float type may be derived from any constant type
+  bool IsFloatTypes() const {
+    return IsFloat() || IsZero() || IsOne() ||
+        type_ == kRegTypeConstPosByte || type_ == kRegTypeConstByte ||
+        type_ == kRegTypeConstPosShort || type_ == kRegTypeConstShort ||
+        type_ == kRegTypeConstChar || type_ == kRegTypeConstInteger;
+  }
+
+  bool IsLongTypes() const {
+    return IsLong() || type_ == kRegTypeConstLo;
+  }
+
+  bool IsDoubleTypes() const {
+    return IsDouble() || type_ == kRegTypeConstLo;
+  }
+
+  const RegType& VerifyAgainst(const RegType& check_type, RegTypeCache* reg_types) const;
+
+  const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const;
+
+  bool Equals(const RegType& other) const {
+    return type_ == other.type_ && klass_ == other.klass_ && allocation_pc_ == other.allocation_pc_;
   }
 
   /*
-   * Convert the initialized reference "type" to a Class pointer
-   * (does not expect uninit ref types or "zero").
+   * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
+   * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
+   * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
+   * is the deepest (lowest upper bound) parent of S and T).
+   *
+   * This operation applies for regular classes and arrays, however, for interface types there needn't
+   * be a partial ordering on the types. We could solve the problem of a lack of a partial order by
+   * introducing sets of types, however, the only operation permissible on an interface is
+   * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
+   * types until an invoke-interface call on the interface typed reference at runtime and allow
+   * the perversion of Object being assignable to an interface type (note, however, that we don't
+   * allow assignment of Object or Interface to any concrete class and are therefore type safe).
+   *
+   * [1] Java bytecode verifcation: algorithms and formalizations, Xavier Leroy
    */
-  static Class* RegTypeInitializedReferenceToClass(RegType type) {
-    DCHECK(RegTypeIsReference(type) && type != kRegTypeZero);
-    if ((type & 0x01) == 0) {
-      return (Class*) type;
-    } else {
-      LOG(ERROR) << "VFY: attempted to use uninitialized reference";
-      return NULL;
-    }
-  }
-
-  /* Extract the index into the uninitialized instance map table. */
-  static inline int RegTypeToUninitIndex(RegType type) {
-    DCHECK(RegTypeIsUninitReference(type));
-    return (type & ~kRegTypeUninitMask) >> kRegTypeUninitShift;
-  }
-
-  /* Convert the reference "type" to a Class pointer. */
-  static Class* RegTypeReferenceToClass(RegType type,
-      const UninitInstanceMap* uninit_map) {
-    DCHECK(RegTypeIsReference(type) && type != kRegTypeZero);
-    if (RegTypeIsUninitReference(type)) {
-      DCHECK(uninit_map != NULL);
-      return GetUninitInstance(uninit_map, RegTypeToUninitIndex(type));
-    } else {
-        return (Class*) type;
-    }
-  }
-
-  /* Convert the ClassObject pointer to an (initialized) register type. */
-  static inline RegType RegTypeFromClass(Class* klass) {
-    return (uint32_t) klass;
-  }
-
-  /* Return the RegType for the uninitialized reference in slot "uidx". */
-  static inline RegType RegTypeFromUninitIndex(int uidx) {
-    return (uint32_t) (kRegTypeUninit | (uidx << kRegTypeUninitShift));
-  }
-
-  /*
-   * Generate the register map for a method that has just been verified
-   * (i.e. we're doing this as part of verification).
-   *
-   * For type-precise determination we have all the data we need, so we
-   * just need to encode it in some clever fashion.
-   *
-   * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
-   */
-  static RegisterMap* GenerateRegisterMapV(VerifierData* vdata);
-
-  /*
-   * Get the expanded form of the register map associated with the specified
-   * method. May update the RegisterMap, possibly freeing the previous map.
-   *
-   * Returns NULL on failure (e.g. unable to expand map).
-   *
-   * NOTE: this function is not synchronized; external locking is mandatory.
-   * (This is expected to be called at GC time.)
-   */
-  static inline RegisterMap* GetExpandedRegisterMap(Method* method) {
-    if (method->GetRegisterMapHeader() == NULL ||
-        method->GetRegisterMapData() == NULL) {
-      return NULL;
-    }
-    RegisterMap* cur_map = new RegisterMap(method->GetRegisterMapHeader(),
-        method->GetRegisterMapData());
-    uint8_t format = cur_map->header_->format_;
-    if (format == kRegMapFormatCompact8 || format == kRegMapFormatCompact16) {
-      return cur_map;
-    } else {
-      return GetExpandedRegisterMapHelper(method, cur_map);
-    }
-  }
-
-  /*
-   * Get the expanded form of the register map associated with the method.
-   *
-   * If the map is already in one of the uncompressed formats, we return
-   * immediately.  Otherwise, we expand the map and replace method's register
-   * map pointer, freeing it if it was allocated on the heap.
-   *
-   * NOTE: this function is not synchronized; external locking is mandatory
-   * (unless we're in the zygote, where single-threaded access is guaranteed).
-   */
-  static RegisterMap* GetExpandedRegisterMapHelper(Method* method,
-      RegisterMap* map);
-
-  /* Return the data for the specified address, or NULL if not found. */
-  static const uint8_t* RegisterMapGetLine(const RegisterMap* map, int addr);
-
-  /*
-   * Determine if the RegType value is a reference type.
-   *
-   * Ordinarily we include kRegTypeZero in the "is it a reference"
-   * check. There's no value in doing so here, because we know
-   * the register can't hold anything but zero.
-   */
-  static inline bool IsReferenceType(RegType type) {
-    return (type > kRegTypeMAX || type == kRegTypeUninit);
-  }
-
-  /* Toggle the value of the "idx"th bit in "ptr". */
-  static inline void ToggleBit(uint8_t* ptr, int idx) {
-    ptr[idx >> 3] ^= 1 << (idx & 0x07);
-  }
-
-  /*
-   * Given a line of registers, output a bit vector that indicates whether
-   * or not the register holds a reference type (which could be null).
-   *
-   * We use '1' to indicate it's a reference, '0' for anything else (numeric
-   * value, uninitialized data, merge conflict). Register 0 will be found
-   * in the low bit of the first byte.
-   */
-  static void OutputTypeVector(const RegType* regs, int insn_reg_count,
-      uint8_t* data);
-
-  /*
-   * Double-check the map.
-   *
-   * We run through all of the data in the map, and compare it to the original.
-   * Only works on uncompressed data.
-   */
-  static bool VerifyMap(VerifierData* vdata, const RegisterMap* map);
-
-  /* Compare two register maps. Returns true if they're equal, false if not. */
-  static bool CompareMaps(const RegisterMap* map1, const RegisterMap* map2);
-
-  /* Compute the size, in bytes, of a register map. */
-  static size_t ComputeRegisterMapSize(const RegisterMap* map);
-
-  /*
-   * Compute the difference between two bit vectors.
-   *
-   * If "leb_out_buf" is non-NULL, we output the bit indices in ULEB128 format
-   * as we go. Otherwise, we just generate the various counts.
-   *
-   * The bit vectors are compared byte-by-byte, so any unused bits at the
-   * end must be zero.
-   *
-   * Returns the number of bytes required to hold the ULEB128 output.
-   *
-   * If "first_bit_changed_ptr" or "num_bits_changed_ptr" are non-NULL, they
-   * will receive the index of the first changed bit and the number of changed
-   * bits, respectively.
-   */
-  static int ComputeBitDiff(const uint8_t* bits1, const uint8_t* bits2,
-      int byte_width, int* first_bit_changed_ptr, int* num_bits_changed_ptr,
-      uint8_t* leb_out_buf);
-
-  /*
-   * Compress the register map with differential encoding.
-   *
-   * On success, returns a newly-allocated RegisterMap. If the map is not
-   * compatible for some reason, or fails to get smaller, this will return NULL.
-   */
-  static RegisterMap* CompressMapDifferential(const RegisterMap* map);
-
-  /*
-   * Expand a compressed map to an uncompressed form.
-   *
-   * Returns a newly-allocated RegisterMap on success, or NULL on failure.
-   *
-   * TODO: consider using the linear allocator or a custom allocator with
-   * LRU replacement for these instead of the native heap.
-   */
-  static RegisterMap* UncompressMapDifferential(const RegisterMap* map);
-
-
-  /* Verify a class. Returns "true" on success. */
-  static bool VerifyClass(Class* klass);
+  static Class* ClassJoin(Class* s, Class* t);
 
  private:
+  friend class RegTypeCache;
+
+  // Address given to an allocation_pc for an initialized object.
+  static const uint32_t kInitArgAddr = -2;
+
+  // Address given to an uninitialized allocation_pc if an object is uninitialized through being
+  // a constructor.
+  static const uint32_t kUninitThisArgAddr = -1;
+
+  RegType(Type type, Class* klass, uint32_t allocation_pc, uint16_t cache_id) :
+    type_(type), klass_(klass), allocation_pc_(allocation_pc), cache_id_(cache_id) {
+    DCHECK(type >= kRegTypeReference || allocation_pc_ == kInitArgAddr);
+  }
+
+  const Type type_;  // The current type of the register
+
+  // If known the type of the register
+  Class* klass_;
+
+  // Address an uninitialized reference was created
+  const uint32_t allocation_pc_;
+
+  // A RegType cache densely encodes types, this is the location in the cache for this type
+  const uint16_t cache_id_;
+
+  /*
+   * Merge result table for primitive values. The table is symmetric along the diagonal.
+   *
+   * Note that 32-bit int/float do not merge into 64-bit long/double. This is a register merge, not
+   * a widening conversion. Only the "implicit" widening within a category, e.g. byte to short, is
+   * allowed.
+   *
+   * Dalvik does not draw a distinction between int and float, but we enforce that once a value is
+   * used as int, it can't be used as float, and vice-versa. We do not allow free exchange between
+   * 32-bit int/float and 64-bit long/double.
+   *
+   * Note that Uninit + Uninit = Uninit. This holds true because we only use this when the RegType
+   * value is exactly equal to kRegTypeUninit, which can only happen for the zeroth entry in the
+   * table.
+   *
+   * "Unknown" never merges with anything known. The only time a register transitions from "unknown"
+   * to "known" is when we're executing code for the first time, and we handle that with a simple
+   * copy.
+   */
+  static const RegType::Type merge_table_[kRegTypeReference][kRegTypeReference];
+
+  DISALLOW_COPY_AND_ASSIGN(RegType);
+};
+std::ostream& operator<<(std::ostream& os, const RegType& rhs);
+
+class RegTypeCache {
+ public:
+  explicit RegTypeCache() : entries_(RegType::kRegTypeReference) {
+    Unknown();  // ensure Unknown is initialized
+  }
+  ~RegTypeCache() {
+    STLDeleteElements(&entries_);
+  }
+
+  const RegType& GetFromId(uint16_t id) {
+    DCHECK_LT(id, entries_.size());
+    RegType* result = entries_[id];
+    DCHECK(result != NULL);
+    return *result;
+  }
+
+  const RegType& From(RegType::Type type, const ClassLoader* loader, const std::string& descriptor);
+  const RegType& FromClass(Class* klass);
+  const RegType& FromCat1Const(int32_t value);
+  const RegType& FromDescriptor(const ClassLoader* loader, const std::string& descriptor);
+  const RegType& FromType(RegType::Type);
+
+  const RegType& Boolean() { return FromType(RegType::kRegTypeBoolean); }
+  const RegType& Byte()    { return FromType(RegType::kRegTypeByte); }
+  const RegType& Char()    { return FromType(RegType::kRegTypeChar); }
+  const RegType& Short()   { return FromType(RegType::kRegTypeShort); }
+  const RegType& Integer() { return FromType(RegType::kRegTypeInteger); }
+  const RegType& Float()   { return FromType(RegType::kRegTypeFloat); }
+  const RegType& Long()    { return FromType(RegType::kRegTypeLongLo); }
+  const RegType& Double()  { return FromType(RegType::kRegTypeDoubleLo); }
+
+  const RegType& JavaLangClass()  { return From(RegType::kRegTypeReference, NULL, "Ljava/lang/Class;"); }
+  const RegType& JavaLangObject() { return From(RegType::kRegTypeReference, NULL, "Ljava/lang/Object;"); }
+  const RegType& JavaLangString() { return From(RegType::kRegTypeReference, NULL, "Ljava/lang/String;"); }
+
+  const RegType& Unknown()  { return FromType(RegType::kRegTypeUnknown); }
+  const RegType& Conflict() { return FromType(RegType::kRegTypeConflict); }
+  const RegType& Zero()     { return FromType(RegType::kRegTypeZero); }
+  const RegType& ConstLo()  { return FromType(RegType::kRegTypeConstLo); }
+
+  const RegType& Uninitialized(Class* klass, uint32_t allocation_pc);
+  const RegType& UninitializedThisArgument(Class* klass);
+
+ private:
+  // The allocated entries
+  std::vector<RegType*> entries_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegTypeCache);
+};
+
+class InsnFlags {
+ public:
+  InsnFlags() : length_(0), flags_(0) {}
+
+  void SetLengthInCodeUnits(size_t length) {
+    CHECK_LT(length, 65536u);
+    length_ = length;
+  }
+  size_t GetLengthInCodeUnits() {
+    return length_;
+  }
+  bool IsOpcode() const {
+    return length_ != 0;
+  }
+
+  void SetInTry() {
+    flags_ |= 1 << kInsnFlagInTry;
+  }
+  void ClearInTry() {
+    flags_ &= ~(1 << kInsnFlagInTry);
+  }
+  bool IsInTry() const {
+    return (flags_ & (1 << kInsnFlagInTry)) != 0;
+  }
+
+  void SetBranchTarget() {
+    flags_ |= 1 << kInsnFlagBranchTarget;
+  }
+  void ClearBranchTarget() {
+    flags_ &= ~(1 << kInsnFlagBranchTarget);
+  }
+  bool IsBranchTarget() const {
+    return (flags_ & (1 << kInsnFlagBranchTarget)) != 0;
+  }
+
+  void SetGcPoint() {
+    flags_ |= 1 << kInsnFlagGcPoint;
+  }
+  void ClearGcPoint() {
+    flags_ &= ~(1 << kInsnFlagGcPoint);
+  }
+  bool IsGcPoint() const {
+    return (flags_ & (1 << kInsnFlagGcPoint)) != 0;
+  }
+
+  void SetVisited() {
+    flags_ |= 1 << kInsnFlagVisited;
+  }
+  void ClearVisited() {
+    flags_ &= ~(1 << kInsnFlagVisited);
+  }
+  bool IsVisited() const {
+    return (flags_ & (1 << kInsnFlagVisited)) != 0;
+  }
+
+  void SetChanged() {
+    flags_ |= 1 << kInsnFlagChanged;
+  }
+  void ClearChanged() {
+    flags_ &= ~(1 << kInsnFlagChanged);
+  }
+  bool IsChanged() const {
+    return (flags_ & (1 << kInsnFlagChanged)) != 0;
+  }
+
+  bool IsVisitedOrChanged() const {
+    return IsVisited() || IsChanged();
+  }
+
+  void Dump(std::ostream& os) {
+    char encoding[6];
+    if (!IsOpcode()) {
+      strncpy(encoding, "XXXXX", sizeof(encoding));
+    } else {
+      strncpy(encoding, "-----", sizeof(encoding));
+      if (IsInTry())        encoding[kInsnFlagInTry] = 'T';
+      if (IsBranchTarget()) encoding[kInsnFlagBranchTarget] = 'B';
+      if (IsGcPoint())      encoding[kInsnFlagGcPoint] = 'G';
+      if (IsVisited())      encoding[kInsnFlagVisited] = 'V';
+      if (IsChanged())      encoding[kInsnFlagChanged] = 'C';
+    }
+    os << encoding;
+  }
+ private:
+  enum InsnFlag {
+    kInsnFlagInTry,
+    kInsnFlagBranchTarget,
+    kInsnFlagGcPoint,
+    kInsnFlagVisited,
+    kInsnFlagChanged,
+  };
+
+  // Size of instruction in code units
+  uint16_t length_;
+  uint8_t flags_;
+};
+
+/*
+ * "Direct" and "virtual" methods are stored independently. The type of call used to invoke the
+ * method determines which list we search, and whether we travel up into superclasses.
+ *
+ * (<clinit>, <init>, and methods declared "private" or "static" are stored in the "direct" list.
+ * All others are stored in the "virtual" list.)
+ */
+enum MethodType {
+  METHOD_UNKNOWN  = 0,
+  METHOD_DIRECT,      // <init>, private
+  METHOD_STATIC,      // static
+  METHOD_VIRTUAL,     // virtual, super
+  METHOD_INTERFACE    // interface
+};
+
+const int kRegTypeUninitMask = 0xff;
+const int kRegTypeUninitShift = 8;
+
+/*
+ * Register type categories, for type checking.
+ *
+ * The spec says category 1 includes boolean, byte, char, short, int, float, reference, and
+ * returnAddress. Category 2 includes long and double.
+ *
+ * We treat object references separately, so we have "category1nr". We don't support jsr/ret, so
+ * there is no "returnAddress" type.
+ */
+enum TypeCategory {
+  kTypeCategoryUnknown = 0,
+  kTypeCategory1nr = 1,         // boolean, byte, char, short, int, float
+  kTypeCategory2 = 2,           // long, double
+  kTypeCategoryRef = 3,         // object reference
+};
+
+/*
+ * An enumeration of problems that can turn up during verification.
+ * VERIFY_ERROR_GENERIC denotes a failure that causes the entire class to be rejected. Other errors
+ * denote verification errors that cause bytecode to be rewritten to fail at runtime.
+ */
+enum VerifyError {
+  VERIFY_ERROR_NONE = 0,      /* no error; must be zero */
+  VERIFY_ERROR_GENERIC,       /* VerifyError */
+
+  VERIFY_ERROR_NO_CLASS,      /* NoClassDefFoundError */
+  VERIFY_ERROR_NO_FIELD,      /* NoSuchFieldError */
+  VERIFY_ERROR_NO_METHOD,     /* NoSuchMethodError */
+  VERIFY_ERROR_ACCESS_CLASS,  /* IllegalAccessError */
+  VERIFY_ERROR_ACCESS_FIELD,  /* IllegalAccessError */
+  VERIFY_ERROR_ACCESS_METHOD, /* IllegalAccessError */
+  VERIFY_ERROR_CLASS_CHANGE,  /* IncompatibleClassChangeError */
+  VERIFY_ERROR_INSTANTIATION, /* InstantiationError */
+};
+std::ostream& operator<<(std::ostream& os, const VerifyError& rhs);
+
+/*
+ * Identifies the type of reference in the instruction that generated the verify error
+ * (e.g. VERIFY_ERROR_ACCESS_CLASS could come from a method, field, or class reference).
+ *
+ * This must fit in two bits.
+ */
+enum VerifyErrorRefType {
+  VERIFY_ERROR_REF_CLASS  = 0,
+  VERIFY_ERROR_REF_FIELD  = 1,
+  VERIFY_ERROR_REF_METHOD = 2,
+};
+const int kVerifyErrorRefTypeShift = 6;
+
+/*
+ * Format enumeration for RegisterMap data area.
+ */
+enum RegisterMapFormat {
+  kRegMapFormatUnknown = 0,
+  kRegMapFormatNone,          /* indicates no map data follows */
+  kRegMapFormatCompact8,      /* compact layout, 8-bit addresses */
+  kRegMapFormatCompact16,     /* compact layout, 16-bit addresses */
+};
+
+// During verification, we associate one of these with every "interesting" instruction. We track
+// the status of all registers, and (if the method has any monitor-enter instructions) maintain a
+// stack of entered monitors (identified by code unit offset).
+// If live-precise register maps are enabled, the "liveRegs" vector will be populated. Unlike the
+// other lists of registers here, we do not track the liveness of the method result register
+// (which is not visible to the GC).
+class RegisterLine {
+ public:
+  RegisterLine(size_t num_regs, DexVerifier* verifier) :
+    line_(new uint16_t[num_regs]), verifier_(verifier), num_regs_(num_regs) {
+    memset(line_.get(), 0, num_regs_ * sizeof(uint16_t));
+    result_[0] = RegType::kRegTypeUnknown;
+    result_[1] = RegType::kRegTypeUnknown;
+  }
+
+  // Implement category-1 "move" instructions. Copy a 32-bit value from "vsrc" to "vdst".
+  void CopyRegister1(uint32_t vdst, uint32_t vsrc, TypeCategory cat);
+
+  // Implement category-2 "move" instructions. Copy a 64-bit value from "vsrc" to "vdst". This
+  // copies both halves of the register.
+  void CopyRegister2(uint32_t vdst, uint32_t vsrc);
+
+  // Implement "move-result". Copy the category-1 value from the result register to another
+  // register, and reset the result register.
+  void CopyResultRegister1(uint32_t vdst, bool is_reference);
+
+  // Implement "move-result-wide". Copy the category-2 value from the result register to another
+  // register, and reset the result register.
+  void CopyResultRegister2(uint32_t vdst);
+
+  // Set the invisible result register to unknown
+  void SetResultTypeToUnknown();
+
+  // Set the type of register N, verifying that the register is valid.  If "newType" is the "Lo"
+  // part of a 64-bit value, register N+1 will be set to "newType+1".
+  // The register index was validated during the static pass, so we don't need to check it here.
+  void SetRegisterType(uint32_t vdst, const RegType& new_type);
+
+  /* Set the type of the "result" register. */
+  void SetResultRegisterType(const RegType& new_type);
+
+  // Get the type of register vsrc.
+  const RegType& GetRegisterType(uint32_t vsrc) const;
+
+  bool VerifyRegisterType(uint32_t vsrc, const RegType& check_type);
+
+  void CopyFromLine(const RegisterLine* src) {
+    DCHECK_EQ(num_regs_, src->num_regs_);
+    memcpy(line_.get(), src->line_.get(), num_regs_ * sizeof(uint16_t));
+    monitors_ = src->monitors_;
+    reg_to_lock_depths_ = src->reg_to_lock_depths_;
+  }
+
+  void Dump(std::ostream& os) const {
+    for (size_t i = 0; i < num_regs_; i++) {
+      GetRegisterType(i).Dump(os);
+    }
+  }
+
+  void FillWithGarbage() {
+    memset(line_.get(), 0xf1, num_regs_ * sizeof(uint16_t));
+    while (!monitors_.empty()) {
+      monitors_.pop();
+    }
+    reg_to_lock_depths_.clear();
+  }
+
+  /*
+   * We're creating a new instance of class C at address A. Any registers holding instances
+   * previously created at address A must be initialized by now. If not, we mark them as "conflict"
+   * to prevent them from being used (otherwise, MarkRefsAsInitialized would mark the old ones and
+   * the new ones at the same time).
+   */
+  void MarkUninitRefsAsInvalid(const RegType& uninit_type);
+
+  /*
+   * Update all registers holding "uninit_type" to instead hold the corresponding initialized
+   * reference type. This is called when an appropriate constructor is invoked -- all copies of
+   * the reference must be marked as initialized.
+   */
+  void MarkRefsAsInitialized(const RegType& uninit_type);
+
+  /*
+   * Check constraints on constructor return. Specifically, make sure that the "this" argument got
+   * initialized.
+   * The "this" argument to <init> uses code offset kUninitThisArgAddr, which puts it at the start
+   * of the list in slot 0. If we see a register with an uninitialized slot 0 reference, we know it
+   * somehow didn't get initialized.
+   */
+  bool CheckConstructorReturn() const;
+
+  // Compare two register lines. Returns 0 if they match.
+  // Using this for a sort is unwise, since the value can change based on machine endianness.
+  int CompareLine(const RegisterLine* line2) const {
+    DCHECK(monitors_ == line2->monitors_);
+    // TODO: DCHECK(reg_to_lock_depths_ == line2->reg_to_lock_depths_);
+    return memcmp(line_.get(), line2->line_.get(), num_regs_ * sizeof(uint16_t));
+  }
+
+  size_t NumRegs() const {
+    return num_regs_;
+  }
+
+  /*
+   * Get the "this" pointer from a non-static method invocation. This returns the RegType so the
+   * caller can decide whether it needs the reference to be initialized or not. (Can also return
+   * kRegTypeZero if the reference can only be zero at this point.)
+   *
+   * The argument count is in vA, and the first argument is in vC, for both "simple" and "range"
+   * versions. We just need to make sure vA is >= 1 and then return vC.
+   */
+  const RegType& GetInvocationThis(const Instruction::DecodedInstruction& dec_insn);
+
+  /*
+   * Get the value from a register, and cast it to a Class. Sets "*failure" if something fails.
+   * This fails if the register holds an uninitialized class.
+   * If the register holds kRegTypeZero, this returns a NULL pointer.
+   */
+  Class* GetClassFromRegister(uint32_t vsrc) const;
+
+  /*
+   * Verify types for a simple two-register instruction (e.g. "neg-int").
+   * "dst_type" is stored into vA, and "src_type" is verified against vB.
+   */
+  void CheckUnaryOp(const Instruction::DecodedInstruction& dec_insn,
+                    const RegType& dst_type, const RegType& src_type);
+
+  /*
+   * Verify types for a simple three-register instruction (e.g. "add-int").
+   * "dst_type" is stored into vA, and "src_type1"/"src_type2" are verified
+   * against vB/vC.
+   */
+  void CheckBinaryOp(const Instruction::DecodedInstruction& dec_insn,
+                     const RegType& dst_type, const RegType& src_type1, const RegType& src_type2,
+                     bool check_boolean_op);
+
+  /*
+   * Verify types for a binary "2addr" operation. "src_type1"/"src_type2"
+   * are verified against vA/vB, then "dst_type" is stored into vA.
+   */
+  void CheckBinaryOp2addr(const Instruction::DecodedInstruction& dec_insn,
+                          const RegType& dst_type,
+                          const RegType& src_type1, const RegType& src_type2,
+                          bool check_boolean_op);
+
+  /*
+   * Verify types for A two-register instruction with a literal constant (e.g. "add-int/lit8").
+   * "dst_type" is stored into vA, and "src_type" is verified against vB.
+   *
+   * If "check_boolean_op" is set, we use the constant value in vC.
+   */
+  void CheckLiteralOp(const Instruction::DecodedInstruction& dec_insn,
+                      const RegType& dst_type, const RegType& src_type, bool check_boolean_op);
+
+  // Verify/push monitor onto the monitor stack, locking the value in reg_idx at location insn_idx.
+  void PushMonitor(uint32_t reg_idx, int32_t insn_idx);
+
+  // Verify/pop monitor from monitor stack ensuring that we believe the monitor is locked
+  void PopMonitor(uint32_t reg_idx);
+
+  // Stack of currently held monitors and where they were locked
+  size_t MonitorStackDepth() const {
+    return monitors_.size();
+  }
+
+  // We expect no monitors to be held at certain points, such a method returns. Verify the stack
+  // is empty, failing and returning false if not.
+  bool VerifyMonitorStackEmpty();
+
+  bool MergeRegisters(const RegisterLine* incoming_line);
+
+  size_t GetMaxReferenceReg(size_t max_ref_reg) {
+    size_t i = static_cast<int>(max_ref_reg) < 0 ? 0 : max_ref_reg;
+    for(; i < num_regs_; i++) {
+      if (line_[i] >= RegType::kRegTypeReference) {
+        max_ref_reg = i;
+      }
+    }
+    return max_ref_reg;
+  }
+
+  // Write a bit at each register location that holds a reference
+  void WriteReferenceBitMap(int8_t* data, size_t max_bytes);
+ private:
+
+  void CopyRegToLockDepth(size_t dst, size_t src) {
+    if (reg_to_lock_depths_.count(src) > 0) {
+      uint32_t depths = reg_to_lock_depths_[src];
+      reg_to_lock_depths_[dst] = depths;
+    }
+  }
+
+  bool IsSetLockDepth(size_t reg, size_t depth) {
+    if (reg_to_lock_depths_.count(reg) > 0) {
+      uint32_t depths = reg_to_lock_depths_[reg];
+      return (depths & (1 << depth)) != 0;
+    } else {
+      return false;
+    }
+  }
+
+  void SetRegToLockDepth(size_t reg, size_t depth) {
+    CHECK_LT(depth, 32u);
+    DCHECK(!IsSetLockDepth(reg, depth));
+    uint32_t depths;
+    if (reg_to_lock_depths_.count(reg) > 0) {
+      depths = reg_to_lock_depths_[reg];
+      depths = depths | (1 << depth);
+    } else {
+      depths = 1 << depth;
+    }
+    reg_to_lock_depths_[reg] = depths;
+  }
+
+  void ClearRegToLockDepth(size_t reg, size_t depth) {
+    CHECK_LT(depth, 32u);
+    DCHECK(IsSetLockDepth(reg, depth));
+    uint32_t depths = reg_to_lock_depths_[reg];
+    depths = depths ^ (1 << depth);
+    if (depths != 0) {
+      reg_to_lock_depths_[reg] = depths;
+    } else {
+      reg_to_lock_depths_.erase(reg);
+    }
+  }
+
+  void ClearAllRegToLockDepths(size_t reg) {
+    reg_to_lock_depths_.erase(reg);
+  }
+
+  // Storage for the result register's type, valid after an invocation
+  uint16_t result_[2];
+
+  // An array of RegType Ids associated with each dex register
+  UniquePtr<uint16_t[]> line_;
+
+  // Back link to the verifier
+  DexVerifier* verifier_;
+
+  // Length of reg_types_
+  const size_t num_regs_;
+  // A stack of monitor enter locations
+  std::stack<uint32_t> monitors_;
+  // A map from register to a bit vector of indices into the monitors_ stack. As we pop the monitor
+  // stack we verify that monitor-enter/exit are correctly nested. That is, if there was a
+  // monitor-enter on v5 and then on v6, we expect the monitor-exit to be on v6 then on v5
+  std::map<uint32_t, uint32_t> reg_to_lock_depths_;
+};
+std::ostream& operator<<(std::ostream& os, const RegisterLine& rhs);
+
+class PcToRegisterLineTable {
+ public:
+  // We don't need to store the register data for many instructions, because we either only need
+  // it at branch points (for verification) or GC points and branches (for verification +
+  // type-precise register analysis).
+  enum RegisterTrackingMode {
+    kTrackRegsBranches,
+    kTrackRegsGcPoints,
+    kTrackRegsAll,
+  };
+  PcToRegisterLineTable() {}
+  ~PcToRegisterLineTable() {
+    STLDeleteValues(&pc_to_register_line_);
+  }
+
+  // Initialize the RegisterTable. Every instruction address can have a different set of information
+  // about what's in which register, but for verification purposes we only need to store it at
+  // branch target addresses (because we merge into that).
+  void Init(RegisterTrackingMode mode, InsnFlags* flags, uint32_t insns_size,
+            uint16_t registers_size, DexVerifier* verifier);
+
+  RegisterLine* GetLine(size_t idx) {
+    return pc_to_register_line_[idx];
+  }
+
+ private:
+  // Map from a dex pc to the register status associated with it
+  std::map<int32_t, RegisterLine*> pc_to_register_line_;
+
+  // Number of registers we track for each instruction. This is equal to the method's declared
+  // "registersSize" plus kExtraRegs (2).
+  size_t insn_reg_count_plus_;
+};
+
+
+
+// The verifier
+class DexVerifier {
+ public:
+  /* Verify a class. Returns "true" on success. */
+  static bool VerifyClass(const Class* klass);
   /*
    * Perform verification on a single method.
    *
@@ -715,12 +831,74 @@
    */
   static bool VerifyMethod(Method* method);
 
+  uint8_t EncodePcToReferenceMapData() const;
+
+  uint32_t DexFileVersion() const {
+    return dex_file_->GetVersion();
+  }
+
+  RegTypeCache* GetRegTypeCache() {
+    return &reg_types_;
+  }
+
+  // Verification failed
+  std::ostream& Fail(VerifyError error) {
+    CHECK_EQ(failure_, VERIFY_ERROR_NONE);
+    failure_ = error;
+    return fail_messages_ << "VFY: " << PrettyMethod(method_)
+                          << '[' << (void*)work_insn_idx_ << "] : ";
+  }
+
+  // Log for verification information
+  std::ostream& LogVerifyInfo() {
+    return info_messages_ << "VFY: " << PrettyMethod(method_)
+                          << '[' << (void*)work_insn_idx_ << "] : ";
+  }
+
+  // Dump the state of the verifier, namely each instruction, what flags are set on it, register
+  // information
+  void Dump(std::ostream& os);
+
+ private:
+
+  explicit DexVerifier(Method* method);
+
+  bool Verify();
+
+  /*
+   * Compute the width of the instruction at each address in the instruction stream, and store it in
+   * insn_flags_. Addresses that are in the middle of an instruction, or that are part of switch
+   * table data, are not touched (so the caller should probably initialize "insn_flags" to zero).
+   *
+   * The "new_instance_count_" and "monitor_enter_count_" fields in vdata are also set.
+   *
+   * Performs some static checks, notably:
+   * - opcode of first instruction begins at index 0
+   * - only documented instructions may appear
+   * - each instruction follows the last
+   * - last byte of last instruction is at (code_length-1)
+   *
+   * Logs an error and returns "false" on failure.
+   */
+  bool ComputeWidthsAndCountOps();
+
+  /*
+   * 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.
+   */
+  bool ScanTryCatchBlocks();
+
   /*
    * Perform static verification on all instructions in a method.
    *
    * Walks through instructions in a method calling VerifyInstruction on each.
    */
-  static bool VerifyInstructions(VerifierData* vdata);
+  bool VerifyInstructions();
 
   /*
    * Perform static verification on an instruction.
@@ -755,318 +933,82 @@
    * - (earlier) for each exception handler, the handler must start at a valid
    *   instruction
    */
-  static bool VerifyInstruction(VerifierData* vdata,
-      const Instruction* inst, uint32_t code_offset);
-
-  /* Perform detailed code-flow analysis on a single method. */
-  static bool VerifyCodeFlow(VerifierData* vdata);
-
-  /*
-   * Compute the width of the instruction at each address in the instruction
-   * stream, and store it in vdata->insn_flags. Addresses that are in the
-   * middle of an instruction, or that are part of switch table data, are not
-   * touched (so the caller should probably initialize "insn_flags" to zero).
-   *
-   * The "new_instance_count_" and "monitor_enter_count_" fields in vdata are
-   * also set.
-   *
-   * Performs some static checks, notably:
-   * - opcode of first instruction begins at index 0
-   * - only documented instructions may appear
-   * - each instruction follows the last
-   * - last byte of last instruction is at (code_length-1)
-   *
-   * Logs an error and returns "false" on failure.
-   */
-  static bool ComputeWidthsAndCountOps(VerifierData* vdata);
-
-  /*
-   * 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(VerifierData* vdata);
-
-  /*
-   * Extract the relative offset from a branch instruction.
-   *
-   * Returns "false" on failure (e.g. this isn't a branch instruction).
-   */
-  static bool GetBranchOffset(const DexFile::CodeItem* code_item,
-      const InsnFlags insn_flags[], uint32_t cur_offset, int32_t* pOffset,
-      bool* pConditional, bool* selfOkay);
-
-  /*
-   * 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);
-
-  /*
-   * 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);
-
-  /*
-   * 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);
-
-  /*
-   * 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);
-
-  /*
-   * 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);
-
-  /*
-   * 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);
-
-  /* Ensure that the string index is in the valid range. */
-  static bool CheckStringIndex(const DexFile* dex_file, uint32_t idx);
+  bool VerifyInstruction(const Instruction* inst, uint32_t code_offset);
 
   /* Ensure that the register index is valid for this code item. */
-  static bool CheckRegisterIndex(const DexFile::CodeItem* code_item,
-      uint32_t idx);
+  bool CheckRegisterIndex(uint32_t idx);
 
   /* Ensure that the wide register index is valid for this code item. */
-  static bool CheckWideRegisterIndex(const DexFile::CodeItem* code_item,
-      uint32_t idx);
+  bool CheckWideRegisterIndex(uint32_t idx);
 
-  /*
-   * 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[]);
+  // 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.
+  bool CheckFieldIndex(uint32_t idx);
 
-  /*
-   * 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);
+  // Perform static checks on a method invocation instruction. All we do here is ensure that the
+  // method index is in the valid range.
+  bool CheckMethodIndex(uint32_t idx);
 
-  /*
-   * 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,
-      InsnFlags insn_flags[], uint32_t cur_offset);
+  // Perform static checks on a "new-instance" instruction. Specifically, make sure the class
+  // reference isn't for an array class.
+  bool CheckNewInstance(uint32_t idx);
 
-  /*
-   * 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 dex format forbids certain instructions from branching to itself.
-   *
-   * Updates "insnFlags", setting the "branch target" flag.
-   */
-  static bool CheckBranchTarget(const DexFile::CodeItem* code_item,
-      InsnFlags insn_flags[], uint32_t cur_offset);
+  /* Ensure that the string index is in the valid range. */
+  bool CheckStringIndex(uint32_t idx);
 
-  /*
-   * Initialize the RegisterTable.
-   *
-   * Every instruction address can have a different set of information about
-   * what's in which register, but for verification purposes we only need to
-   * store it at branch target addresses (because we merge into that).
-   *
-   * By zeroing out the regType storage we are effectively initializing the
-   * register information to kRegTypeUnknown.
-   *
-   * We jump through some hoops here to minimize the total number of
-   * allocations we have to perform per method verified.
-   */
-  static bool InitRegisterTable(VerifierData* vdata, RegisterTable* reg_table,
-      RegisterTrackingMode track_regs_for);
+  // Perform static checks on an instruction that takes a class constant. Ensure that the class
+  // index is in the valid range.
+  bool CheckTypeIndex(uint32_t idx);
 
-  /* Get the register line for the given instruction in the current method. */
-  static inline RegisterLine* GetRegisterLine(const RegisterTable* reg_table,
-      int insn_idx) {
-    return &reg_table->register_lines_[insn_idx];
-  }
+  // 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.
+  bool CheckNewArray(uint32_t idx);
 
-  /* Copy a register line. */
-  static inline void CopyRegisterLine(RegisterLine* dst,
-      const RegisterLine* src, size_t num_regs) {
-    memcpy(dst->reg_types_.get(), src->reg_types_.get(), num_regs * sizeof(RegType));
+  // Verify an array data table. "cur_offset" is the offset of the fill-array-data instruction.
+  bool CheckArrayData(uint32_t cur_offset);
 
-    DCHECK((src->monitor_entries_.get() == NULL && dst->monitor_entries_.get() == NULL) ||
-        (src->monitor_entries_.get() != NULL && dst->monitor_entries_.get() != NULL));
-    if (dst->monitor_entries_.get() != NULL) {
-      DCHECK(dst->monitor_stack_.get() != NULL);
-      memcpy(dst->monitor_entries_.get(), src->monitor_entries_.get(),
-          num_regs * sizeof(MonitorEntries));
-      memcpy(dst->monitor_stack_.get(), src->monitor_stack_.get(),
-          kMaxMonitorStackDepth * sizeof(uint32_t));
-      dst->monitor_stack_top_ = src->monitor_stack_top_;
-    }
-  }
+  // 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 dex format forbids certain instructions from branching to themselves.
+  // Updates "insnFlags", setting the "branch target" flag.
+  bool CheckBranchTarget(uint32_t cur_offset);
 
-  /* Copy a register line into the table. */
-  static inline void CopyLineToTable(RegisterTable* reg_table, int insn_idx,
-      const RegisterLine* src) {
-    RegisterLine* dst = GetRegisterLine(reg_table, insn_idx);
-    DCHECK(dst->reg_types_.get() != NULL);
-    CopyRegisterLine(dst, src, reg_table->insn_reg_count_plus_);
-  }
+  // Verify a switch table. "cur_offset" is the offset of the switch instruction.
+  // Updates "insnFlags", setting the "branch target" flag.
+  bool CheckSwitchTargets(uint32_t cur_offset);
 
-  /* Copy a register line out of the table. */
-  static inline void CopyLineFromTable(RegisterLine* dst,
-      const RegisterTable* reg_table, int insn_idx) {
-    RegisterLine* src = GetRegisterLine(reg_table, insn_idx);
-    DCHECK(src->reg_types_.get() != NULL);
-    CopyRegisterLine(dst, src, reg_table->insn_reg_count_plus_);
-  }
+  // 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.
+  bool CheckVarArgRegs(uint32_t vA, uint32_t arg[]);
 
-#ifndef NDEBUG
-  /*
-   * Compare two register lines. Returns 0 if they match.
-   *
-   * Using this for a sort is unwise, since the value can change based on
-   * machine endianness.
-   */
-  static inline int CompareLineToTable(const RegisterTable* reg_table,
-      int insn_idx, const RegisterLine* line2) {
-    const RegisterLine* line1 = GetRegisterLine(reg_table, insn_idx);
-    if (line1->monitor_entries_.get() != NULL) {
-      int result;
+  // 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.
+  bool CheckVarArgRangeRegs(uint32_t vA, uint32_t vC);
 
-      if (line2->monitor_entries_.get() == NULL)
-        return 1;
-      result = memcmp(line1->monitor_entries_.get(), line2->monitor_entries_.get(),
-          reg_table->insn_reg_count_plus_ * sizeof(MonitorEntries));
-      if (result != 0) {
-        LOG(ERROR) << "monitor_entries_ mismatch";
-        return result;
-      }
-      result = line1->monitor_stack_top_ - line2->monitor_stack_top_;
-      if (result != 0) {
-        LOG(ERROR) << "monitor_stack_top_ mismatch";
-        return result;
-      }
-      result = memcmp(line1->monitor_stack_.get(), line2->monitor_stack_.get(),
-            line1->monitor_stack_top_);
-      if (result != 0) {
-        LOG(ERROR) << "monitor_stack_ mismatch";
-        return result;
-      }
-    }
-    return memcmp(line1->reg_types_.get(), line2->reg_types_.get(),
-        reg_table->insn_reg_count_plus_ * sizeof(RegType));
-  }
-#endif
+  // Extract the relative offset from a branch instruction.
+  // Returns "false" on failure (e.g. this isn't a branch instruction).
+  bool GetBranchOffset(uint32_t cur_offset, int32_t* pOffset, bool* pConditional,
+                       bool* selfOkay);
 
-  /*
-   * Create a new uninitialized instance map.
-   *
-   * The map is allocated and populated with address entries. The addresses
-   * appear in ascending order to allow binary searching.
-   *
-   * Very few methods have 10 or more new-instance instructions; the
-   * majority have 0 or 1. Occasionally a static initializer will have 200+.
-   *
-   * TODO: merge this into the static pass or initRegisterTable; want to
-   * avoid walking through the instructions yet again just to set up this table
-   */
-  static UninitInstanceMap* CreateUninitInstanceMap(VerifierData* vdata);
+  /* Perform detailed code-flow analysis on a single method. */
+  bool VerifyCodeFlow();
 
-  /* Returns true if this method is a constructor. */
-  static bool IsInitMethod(const Method* method);
-
-  /*
-   * Look up a class reference given as a simple string descriptor.
-   *
-   * If we can't find it, return a generic substitute when possible.
-   */
-  static Class* LookupClassByDescriptor(const Method* method,
-      const char* descriptor, VerifyError* failure);
-
-  /*
-   * Look up a class reference in a signature. Could be an arg or the
-   * return value.
-   *
-   * Advances "*sig" to the last character in the signature (that is, to
-   * the ';').
-   *
-   * NOTE: this is also expected to verify the signature.
-   */
-  static Class* LookupSignatureClass(const Method* method, std::string sig,
-      VerifyError* failure);
-
-  /*
-   * Look up an array class reference in a signature. Could be an arg or the
-   * return value.
-   *
-   * Advances "*sig" to the last character in the signature.
-   *
-   * NOTE: this is also expected to verify the signature.
-   */
-  static Class* LookupSignatureArrayClass(const Method* method,
-      std::string sig, VerifyError* failure);
-
-  /*
-   * Set the register types for the first instruction in the method based on
-   * the method signature.
-   *
-   * This has the side-effect of validating the signature.
-   *
-   * Returns "true" on success.
-   */
-  static bool SetTypesFromSignature(VerifierData* vdata, RegType* reg_types);
-
-  /*
-   * Set the class object associated with the instruction at "addr".
-   *
-   * Returns the map slot index, or -1 if the address isn't listed in the map
-   * (shouldn't happen) or if a class is already associated with the address
-   * (bad bytecode).
-   *
-   * Entries, once set, do not change -- a given address can only allocate
-   * one type of object.
-   */
-  static int SetUninitInstance(UninitInstanceMap* uninit_map, int addr,
-      Class* klass);
+  // Set the register types for the first instruction in the method based on the method signature.
+  // This has the side-effect of validating the signature.
+  bool SetTypesFromSignature();
 
   /*
    * Perform code flow on a method.
    *
-   * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
-   * on the first instruction, process it (setting additional "changed" bits),
-   * and repeat until there are no more.
+   * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit on the first
+   * instruction, process it (setting additional "changed" bits), and repeat until there are no
+   * more.
    *
    * v3 4.11.1.1
    * - (N/A) operand stack is always the same size
@@ -1075,27 +1017,25 @@
    * - methods are invoked with the appropriate arguments
    * - fields are assigned using values of appropriate types
    * - opcodes have the correct type values in operand registers
-   * - there is never an uninitialized class instance in a local variable in
-   *   code protected by an exception handler (operand stack is okay, because
-   *   the operand stack is discarded when an exception is thrown) [can't
-   *   know what's a local var w/o the debug info -- should fall out of
+   * - there is never an uninitialized class instance in a local variable in code protected by an
+   *   exception handler (operand stack is okay, because the operand stack is discarded when an
+   *   exception is thrown) [can't know what's a local var w/o the debug info -- should fall out of
    *   register typing]
    *
    * v3 4.11.1.2
    * - execution cannot fall off the end of the code
    *
-   * (We also do many of the items described in the "static checks" sections,
-   * because it's easier to do them here.)
+   * (We also do many of the items described in the "static checks" sections, because it's easier to
+   * do them here.)
    *
-   * We need an array of RegType values, one per register, for every
-   * instruction. If the method uses monitor-enter, we need extra data
-   * for every register, and a stack for every "interesting" instruction.
-   * In theory this could become quite large -- up to several megabytes for
-   * a monster function.
+   * We need an array of RegType values, one per register, for every instruction. If the method uses
+   * monitor-enter, we need extra data for every register, and a stack for every "interesting"
+   * instruction. In theory this could become quite large -- up to several megabytes for a monster
+   * function.
    *
    * NOTE:
-   * The spec forbids backward branches when there's an uninitialized reference
-   * in a register. The idea is to prevent something like this:
+   * The spec forbids backward branches when there's an uninitialized reference in a register. The
+   * idea is to prevent something like this:
    *   loop:
    *     move r1, r0
    *     new-instance r0, MyClass
@@ -1103,571 +1043,85 @@
    *     if-eq rN, loop  // once
    *   initialize r0
    *
-   * This leaves us with two different instances, both allocated by the
-   * same instruction, but only one is initialized. The scheme outlined in
-   * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
-   * backward branches. We achieve identical results without restricting
-   * code reordering by specifying that you can't execute the new-instance
-   * instruction if a register contains an uninitialized instance created
-   * by that same instrutcion.
+   * This leaves us with two different instances, both allocated by the same instruction, but only
+   * one is initialized. The scheme outlined in v3 4.11.1.4 wouldn't catch this, so they work around
+   * it by preventing backward branches. We achieve identical results without restricting code
+   * reordering by specifying that you can't execute the new-instance instruction if a register
+   * contains an uninitialized instance created by that same instruction.
    */
-  static bool CodeFlowVerifyMethod(VerifierData* vdata,
-      RegisterTable* reg_table);
+  bool CodeFlowVerifyMethod();
 
   /*
    * Perform verification for a single instruction.
    *
-   * This requires fully decoding the instruction to determine the effect
-   * it has on registers.
+   * This requires fully decoding the instruction to determine the effect it has on registers.
    *
-   * Finds zero or more following instructions and sets the "changed" flag
-   * if execution at that point needs to be (re-)evaluated. Register changes
-   * are merged into "reg_types_" at the target addresses. Does not set or
-   * clear any other flags in "insn_flags".
+   * Finds zero or more following instructions and sets the "changed" flag if execution at that
+   * point needs to be (re-)evaluated. Register changes are merged into "reg_types_" at the target
+   * addresses. Does not set or clear any other flags in "insn_flags_".
    */
-  static bool CodeFlowVerifyInstruction(VerifierData* vdata,
-      RegisterTable* reg_table, uint32_t insn_idx, size_t* start_guess);
+  bool CodeFlowVerifyInstruction(uint32_t* start_guess);
+
+  // Perform verification of an aget instruction. The destination register's type will be set to
+  // be that of component type of the array unless the array type is unknown, in which case a
+  // bottom type inferred from the type of instruction is used. is_primitive is false for an
+  // aget-object.
+  void VerifyAGet(const Instruction::DecodedInstruction& insn, const RegType& insn_type,
+                  bool is_primitive);
+
+  // Perform verification of an aput instruction.
+  void VerifyAPut(const Instruction::DecodedInstruction& insn, const RegType& insn_type,
+                  bool is_primitive);
+
+  // Lookup instance field and fail for resolution violations
+  Field* GetInstanceField(const RegType& obj_type, int field_idx);
+
+  // Perform verification of an iget instruction.
+  void VerifyIGet(const Instruction::DecodedInstruction& insn, const RegType& insn_type,
+                  bool is_primitive);
+
+  // Perform verification of an iput instruction.
+  void VerifyIPut(const Instruction::DecodedInstruction& insn, const RegType& insn_type,
+                  bool is_primitive);
+
+  // Lookup static field and fail for resolution violations
+  Field* GetStaticField(int field_idx);
+
+  // Perform verification of an sget instruction.
+  void VerifySGet(const Instruction::DecodedInstruction& insn, const RegType& insn_type,
+                  bool is_primitive);
+
+  // Perform verification of an sput instruction.
+  void VerifySPut(const Instruction::DecodedInstruction& insn, const RegType& insn_type,
+                  bool is_primitive);
+
+  // Verify that the arguments in a filled-new-array instruction are valid.
+  // "res_class" is the class refered to by dec_insn->vB_.
+  void VerifyFilledNewArrayRegs(const Instruction::DecodedInstruction& dec_insn, Class* res_class,
+                                bool is_range);
 
   /*
-   * Replace an instruction with "throw-verification-error". This allows us to
-   * defer error reporting until the code path is first used.
-   *
-   * This is expected to be called during "just in time" verification, not
-   * from within dexopt. (Verification failures in dexopt will result in
-   * postponement of verification to first use of the class.)
-   *
-   * The throw-verification-error instruction requires two code units. Some
-   * of the replaced instructions require three; the third code unit will
-   * receive a "nop". The instruction's length will be left unchanged
-   * in "insn_flags".
-   *
-   * The VM postpones setting of debugger breakpoints in unverified classes,
-   * so there should be no clashes with the debugger.
-   *
-   * Returns "true" on success.
-   */
-  static bool ReplaceFailingInstruction(const DexFile::CodeItem* code_item,
-      int insn_idx, VerifyError failure);
-
-  /* Update a 16-bit opcode in a dex file. */
-  static void UpdateCodeUnit(const uint16_t* ptr, uint16_t new_val);
-
-  /* Handle a monitor-enter instruction. */
-  static void HandleMonitorEnter(RegisterLine* work_line, uint32_t reg_idx,
-      uint32_t insn_idx, VerifyError* failure);
-
-  /* Handle a monitor-exit instruction. */
-  static void HandleMonitorExit(RegisterLine* work_line, uint32_t reg_idx,
-      uint32_t insn_idx, VerifyError* failure);
-
-  /*
-   * Look up an instance field, specified by "field_idx", that is going to be
-   * accessed in object "obj_type". This resolves the field and then verifies
-   * that the class containing the field is an instance of the reference in
-   * "obj_type".
-   *
-   * It is possible for "obj_type" to be kRegTypeZero, meaning that we might
-   * have a null reference. This is a runtime problem, so we allow it,
-   * skipping some of the type checks.
-   *
-   * In general, "obj_type" must be an initialized reference. However, we
-   * allow it to be uninitialized if this is an "<init>" method and the field
-   * is declared within the "obj_type" class.
-   *
-   * Returns a Field on success, returns NULL and sets "*failure" on failure.
-   */
-  static Field* GetInstField(VerifierData* vdata, RegType obj_type,
-      int field_idx, VerifyError* failure);
-
-  /*
-   * Look up a static field.
-   *
-   * Returns a StaticField on success, returns NULL and sets "*failure"
-   * on failure.
-   */
-  static Field* GetStaticField(VerifierData* vdata, int field_idx,
-      VerifyError* failure);
-  /*
-   * For the "move-exception" instruction at "insn_idx", which must be at an
-   * exception handler address, determine the first common superclass of
-   * all exceptions that can land here. (For javac output, we're probably
-   * looking at multiple spans of bytecode covered by one "try" that lands
-   * at an exception-specific "catch", but in general the handler could be
-   * shared for multiple exceptions.)
-   *
-   * Returns NULL if no matching exception handler can be found, or if the
-   * exception is not a subclass of Throwable.
-   */
-  static Class* GetCaughtExceptionType(VerifierData* vdata, int insn_idx,
-      VerifyError* failure);
-
-  /*
-   * Get the type of register N.
-   *
-   * The register index was validated during the static pass, so we don't
-   * need to check it here.
-   */
-  static inline RegType GetRegisterType(const RegisterLine* register_line,
-      uint32_t vsrc) {
-    return register_line->reg_types_[vsrc];
-  }
-
-  /*
-   * Return the register type for the method. We can't just use the
-   * already-computed DalvikJniReturnType, because if it's a reference type
-   * we need to do the class lookup.
-   *
-   * Returned references are assumed to be initialized.
-   *
-   * Returns kRegTypeUnknown for "void".
-   */
-  static RegType GetMethodReturnType(const DexFile* dex_file,
-      const Method* method);
-
-  /*
-   * Get the value from a register, and cast it to a Class. Sets
-   * "*failure" if something fails.
-   *
-   * This fails if the register holds an uninitialized class.
-   *
-   * If the register holds kRegTypeZero, this returns a NULL pointer.
-   */
-  static Class* GetClassFromRegister(const RegisterLine* register_line,
-      uint32_t vsrc, VerifyError* failure);
-
-  /*
-   * Get the "this" pointer from a non-static method invocation. This
-   * returns the RegType so the caller can decide whether it needs the
-   * reference to be initialized or not. (Can also return kRegTypeZero
-   * if the reference can only be zero at this point.)
-   *
-   * The argument count is in vA, and the first argument is in vC, for both
-   * "simple" and "range" versions. We just need to make sure vA is >= 1
-   * and then return vC.
-   */
-  static RegType GetInvocationThis(const RegisterLine* register_line,
-      const Instruction::DecodedInstruction* dec_insn, VerifyError* failure);
-
-  /*
-   * Set the type of register N, verifying that the register is valid. If
-   * "new_type" is the "Lo" part of a 64-bit value, register N+1 will be
-   * set to "new_type+1".
-   *
-   * The register index was validated during the static pass, so we don't
-   * need to check it here.
-   *
-   * TODO: clear mon stack bits
-   */
-  static void SetRegisterType(RegisterLine* register_line, uint32_t vdst,
-      RegType new_type);
-
-  /*
-   * Verify that the contents of the specified register have the specified
-   * type (or can be converted to it through an implicit widening conversion).
-   *
-   * This will modify the type of the source register if it was originally
-   * derived from a constant to prevent mixing of int/float and long/double.
-   *
-   * If "vsrc" is a reference, both it and the "vsrc" register must be
-   * initialized ("vsrc" may be Zero). This will verify that the value in
-   * the register is an instance of check_type, or if check_type is an
-   * interface, verify that the register implements check_type.
-   */
-  static void VerifyRegisterType(RegisterLine* register_line, uint32_t vsrc,
-      RegType check_type, VerifyError* failure);
-
-  /* Set the type of the "result" register. */
-  static void SetResultRegisterType(RegisterLine* register_line,
-      const int insn_reg_count, RegType new_type);
-
-  /*
-   * Update all registers holding "uninit_type" to instead hold the
-   * corresponding initialized reference type. This is called when an
-   * appropriate <init> method is invoked -- all copies of the reference
-   * must be marked as initialized.
-   */
-  static void MarkRefsAsInitialized(RegisterLine* register_line,
-      int insn_reg_count, UninitInstanceMap* uninit_map, RegType uninit_type,
-      VerifyError* failure);
-
-  /*
-   * Implement category-1 "move" instructions. Copy a 32-bit value from
-   * "vsrc" to "vdst".
-   */
-  static void CopyRegister1(RegisterLine* register_line, uint32_t vdst,
-      uint32_t vsrc, TypeCategory cat, VerifyError* failure);
-
-  /*
-   * Implement category-2 "move" instructions. Copy a 64-bit value from
-   * "vsrc" to "vdst". This copies both halves of the register.
-   */
-  static void CopyRegister2(RegisterLine* register_line, uint32_t vdst,
-      uint32_t vsrc, VerifyError* failure);
-
-  /*
-   * Implement "move-result". Copy the category-1 value from the result
-   * register to another register, and reset the result register.
-   */
-  static void CopyResultRegister1(RegisterLine* register_line,
-      const int insn_reg_count, uint32_t vdst, TypeCategory cat,
-      VerifyError* failure);
-
-  /*
-   * Implement "move-result-wide". Copy the category-2 value from the result
-   * register to another register, and reset the result register.
-   */
-  static void CopyResultRegister2(RegisterLine* register_line,
-      const int insn_reg_count, uint32_t vdst, VerifyError* failure);
-
-  /*
-   * Compute the "class depth" of a class. This is the distance from the
-   * class to the top of the tree, chasing superclass links. java.lang.Object
-   * has a class depth of 0.
-   */
-  static int GetClassDepth(Class* klass);
-
-  /*
-   * Given two classes, walk up the superclass tree to find a common
-   * ancestor. (Called from findCommonSuperclass().)
-   *
-   * TODO: consider caching the class depth in the class object so we don't
-   * have to search for it here.
-   */
-  static Class* DigForSuperclass(Class* c1, Class* c2);
-
-  /*
-   * Merge two array classes. We can't use the general "walk up to the
-   * superclass" merge because the superclass of an array is always Object.
-   * We want String[] + Integer[] = Object[]. This works for higher dimensions
-   * as well, e.g. String[][] + Integer[][] = Object[][].
-   *
-   * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
-   *
-   * If Class implements Type, Class[] + Type[] = Type[].
-   *
-   * If the dimensions don't match, we want to convert to an array of Object
-   * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
-   *
-   * Arrays of primitive types effectively have one less dimension when
-   * merging. int[] + float[] = Object, int[] + String[] = Object,
-   * int[][] + float[][] = Object[], int[][] + String[] = Object[]. (The
-   * only time this function doesn't return an array class is when one of
-   * the arguments is a 1-dimensional primitive array.)
-   *
-   * This gets a little awkward because we may have to ask the VM to create
-   * a new array type with the appropriate element and dimensions. However, we
-   * shouldn't be doing this often.
-   */
-  static Class* FindCommonArraySuperclass(Class* c1, Class* c2);
-
-  /*
-   * Find the first common superclass of the two classes. We're not
-   * interested in common interfaces.
-   *
-   * The easiest way to do this for concrete classes is to compute the "class
-   * depth" of each, move up toward the root of the deepest one until they're
-   * at the same depth, then walk both up to the root until they match.
-   *
-   * If both classes are arrays, we need to merge based on array depth and
-   * element type.
-   *
-   * If one class is an interface, we check to see if the other class/interface
-   * (or one of its predecessors) implements the interface. If so, we return
-   * the interface; otherwise, we return Object.
-   *
-   * NOTE: we continue the tradition of "lazy interface handling". To wit,
-   * suppose we have three classes:
-   *   One implements Fancy, Free
-   *   Two implements Fancy, Free
-   *   Three implements Free
-   * where Fancy and Free are unrelated interfaces. The code requires us
-   * to merge One into Two. Ideally we'd use a common interface, which
-   * gives us a choice between Fancy and Free, and no guidance on which to
-   * use. If we use Free, we'll be okay when Three gets merged in, but if
-   * we choose Fancy, we're hosed. The "ideal" solution is to create a
-   * set of common interfaces and carry that around, merging further references
-   * into it. This is a pain. The easy solution is to simply boil them
-   * down to Objects and let the runtime invokeinterface call fail, which
-   * is what we do.
-   */
-  static Class* FindCommonSuperclass(Class* c1, Class* c2);
-
-  /*
-   * Resolves a class based on an index and performs access checks to ensure
-   * the referrer can access the resolved class.
-   *
+   * Resolves a class based on an index and performs access checks to ensure the referrer can
+   * access the resolved class.
    * Exceptions caused by failures are cleared before returning.
-   *
    * Sets "*failure" on failure.
    */
-  static Class* ResolveClassAndCheckAccess(const DexFile* dex_file,
-      uint32_t class_idx, const Class* referrer, VerifyError* failure);
+  Class* ResolveClassAndCheckAccess(uint32_t class_idx);
+
+  /*
+   * For the "move-exception" instruction at "work_insn_idx_", which must be at an exception handler
+   * address, determine the first common superclass of all exceptions that can land here.
+   * Returns NULL if no matching exception handler can be found, or if the exception is not a
+   * subclass of Throwable.
+   */
+  Class* GetCaughtExceptionType();
 
   /*
    * Resolves a method based on an index and performs access checks to ensure
    * the referrer can access the resolved method.
-   *
    * Does not throw exceptions.
-   *
-   * Sets "*failure" on failure.
    */
-  static Method* ResolveMethodAndCheckAccess(const DexFile* dex_file,
-      uint32_t method_idx, const Class* referrer, VerifyError* failure,
-      bool is_direct);
-
-  /*
-   * Resolves a field based on an index and performs access checks to ensure
-   * the referrer can access the resolved field.
-   *
-   * Exceptions caused by failures are cleared before returning.
-   *
-   * Sets "*failure" on failure.
-   */
-  static Field* ResolveFieldAndCheckAccess(const DexFile* dex_file,
-      uint32_t class_idx, const Class* referrer, VerifyError* failure,
-      bool is_static);
-
-  /*
-   * Merge two RegType values.
-   *
-   * Sets "*changed" to "true" if the result doesn't match "type1".
-   */
-  static RegType MergeTypes(RegType type1, RegType type2, bool* changed);
-
-  /*
-   * Merge the bits that indicate which monitor entry addresses on the stack
-   * are associated with this register.
-   *
-   * The merge is a simple bitwise AND.
-   *
-   * Sets "*changed" to "true" if the result doesn't match "ents1".
-   */
-  static MonitorEntries MergeMonitorEntries(MonitorEntries ents1,
-      MonitorEntries ents2, bool* changed);
-
-  /*
-   * We're creating a new instance of class C at address A. Any registers
-   * holding instances previously created at address A must be initialized
-   * by now. If not, we mark them as "conflict" to prevent them from being
-   * used (otherwise, MarkRefsAsInitialized would mark the old ones and the
-   * new ones at the same time).
-   */
-  static void MarkUninitRefsAsInvalid(RegisterLine* register_line,
-      int insn_reg_count, UninitInstanceMap* uninit_map, RegType uninit_type);
-
-  /*
-   * Control can transfer to "next_insn".
-   *
-   * Merge the registers from "work_line" into "reg_table" at "next_insn", and
-   * set the "changed" flag on the target address if any of the registers
-   * has changed.
-   *
-   * Returns "false" if we detect mismatched monitor stacks.
-   */
-  static bool UpdateRegisters(InsnFlags* insn_flags, RegisterTable* reg_table,
-      int next_insn, const RegisterLine* work_line);
-
-  /*
-   * Determine whether we can convert "src_type" to "check_type", where
-   * "check_type" is one of the category-1 non-reference types.
-   *
-   * Constant derived types may become floats, but other values may not.
-   */
-  static bool CanConvertTo1nr(RegType src_type, RegType check_type);
-
-  /* Determine whether the category-2 types are compatible. */
-  static bool CanConvertTo2(RegType src_type, RegType check_type);
-
-  /* Convert a VM PrimitiveType enum value to the equivalent RegType value. */
-  static RegType PrimitiveTypeToRegType(Class::PrimitiveType prim_type);
-
-  /*
-   * Convert a const derived RegType to the equivalent non-const RegType value.
-   * Does nothing if the argument type isn't const derived.
-   */
-  static RegType ConstTypeToRegType(RegType const_type);
-
-  /*
-   * Given a 32-bit constant, return the most-restricted RegType enum entry
-   * that can hold the value. The types used here indicate the value came
-   * from a const instruction, and may not correctly represent the real type
-   * of the value. Upon use, a constant derived type is updated with the
-   * type from the use, which will be unambiguous.
-   */
-  static char DetermineCat1Const(int32_t value);
-
-  /*
-   * If "field" is marked "final", make sure this is the either <clinit>
-   * or <init> as appropriate.
-   *
-   * Sets "*failure" on failure.
-   */
-  static void CheckFinalFieldAccess(const Method* method, const Field* field,
-      VerifyError* failure);
-
-  /*
-   * Make sure that the register type is suitable for use as an array index.
-   *
-   * Sets "*failure" if not.
-   */
-  static void CheckArrayIndexType(const Method* method, RegType reg_type,
-      VerifyError* failure);
-
-  /*
-   * Check constraints on constructor return. Specifically, make sure that
-   * the "this" argument got initialized.
-   *
-   * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
-   * puts it at the start of the list in slot 0. If we see a register with
-   * an uninitialized slot 0 reference, we know it somehow didn't get
-   * initialized.
-   *
-   * Returns "true" if all is well.
-   */
-  static bool CheckConstructorReturn(const Method* method,
-      const RegisterLine* register_line, const int insn_reg_count);
-
-  /*
-   * Verify that the target instruction is not "move-exception". It's important
-   * that the only way to execute a move-exception is as the first instruction
-   * of an exception handler.
-   *
-   * Returns "true" if all is well, "false" if the target instruction is
-   * move-exception.
-   */
-  static bool CheckMoveException(const uint16_t* insns, int insn_idx);
-
-  /*
-   * See if "type" matches "cat". All we're really looking for here is that
-   * we're not mixing and matching 32-bit and 64-bit quantities, and we're
-   * not mixing references with numerics. (For example, the arguments to
-   * "a < b" could be integers of different sizes, but they must both be
-   * integers. Dalvik is less specific about int vs. float, so we treat them
-   * as equivalent here.)
-   *
-   * For category 2 values, "type" must be the "low" half of the value.
-   *
-   * Sets "*failure" if something looks wrong.
-   */
-  static void CheckTypeCategory(RegType type, TypeCategory cat,
-      VerifyError* failure);
-
-  /*
-   * For a category 2 register pair, verify that "type_h" is the appropriate
-   * high part for "type_l".
-   *
-   * Does not verify that "type_l" is in fact the low part of a 64-bit
-   * register pair.
-   */
-  static void CheckWidePair(RegType type_l, RegType type_h,
-      VerifyError* failure);
-
-  /*
-   * Verify types for a simple two-register instruction (e.g. "neg-int").
-   * "dst_type" is stored into vA, and "src_type" is verified against vB.
-   */
-  static void CheckUnop(RegisterLine* register_line,
-      Instruction::DecodedInstruction* dec_insn, RegType dst_type,
-      RegType src_type, VerifyError* failure);
-
-  /*
-   * Verify types for a simple three-register instruction (e.g. "add-int").
-   * "dst_type" is stored into vA, and "src_type1"/"src_type2" are verified
-   * against vB/vC.
-   */
-  static void CheckBinop(RegisterLine* register_line,
-      Instruction::DecodedInstruction* dec_insn, RegType dst_type,
-      RegType src_type1, RegType src_type2, bool check_boolean_op,
-      VerifyError* failure);
-
-  /*
-   * Verify types for a binary "2addr" operation. "src_type1"/"src_type2"
-   * are verified against vA/vB, then "dst_type" is stored into vA.
-   */
-  static void CheckBinop2addr(RegisterLine* register_line,
-      Instruction::DecodedInstruction* dec_insn, RegType dst_type,
-      RegType src_type1, RegType src_type2, bool check_boolean_op,
-      VerifyError* failure);
-
-  /*
-   * Treat right-shifting as a narrowing conversion when possible.
-   *
-   * For example, right-shifting an int 24 times results in a value that can
-   * be treated as a byte.
-   *
-   * Things get interesting when contemplating sign extension. Right-
-   * shifting an integer by 16 yields a value that can be represented in a
-   * "short" but not a "char", but an unsigned right shift by 16 yields a
-   * value that belongs in a char rather than a short. (Consider what would
-   * happen if the result of the shift were cast to a char or short and then
-   * cast back to an int. If sign extension, or the lack thereof, causes
-   * a change in the 32-bit representation, then the conversion was lossy.)
-   *
-   * A signed right shift by 17 on an integer results in a short. An unsigned
-   * right shfit by 17 on an integer results in a posshort, which can be
-   * assigned to a short or a char.
-   *
-   * An unsigned right shift on a short can actually expand the result into
-   * a 32-bit integer. For example, 0xfffff123 >>> 8 becomes 0x00fffff1,
-   * which can't be represented in anything smaller than an int.
-   *
-   * javac does not generate code that takes advantage of this, but some
-   * of the code optimizers do. It's generally a peephole optimization
-   * that replaces a particular sequence, e.g. (bipush 24, ishr, i2b) is
-   * replaced by (bipush 24, ishr). Knowing that shifting a short 8 times
-   * to the right yields a byte is really more than we need to handle the
-   * code that's out there, but support is not much more complex than just
-   * handling integer.
-   *
-   * Right-shifting never yields a boolean value.
-   *
-   * Returns the new register type.
-   */
-  static RegType AdjustForRightShift(RegisterLine* register_line, int reg,
-      unsigned int shift_count, bool is_unsigned_shift);
-
-  /*
-   * We're performing an operation like "and-int/2addr" that can be
-   * performed on booleans as well as integers. We get no indication of
-   * boolean-ness, but we can infer it from the types of the arguments.
-   *
-   * Assumes we've already validated reg1/reg2.
-   *
-   * TODO: consider generalizing this. The key principle is that the
-   * result of a bitwise operation can only be as wide as the widest of
-   * the operands. You can safely AND/OR/XOR two chars together and know
-   * you still have a char, so it's reasonable for the compiler or "dx"
-   * to skip the int-to-char instruction. (We need to do this for boolean
-   * because there is no int-to-boolean operation.)
-   *
-   * Returns true if both args are Boolean, Zero, or One.
-   */
-  static bool UpcastBooleanOp(RegisterLine* register_line, uint32_t reg1,
-      uint32_t reg2);
-
-  /*
-   * Verify types for A two-register instruction with a literal constant
-   * (e.g. "add-int/lit8"). "dst_type" is stored into vA, and "src_type" is
-   * verified against vB.
-   *
-   * If "check_boolean_op" is set, we use the constant value in vC.
-   */
-  static void CheckLitop(RegisterLine* register_line,
-      Instruction::DecodedInstruction* dec_insn, RegType dst_type,
-      RegType src_type, bool check_boolean_op, VerifyError* failure);
-
-  /*
-   * Verify that the arguments in a filled-new-array instruction are valid.
-   *
-   * "res_class" is the class refered to by dec_insn->vB_.
-   */
-  static void VerifyFilledNewArrayRegs(const Method* method,
-      RegisterLine* register_line,
-      const Instruction::DecodedInstruction* dec_insn, Class* res_class,
-      bool is_range, VerifyError* failure);
-
-  /* See if the method matches the MethodType. */
-  static bool IsCorrectInvokeKind(MethodType method_type, Method* res_method);
+  Method* ResolveMethodAndCheckAccess(uint32_t method_idx,  bool is_direct);
 
   /*
    * Verify the arguments to a method. We're executing in "method", making
@@ -1691,19 +1145,170 @@
    * Returns the resolved method on success, NULL on failure (with *failure
    * set appropriately).
    */
-  static Method* VerifyInvocationArgs(VerifierData* vdata,
-      RegisterLine* register_line, const int insn_reg_count,
-      const Instruction::DecodedInstruction* dec_insn, MethodType method_type,
-      bool is_range, bool is_super, VerifyError* failure);
+  Method* VerifyInvocationArgs(const Instruction::DecodedInstruction& dec_insn,
+                               MethodType method_type, bool is_range, bool is_super);
 
-  /* Dump the register types for the specifed address to the log file. */
-  static void DumpRegTypes(const VerifierData* vdata,
-      const RegisterLine* register_line, int addr, const char* addr_name,
-      const UninitInstanceMap* uninit_map);
+  /*
+   * Return the register type for the method. We can't just use the already-computed
+   * DalvikJniReturnType, because if it's a reference type we need to do the class lookup.
+   * Returned references are assumed to be initialized. Returns kRegTypeUnknown for "void".
+   */
+  const RegType& GetMethodReturnType() {
+    return reg_types_.FromClass(method_->GetReturnType());
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(DexVerifier);
+  /*
+   * Verify that the target instruction is not "move-exception". It's important that the only way
+   * to execute a move-exception is as the first instruction of an exception handler.
+   * Returns "true" if all is well, "false" if the target instruction is move-exception.
+   */
+  bool CheckMoveException(const uint16_t* insns, int insn_idx);
+
+  /*
+   * Replace an instruction with "throw-verification-error". This allows us to
+   * defer error reporting until the code path is first used.
+   */
+  void ReplaceFailingInstruction();
+
+  /*
+  * Control can transfer to "next_insn". Merge the registers from merge_line into the table at
+  * next_insn, and set the changed flag on the target address if any of the registers were changed.
+  * Returns "false" if an error is encountered.
+  */
+  bool UpdateRegisters(uint32_t next_insn, const RegisterLine* merge_line);
+
+  /*
+   * Generate the GC map for a method that has just been verified (i.e. we're doing this as part of
+   * verification). For type-precise determination we have all the data we need, so we just need to
+   * encode it in some clever fashion.
+   * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
+   */
+  ByteArray* GenerateGcMap();
+
+  // Verify that the GC map associated with method_ is well formed
+  void VerifyGcMap();
+
+  // Compute sizes for GC map data
+  void ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
+
+  Class* JavaLangThrowable();
+
+  InsnFlags CurrentInsnFlags() {
+    return insn_flags_[work_insn_idx_];
+  }
+
+  RegTypeCache reg_types_;
+
+  PcToRegisterLineTable reg_table_;
+
+  // Storage for the register status we're currently working on.
+  UniquePtr<RegisterLine> work_line_;
+
+  // Lazily initialized reference to java.lang.Class<java.lang.Throwable>
+  Class* java_lang_throwable_;
+
+  // The address of the instruction we're currently working on, note that this is in 2 byte
+  // quantities
+  uint32_t work_insn_idx_;
+
+  // Storage for the register status we're saving for later.
+  UniquePtr<RegisterLine> saved_line_;
+
+  Method* method_;  // The method we're working on.
+  const DexFile* dex_file_;  // The dex file containing the method.
+  const DexFile::CodeItem* code_item_;  // The code item containing the code for the method.
+  UniquePtr<InsnFlags[]> insn_flags_;  // Instruction widths and flags, one entry per code unit.
+
+  // The type of any error that occurs
+  VerifyError failure_;
+
+  // Failure message log
+  std::ostringstream fail_messages_;
+  // Info message log
+  std::ostringstream info_messages_;
+
+  // The number of occurrences of specific opcodes.
+  size_t new_instance_count_;
+  size_t monitor_enter_count_;
 };
 
+// Lightweight wrapper for PC to reference bit maps.
+class PcToReferenceMap {
+ public:
+  PcToReferenceMap(Method* m) {
+    data_ = down_cast<ByteArray*>(m->GetGcMap());
+    CHECK(data_ != NULL);
+    // Check the size of the table agrees with the number of entries
+    size_t data_size = data_->GetLength() - 4;
+    DCHECK_EQ(EntryWidth() * NumEntries(), data_size);
+  }
+
+  // The number of entries in the table
+  size_t NumEntries() const {
+    return GetData()[2] | (GetData()[3] << 8);
+  }
+
+  // Get the PC at the given index
+  uint16_t GetPC(size_t index) const {
+    size_t entry_offset = index * EntryWidth();
+    if (PcWidth() == 1) {
+      return Table()[entry_offset];
+    } else {
+      return Table()[entry_offset] | (Table()[entry_offset + 1] << 8);
+    }
+  }
+
+  // Return address of bitmap encoding what are live references
+  const uint8_t* GetBitMap(size_t index) const {
+    size_t entry_offset = index * EntryWidth();
+    return &Table()[entry_offset + PcWidth()];
+  }
+
+  // Find the bitmap associated with the given dex pc
+  const uint8_t* FindBitMap(uint16_t dex_pc, bool error_if_not_present = true) const;
+
+  // The number of bytes used to encode registers
+  size_t RegWidth() const {
+    return GetData()[1];
+  }
+
+ private:
+  // Table of num_entries * (dex pc, bitmap)
+  const uint8_t* Table() const {
+    return GetData() + 4;
+  }
+
+  // The format of the table of the PCs for the table
+  RegisterMapFormat Format() const {
+    return static_cast<RegisterMapFormat>(GetData()[0]);
+  }
+
+  // Number of bytes used to encode a dex pc
+  size_t PcWidth() const {
+    RegisterMapFormat format = Format();
+    switch (format) {
+      case kRegMapFormatCompact8:
+        return 1;
+      case kRegMapFormatCompact16:
+        return 2;
+      default:
+        LOG(FATAL) << "Invalid format " << static_cast<int>(format);
+        return -1;
+    }
+  }
+
+  // The width of an entry in the table
+  size_t EntryWidth() const {
+    return PcWidth() + RegWidth();
+  }
+
+  const uint8_t* GetData() const {
+    return reinterpret_cast<uint8_t*>(data_->GetData());
+  }
+  ByteArray* data_;  // The header and table data
+};
+
+}  // namespace verifier
 }  // namespace art
 
 #endif  // ART_SRC_DEX_VERIFY_H_
diff --git a/src/dex_verifier_test.cc b/src/dex_verifier_test.cc
index 0560abf..e6447ba 100644
--- a/src/dex_verifier_test.cc
+++ b/src/dex_verifier_test.cc
@@ -10,6 +10,7 @@
 #include "dex_file.h"
 
 namespace art {
+namespace verifier {
 
 class DexVerifierTest : public CommonTest {
  protected:
@@ -43,4 +44,264 @@
   ASSERT_TRUE(DexVerifier::VerifyClass(klass));
 }
 
+TEST_F(DexVerifierTest, RegTypes_Primitives) {
+  RegTypeCache cache;
+
+  const RegType& bool_reg_type = cache.Boolean();
+  EXPECT_FALSE(bool_reg_type.IsUnknown());
+  EXPECT_FALSE(bool_reg_type.IsConflict());
+  EXPECT_FALSE(bool_reg_type.IsZero());
+  EXPECT_FALSE(bool_reg_type.IsOne());
+  EXPECT_FALSE(bool_reg_type.IsConstLo());
+  EXPECT_TRUE(bool_reg_type.IsBoolean());
+  EXPECT_FALSE(bool_reg_type.IsByte());
+  EXPECT_FALSE(bool_reg_type.IsChar());
+  EXPECT_FALSE(bool_reg_type.IsShort());
+  EXPECT_FALSE(bool_reg_type.IsInteger());
+  EXPECT_FALSE(bool_reg_type.IsLong());
+  EXPECT_FALSE(bool_reg_type.IsFloat());
+  EXPECT_FALSE(bool_reg_type.IsDouble());
+  EXPECT_FALSE(bool_reg_type.IsReference());
+  EXPECT_FALSE(bool_reg_type.IsLowHalf());
+  EXPECT_FALSE(bool_reg_type.IsHighHalf());
+  EXPECT_FALSE(bool_reg_type.IsLongOrDoubleTypes());
+  EXPECT_FALSE(bool_reg_type.IsReferenceTypes());
+  EXPECT_TRUE(bool_reg_type.IsCategory1Types());
+  EXPECT_FALSE(bool_reg_type.IsCategory2Types());
+  EXPECT_TRUE(bool_reg_type.IsBooleanTypes());
+  EXPECT_TRUE(bool_reg_type.IsByteTypes());
+  EXPECT_TRUE(bool_reg_type.IsShortTypes());
+  EXPECT_TRUE(bool_reg_type.IsCharTypes());
+  EXPECT_TRUE(bool_reg_type.IsIntegralTypes());
+  EXPECT_FALSE(bool_reg_type.IsFloatTypes());
+  EXPECT_FALSE(bool_reg_type.IsLongTypes());
+  EXPECT_FALSE(bool_reg_type.IsDoubleTypes());
+  EXPECT_TRUE(bool_reg_type.IsArrayIndexTypes());
+
+  const RegType& byte_reg_type = cache.Byte();
+  EXPECT_FALSE(byte_reg_type.IsUnknown());
+  EXPECT_FALSE(byte_reg_type.IsConflict());
+  EXPECT_FALSE(byte_reg_type.IsZero());
+  EXPECT_FALSE(byte_reg_type.IsOne());
+  EXPECT_FALSE(byte_reg_type.IsConstLo());
+  EXPECT_FALSE(byte_reg_type.IsBoolean());
+  EXPECT_TRUE(byte_reg_type.IsByte());
+  EXPECT_FALSE(byte_reg_type.IsChar());
+  EXPECT_FALSE(byte_reg_type.IsShort());
+  EXPECT_FALSE(byte_reg_type.IsInteger());
+  EXPECT_FALSE(byte_reg_type.IsLong());
+  EXPECT_FALSE(byte_reg_type.IsFloat());
+  EXPECT_FALSE(byte_reg_type.IsDouble());
+  EXPECT_FALSE(byte_reg_type.IsReference());
+  EXPECT_FALSE(byte_reg_type.IsLowHalf());
+  EXPECT_FALSE(byte_reg_type.IsHighHalf());
+  EXPECT_FALSE(byte_reg_type.IsLongOrDoubleTypes());
+  EXPECT_FALSE(byte_reg_type.IsReferenceTypes());
+  EXPECT_TRUE(byte_reg_type.IsCategory1Types());
+  EXPECT_FALSE(byte_reg_type.IsCategory2Types());
+  EXPECT_FALSE(byte_reg_type.IsBooleanTypes());
+  EXPECT_TRUE(byte_reg_type.IsByteTypes());
+  EXPECT_TRUE(byte_reg_type.IsShortTypes());
+  EXPECT_FALSE(byte_reg_type.IsCharTypes());
+  EXPECT_TRUE(byte_reg_type.IsIntegralTypes());
+  EXPECT_FALSE(byte_reg_type.IsFloatTypes());
+  EXPECT_FALSE(byte_reg_type.IsLongTypes());
+  EXPECT_FALSE(byte_reg_type.IsDoubleTypes());
+  EXPECT_TRUE(byte_reg_type.IsArrayIndexTypes());
+
+  const RegType& char_reg_type = cache.Char();
+  EXPECT_FALSE(char_reg_type.IsUnknown());
+  EXPECT_FALSE(char_reg_type.IsConflict());
+  EXPECT_FALSE(char_reg_type.IsZero());
+  EXPECT_FALSE(char_reg_type.IsOne());
+  EXPECT_FALSE(char_reg_type.IsConstLo());
+  EXPECT_FALSE(char_reg_type.IsBoolean());
+  EXPECT_FALSE(char_reg_type.IsByte());
+  EXPECT_TRUE(char_reg_type.IsChar());
+  EXPECT_FALSE(char_reg_type.IsShort());
+  EXPECT_FALSE(char_reg_type.IsInteger());
+  EXPECT_FALSE(char_reg_type.IsLong());
+  EXPECT_FALSE(char_reg_type.IsFloat());
+  EXPECT_FALSE(char_reg_type.IsDouble());
+  EXPECT_FALSE(char_reg_type.IsReference());
+  EXPECT_FALSE(char_reg_type.IsLowHalf());
+  EXPECT_FALSE(char_reg_type.IsHighHalf());
+  EXPECT_FALSE(char_reg_type.IsLongOrDoubleTypes());
+  EXPECT_FALSE(char_reg_type.IsReferenceTypes());
+  EXPECT_TRUE(char_reg_type.IsCategory1Types());
+  EXPECT_FALSE(char_reg_type.IsCategory2Types());
+  EXPECT_FALSE(char_reg_type.IsBooleanTypes());
+  EXPECT_FALSE(char_reg_type.IsByteTypes());
+  EXPECT_FALSE(char_reg_type.IsShortTypes());
+  EXPECT_TRUE(char_reg_type.IsCharTypes());
+  EXPECT_TRUE(char_reg_type.IsIntegralTypes());
+  EXPECT_FALSE(char_reg_type.IsFloatTypes());
+  EXPECT_FALSE(char_reg_type.IsLongTypes());
+  EXPECT_FALSE(char_reg_type.IsDoubleTypes());
+  EXPECT_TRUE(char_reg_type.IsArrayIndexTypes());
+
+  const RegType& short_reg_type = cache.Short();
+  EXPECT_FALSE(short_reg_type.IsUnknown());
+  EXPECT_FALSE(short_reg_type.IsConflict());
+  EXPECT_FALSE(short_reg_type.IsZero());
+  EXPECT_FALSE(short_reg_type.IsOne());
+  EXPECT_FALSE(short_reg_type.IsConstLo());
+  EXPECT_FALSE(short_reg_type.IsBoolean());
+  EXPECT_FALSE(short_reg_type.IsByte());
+  EXPECT_FALSE(short_reg_type.IsChar());
+  EXPECT_TRUE(short_reg_type.IsShort());
+  EXPECT_FALSE(short_reg_type.IsInteger());
+  EXPECT_FALSE(short_reg_type.IsLong());
+  EXPECT_FALSE(short_reg_type.IsFloat());
+  EXPECT_FALSE(short_reg_type.IsDouble());
+  EXPECT_FALSE(short_reg_type.IsReference());
+  EXPECT_FALSE(short_reg_type.IsLowHalf());
+  EXPECT_FALSE(short_reg_type.IsHighHalf());
+  EXPECT_FALSE(short_reg_type.IsLongOrDoubleTypes());
+  EXPECT_FALSE(short_reg_type.IsReferenceTypes());
+  EXPECT_TRUE(short_reg_type.IsCategory1Types());
+  EXPECT_FALSE(short_reg_type.IsCategory2Types());
+  EXPECT_FALSE(short_reg_type.IsBooleanTypes());
+  EXPECT_FALSE(short_reg_type.IsByteTypes());
+  EXPECT_TRUE(short_reg_type.IsShortTypes());
+  EXPECT_FALSE(short_reg_type.IsCharTypes());
+  EXPECT_TRUE(short_reg_type.IsIntegralTypes());
+  EXPECT_FALSE(short_reg_type.IsFloatTypes());
+  EXPECT_FALSE(short_reg_type.IsLongTypes());
+  EXPECT_FALSE(short_reg_type.IsDoubleTypes());
+  EXPECT_TRUE(short_reg_type.IsArrayIndexTypes());
+
+  const RegType& int_reg_type = cache.Integer();
+  EXPECT_FALSE(int_reg_type.IsUnknown());
+  EXPECT_FALSE(int_reg_type.IsConflict());
+  EXPECT_FALSE(int_reg_type.IsZero());
+  EXPECT_FALSE(int_reg_type.IsOne());
+  EXPECT_FALSE(int_reg_type.IsConstLo());
+  EXPECT_FALSE(int_reg_type.IsBoolean());
+  EXPECT_FALSE(int_reg_type.IsByte());
+  EXPECT_FALSE(int_reg_type.IsChar());
+  EXPECT_FALSE(int_reg_type.IsShort());
+  EXPECT_TRUE(int_reg_type.IsInteger());
+  EXPECT_FALSE(int_reg_type.IsLong());
+  EXPECT_FALSE(int_reg_type.IsFloat());
+  EXPECT_FALSE(int_reg_type.IsDouble());
+  EXPECT_FALSE(int_reg_type.IsReference());
+  EXPECT_FALSE(int_reg_type.IsLowHalf());
+  EXPECT_FALSE(int_reg_type.IsHighHalf());
+  EXPECT_FALSE(int_reg_type.IsLongOrDoubleTypes());
+  EXPECT_FALSE(int_reg_type.IsReferenceTypes());
+  EXPECT_TRUE(int_reg_type.IsCategory1Types());
+  EXPECT_FALSE(int_reg_type.IsCategory2Types());
+  EXPECT_FALSE(int_reg_type.IsBooleanTypes());
+  EXPECT_FALSE(int_reg_type.IsByteTypes());
+  EXPECT_FALSE(int_reg_type.IsShortTypes());
+  EXPECT_FALSE(int_reg_type.IsCharTypes());
+  EXPECT_TRUE(int_reg_type.IsIntegralTypes());
+  EXPECT_FALSE(int_reg_type.IsFloatTypes());
+  EXPECT_FALSE(int_reg_type.IsLongTypes());
+  EXPECT_FALSE(int_reg_type.IsDoubleTypes());
+  EXPECT_TRUE(int_reg_type.IsArrayIndexTypes());
+
+  const RegType& long_reg_type = cache.Long();
+  EXPECT_FALSE(long_reg_type.IsUnknown());
+  EXPECT_FALSE(long_reg_type.IsConflict());
+  EXPECT_FALSE(long_reg_type.IsZero());
+  EXPECT_FALSE(long_reg_type.IsOne());
+  EXPECT_FALSE(long_reg_type.IsConstLo());
+  EXPECT_FALSE(long_reg_type.IsBoolean());
+  EXPECT_FALSE(long_reg_type.IsByte());
+  EXPECT_FALSE(long_reg_type.IsChar());
+  EXPECT_FALSE(long_reg_type.IsShort());
+  EXPECT_FALSE(long_reg_type.IsInteger());
+  EXPECT_TRUE(long_reg_type.IsLong());
+  EXPECT_FALSE(long_reg_type.IsFloat());
+  EXPECT_FALSE(long_reg_type.IsDouble());
+  EXPECT_FALSE(long_reg_type.IsReference());
+  EXPECT_TRUE(long_reg_type.IsLowHalf());
+  EXPECT_FALSE(long_reg_type.IsHighHalf());
+  EXPECT_TRUE(long_reg_type.IsLongOrDoubleTypes());
+  EXPECT_FALSE(long_reg_type.IsReferenceTypes());
+  EXPECT_FALSE(long_reg_type.IsCategory1Types());
+  EXPECT_TRUE(long_reg_type.IsCategory2Types());
+  EXPECT_FALSE(long_reg_type.IsBooleanTypes());
+  EXPECT_FALSE(long_reg_type.IsByteTypes());
+  EXPECT_FALSE(long_reg_type.IsShortTypes());
+  EXPECT_FALSE(long_reg_type.IsCharTypes());
+  EXPECT_FALSE(long_reg_type.IsIntegralTypes());
+  EXPECT_FALSE(long_reg_type.IsFloatTypes());
+  EXPECT_TRUE(long_reg_type.IsLongTypes());
+  EXPECT_FALSE(long_reg_type.IsDoubleTypes());
+  EXPECT_FALSE(long_reg_type.IsArrayIndexTypes());
+
+  const RegType& float_reg_type = cache.Float();
+  EXPECT_FALSE(float_reg_type.IsUnknown());
+  EXPECT_FALSE(float_reg_type.IsConflict());
+  EXPECT_FALSE(float_reg_type.IsZero());
+  EXPECT_FALSE(float_reg_type.IsOne());
+  EXPECT_FALSE(float_reg_type.IsConstLo());
+  EXPECT_FALSE(float_reg_type.IsBoolean());
+  EXPECT_FALSE(float_reg_type.IsByte());
+  EXPECT_FALSE(float_reg_type.IsChar());
+  EXPECT_FALSE(float_reg_type.IsShort());
+  EXPECT_FALSE(float_reg_type.IsInteger());
+  EXPECT_FALSE(float_reg_type.IsLong());
+  EXPECT_TRUE(float_reg_type.IsFloat());
+  EXPECT_FALSE(float_reg_type.IsDouble());
+  EXPECT_FALSE(float_reg_type.IsReference());
+  EXPECT_FALSE(float_reg_type.IsLowHalf());
+  EXPECT_FALSE(float_reg_type.IsHighHalf());
+  EXPECT_FALSE(float_reg_type.IsLongOrDoubleTypes());
+  EXPECT_FALSE(float_reg_type.IsReferenceTypes());
+  EXPECT_TRUE(float_reg_type.IsCategory1Types());
+  EXPECT_FALSE(float_reg_type.IsCategory2Types());
+  EXPECT_FALSE(float_reg_type.IsBooleanTypes());
+  EXPECT_FALSE(float_reg_type.IsByteTypes());
+  EXPECT_FALSE(float_reg_type.IsShortTypes());
+  EXPECT_FALSE(float_reg_type.IsCharTypes());
+  EXPECT_FALSE(float_reg_type.IsIntegralTypes());
+  EXPECT_TRUE(float_reg_type.IsFloatTypes());
+  EXPECT_FALSE(float_reg_type.IsLongTypes());
+  EXPECT_FALSE(float_reg_type.IsDoubleTypes());
+  EXPECT_FALSE(float_reg_type.IsArrayIndexTypes());
+
+  const RegType& double_reg_type = cache.Double();
+  EXPECT_FALSE(double_reg_type.IsUnknown());
+  EXPECT_FALSE(double_reg_type.IsConflict());
+  EXPECT_FALSE(double_reg_type.IsZero());
+  EXPECT_FALSE(double_reg_type.IsOne());
+  EXPECT_FALSE(double_reg_type.IsConstLo());
+  EXPECT_FALSE(double_reg_type.IsBoolean());
+  EXPECT_FALSE(double_reg_type.IsByte());
+  EXPECT_FALSE(double_reg_type.IsChar());
+  EXPECT_FALSE(double_reg_type.IsShort());
+  EXPECT_FALSE(double_reg_type.IsInteger());
+  EXPECT_FALSE(double_reg_type.IsLong());
+  EXPECT_FALSE(double_reg_type.IsFloat());
+  EXPECT_TRUE(double_reg_type.IsDouble());
+  EXPECT_FALSE(double_reg_type.IsReference());
+  EXPECT_TRUE(double_reg_type.IsLowHalf());
+  EXPECT_FALSE(double_reg_type.IsHighHalf());
+  EXPECT_TRUE(double_reg_type.IsLongOrDoubleTypes());
+  EXPECT_FALSE(double_reg_type.IsReferenceTypes());
+  EXPECT_FALSE(double_reg_type.IsCategory1Types());
+  EXPECT_TRUE(double_reg_type.IsCategory2Types());
+  EXPECT_FALSE(double_reg_type.IsBooleanTypes());
+  EXPECT_FALSE(double_reg_type.IsByteTypes());
+  EXPECT_FALSE(double_reg_type.IsShortTypes());
+  EXPECT_FALSE(double_reg_type.IsCharTypes());
+  EXPECT_FALSE(double_reg_type.IsIntegralTypes());
+  EXPECT_FALSE(double_reg_type.IsFloatTypes());
+  EXPECT_FALSE(double_reg_type.IsLongTypes());
+  EXPECT_TRUE(double_reg_type.IsDoubleTypes());
+  EXPECT_FALSE(double_reg_type.IsArrayIndexTypes());
+}
+
+// TODO: test reference RegType
+// TODO: test constant RegType
+// TODO: test VerifyAgainst
+// TODO: test Merge
+// TODO: test Equals
+// TODO: test ClassJoin
+
+}  // namespace verifier
 }  // namespace art
diff --git a/src/exception_test.cc b/src/exception_test.cc
index ab462a9..df64329 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -36,14 +36,12 @@
     method_f_ = my_klass_->FindVirtualMethod("f", "()I");
     ASSERT_TRUE(method_f_ != NULL);
     method_f_->SetFrameSizeInBytes(kStackAlignment);
-    method_f_->SetReturnPcOffsetInBytes(kStackAlignment - kPointerSize);
     method_f_->SetCode(CompiledMethod::CodePointer(&fake_code_[0], kThumb2));
     method_f_->SetMappingTable(&fake_mapping_data_[0]);
 
     method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
     ASSERT_TRUE(method_g_ != NULL);
     method_g_->SetFrameSizeInBytes(kStackAlignment);
-    method_g_->SetReturnPcOffsetInBytes(kStackAlignment - kPointerSize);
     method_g_->SetCode(CompiledMethod::CodePointer(&fake_code_[0], kThumb2));
     method_g_->SetMappingTable(&fake_mapping_data_[0]);
   }
@@ -66,7 +64,7 @@
   ASSERT_TRUE(code_item != NULL);
 
   ASSERT_EQ(2u, code_item->tries_size_);
-  ASSERT_NE(0u, code_item->insns_size_);
+  ASSERT_NE(0u, code_item->insns_size_in_code_units_);
 
   const struct DexFile::TryItem *t0, *t1;
   t0 = dex_->dexGetTryItems(*code_item, 0);
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 3dcde8e..30b19a8 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -207,7 +207,6 @@
   CHECK(method != NULL);
   method->SetCode(code_);
   method->SetFrameSizeInBytes(frame_size_in_bytes_);
-  method->SetReturnPcOffsetInBytes(return_pc_offset_in_bytes_);
   method->SetCoreSpillMask(core_spill_mask_);
   method->SetFpSpillMask(fp_spill_mask_);
   method->SetMappingTable(mapping_table_);
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 797c187..2635bf8 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -243,7 +243,6 @@
   // Note that we leave the offset and values back in the Method where ImageWriter will find them
   method->SetOatCodeOffset(code_offset);
   method->SetFrameSizeInBytes(frame_size_in_bytes);
-  method->SetReturnPcOffsetInBytes(return_pc_offset_in_bytes);
   method->SetCoreSpillMask(core_spill_mask);
   method->SetFpSpillMask(fp_spill_mask);
   method->SetOatMappingTableOffset(mapping_table_offset);
diff --git a/src/oatdump.cc b/src/oatdump.cc
index a50aecb..73b92a0 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -361,22 +361,18 @@
         } else {
           StringAppendF(&summary, "\tNATIVE UNREGISTERED\n");
         }
-        DCHECK(method->GetRegisterMapHeader() == NULL) << PrettyMethod(method);
-        DCHECK(method->GetRegisterMapData() == NULL) << PrettyMethod(method);
+        DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
       } else if (method->IsAbstract()) {
         StringAppendF(&summary, "\tABSTRACT\n");
-        DCHECK(method->GetRegisterMapHeader() == NULL) << PrettyMethod(method);
-        DCHECK(method->GetRegisterMapData() == NULL) << PrettyMethod(method);
+        DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
       } else if (method->IsCalleeSaveMethod()) {
         StringAppendF(&summary, "\tCALLEE SAVE METHOD\n");
-        DCHECK(method->GetRegisterMapHeader() == NULL) << PrettyMethod(method);
-        DCHECK(method->GetRegisterMapData() == NULL) << PrettyMethod(method);
+        DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
       } else {
-        size_t register_map_bytes = (method->GetRegisterMapHeader()->GetLength() +
-                                     method->GetRegisterMapData()->GetLength());
+        size_t register_map_bytes = method->GetGcMap()->SizeOf();
         state->stats_.register_map_bytes += register_map_bytes;
 
         if (method->GetMappingTable() != NULL) {
@@ -388,7 +384,7 @@
         class DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
         const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
         const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
-        size_t dex_instruction_bytes = code_item->insns_size_ * 2;
+        size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
         state->stats_.dex_instruction_bytes += dex_instruction_bytes;
       }
     }
diff --git a/src/object.cc b/src/object.cc
index 6ea1f59..ab95885 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -831,21 +831,23 @@
 size_t Class::PrimitiveSize() const {
   switch (GetPrimitiveType()) {
     case kPrimBoolean:
-    case kPrimByte:
+    case kPrimByte:    return 1;
     case kPrimChar:
-    case kPrimShort:
+    case kPrimShort:   return 2;
     case kPrimInt:
-    case kPrimFloat:
-      return sizeof(int32_t);
+    case kPrimFloat:   return 4;
     case kPrimLong:
-    case kPrimDouble:
-      return sizeof(int64_t);
+    case kPrimDouble:  return 8;
     default:
       LOG(FATAL) << "Primitive type size calculation on invalid type " << this;
       return 0;
   }
 }
 
+size_t Class::PrimitiveFieldSize() const {
+  return PrimitiveSize() <= 4 ? 4 : 8;
+}
+
 size_t Class::GetTypeSize(const String* descriptor) {
   switch (descriptor->CharAt(0)) {
   case 'B': return 1;  // byte
@@ -982,14 +984,12 @@
 }
 
 const ClassLoader* Class::GetClassLoader() const {
-  return GetFieldObject<const ClassLoader*>(
-      OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), false);
+  return GetFieldObject<const ClassLoader*>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), false);
 }
 
 void Class::SetClassLoader(const ClassLoader* new_cl) {
   ClassLoader* new_class_loader = const_cast<ClassLoader*>(new_cl);
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_),
-                 new_class_loader, false);
+  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false);
 }
 
 Method* Class::FindVirtualMethodForInterface(Method* method, bool can_throw) {
diff --git a/src/object.h b/src/object.h
index 882c025..752d405 100644
--- a/src/object.h
+++ b/src/object.h
@@ -538,14 +538,6 @@
 
   void SetName(String* new_name);
 
-  ByteArray* GetRegisterMapData() const;
-
-  void SetRegisterMapData(ByteArray* data);
-
-  ByteArray* GetRegisterMapHeader() const;
-
-  void SetRegisterMapHeader(ByteArray* header);
-
   String* GetShorty() const;
 
   void SetShorty(String* new_shorty);
@@ -857,6 +849,14 @@
     SetVmapTable(reinterpret_cast<uint16_t*>(vmap_table_offset));
   }
 
+  Object* GetGcMap() const {
+    return GetFieldObject<Object*>(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), false);
+  }
+
+  void SetGcMap(Object* data) {
+    SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), data, false);
+  }
+
   size_t GetFrameSizeInBytes() const {
     DCHECK_EQ(sizeof(size_t), sizeof(uint32_t));
     size_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(Method, frame_size_in_bytes_), false);
@@ -872,15 +872,7 @@
   }
 
   size_t GetReturnPcOffsetInBytes() const {
-    DCHECK_EQ(sizeof(size_t), sizeof(uint32_t));
-    return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, return_pc_offset_in_bytes_), false);
-  }
-
-  void SetReturnPcOffsetInBytes(size_t return_pc_offset_in_bytes) {
-    DCHECK_EQ(sizeof(size_t), sizeof(uint32_t));
-    DCHECK_LT(return_pc_offset_in_bytes, GetFrameSizeInBytes());
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, return_pc_offset_in_bytes_),
-               return_pc_offset_in_bytes, false);
+    return GetFrameSizeInBytes() - kPointerSize;
   }
 
   bool IsRegistered() const;
@@ -1043,9 +1035,8 @@
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
   ObjectArray<String>* dex_cache_strings_;
 
-  // Byte arrays that hold data for the register maps
-  const ByteArray* register_map_data_;
-  const ByteArray* register_map_header_;
+  // Garbage collection map
+  Object* gc_map_;
 
   // The short-form method descriptor string.
   String* shorty_;
@@ -1089,6 +1080,7 @@
   // Index of the return type
   uint32_t java_return_type_idx_;
 
+  // Mapping from native pc to dex pc
   const uint32_t* mapping_table_;
 
   // For concrete virtual methods, this is the offset of the method in Class::vtable_.
@@ -1111,9 +1103,9 @@
   // Method prototype descriptor string (return and argument types).
   uint32_t proto_idx_;
 
-  // Offset of return PC within frame for compiled code (in bytes)
-  size_t return_pc_offset_in_bytes_;
-
+  // When a register is promoted into a register, the spill mask holds which registers hold dex
+  // registers. The first promoted register's corresponding dex register is vmap_table_[1], the Nth
+  // is vmap_table_[N]. vmap_table_[0] holds the length of the table.
   const uint16_t* vmap_table_;
 
   uint32_t java_slot_;
@@ -1443,8 +1435,19 @@
     return GetPrimitiveType() == kPrimVoid;
   }
 
+  size_t PrimitiveFieldSize() const;
+
   size_t PrimitiveSize() const;
 
+  // Depth of class from java.lang.Object
+  size_t Depth() {
+    size_t depth = 0;
+    for(Class* klass = this; klass->GetSuperClass() != NULL; klass = klass->GetSuperClass()) {
+      depth++;
+    }
+    return depth;
+  }
+
   bool IsArrayClass() const {
     return GetComponentType() != NULL;
   }
@@ -1558,6 +1561,11 @@
 
   bool IsSubClass(const Class* klass) const;
 
+  // Can src be assigned to this class? For example, String can be assigned to Object (by an
+  // upcast), however, an Object cannot be assigned to a String as a potentially exception throwing
+  // downcast would be necessary. Similarly for interfaces, a class that implements (or an interface
+  // that extends) another can be assigned to its parent, but not vice-versa. All Classes may assign
+  // to themselves. Classes for primitive types may not assign to each other.
   bool IsAssignableFrom(const Class* src) const {
     DCHECK(src != NULL);
     if (this == src) {
@@ -1571,7 +1579,7 @@
     } else if (src->IsArrayClass()) {
       return IsAssignableFromArray(src);
     } else {
-      return src->IsSubClass(this);
+      return !src->IsInterface() && src->IsSubClass(this);
     }
   }
 
@@ -2535,22 +2543,6 @@
   SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, name_), new_name, false);
 }
 
-inline ByteArray* Method::GetRegisterMapData() const {
-  return GetFieldObject<ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, register_map_data_), false);
-}
-
-inline void Method::SetRegisterMapData(ByteArray* data) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, register_map_data_), data, false);
-}
-
-inline ByteArray* Method::GetRegisterMapHeader() const {
-  return GetFieldObject<ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, register_map_header_), false);
-}
-
-inline void Method::SetRegisterMapHeader(ByteArray* header) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, register_map_header_), header, false);
-}
-
 inline String* Method::GetShorty() const {
   DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Method, shorty_), false);
diff --git a/src/object_test.cc b/src/object_test.cc
index c493126..db1d331 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -350,6 +350,30 @@
   EXPECT_TRUE(X->IsAssignableFrom(Y));
   EXPECT_FALSE(Y->IsAssignableFrom(X));
   EXPECT_TRUE(Y->IsAssignableFrom(Y));
+
+  // class final String implements CharSequence, ..
+  Class* string = class_linker_->FindSystemClass("Ljava/lang/String;");
+  Class* charseq = class_linker_->FindSystemClass("Ljava/lang/CharSequence;");
+  // Can String be assigned to CharSequence without a cast?
+  EXPECT_TRUE(charseq->IsAssignableFrom(string));
+  // Can CharSequence be assigned to String without a cast?
+  EXPECT_FALSE(string->IsAssignableFrom(charseq));
+
+  // Primitive types are only assignable to themselves
+  const char* prims = "ZBCSIJFD";
+  Class* prim_types[strlen(prims)];
+  for (size_t i = 0; i < strlen(prims); i++) {
+    prim_types[i] = class_linker_->FindPrimitiveClass(prims[i]);
+  }
+  for (size_t i = 0; i < strlen(prims); i++) {
+    for (size_t j = 0; i < strlen(prims); i++) {
+      if (i == j) {
+        EXPECT_TRUE(prim_types[i]->IsAssignableFrom(prim_types[j]));
+      } else {
+        EXPECT_FALSE(prim_types[i]->IsAssignableFrom(prim_types[j]));
+      }
+    }
+  }
 }
 
 TEST_F(ObjectTest, IsAssignableFromArray) {
diff --git a/src/runtime.cc b/src/runtime.cc
index 46ec8fb..a144c44 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -775,12 +775,10 @@
                                  __builtin_popcount(fp_spills) /* fprs */ +
                                  1 /* Method* */) * kPointerSize, kStackAlignment);
     method->SetFrameSizeInBytes(frame_size);
-    method->SetReturnPcOffsetInBytes(frame_size - kPointerSize);
     method->SetCoreSpillMask(core_spills);
     method->SetFpSpillMask(fp_spills);
   } else if (insns == kX86) {
     method->SetFrameSizeInBytes(32);
-    method->SetReturnPcOffsetInBytes(28);
     method->SetCoreSpillMask((1 << art::x86::EBX) | (1 << art::x86::EBP) | (1 << art::x86::ESI) |
                              (1 << art::x86::EDI));
     method->SetFpSpillMask(0);
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 72720ba..c7140f1 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -146,18 +146,18 @@
 }
 
 static std::string ClassNameFromIndex(Method* method, uint32_t ref,
-                                      DexVerifier::VerifyErrorRefType ref_type, bool access) {
+                                      verifier::VerifyErrorRefType ref_type, bool access) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
 
   uint16_t type_idx = 0;
-  if (ref_type == DexVerifier::VERIFY_ERROR_REF_FIELD) {
+  if (ref_type == verifier::VERIFY_ERROR_REF_FIELD) {
     const DexFile::FieldId& id = dex_file.GetFieldId(ref);
     type_idx = id.class_idx_;
-  } else if (ref_type == DexVerifier::VERIFY_ERROR_REF_METHOD) {
+  } else if (ref_type == verifier::VERIFY_ERROR_REF_METHOD) {
     const DexFile::MethodId& id = dex_file.GetMethodId(ref);
     type_idx = id.class_idx_;
-  } else if (ref_type == DexVerifier::VERIFY_ERROR_REF_CLASS) {
+  } else if (ref_type == verifier::VERIFY_ERROR_REF_CLASS) {
     type_idx = ref;
   } else {
     CHECK(false) << static_cast<int>(ref_type);
@@ -177,8 +177,8 @@
 }
 
 static std::string FieldNameFromIndex(const Method* method, uint32_t ref,
-                                      DexVerifier::VerifyErrorRefType ref_type, bool access) {
-  CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(DexVerifier::VERIFY_ERROR_REF_FIELD));
+                                      verifier::VerifyErrorRefType ref_type, bool access) {
+  CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_FIELD));
 
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
@@ -199,8 +199,8 @@
 }
 
 static std::string MethodNameFromIndex(const Method* method, uint32_t ref,
-                                DexVerifier::VerifyErrorRefType ref_type, bool access) {
-  CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(DexVerifier::VERIFY_ERROR_REF_METHOD));
+                                verifier::VerifyErrorRefType ref_type, bool access) {
+  CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_METHOD));
 
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
@@ -227,49 +227,49 @@
   frame.Next();
   Method* method = frame.GetMethod();
 
-  DexVerifier::VerifyErrorRefType ref_type =
-      static_cast<DexVerifier::VerifyErrorRefType>(kind >> kVerifyErrorRefTypeShift);
+  verifier::VerifyErrorRefType ref_type =
+      static_cast<verifier::VerifyErrorRefType>(kind >> verifier::kVerifyErrorRefTypeShift);
 
   const char* exception_class = "Ljava/lang/VerifyError;";
   std::string msg;
 
-  switch (static_cast<DexVerifier::VerifyError>(kind & ~(0xff << kVerifyErrorRefTypeShift))) {
-  case DexVerifier::VERIFY_ERROR_NO_CLASS:
+  switch (static_cast<verifier::VerifyError>(kind & ~(0xff << verifier::kVerifyErrorRefTypeShift))) {
+  case verifier::VERIFY_ERROR_NO_CLASS:
     exception_class = "Ljava/lang/NoClassDefFoundError;";
     msg = ClassNameFromIndex(method, ref, ref_type, false);
     break;
-  case DexVerifier::VERIFY_ERROR_NO_FIELD:
+  case verifier::VERIFY_ERROR_NO_FIELD:
     exception_class = "Ljava/lang/NoSuchFieldError;";
     msg = FieldNameFromIndex(method, ref, ref_type, false);
     break;
-  case DexVerifier::VERIFY_ERROR_NO_METHOD:
+  case verifier::VERIFY_ERROR_NO_METHOD:
     exception_class = "Ljava/lang/NoSuchMethodError;";
     msg = MethodNameFromIndex(method, ref, ref_type, false);
     break;
-  case DexVerifier::VERIFY_ERROR_ACCESS_CLASS:
+  case verifier::VERIFY_ERROR_ACCESS_CLASS:
     exception_class = "Ljava/lang/IllegalAccessError;";
     msg = ClassNameFromIndex(method, ref, ref_type, true);
     break;
-  case DexVerifier::VERIFY_ERROR_ACCESS_FIELD:
+  case verifier::VERIFY_ERROR_ACCESS_FIELD:
     exception_class = "Ljava/lang/IllegalAccessError;";
     msg = FieldNameFromIndex(method, ref, ref_type, true);
     break;
-  case DexVerifier::VERIFY_ERROR_ACCESS_METHOD:
+  case verifier::VERIFY_ERROR_ACCESS_METHOD:
     exception_class = "Ljava/lang/IllegalAccessError;";
     msg = MethodNameFromIndex(method, ref, ref_type, true);
     break;
-  case DexVerifier::VERIFY_ERROR_CLASS_CHANGE:
+  case verifier::VERIFY_ERROR_CLASS_CHANGE:
     exception_class = "Ljava/lang/IncompatibleClassChangeError;";
     msg = ClassNameFromIndex(method, ref, ref_type, false);
     break;
-  case DexVerifier::VERIFY_ERROR_INSTANTIATION:
+  case verifier::VERIFY_ERROR_INSTANTIATION:
     exception_class = "Ljava/lang/InstantiationError;";
     msg = ClassNameFromIndex(method, ref, ref_type, false);
     break;
-  case DexVerifier::VERIFY_ERROR_GENERIC:
+  case verifier::VERIFY_ERROR_GENERIC:
     // Generic VerifyError; use default exception, no message.
     break;
-  case DexVerifier::VERIFY_ERROR_NONE:
+  case verifier::VERIFY_ERROR_NONE:
     CHECK(false);
     break;
   }
@@ -297,7 +297,7 @@
   frame.Next();
   Method* method = frame.GetMethod();
   self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
-      MethodNameFromIndex(method, method_idx, DexVerifier::VERIFY_ERROR_REF_METHOD, false).c_str());
+      MethodNameFromIndex(method, method_idx, verifier::VERIFY_ERROR_REF_METHOD, false).c_str());
   self->DeliverException();
 }
 
@@ -355,8 +355,8 @@
     const DexFile& dex_file = Runtime::Current()->GetClassLinker()
                                   ->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
     const DexFile::CodeItem* code = dex_file.GetCodeItem(caller->GetCodeItemOffset());
-    CHECK_LT(dex_pc, code->insns_size_);
-    const Instruction* instr = Instruction::At(reinterpret_cast<const byte*>(&code->insns_[dex_pc]));
+    CHECK_LT(dex_pc, code->insns_size_in_code_units_);
+    const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
     Instruction::Code instr_code = instr->Opcode();
     is_static = (instr_code == Instruction::INVOKE_STATIC) ||
                 (instr_code == Instruction::INVOKE_STATIC_RANGE);
diff --git a/src/thread.cc b/src/thread.cc
index cbd1bda..2736140 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1356,8 +1356,8 @@
     }
     // Process register map (which native and callee save methods don't have)
     if (!m->IsNative() && !m->IsCalleeSaveMethod()) {
-      UniquePtr<art::DexVerifier::RegisterMap> map(art::DexVerifier::GetExpandedRegisterMap(m));
-      const uint8_t* reg_bitmap = art::DexVerifier::RegisterMapGetLine(map.get(), m->ToDexPC(pc));
+      verifier::PcToReferenceMap map(m);
+      const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc));
       CHECK(reg_bitmap != NULL);
       const uint16_t* vmap = m->GetVmapTable();
       // For all dex registers
diff --git a/src/utils.cc b/src/utils.cc
index bfd7e79..3922033 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -10,6 +10,7 @@
 #include <unistd.h>
 
 #include "UniquePtr.h"
+#include "class_loader.h"
 #include "file.h"
 #include "object.h"
 #include "os.h"
@@ -165,6 +166,20 @@
   return result;
 }
 
+std::string PrettyClassAndClassLoader(const Class* c) {
+  if (c == NULL) {
+    return "null";
+  }
+  std::string result;
+  result += "java.lang.Class<";
+  result += PrettyDescriptor(c->GetDescriptor());
+  result += ",";
+  result += PrettyTypeOf(c->GetClassLoader());
+  // TODO: add an identifying hash value for the loader
+  result += ">";
+  return result;
+}
+
 std::string MangleForJni(const std::string& s) {
   std::string result;
   size_t char_count = CountModifiedUtf8Chars(s.c_str());
diff --git a/src/utils.h b/src/utils.h
index df1e1c1..53a0378 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -175,6 +175,9 @@
 // Given String.class, the output would be "java.lang.Class<java.lang.String>".
 std::string PrettyClass(const Class* c);
 
+// Returns a human-readable form of the name of the given class with its class loader.
+std::string PrettyClassAndClassLoader(const Class* c);
+
 // Performs JNI name mangling as described in section 11.3 "Linking Native Methods"
 // of the JNI spec.
 std::string MangleForJni(const std::string& s);
diff --git a/src/utils_test.cc b/src/utils_test.cc
index bf66d05..f1944f0 100644
--- a/src/utils_test.cc
+++ b/src/utils_test.cc
@@ -80,6 +80,14 @@
   EXPECT_EQ("java.lang.Class<java.lang.String[]>", PrettyClass(o->GetClass()));
 }
 
+TEST_F(UtilsTest, PrettyClassAndClassLoader) {
+  EXPECT_EQ("null", PrettyClassAndClassLoader(NULL));
+  Class* c = class_linker_->FindSystemClass("[Ljava/lang/String;");
+  ASSERT_TRUE(c != NULL);
+  Object* o = ObjectArray<String>::Alloc(c, 0);
+  EXPECT_EQ("java.lang.Class<java.lang.String[],null>", PrettyClassAndClassLoader(o->GetClass()));
+}
+
 TEST_F(UtilsTest, PrettyField) {
   EXPECT_EQ("null", PrettyField(NULL));
 
diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/ReferenceMap/stack_walk_refmap_jni.cc
index ca46569..af2c4f3 100644
--- a/test/ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/ReferenceMap/stack_walk_refmap_jni.cc
@@ -10,15 +10,15 @@
 
 namespace art {
 
-#define REG(method, reg_vector, reg) \
+#define REG(method, reg_bitmap, reg) \
   ( ((reg) < (method)->NumRegisters()) &&                       \
-    (( *((reg_vector) + (reg)/8) >> ((reg) % 8) ) & 0x01) )
+    (( *((reg_bitmap) + (reg)/8) >> ((reg) % 8) ) & 0x01) )
 
 #define CHECK_REGS(...) do {          \
     int t[] = {__VA_ARGS__};             \
     int t_size = sizeof(t) / sizeof(*t);      \
     for (int i = 0; i < t_size; ++i)          \
-      EXPECT_TRUE(REG(m, reg_vector, t[i])) << "Error: Reg " << i << " is not in RegisterMap"; \
+      EXPECT_TRUE(REG(m, reg_bitmap, t[i])) << "Error: Reg " << i << " is not in RegisterMap"; \
   } while(false)
 
 // << "Error: Reg " << i << " is not in RegisterMap";
@@ -34,9 +34,7 @@
     }
     LOG(INFO) << "At " << PrettyMethod(m, false);
 
-    art::DexVerifier::RegisterMap* map = new art::DexVerifier::RegisterMap(
-        m->GetRegisterMapHeader(),
-        m->GetRegisterMapData());
+    verifier::PcToReferenceMap map(m);
 
     if (!pc) {
       // pc == NULL: m is either a native method or a phony method
@@ -47,112 +45,112 @@
       return;
     }
 
-    const uint8_t* reg_vector = NULL;
+    const uint8_t* reg_bitmap = NULL;
     std::string m_name = m->GetName()->ToModifiedUtf8();
 
     // Given the method name and the number of times the method has been called,
     // we know the Dex registers with live reference values. Assert that what we
     // find is what is expected.
     if (m_name.compare("f") == 0) {
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x01U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg1: " << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x01U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg1: " << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(7);  //v7: this
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x02U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg2: " << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x02U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg2: " << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(7);  //v7: this
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x03U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg3: " << std::hex << reg_vector[0] << reg_vector[1];
+      reg_bitmap = map.FindBitMap(0x03U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg3: " << std::hex << reg_bitmap[0] << reg_bitmap[1];
         CHECK_REGS(7);  //v7: this
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x05U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg4: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x05U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg4: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 7);  //v0: x, v7: this
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x06U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg5: " << std::hex << reg_vector[0] << reg_vector[1];
+      reg_bitmap = map.FindBitMap(0x06U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg5: " << std::hex << reg_bitmap[0] << reg_bitmap[1];
         CHECK_REGS(0, 7);  //v0: x, v7: this
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x08U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg6: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x08U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg6: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 2, 7);  //v0: x, v2: y, v7: this
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x0bU);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg7: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x0bU);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg7: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 2, 7);  //v0: x, v2: y, v7: this
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x0cU);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg8: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x0cU);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg8: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 2, 7);  //v0: x, v2: y, v7: this
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x38U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg9: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x38U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg9: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 2, 7);  //v0: x, v2: y, v7: this
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x39U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg10: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x39U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg10: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 2, 7, 1);  //v0: x, v2: y, v7: this, v1: ex
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x3aU);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg11: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x3aU);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg11: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 2, 7, 1);  //v0: x, v2: y, v7: this, v1: y
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x16U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg12: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x16U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg12: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 7, 1);  //v0: x, v7: this, v1: y
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x20U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg13: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x20U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg13: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 7, 1);  //v0: x, v7: this, v1: y
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x22U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg14: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x22U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg14: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 7, 1);  //v0: x, v7: this, v1: y
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x25U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg15: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x25U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg15: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0);  //v0: x, v7: this, v1: y
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x26U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg16: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x26U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg16: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 7, 1);  //v0: y, v7: this, v1: y
       }
 
-      reg_vector = art::DexVerifier::RegisterMapGetLine(map, 0x14U);
-      if (reg_vector) {
-        LOG(WARNING) << "Reg17: " << std::hex << *reg_vector << *(reg_vector+1);
+      reg_bitmap = map.FindBitMap(0x14U);
+      if (reg_bitmap) {
+        LOG(WARNING) << "Reg17: " << std::hex << *reg_bitmap << *(reg_bitmap+1);
         CHECK_REGS(0, 7);  //v0: y, v7: this
       }
     }
diff --git a/test/StackWalk/stack_walk_jni.cc b/test/StackWalk/stack_walk_jni.cc
index 5e4a8a2..6a23d1f 100644
--- a/test/StackWalk/stack_walk_jni.cc
+++ b/test/StackWalk/stack_walk_jni.cc
@@ -10,15 +10,15 @@
 
 namespace art {
 
-#define REG(method, reg_vector, reg) \
+#define REG(method, reg_bitmap, reg) \
   ( ((reg) < (method)->NumRegisters()) &&                       \
-    (( *((reg_vector) + (reg)/8) >> ((reg) % 8) ) & 0x01) )
+    (( *((reg_bitmap) + (reg)/8) >> ((reg) % 8) ) & 0x01) )
 
 #define CHECK_REGS(...) do {          \
     int t[] = {__VA_ARGS__};             \
     int t_size = sizeof(t) / sizeof(*t);      \
     for (int i = 0; i < t_size; ++i)          \
-      CHECK(REG(m, reg_vector, t[i])) << "Error: Reg " << i << " is not in RegisterMap";  \
+      CHECK(REG(m, reg_bitmap, t[i])) << "Error: Reg " << i << " is not in RegisterMap";  \
   } while(false)
 
 static int gJava_StackWalk_refmap_calls = 0;
@@ -29,31 +29,22 @@
 
   void VisitFrame(const Frame& frame, uintptr_t pc) {
     Method* m = frame.GetMethod();
-    if (!m ||m->IsNative()) {
-      return;
-    }
+    CHECK(m != NULL);
     LOG(INFO) << "At " << PrettyMethod(m, false);
 
-    art::DexVerifier::RegisterMap* map = new art::DexVerifier::RegisterMap(
-        m->GetRegisterMapHeader(),
-        m->GetRegisterMapData());
-
-    if (!pc) {
-      // pc == NULL: m is either a native method or a phony method
-      return;
-    }
-    if (m->IsCalleeSaveMethod()) {
+    if (m->IsCalleeSaveMethod() || m->IsNative()) {
       LOG(WARNING) << "no PC for " << PrettyMethod(m);
+      CHECK_EQ(pc, 0u);
       return;
     }
-
-    const uint8_t* reg_vector = art::DexVerifier::RegisterMapGetLine(map, m->ToDexPC(pc));
-    std::string m_name = m->GetName()->ToModifiedUtf8();
+    verifier::PcToReferenceMap map(m);
+    const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc));
+    String* m_name = m->GetName();
 
     // Given the method name and the number of times the method has been called,
     // we know the Dex registers with live reference values. Assert that what we
     // find is what is expected.
-    if (m_name.compare("f") == 0) {
+    if (m_name->Equals("f") == 0) {
       if (gJava_StackWalk_refmap_calls == 1) {
         CHECK_EQ(1U, m->ToDexPC(pc));
         CHECK_REGS(1);
@@ -62,7 +53,7 @@
         CHECK_EQ(5U, m->ToDexPC(pc));
         CHECK_REGS(1);
       }
-    } else if (m_name.compare("g") == 0) {
+    } else if (m_name->Equals("g") == 0) {
       if (gJava_StackWalk_refmap_calls == 1) {
         CHECK_EQ(0xcU, m->ToDexPC(pc));
         CHECK_REGS(0, 2);  // Note that v1 is not in the minimal root set
@@ -71,7 +62,7 @@
         CHECK_EQ(0xcU, m->ToDexPC(pc));
         CHECK_REGS(0, 2);
       }
-    } else if (m_name.compare("shlemiel") == 0) {
+    } else if (m_name->Equals("shlemiel") == 0) {
       if (gJava_StackWalk_refmap_calls == 1) {
         CHECK_EQ(0x380U, m->ToDexPC(pc));
         CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
@@ -81,8 +72,7 @@
         CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
       }
     }
-
-    LOG(INFO) << reg_vector;
+    LOG(INFO) << reg_bitmap;
   }
 };