Tolerant compilation of classes with missing super classes

Change-Id: If64f25ae36204ab2ea5499f27601696dea9d4016
diff --git a/Android.mk b/Android.mk
index 5801447..ba7cf62 100644
--- a/Android.mk
+++ b/Android.mk
@@ -127,7 +127,7 @@
 
 .PHONY: test-art-target-oat-process-Calculator
 # Note that using this instead of "adb shell am start" make sure that the /data/art-cache is up-to-date
-test-art-target-oat-process-Calculator: $(TARGET_OUT_APPS)/Calculator.oat test-art-target-sync
+test-art-target-oat-process-Calculator: $(TARGET_OUT_APPS)/Calculator.oat $(TARGET_OUT_JAVA_LIBRARIES)/am.oat test-art-target-sync
 	mkdir -p $(TARGET_OUT_DATA)/art-cache
 	unzip $(TARGET_OUT_APPS)/Calculator.apk classes.dex -d $(TARGET_OUT_DATA)/art-cache
 	mv $(TARGET_OUT_DATA)/art-cache/classes.dex $(TARGET_OUT_DATA)/art-cache/system@app@Calculator.apk@classes.dex.c96b4ebb # crc32 from "unzip -lv $(TARGET_OUT_APPS)/Calculator.apk"
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 1c25f61..fb47c48 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -39,6 +39,7 @@
 void ThrowVirtualMachineError(const char* fmt, ...) {
   va_list args;
   va_start(args, fmt);
+  UNIMPLEMENTED(FATAL) << "VirtualMachineError is abstract, throw something else";
   Thread::Current()->ThrowNewExceptionV("Ljava/lang/VirtualMachineError;", fmt, args);
   va_end(args);
 }
@@ -1649,8 +1650,10 @@
   if (klass->GetSuperClassTypeIdx() != DexFile::kDexNoIndex) {
     Class* super_class = ResolveType(dex_file, klass->GetSuperClassTypeIdx(), klass);
     if (super_class == NULL) {
-      ThrowVirtualMachineError("Failed to resolve superclass with type index %d for class %s",
-          klass->GetSuperClassTypeIdx(), PrettyDescriptor(klass->GetDescriptor()).c_str());
+      DCHECK(Thread::Current()->IsExceptionPending());
+      // TODO: can't ThrowVirtualMachineError, its abstract
+      // ThrowVirtualMachineError("Failed to resolve superclass with type index %d for class %s",
+      //     klass->GetSuperClassTypeIdx(), PrettyDescriptor(klass->GetDescriptor()).c_str());
       return false;
     }
     klass->SetSuperClass(super_class);
@@ -2062,8 +2065,8 @@
     Field* field = fields->Get(i);
     if (false) {  // enable to debug field layout
       LOG(INFO) << "LinkFields: " << (instance ? "instance" : "static")
-                << " class=" << klass->GetDescriptor()->ToModifiedUtf8()
-                << " field=" << field->GetName()->ToModifiedUtf8()
+                << " class=" << PrettyClass(klass)
+                << " field=" << PrettyField(field)
                 << " offset=" << field->GetField32(MemberOffset(Field::OffsetOffset()), false);
     }
     const Class* type = field->GetTypeDuringLinking();
@@ -2242,8 +2245,12 @@
 
   const char* name = dex_file.dexStringById(field_id.name_idx_);
   Class* field_type = ResolveType(dex_file, field_id.type_idx_, dex_cache, class_loader);
-  // TODO: LinkageError?
-  CHECK(field_type != NULL);
+  if (field_type == NULL) {
+    // TODO: LinkageError?
+    UNIMPLEMENTED(WARNING) << "Failed to resolve type of field " << name
+                           << " in " << PrettyClass(klass);
+    return NULL;
+}
   if (is_static) {
     resolved = klass->FindStaticField(name, field_type);
   } else {
diff --git a/src/compiler.cc b/src/compiler.cc
index 54793ba..d29e8ca 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -105,7 +105,13 @@
       for (size_t i = 0; i < num_static_fields; ++i) {
         DexFile::Field dex_field;
         dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
-        class_linker->ResolveField(dex_file, dex_field.field_idx_, dex_cache, class_loader, true);
+        Field* field = class_linker->ResolveField(dex_file, dex_field.field_idx_, dex_cache,
+                                                  class_loader, true);
+        if (field == NULL) {
+          Thread* self = Thread::Current();
+          CHECK(self->IsExceptionPending());
+          self->ClearException();
+        }
       }
     }
     if (num_instance_fields != 0) {
@@ -113,7 +119,13 @@
       for (size_t i = 0; i < num_instance_fields; ++i) {
         DexFile::Field dex_field;
         dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
-        class_linker->ResolveField(dex_file, dex_field.field_idx_, dex_cache, class_loader, false);
+        Field* field = class_linker->ResolveField(dex_file, dex_field.field_idx_, dex_cache,
+                                                  class_loader, false);
+        if (field == NULL) {
+          Thread* self = Thread::Current();
+          CHECK(self->IsExceptionPending());
+          self->ClearException();
+        }
       }
     }
     if (num_direct_methods != 0) {
@@ -121,8 +133,13 @@
       for (size_t i = 0; i < num_direct_methods; ++i) {
         DexFile::Method dex_method;
         dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
-        class_linker->ResolveMethod(dex_file, dex_method.method_idx_, dex_cache, class_loader,
-                                    true);
+        Method* method = class_linker->ResolveMethod(dex_file, dex_method.method_idx_, dex_cache,
+                                                     class_loader, true);
+        if (method == NULL) {
+          Thread* self = Thread::Current();
+          CHECK(self->IsExceptionPending());
+          self->ClearException();
+        }
       }
     }
     if (num_virtual_methods != 0) {
@@ -130,8 +147,13 @@
       for (size_t i = 0; i < num_virtual_methods; ++i) {
         DexFile::Method dex_method;
         dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
-        class_linker->ResolveMethod(dex_file, dex_method.method_idx_, dex_cache, class_loader,
-                                    false);
+        Method* method = class_linker->ResolveMethod(dex_file, dex_method.method_idx_, dex_cache,
+                                                     class_loader, false);
+        if (method == NULL) {
+          Thread* self = Thread::Current();
+          CHECK(self->IsExceptionPending());
+          self->ClearException();
+        }
       }
     }
   }
