Add "kind" argument to Get/SetVReg.

In order to determine where a register is promoted its necessary to know
the kind of use of the register.
Extend notion of precise-ness to numeric verifier register types.
Dump verifier output in oatdump.
Dump vregs with their location or constant value.
Introduce indenting ostream utility.

Change-Id: Ia3d29497877976bc24465484743bca08236e1768
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 2149490..d6cd665dd 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -25,6 +25,7 @@
 #include "dex_instruction.h"
 #include "dex_instruction_visitor.h"
 #include "verifier/dex_gc_map.h"
+#include "indenter.h"
 #include "intern_table.h"
 #include "leb128.h"
 #include "logging.h"
@@ -324,22 +325,37 @@
   return result;
 }
 
-void MethodVerifier::VerifyMethodAndDump(AbstractMethod* method) {
-  CHECK(method != NULL);
-  MethodHelper mh(method);
-  MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(),
-                          mh.GetClassDefIndex(), mh.GetCodeItem(), method->GetDexMethodIndex(),
-                          method, method->GetAccessFlags());
+void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_idx,
+                                         const DexFile* dex_file, DexCache* dex_cache,
+                                         ClassLoader* class_loader, uint32_t class_def_idx,
+                                         const DexFile::CodeItem* code_item, AbstractMethod* method,
+                                         uint32_t method_access_flags) {
+  MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item,
+                          dex_method_idx, method, method_access_flags);
   verifier.Verify();
-  verifier.DumpFailures(LOG(INFO) << "Dump of method " << PrettyMethod(method) << "\n")
-      << verifier.info_messages_.str() << MutatorLockedDumpable<MethodVerifier>(verifier);
+  verifier.DumpFailures(os);
+  os << verifier.info_messages_.str();
+  verifier.Dump(os);
+}
+
+std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_method_idx,
+                                                   const DexFile* dex_file, DexCache* dex_cache,
+                                                   ClassLoader* class_loader,
+                                                   uint32_t class_def_idx,
+                                                   const DexFile::CodeItem* code_item,
+                                                   AbstractMethod* method,
+                                                   uint32_t method_access_flags, uint32_t dex_pc) {
+  MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item,
+                          dex_method_idx, method, method_access_flags);
+  verifier.Verify();
+  return verifier.DescribeVRegs(dex_pc);
 }
 
 MethodVerifier::MethodVerifier(const DexFile* dex_file, DexCache* dex_cache,
     ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item,
-    uint32_t method_idx, AbstractMethod* method, uint32_t method_access_flags)
+    uint32_t dex_method_idx, AbstractMethod* method, uint32_t method_access_flags)
     : work_insn_idx_(-1),
-      method_idx_(method_idx),
+      dex_method_idx_(dex_method_idx),
       foo_method_(method),
       method_access_flags_(method_access_flags),
       dex_file_(dex_file),
@@ -355,7 +371,8 @@
       monitor_enter_count_(0) {
 }
 
-void MethodVerifier::FindLocksAtDexPc(AbstractMethod* m, uint32_t dex_pc, std::vector<uint32_t>& monitor_enter_dex_pcs) {
+void MethodVerifier::FindLocksAtDexPc(AbstractMethod* m, uint32_t dex_pc,
+                                      std::vector<uint32_t>& monitor_enter_dex_pcs) {
   MethodHelper mh(m);
   MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(),
                           mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(),
@@ -446,7 +463,7 @@
     }
   }
   failures_.push_back(error);
-  std::string location(StringPrintf("%s: [0x%X]", PrettyMethod(method_idx_, *dex_file_).c_str(),
+  std::string location(StringPrintf("%s: [0x%X]", PrettyMethod(dex_method_idx_, *dex_file_).c_str(),
                                     work_insn_idx_));
   std::ostringstream* failure_message = new std::ostringstream(location);
   failure_messages_.push_back(failure_message);
@@ -1000,7 +1017,7 @@
   if (!SetTypesFromSignature()) {
     DCHECK_NE(failures_.size(), 0U);
     std::string prepend("Bad signature in ");
-    prepend += PrettyMethod(method_idx_, *dex_file_);
+    prepend += PrettyMethod(dex_method_idx_, *dex_file_);
     PrependToLastFailMessage(prepend);
     return false;
   }
@@ -1010,7 +1027,7 @@
     return false;
   }
 
-  Compiler::MethodReference ref(dex_file_, method_idx_);
+  Compiler::MethodReference ref(dex_file_, dex_method_idx_);
 
 #if !defined(ART_USE_LLVM_COMPILER)
 
@@ -1054,17 +1071,28 @@
     os << "Native method\n";
     return;
   }
