diff options
author | Andreas Gampe <agampe@google.com> | 2016-04-21 12:21:55 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2016-04-22 09:35:14 -0700 |
commit | fc49fa05c51a26ba1b185401cdba95cea1b67b39 (patch) | |
tree | 8f870cb7448434eb733a36060dcf7641977efaa7 /runtime/class_linker.cc | |
parent | 89a48396e0f0482e0ab446a1b2bd3217a51746b1 (diff) | |
download | android_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.cc | 23 |
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 |