@@ -153,10 +175,23 @@
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
     const char* descriptor = dex_file.GetClassDescriptor(class_def);
     Class* klass = class_linker->FindClass(descriptor, class_loader);
-    CHECK(klass->IsResolved());
-    CHECK(klass != NULL);
+    if (klass == NULL) {
+      Thread* self = Thread::Current();
+      CHECK(self->IsExceptionPending());
+      self->ClearException();
+      continue;
+    }
+    CHECK(klass->IsResolved()) << PrettyClass(klass);
     class_linker->VerifyClass(klass);
-    CHECK(klass->IsVerified() || klass->IsErroneous());
+    CHECK(klass->IsVerified() || klass->IsErroneous()) << PrettyClass(klass);
+    //CHECK(!Thread::Current()->IsExceptionPending());
+    if (klass->IsErroneous()) {
+      Thread* self = Thread::Current();
+      if (self->IsExceptionPending()) {
+        UNIMPLEMENTED(WARNING) << "Verifier failed to cleanup exceptions internally";
+        self->ClearException();
+      }
+    }
   }
   dex_file.ChangePermissions(PROT_READ);
 }
@@ -212,8 +247,7 @@
     if (klass == NULL) {
       // previous verification error will cause FindClass to throw
       Thread* self = Thread::Current();
-      // CHECK(self->IsExceptionPending());
-      UNIMPLEMENTED(WARNING) << "CHECK for verification error after FindClass " << descriptor;
+      CHECK(self->IsExceptionPending());
       self->ClearException();
     } else {
       CompileClass(klass);
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 6ea276f..ee81543 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -2548,6 +2548,7 @@
         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;
@@ -3802,6 +3803,7 @@
       method->GetDeclaringClass(), failure, false);
   if (field == NULL) {
     LOG(ERROR) << "VFY: unable to resolve instance field " << field_idx;
+    *failure = VERIFY_ERROR_GENERIC;
     return field;
   }
 
@@ -4436,13 +4438,14 @@
     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);
+      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);
+      // TODO: restore this assert?
+      // DCHECK(*failure != VERIFY_ERROR_NONE) << PrettyClass(referrer) << " " << PrettyClass(klass);
       return NULL;
     }
 
@@ -4692,8 +4695,10 @@
 
 void DexVerifier::CheckFinalFieldAccess(const Method* method,
     const Field* field, VerifyError* failure) {
-  if (!field->IsFinal())
+  DCHECK(field != NULL);
+  if (!field->IsFinal()) {
     return;
+  }
 
   /* make sure we're in the same class */
   if (method->GetDeclaringClass() != field->GetDeclaringClass()) {
diff --git a/src/object.cc b/src/object.cc
index f47f16e..ff49ad3 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -751,7 +751,9 @@
     (*stub)(this, receiver, self, args, result);
     LOG(INFO) << "returned " << PrettyMethod(this) << " code=" << (void*) GetCode() << " stub=" << (void*) stub;
   } else {
-    LOG(WARNING) << "Not invoking method with no associated code: " << PrettyMethod(this);
+    if (Runtime::Current()->IsStarted()) {
+      LOG(WARNING) << "Not invoking method with no associated code: " << PrettyMethod(this);
+    }
     if (result != NULL) {
       result->j = 0;
     }
@@ -782,8 +784,8 @@
 
 void Class::SetStatus(Status new_status) {
   CHECK(new_status > GetStatus() || new_status == kStatusError ||
-      !Runtime::Current()->IsStarted()) << GetDescriptor()->ToModifiedUtf8();
-  CHECK(sizeof(Status) == sizeof(uint32_t));
+      !Runtime::Current()->IsStarted()) << PrettyClass(this);
+  CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this);
   return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_),
                     new_status, false);
 }