-  reg_types_.Dump(os);
+  {
+    os << "Register Types:\n";
+    Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+    std::ostream indent_os(&indent_filter);
+    reg_types_.Dump(indent_os);
+  }
   os << "Dumping instructions and register lines:\n";
+  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+  std::ostream indent_os(&indent_filter);
   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()) {
-    os << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].Dump()
-       << " " << inst->DumpHex(5) << " " << inst->DumpString(dex_file_) << "\n";
     RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
     if (reg_line != NULL) {
-      os << reg_line->Dump() << "\n";
+      indent_os << reg_line->Dump() << "\n";
     }
+    indent_os << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].Dump() << " ";
+    const bool kDumpHexOfInstruction = false;
+    if (kDumpHexOfInstruction) {
+      indent_os << inst->DumpHex(5) << " ";
+    }
+    indent_os << inst->DumpString(dex_file_) << "\n";
     inst = inst->Next();
   }
 }
@@ -1108,7 +1136,7 @@
   }
 
   const DexFile::ProtoId& proto_id =
-      dex_file_->GetMethodPrototype(dex_file_->GetMethodId(method_idx_));
+      dex_file_->GetMethodPrototype(dex_file_->GetMethodId(dex_method_idx_));
   DexFileParameterIterator iterator(*dex_file_, proto_id);
 
   for (; iterator.HasNext(); iterator.Next()) {
@@ -1153,8 +1181,9 @@
         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
+        const RegType& lo_half = descriptor[0] == 'J' ? reg_types_.LongLo() : reg_types_.DoubleLo();
+        const RegType& hi_half = descriptor[0] == 'J' ? reg_types_.LongHi() : reg_types_.DoubleHi();
+        reg_line->SetRegisterTypeWide(arg_start + cur_arg, lo_half, hi_half);
         cur_arg++;
         break;
       }
@@ -1250,7 +1279,7 @@
         if (work_line_->CompareLine(register_line) != 0) {
           Dump(std::cout);
           std::cout << info_messages_.str();
-          LOG(FATAL) << "work_line diverged in " << PrettyMethod(method_idx_, *dex_file_)
+          LOG(FATAL) << "work_line diverged in " << PrettyMethod(dex_method_idx_, *dex_file_)
                      << "@" << reinterpret_cast<void*>(work_insn_idx_) << "\n"
                      << " work_line=" << *work_line_ << "\n"
                      << "  expected=" << *register_line;
@@ -1259,7 +1288,7 @@
 #endif
     }
     if (!CodeFlowVerifyInstruction(&start_guess)) {
-      std::string prepend(PrettyMethod(method_idx_, *dex_file_));
+      std::string prepend(PrettyMethod(dex_method_idx_, *dex_file_));
       prepend += " failed to verify: ";
       PrependToLastFailMessage(prepend);
       return false;
@@ -1500,32 +1529,51 @@
       }
       break;
 
-    case Instruction::CONST_4:
       /* could be boolean, int, float, or a null reference */
+    case Instruction::CONST_4:
       work_line_->SetRegisterType(dec_insn.vA,
-                                  reg_types_.FromCat1Const((dec_insn.vB << 28) >> 28));
+                                  reg_types_.FromCat1Const(static_cast<int32_t>(dec_insn.vB << 28) >> 28, true));
       break;
     case Instruction::CONST_16:
-      /* could be boolean, int, float, or a null reference */
       work_line_->SetRegisterType(dec_insn.vA,
-                                  reg_types_.FromCat1Const(static_cast<int16_t>(dec_insn.vB)));
+                                  reg_types_.FromCat1Const(static_cast<int16_t>(dec_insn.vB), true));
       break;
     case Instruction::CONST:
-      /* could be boolean, int, float, or a null reference */
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.FromCat1Const(dec_insn.vB));
+      work_line_->SetRegisterType(dec_insn.vA, reg_types_.FromCat1Const(dec_insn.vB, true));
       break;
     case Instruction::CONST_HIGH16:
-      /* could be boolean, int, float, or a null reference */
       work_line_->SetRegisterType(dec_insn.vA,
-                                  reg_types_.FromCat1Const(dec_insn.vB << 16));
+                                  reg_types_.FromCat1Const(dec_insn.vB << 16, true));
       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 */
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.ConstLo());
+    case Instruction::CONST_WIDE_16: {
+      int64_t val = static_cast<int16_t>(dec_insn.vB);
+      const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
+      const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
+      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
       break;
+    }
+    case Instruction::CONST_WIDE_32: {
+      int64_t val = static_cast<int32_t>(dec_insn.vB);
+      const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
+      const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
+      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      break;
+    }
+    case Instruction::CONST_WIDE: {
+      int64_t val = dec_insn.vB_wide;
+      const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
+      const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
+      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      break;
+    }
+    case Instruction::CONST_WIDE_HIGH16: {
+      int64_t val = static_cast<uint64_t>(dec_insn.vB) << 48;
+      const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
+      const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
+      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      break;
+    }
     case Instruction::CONST_STRING:
     case Instruction::CONST_STRING_JUMBO:
       work_line_->SetRegisterType(dec_insn.vA, reg_types_.JavaLangString());
@@ -1658,19 +1706,23 @@
       break;
     case Instruction::CMPL_DOUBLE:
     case Instruction::CMPG_DOUBLE:
-      if (!work_line_->VerifyRegisterType(dec_insn.vB, reg_types_.Double())) {
+      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vB, reg_types_.DoubleLo(),
+                                              reg_types_.DoubleHi())) {
         break;
       }
-      if (!work_line_->VerifyRegisterType(dec_insn.vC, reg_types_.Double())) {
+      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vC, reg_types_.DoubleLo(),
+                                              reg_types_.DoubleHi())) {
         break;
       }
       work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
       break;
     case Instruction::CMP_LONG:
-      if (!work_line_->VerifyRegisterType(dec_insn.vB, reg_types_.Long())) {
+      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vB, reg_types_.LongLo(),
+                                              reg_types_.LongHi())) {
         break;
       }
-      if (!work_line_->VerifyRegisterType(dec_insn.vC, reg_types_.Long())) {
+      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vC, reg_types_.LongLo(),
+                                              reg_types_.LongHi())) {
         break;
       }
       work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
@@ -1792,7 +1844,7 @@
       VerifyAGet(dec_insn, reg_types_.Integer(), true);
       break;
     case Instruction::AGET_WIDE:
-      VerifyAGet(dec_insn, reg_types_.Long(), true);
+      VerifyAGet(dec_insn, reg_types_.LongLo(), true);
       break;
     case Instruction::AGET_OBJECT:
       VerifyAGet(dec_insn, reg_types_.JavaLangObject(false), false);
@@ -1814,7 +1866,7 @@
       VerifyAPut(dec_insn, reg_types_.Integer(), true);
       break;
     case Instruction::APUT_WIDE:
-      VerifyAPut(dec_insn, reg_types_.Long(), true);
+      VerifyAPut(dec_insn, reg_types_.LongLo(), true);
       break;
     case Instruction::APUT_OBJECT:
       VerifyAPut(dec_insn, reg_types_.JavaLangObject(false), false);
@@ -1836,7 +1888,7 @@
       VerifyISGet(dec_insn, reg_types_.Integer(), true, false);
       break;
     case Instruction::IGET_WIDE:
-      VerifyISGet(dec_insn, reg_types_.Long(), true, false);
+      VerifyISGet(dec_insn, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IGET_OBJECT:
       VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, false);
@@ -1858,7 +1910,7 @@
       VerifyISPut(dec_insn, reg_types_.Integer(), true, false);
       break;
     case Instruction::IPUT_WIDE:
-      VerifyISPut(dec_insn, reg_types_.Long(), true, false);
+      VerifyISPut(dec_insn, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IPUT_OBJECT:
       VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, false);
@@ -1880,7 +1932,7 @@
       VerifyISGet(dec_insn, reg_types_.Integer(), true, true);
       break;
     case Instruction::SGET_WIDE:
-      VerifyISGet(dec_insn, reg_types_.Long(), true, true);
+      VerifyISGet(dec_insn, reg_types_.LongLo(), true, true);
       break;
     case Instruction::SGET_OBJECT:
       VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, true);
