summaryrefslogtreecommitdiffstats
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2016-04-21 12:21:55 -0700
committerAndreas Gampe <agampe@google.com>2016-04-22 09:35:14 -0700
commitfc49fa05c51a26ba1b185401cdba95cea1b67b39 (patch)
tree8f870cb7448434eb733a36060dcf7641977efaa7 /runtime/class_linker.cc
parent89a48396e0f0482e0ab446a1b2bd3217a51746b1 (diff)
downloadandroid_art-fc49fa05c51a26ba1b185401cdba95cea1b67b39.tar.gz
android_art-fc49fa05c51a26ba1b185401cdba95cea1b67b39.tar.bz2
android_art-fc49fa05c51a26ba1b185401cdba95cea1b67b39.zip
ART: Slightly change InitializeClass flow
Since 884f3b83ed6b2a378535ac6b2be57d6b2e22de09, verification isn't run completely under a class' lock. This means it is possible to race from unverified to initialized in InitializeClass. So check the class state after VerifyClass, and handle new success and failure cases. Bug: 28254258 Change-Id: I22a6121477e409987281bc81c28b6c942f1bd319
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc23
1 files changed, 22 insertions, 1 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 504d860be4..6fc1a5abe7 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4451,7 +4451,20 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
// We failed to verify, expect either the klass to be erroneous or verification failed at
// compile time.
if (klass->IsErroneous()) {
- CHECK(self->IsExceptionPending());
+ // The class is erroneous. This may be a verifier error, or another thread attempted
+ // verification and/or initialization and failed. We can distinguish those cases by
+ // whether an exception is already pending.
+ if (self->IsExceptionPending()) {
+ // Check that it's a VerifyError.
+ DCHECK_EQ("java.lang.Class<java.lang.VerifyError>",
+ PrettyClass(self->GetException()->GetClass()));
+ } else {
+ // Check that another thread attempted initialization.
+ DCHECK_NE(0, klass->GetClinitThreadId());
+ DCHECK_NE(self->GetTid(), klass->GetClinitThreadId());
+ // Need to rethrow the previous failure now.
+ ThrowEarlierClassFailure(klass.Get(), true);
+ }
VlogClassInitializationFailure(klass);
} else {
CHECK(Runtime::Current()->IsAotCompiler());
@@ -4461,6 +4474,14 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
} else {
self->AssertNoPendingException();
}
+
+ // A separate thread could have moved us all the way to initialized. A "simple" example
+ // involves a subclass of the current class being initialized at the same time (which
+ // will implicitly initialize the superclass, if scheduled that way). b/28254258
+ DCHECK_NE(mirror::Class::kStatusError, klass->GetStatus());
+ if (klass->IsInitialized()) {
+ return true;
+ }
}
// If the class is kStatusInitializing, either this thread is