@@ -799,9 +801,9 @@
 }
 
 Object* Class::AllocObject() {
-  DCHECK(!IsAbstract());
-  DCHECK(!IsInterface());
-  DCHECK(!IsPrimitive());
+  DCHECK(!IsAbstract()) << PrettyClass(this);
+  DCHECK(!IsInterface()) << PrettyClass(this);
+  DCHECK(!IsPrimitive()) << PrettyClass(this);
   return Heap::AllocObject(this, this->object_size_);
 }
 
@@ -927,7 +929,7 @@
 
 bool Class::Implements(const Class* klass) const {
   DCHECK(klass != NULL);
-  DCHECK(klass->IsInterface());
+  DCHECK(klass->IsInterface()) << PrettyClass(this);
   // All interfaces implemented directly and by our superclass, and
   // recursively all super-interfaces of those interfaces, are listed
   // in iftable_, so we can just do a linear scan through that.
@@ -961,28 +963,28 @@
 //   Object[]         = int[] --> false
 //
 bool Class::IsArrayAssignableFromArray(const Class* src) const {
-  DCHECK(IsArrayClass());
-  DCHECK(src->IsArrayClass());
+  DCHECK(IsArrayClass())  << PrettyClass(this);
+  DCHECK(src->IsArrayClass()) << PrettyClass(src);
   return GetComponentType()->IsAssignableFrom(src->GetComponentType());
 }
 
 bool Class::IsAssignableFromArray(const Class* src) const {
-  DCHECK(!IsInterface());  // handled first in IsAssignableFrom
-  DCHECK(src->IsArrayClass());
+  DCHECK(!IsInterface()) << PrettyClass(this);  // handled first in IsAssignableFrom
+  DCHECK(src->IsArrayClass()) << PrettyClass(src);
   if (!IsArrayClass()) {
     // If "this" is not also an array, it must be Object.
     // src's super should be java_lang_Object, since it is an array.
     Class* java_lang_Object = src->GetSuperClass();
-    DCHECK(java_lang_Object != NULL);
-    DCHECK(java_lang_Object->GetSuperClass() == NULL);
+    DCHECK(java_lang_Object != NULL) << PrettyClass(src);
+    DCHECK(java_lang_Object->GetSuperClass() == NULL) << PrettyClass(src);
     return this == java_lang_Object;
   }
   return IsArrayAssignableFromArray(src);
 }
 
 bool Class::IsSubClass(const Class* klass) const {
-  DCHECK(!IsInterface());
-  DCHECK(!IsArrayClass());
+  DCHECK(!IsInterface()) << PrettyClass(this);
+  DCHECK(!IsArrayClass()) << PrettyClass(this);
   const Class* current = this;
   do {
     if (current == klass) {
@@ -1055,8 +1057,8 @@
 
 Method* Class::FindVirtualMethodForInterface(Method* method) {
   Class* declaring_class = method->GetDeclaringClass();
-  DCHECK(declaring_class != NULL);
-  DCHECK(declaring_class->IsInterface());
+  DCHECK(declaring_class != NULL) << PrettyClass(this);
+  DCHECK(declaring_class->IsInterface()) << PrettyMethod(method);
   // TODO cache to improve lookup speed
   int32_t iftable_count = GetIfTableCount();
   ObjectArray<InterfaceEntry>* iftable = GetIfTable();
diff --git a/src/object.h b/src/object.h
index ba8aaa9..e94671b 100644
--- a/src/object.h
+++ b/src/object.h
@@ -2177,7 +2177,7 @@
       GetFieldObject<Class*>(
           OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_), false);
   DCHECK(result != NULL);
-  DCHECK(result->IsLoaded() || result->IsErroneous());
+  DCHECK(result->IsIdxLoaded() || result->IsErroneous());
   return result;
 }
 
@@ -2607,7 +2607,7 @@
 }
 
 inline uint32_t Method::GetAccessFlags() const {
-  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
+  DCHECK(GetDeclaringClass()->IsIdxLoaded() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), false);
 }
 
diff --git a/src/thread.cc b/src/thread.cc
index 71b9090..004eaae 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -233,7 +233,7 @@
     }
     return NULL;  // Failure
   } else {
-    CHECK(klass->IsArrayClass());
+    CHECK(klass->IsArrayClass()) << PrettyClass(klass);
     return Array::Alloc(klass, component_count);
   }
 }
@@ -253,15 +253,15 @@
       DCHECK(Thread::Current()->IsExceptionPending());
       return NULL;  // Failure
     }
-    CHECK(klass->IsArrayClass());
+    CHECK(klass->IsArrayClass()) << PrettyClass(klass);
   }
   return Array::Alloc(klass, component_count);
 }
 
 // Check whether it is safe to cast one class to the other, throw exception and return -1 on failure
 extern "C" int artCheckCastFromCode(const Class* a, const Class* b) {
-  DCHECK(a->IsClass());
-  DCHECK(b->IsClass());
+  DCHECK(a->IsClass()) << PrettyClass(a);
+  DCHECK(b->IsClass()) << PrettyClass(b);
   if (b->IsAssignableFrom(a)) {
     return 0;  // Success
   } else {