@@ -1902,7 +1954,7 @@
       VerifyISPut(dec_insn, reg_types_.Integer(), true, true);
       break;
     case Instruction::SPUT_WIDE:
-      VerifyISPut(dec_insn, reg_types_.Long(), true, true);
+      VerifyISPut(dec_insn, reg_types_.LongLo(), true, true);
       break;
     case Instruction::SPUT_OBJECT:
       VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, true);
@@ -1927,7 +1979,11 @@
         descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
       }
       const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
-      work_line_->SetResultRegisterType(return_type);
+      if (!return_type.IsLowHalf()) {
+        work_line_->SetResultRegisterType(return_type);
+      } else {
+        work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
+      }
       just_set_result = true;
       break;
     }
@@ -1989,7 +2045,11 @@
       }
       const RegType& return_type = reg_types_.FromDescriptor(class_loader_, return_type_descriptor,
                                                              false);
-      work_line_->SetResultRegisterType(return_type);
+      if (!return_type.IsLowHalf()) {
+        work_line_->SetResultRegisterType(return_type);
+      } else {
+        work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
+      }
       just_set_result = true;
       break;
     }
@@ -2007,7 +2067,11 @@
           descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
         }
         const RegType& return_type =  reg_types_.FromDescriptor(class_loader_, descriptor, false);
-        work_line_->SetResultRegisterType(return_type);
+        if (!return_type.IsLowHalf()) {
+          work_line_->SetResultRegisterType(return_type);
+        } else {
+          work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
+        }
         just_set_result = true;
       }
       break;
@@ -2057,8 +2121,11 @@
         descriptor = MethodHelper(abs_method).GetReturnTypeDescriptor();
       }
       const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
-      work_line_->SetResultRegisterType(return_type);
-      work_line_->SetResultRegisterType(return_type);
+      if (!return_type.IsLowHalf()) {
+        work_line_->SetResultRegisterType(return_type);
+      } else {
+        work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
+      }
       just_set_result = true;
       break;
     }
@@ -2068,49 +2135,61 @@
       break;
     case Instruction::NEG_LONG:
     case Instruction::NOT_LONG:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Long());
+      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+                                   reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::NEG_FLOAT:
       work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Float());
       break;
     case Instruction::NEG_DOUBLE:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Double());
+      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+                                   reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::INT_TO_LONG:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Integer());
+      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+                                     reg_types_.Integer());
       break;
     case Instruction::INT_TO_FLOAT:
       work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_DOUBLE:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Integer());
+      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+                                     reg_types_.Integer());
       break;
     case Instruction::LONG_TO_INT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Long());
+      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Integer(),
+                                       reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::LONG_TO_FLOAT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Long());
+      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Float(),
+                                       reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::LONG_TO_DOUBLE:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Long());
+      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+                                   reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::FLOAT_TO_INT:
       work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Float());
       break;
     case Instruction::FLOAT_TO_LONG:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Float());
+      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+                                     reg_types_.Float());
       break;
     case Instruction::FLOAT_TO_DOUBLE:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Float());
+      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+                                     reg_types_.Float());
       break;
     case Instruction::DOUBLE_TO_INT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Double());
+      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Integer(),
+                                       reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::DOUBLE_TO_LONG:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Double());
+      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+                                   reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::DOUBLE_TO_FLOAT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Double());
+      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Float(),
+                                       reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::INT_TO_BYTE:
       work_line_->CheckUnaryOp(dec_insn, reg_types_.Byte(), reg_types_.Integer());
@@ -2130,12 +2209,14 @@
     case Instruction::SHL_INT:
     case Instruction::SHR_INT:
     case Instruction::USHR_INT:
-      work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
+      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:
-      work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true);
+      work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(),
+                                reg_types_.Integer(), true);
       break;
     case Instruction::ADD_LONG:
     case Instruction::SUB_LONG:
@@ -2145,13 +2226,16 @@
     case Instruction::AND_LONG:
     case Instruction::OR_LONG:
     case Instruction::XOR_LONG:
-      work_line_->CheckBinaryOp(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Long(), false);
+      work_line_->CheckBinaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+                                    reg_types_.LongLo(), reg_types_.LongHi(),
+                                    reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::SHL_LONG:
     case Instruction::SHR_LONG:
     case Instruction::USHR_LONG:
       /* 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);
+      work_line_->CheckBinaryOpWideShift(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+                                         reg_types_.Integer());
       break;
     case Instruction::ADD_FLOAT:
     case Instruction::SUB_FLOAT:
@@ -2165,7 +2249,9 @@
     case Instruction::MUL_DOUBLE:
     case Instruction::DIV_DOUBLE:
     case Instruction::REM_DOUBLE:
-      work_line_->CheckBinaryOp(dec_insn, reg_types_.Double(), reg_types_.Double(), reg_types_.Double(), false);
+      work_line_->CheckBinaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+                                    reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+                                    reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::ADD_INT_2ADDR:
     case Instruction::SUB_INT_2ADDR:
@@ -2192,12 +2278,15 @@
     case Instruction::AND_LONG_2ADDR:
     case Instruction::OR_LONG_2ADDR:
     case Instruction::XOR_LONG_2ADDR:
-      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Long(), false);
+      work_line_->CheckBinaryOp2addrWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+                                         reg_types_.LongLo(), reg_types_.LongHi(),
+                                         reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::SHL_LONG_2ADDR:
     case Instruction::SHR_LONG_2ADDR:
     case Instruction::USHR_LONG_2ADDR:
-      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Integer(), false);
+      work_line_->CheckBinaryOp2addrWideShift(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+                                              reg_types_.Integer());
       break;
     case Instruction::ADD_FLOAT_2ADDR:
     case Instruction::SUB_FLOAT_2ADDR:
@@ -2211,7 +2300,9 @@
     case Instruction::MUL_DOUBLE_2ADDR:
     case Instruction::DIV_DOUBLE_2ADDR:
     case Instruction::REM_DOUBLE_2ADDR:
-      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Double(), reg_types_.Double(),  reg_types_.Double(), false);
+      work_line_->CheckBinaryOp2addrWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+                                         reg_types_.DoubleLo(),  reg_types_.DoubleHi(),
+                                         reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::ADD_INT_LIT16:
     case Instruction::RSUB_INT:
@@ -2290,7 +2381,7 @@
   }  // end - switch (dec_insn.opcode)
 
   if (have_pending_hard_failure_) {
-    if (!Runtime::Current()->IsStarted()) {
+    if (Runtime::Current()->IsCompiler()) {
       /* When compiling, check that the last failure is a hard failure */
       CHECK_EQ(failures_[failures_.size() - 1], VERIFY_ERROR_BAD_CLASS_HARD);
     }
@@ -2645,7 +2736,7 @@
     const RegType& super = GetDeclaringClass().GetSuperClass(&reg_types_);
     if (super.IsUnresolvedTypes()) {
       Fail(VERIFY_ERROR_NO_METHOD) << "unknown super class in invoke-super from "
-                                   << PrettyMethod(method_idx_, *dex_file_)
+                                   << PrettyMethod(dex_method_idx_, *dex_file_)
                                    << " to super " << PrettyMethod(res_method);
       return NULL;
     }
@@ -2653,7 +2744,7 @@
     if (res_method->GetMethodIndex() >= super_klass->GetVTable()->GetLength()) {
       MethodHelper mh(res_method);
       Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from "
-                                   << PrettyMethod(method_idx_, *dex_file_)
+                                   << PrettyMethod(dex_method_idx_, *dex_file_)
                                    << " to super " << super
                                    << "." << mh.GetName()
                                    << mh.GetSignature();
@@ -2768,7 +2859,7 @@
 }
 
 void MethodVerifier::VerifyAGet(const DecodedInstruction& dec_insn,
-                             const RegType& insn_type, bool is_primitive) {
+                                const RegType& insn_type, bool is_primitive) {
   const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC);
   if (!index_type.IsArrayIndexTypes()) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
@@ -2782,7 +2873,8 @@
         work_line_->SetRegisterType(dec_insn.vA, reg_types_.Zero());
       } else {
         // Category 2
-        work_line_->SetRegisterType(dec_insn.vA, reg_types_.ConstLo());
+        work_line_->SetRegisterTypeWide(dec_insn.vA, reg_types_.FromCat2ConstLo(0, false),
+                                        reg_types_.FromCat2ConstHi(0, false));
       }
     } else if (!array_type.IsArrayTypes()) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "not array type " << array_type << " with aget";
@@ -2797,14 +2889,19 @@
             << " 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_BAD_CLASS_HARD) << "array type " << array_type
