Don't retry verification at compile time.
We don't re-verify verified or erroneous classes at compile time. We
also need to not re-verify compile time verified classes or else the
class status can become misleading.
This should fix races seen in dalvik-dev builds since parallel
verification was re-enabled.
Some other code and logic clean up.
Change-Id: Iff8987292064b825742c52e408d38c31eb25c526
diff --git a/src/class_linker.cc b/src/class_linker.cc
index a88a2d6..6e3d903 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2015,25 +2015,32 @@
// TODO: assert that the monitor on the Class is held
ObjectLock lock(klass);
- if (klass->IsVerified()) {
+ // Don't attempt to re-verify if already sufficiently verified.
+ if (klass->IsVerified() ||
+ (klass->IsCompileTimeVerified() && Runtime::Current()->IsCompiler())) {
return;
}
- // The class might already be erroneous if we attempted to verify a subclass
+ // The class might already be erroneous, for example at compile time if we attempted to verify
+ // this class as a parent to another.
if (klass->IsErroneous()) {
ThrowEarlierClassFailure(klass);
return;
}
- CHECK(klass->GetStatus() == Class::kStatusResolved ||
- klass->GetStatus() == Class::kStatusRetryVerificationAtRuntime) << PrettyClass(klass);
- klass->SetStatus(Class::kStatusVerifying);
+ if (klass->GetStatus() == Class::kStatusResolved) {
+ klass->SetStatus(Class::kStatusVerifying);
+ } else {
+ CHECK_EQ(klass->GetStatus(), Class::kStatusRetryVerificationAtRuntime) << PrettyClass(klass);
+ CHECK(!Runtime::Current()->IsCompiler());
+ klass->SetStatus(Class::kStatusVerifyingAtRuntime);
+ }
- // Verify super class
+ // Verify super class.
Class* super = klass->GetSuperClass();
std::string error_msg;
if (super != NULL) {
- // Acquire lock to prevent races on verifying the super class
+ // Acquire lock to prevent races on verifying the super class.
ObjectLock lock(super);
if (!super->IsVerified() && !super->IsErroneous()) {
@@ -2054,7 +2061,6 @@
if (cause.get() != NULL) {
self->GetException()->SetCause(cause.get());
}
- CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyDescriptor(klass);
klass->SetStatus(Class::kStatusError);
return;
}
@@ -2100,7 +2106,7 @@
klass->SetStatus(Class::kStatusVerified);
}
}
- // Sanity check that a verified class has GC maps on all methods
+ // Sanity check that a verified class has GC maps on all methods.
CheckMethodsHaveGcMaps(klass);
} else {
LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass)
@@ -2109,7 +2115,6 @@
Thread* self = Thread::Current();
self->AssertNoPendingException();
self->ThrowNewException("Ljava/lang/VerifyError;", error_msg.c_str());
- CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyDescriptor(klass);
klass->SetStatus(Class::kStatusError);
}
}
@@ -2134,7 +2139,8 @@
CHECK(oat_class.get() != NULL)
<< dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor;
oat_file_class_status = oat_class->GetStatus();
- if (oat_file_class_status == Class::kStatusVerified || oat_file_class_status == Class::kStatusInitialized) {
+ if (oat_file_class_status == Class::kStatusVerified ||
+ oat_file_class_status == Class::kStatusInitialized) {
return true;
}
if (oat_file_class_status == Class::kStatusRetryVerificationAtRuntime) {
@@ -2411,7 +2417,7 @@
bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit, bool can_init_statics) {
CHECK(klass->IsResolved() || klass->IsErroneous())
- << PrettyClass(klass) << " is " << klass->GetStatus();
+ << PrettyClass(klass) << ": state=" << klass->GetStatus();
Thread* self = Thread::Current();
@@ -2663,9 +2669,9 @@
CHECK(klass != NULL);
if (!klass->IsInterface() && klass->HasSuperClass()) {
Class* super_class = klass->GetSuperClass();
- if (super_class->GetStatus() != Class::kStatusInitialized) {
+ if (!super_class->IsInitialized()) {
CHECK(!super_class->IsInterface());
- ObjectLock lock(klass); // Must hold lock on object when initializing.
+ ObjectLock lock(klass); // Must hold lock on object when initializing and setting status.
bool super_initialized = InitializeClass(super_class, can_run_clinit, can_init_fields);
// TODO: check for a pending exception
if (!super_initialized) {