Address various dex2oat hangs

class_linker.cc - add support for no such field error
dex_verifier.cc - address cases where type information isn't available
due to verification errors
dex_verifier.h - support for monitor nesting upto 64 deep

These changes address Bug: 5742499, Bug: 5743100, Bug: 5742810

Change-Id: I2e9a77059314c84f21ad5d194bad77c7f2fa2ee9
diff --git a/src/class_linker.cc b/src/class_linker.cc
index e32f8a5..04a368d8 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -59,13 +59,12 @@
   va_end(args);
 }
 
-void ThrowNoSuchMethodError(const char* kind,
-    Class* c, const StringPiece& name, const StringPiece& signature) {
+void ThrowNoSuchMethodError(bool is_direct, Class* c, const StringPiece& name,
+                            const StringPiece& signature) {
   ClassHelper kh(c);
   std::ostringstream msg;
-  msg << "no " << kind << " method " << name << "." << signature
-      << " in class " << kh.GetDescriptor()
-      << " or its superclasses";
+  msg << "no " << (is_direct ? "direct" : "virtual") << " method " << name << "." << signature
+      << " in class " << kh.GetDescriptor() << " or its superclasses";
   std::string location(kh.GetLocation());
   if (!location.empty()) {
     msg << " (defined in " << location << ")";
@@ -73,6 +72,19 @@
   Thread::Current()->ThrowNewException("Ljava/lang/NoSuchMethodError;", msg.str().c_str());
 }
 
+void ThrowNoSuchFieldError(bool is_static, Class* c, const StringPiece& type,
+                           const StringPiece& name) {
+  ClassHelper kh(c);
+  std::ostringstream msg;
+  msg << "no " << (is_static ? "static": "instance") << " field " << name << " of type " << type
+      << " in class " << kh.GetDescriptor() << " or its superclasses";
+  std::string location(kh.GetLocation());
+  if (!location.empty()) {
+    msg << " (defined in " << location << ")";
+  }
+  Thread::Current()->ThrowNewException("Ljava/lang/NoSuchFieldError;", msg.str().c_str());
+}
+
 void ThrowEarlierClassFailure(Class* c) {
   /*
    * The class failed to initialize on a previous attempt, so we want to throw
@@ -2770,7 +2782,7 @@
   if (resolved != NULL) {
     dex_cache->SetResolvedMethod(method_idx, resolved);
   } else {
-    ThrowNoSuchMethodError(is_direct ? "direct" : "virtual", klass, name, signature);
+    ThrowNoSuchMethodError(is_direct, klass, name, signature);
   }
   return resolved;
 }
@@ -2787,6 +2799,7 @@
   const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
   Class* klass = ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader);
   if (klass == NULL) {
+    DCHECK(Thread::Current()->IsExceptionPending());
     return NULL;
   }
 
@@ -2800,9 +2813,7 @@
   if (resolved != NULL) {
     dex_cache->SetResolvedField(field_idx, resolved);
   } else {
-    // TODO: this check fails when the app class path contains a class from the boot class path
-    CHECK(Thread::Current()->IsExceptionPending())
-        << PrettyClass(klass) << " " << name << " " << type << " " << is_static;
+    ThrowNoSuchFieldError(is_static, klass, type, name);
   }
   return resolved;
 }
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index f6bdd7d..9094067 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -2033,6 +2033,10 @@
       bool is_checkcast = dec_insn.opcode_ == Instruction::CHECK_CAST;
       const RegType& res_type =
           ResolveClassAndCheckAccess(is_checkcast ? dec_insn.vB_ : dec_insn.vC_);
+      if (res_type.IsUnknown()) {
+        CHECK_NE(failure_, VERIFY_ERROR_NONE);
+        break;  // couldn't resolve class
+      }
       // TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
       const RegType& orig_type =
           work_line_->GetRegisterType(is_checkcast ? dec_insn.vA_ : dec_insn.vB_);
@@ -3028,7 +3032,7 @@
   if (res_method == NULL) {
     const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
     const RegType& klass_type = ResolveClassAndCheckAccess(method_id.class_idx_);
-    if(klass_type.IsUnresolvedTypes()) {
+    if(klass_type.IsUnresolvedTypes() || klass_type.IsUnknown()) {
       return NULL;  // Can't resolve Class so no more to do here
     }
     Class* klass = klass_type.GetClass();
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index 201cd2b..5b2f54e 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -707,14 +707,14 @@
 
   void CopyRegToLockDepth(size_t dst, size_t src) {
     if (reg_to_lock_depths_.count(src) > 0) {
-      uint32_t depths = reg_to_lock_depths_[src];
+      uint64_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];
+      uint64_t depths = reg_to_lock_depths_[reg];
       return (depths & (1 << depth)) != 0;
     } else {
       return false;
@@ -722,9 +722,9 @@
   }
 
   void SetRegToLockDepth(size_t reg, size_t depth) {
-    CHECK_LT(depth, 32u);
+    CHECK_LT(depth, 64u);
     DCHECK(!IsSetLockDepth(reg, depth));
-    uint32_t depths;
+    uint64_t depths;
     if (reg_to_lock_depths_.count(reg) > 0) {
       depths = reg_to_lock_depths_[reg];
       depths = depths | (1 << depth);
@@ -735,9 +735,9 @@
   }
 
   void ClearRegToLockDepth(size_t reg, size_t depth) {
-    CHECK_LT(depth, 32u);
+    CHECK_LT(depth, 64u);
     DCHECK(IsSetLockDepth(reg, depth));
-    uint32_t depths = reg_to_lock_depths_[reg];
+    uint64_t depths = reg_to_lock_depths_[reg];
     depths = depths ^ (1 << depth);
     if (depths != 0) {
       reg_to_lock_depths_[reg] = depths;
@@ -766,7 +766,7 @@
   // 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::map<uint32_t, uint64_t> reg_to_lock_depths_;
 };
 std::ostream& operator<<(std::ostream& os, const RegisterLine& rhs);