-              << " incompatible with aget of type " << insn_type;
+                 (insn_type.IsLong() && component_type.IsDouble()))) {
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array type " << array_type
+            << " 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.
+        // 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.
+        if (!component_type.IsLowHalf()) {
           work_line_->SetRegisterType(dec_insn.vA, component_type);
+        } else {
+          work_line_->SetRegisterTypeWide(dec_insn.vA, component_type,
+                                          component_type.HighHalf(&reg_types_));
+        }
       }
     }
   }
@@ -2925,7 +3022,7 @@
       // the field is declared in this class
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "cannot access instance field " << PrettyField(field)
                                         << " of a not fully initialized object within the context of "
-                                        << PrettyMethod(method_idx_, *dex_file_);
+                                        << PrettyMethod(dex_method_idx_, *dex_file_);
       return NULL;
     } else if (!field_klass.IsAssignableFrom(obj_type)) {
       // Trying to access C1.field1 using reference of type C2, which is neither C1 or a sub-class
@@ -2986,7 +3083,11 @@
       return;
     }
   }
-  work_line_->SetRegisterType(dec_insn.vA, field_type);
+  if (!field_type.IsLowHalf()) {
+    work_line_->SetRegisterType(dec_insn.vA, field_type);
+  } else {
+    work_line_->SetRegisterTypeWide(dec_insn.vA, field_type, field_type.HighHalf(&reg_types_));
+  }
 }
 
 void MethodVerifier::VerifyISPut(const DecodedInstruction& dec_insn,
@@ -3113,7 +3214,7 @@
 }
 
 const RegType& MethodVerifier::GetMethodReturnType() {
-  const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx_);
+  const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
   const DexFile::ProtoId& proto_id = dex_file_->GetMethodPrototype(method_id);
   uint16_t return_type_idx = proto_id.return_type_idx_;
   const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(return_type_idx));
@@ -3125,7 +3226,7 @@
     Class* klass = foo_method_->GetDeclaringClass();
     return reg_types_.FromClass(klass, klass->IsFinal());
   } else {
-    const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx_);
+    const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
     const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
     return reg_types_.FromDescriptor(class_loader_, descriptor, false);
   }
@@ -3265,6 +3366,50 @@
   return it->second;
 }
 
+std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_pc) {
+  RegisterLine* line = reg_table_.GetLine(dex_pc);
+  std::vector<int32_t> result;
+  for (size_t i = 0; i < line->NumRegs(); ++i) {
+    const RegType& type = line->GetRegisterType(i);
+    if (type.IsConstant()) {
+      result.push_back(type.IsPreciseConstant() ? kConstant : kImpreciseConstant);
+      result.push_back(type.ConstantValue());
+    } else if (type.IsConstantLo()) {
+      result.push_back(type.IsPreciseConstantLo() ? kConstant : kImpreciseConstant);
+      result.push_back(type.ConstantValueLo());
+    } else if (type.IsConstantHi()) {
+      result.push_back(type.IsPreciseConstantHi() ? kConstant : kImpreciseConstant);
+      result.push_back(type.ConstantValueHi());
+    } else if (type.IsIntegralTypes()) {
+      result.push_back(kIntVReg);
+      result.push_back(0);
+    } else if (type.IsFloat()) {
+      result.push_back(kFloatVReg);
+      result.push_back(0);
+    } else if (type.IsLong()) {
+      result.push_back(kLongLoVReg);
+      result.push_back(0);
+      result.push_back(kLongHiVReg);
+      result.push_back(0);
+      ++i;
+    } else if (type.IsDouble()) {
+      result.push_back(kDoubleLoVReg);
+      result.push_back(0);
+      result.push_back(kDoubleHiVReg);
+      result.push_back(0);
+      ++i;
+    } else if (type.IsUndefined() || type.IsConflict() || type.IsHighHalf()) {
+      result.push_back(kUndefined);
+      result.push_back(0);
+    } else {
+      CHECK(type.IsNonZeroReferenceTypes()) << type;
+      result.push_back(kReferenceVReg);
+      result.push_back(0);
+    }
+  }
+  return result;
+}
+
 Mutex* MethodVerifier::dex_gc_maps_lock_ = NULL;
 MethodVerifier::DexGcMapTable* MethodVerifier::dex_gc_maps_ = NULL;