Verifier sets class to error on hard error, resolved on soft.
This solves problems with the runtime finding classes that were rejected
by the verifier at compile time that end up passing at runtime. Before,
all classes that failed compile time verification were being set to
error, and now only classes that have hard errors should be set to
error.
Change-Id: I3a694d12ba4d6051b0310b21f8161f5aa62b43c3
diff --git a/src/class_linker.cc b/src/class_linker.cc
index cc44a9e..0f7ccad 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2088,9 +2088,9 @@
if (oat_file_class_status == Class::kStatusVerified || oat_file_class_status == Class::kStatusInitialized) {
return true;
}
- if (oat_file_class_status == Class::kStatusError) {
- // Compile time verification failed. Compile time verification can fail because we have
- // incomplete type information. Consider the following:
+ if (oat_file_class_status == Class::kStatusResolved) {
+ // Compile time verification failed with a soft error. Compile time verification can fail
+ // because we have incomplete type information. Consider the following:
// class ... {
// Foo x;
// .... () {
@@ -2108,6 +2108,11 @@
// at compile time).
return false;
}
+ if (oat_file_class_status == Class::kStatusError) {
+ // Compile time verification failed with a hard error. This is caused by invalid instructions
+ // in the class. These errors are unrecoverable.
+ return false;
+ }
if (oat_file_class_status == Class::kStatusNotReady) {
// Status is uninitialized if we couldn't determine the status at compile time, for example,
// not loading the class.
diff --git a/src/compiler.cc b/src/compiler.cc
index b56fd49..7d71278 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -1109,11 +1109,15 @@
// ClassLinker::VerifyClass throws, which isn't useful in the compiler.
CHECK(Thread::Current()->IsExceptionPending());
Thread::Current()->ClearException();
- // We want to try verification again at run-time, so move back into the resolved state.
- klass->SetStatus(Class::kStatusResolved);
+ art::Compiler::ClassReference ref(context->GetDexFile(), class_def_index);
+ if (!verifier::DexVerifier::IsClassRejected(ref)) {
+ // If the erroneous class wasn't rejected by the verifier, it was a soft error. We want
+ // to try verification again at run-time, so move back into the resolved state.
+ klass->SetStatus(Class::kStatusResolved);
+ }
}
- CHECK(klass->IsVerified() || klass->IsResolved()) << PrettyClass(klass);
+ CHECK(klass->IsVerified() || klass->IsResolved() || klass->IsErroneous()) << PrettyClass(klass);
CHECK(!Thread::Current()->IsExceptionPending()) << PrettyTypeOf(Thread::Current()->GetException());
}
@@ -1143,7 +1147,10 @@
const char* descriptor = dex_file.GetClassDescriptor(class_def);
Class* klass = class_linker->FindClass(descriptor, class_loader);
if (klass != NULL) {
- class_linker->EnsureInitialized(klass, false);
+ if (klass->IsVerified()) {
+ // Only try to initialize classes that were successfully verified.
+ class_linker->EnsureInitialized(klass, false);
+ }
// record the final class status if necessary
Class::Status status = klass->GetStatus();
ClassReference ref(&dex_file, class_def_index);