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 {