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) {
diff --git a/src/compiler.cc b/src/compiler.cc
index b010750..b80b6a6 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -1257,7 +1257,8 @@
Thread::Current()->ClearException();
}
- CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous()) << PrettyClass(klass);
+ CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous())
+ << PrettyDescriptor(klass) << ": state=" << klass->GetStatus();
CHECK(!Thread::Current()->IsExceptionPending()) << PrettyTypeOf(Thread::Current()->GetException());
}
diff --git a/src/object.h b/src/object.h
index 36db13d..e746f73 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1176,14 +1176,15 @@
enum Status {
kStatusError = -1,
kStatusNotReady = 0,
- kStatusIdx = 1, // loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_
- kStatusLoaded = 2, // DEX idx values resolved
- kStatusResolved = 3, // part of linking
- kStatusVerifying = 4, // in the process of being verified
- kStatusRetryVerificationAtRuntime = 5, // compile time verification failed, retry at runtime
- kStatusVerified = 6, // logically part of linking; done pre-init
- kStatusInitializing = 7, // class init in progress
- kStatusInitialized = 8, // ready to go
+ kStatusIdx = 1, // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_.
+ kStatusLoaded = 2, // DEX idx values resolved.
+ kStatusResolved = 3, // Part of linking.
+ kStatusVerifying = 4, // In the process of being verified.
+ kStatusRetryVerificationAtRuntime = 5, // Compile time verification failed, retry at runtime.
+ kStatusVerifyingAtRuntime = 6, // Retrying verification at runtime.
+ kStatusVerified = 7, // Logically part of linking; done pre-init.
+ kStatusInitializing = 8, // Class init in progress.
+ kStatusInitialized = 9, // Ready to go.
};
Status GetStatus() const {