Don't allow class status to go backward except for error.
Allow greater parallelism of initialization.
Bug 10393546.
Change-Id: Ic194ed490bb0a986250c09fcf335eb1be9714657
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index bf541c6..d265ed1 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -758,11 +758,6 @@
}
}
-void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) {
- MutexLock mu(Thread::Current(), CompilerDriver::compiled_classes_lock_);
- compiled_classes_.Put(ref, compiled_class);
-}
-
bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file,
uint32_t type_idx) {
if (IsImage() && IsImageClass(dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)))) {
@@ -1428,6 +1423,7 @@
static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manager,
size_t class_def_index)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
+ ATRACE_CALL();
Thread* self = Thread::Current();
jobject jclass_loader = manager->GetClassLoader();
const DexFile& dex_file = *manager->GetDexFile();
@@ -2048,6 +2044,7 @@
static void InitializeClass(const ParallelCompilationManager* manager, size_t class_def_index)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
+ ATRACE_CALL();
const DexFile::ClassDef& class_def = manager->GetDexFile()->GetClassDef(class_def_index);
ScopedObjectAccess soa(Thread::Current());
mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader());
@@ -2056,48 +2053,54 @@
if (klass != NULL) {
// Only try to initialize classes that were successfully verified.
if (klass->IsVerified()) {
- // We don't want class initialization occurring on multiple threads due to deadlock problems.
- // For example, a parent class is initialized (holding its lock) that refers to a sub-class
- // in its static/class initializer causing it to try to acquire the sub-class' lock. While
- // on a second thread the sub-class is initialized (holding its lock) after first initializing
- // its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent
- // lock ordering and consequent potential deadlock.
- // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
- // than use a special Object for the purpose we use the Class of java.lang.Class.
- ObjectLock lock(soa.Self(), klass->GetClass());
- bool can_init_static_fields = manager->GetCompiler()->IsImage() &&
- manager->GetCompiler()->IsImageClass(descriptor);
- manager->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields);
- if (soa.Self()->IsExceptionPending()) {
- soa.Self()->GetException(NULL)->Dump();
- }
+ // Attempt to initialize the class but bail if we either need to initialize the super-class
+ // or static fields.
+ manager->GetClassLinker()->EnsureInitialized(klass, false, false);
if (!klass->IsInitialized()) {
- if (can_init_static_fields) {
- // NoPreloadHolder inner class implies this should not be initialized early.
- bool is_black_listed = StringPiece(descriptor).ends_with("$NoPreloadHolder;");
- if (!is_black_listed) {
- for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
- if (StringPiece(descriptor) == class_initializer_black_list[i]) {
- is_black_listed = true;
- break;
+ // We don't want non-trivial class initialization occurring on multiple threads due to
+ // deadlock problems. For example, a parent class is initialized (holding its lock) that
+ // refers to a sub-class in its static/class initializer causing it to try to acquire the
+ // sub-class' lock. While on a second thread the sub-class is initialized (holding its lock)
+ // after first initializing its parents, whose locks are acquired. This leads to a
+ // parent-to-child and a child-to-parent lock ordering and consequent potential deadlock.
+ // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
+ // than use a special Object for the purpose we use the Class of java.lang.Class.
+ ObjectLock lock(soa.Self(), klass->GetClass());
+ // Attempt to initialize allowing initialization of parent classes but still not static
+ // fields.
+ manager->GetClassLinker()->EnsureInitialized(klass, false, true);
+ if (!klass->IsInitialized()) {
+ // We need to initialize static fields, we only do this for image classes that aren't
+ // black listed or marked with the $NoPreloadHolder.
+ bool can_init_static_fields = manager->GetCompiler()->IsImage() &&
+ manager->GetCompiler()->IsImageClass(descriptor);
+ if (can_init_static_fields) {
+ // NoPreloadHolder inner class implies this should not be initialized early.
+ bool is_black_listed = StringPiece(descriptor).ends_with("$NoPreloadHolder;");
+ if (!is_black_listed) {
+ for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
+ if (StringPiece(descriptor) == class_initializer_black_list[i]) {
+ is_black_listed = true;
+ break;
+ }
+ }
+ }
+ if (!is_black_listed) {
+ VLOG(compiler) << "Initializing: " << descriptor;
+ if (StringPiece(descriptor) == "Ljava/lang/Void;") {
+ // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
+ ObjectLock lock(soa.Self(), klass);
+ mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
+ CHECK_EQ(fields->GetLength(), 1);
+ fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V'));
+ klass->SetStatus(mirror::Class::kStatusInitialized);
+ } else {
+ manager->GetClassLinker()->EnsureInitialized(klass, true, true);
}
}
}
- if (!is_black_listed) {
- VLOG(compiler) << "Initializing: " << descriptor;
- if (StringPiece(descriptor) == "Ljava/lang/Void;") {
- // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
- ObjectLock lock(soa.Self(), klass);
- mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
- CHECK_EQ(fields->GetLength(), 1);
- fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V'));
- klass->SetStatus(mirror::Class::kStatusInitialized);
- } else {
- manager->GetClassLinker()->EnsureInitialized(klass, true, can_init_static_fields);
- }
- soa.Self()->AssertNoPendingException();
- }
}
+ soa.Self()->AssertNoPendingException();
}
// If successfully initialized place in SSB array.
if (klass->IsInitialized()) {
@@ -2105,15 +2108,8 @@
}
}
// Record the final class status if necessary.
- mirror::Class::Status status = klass->GetStatus();
ClassReference ref(manager->GetDexFile(), class_def_index);
- CompiledClass* compiled_class = manager->GetCompiler()->GetCompiledClass(ref);
- if (compiled_class == NULL) {
- compiled_class = new CompiledClass(status);
- manager->GetCompiler()->RecordClassStatus(ref, compiled_class);
- } else {
- DCHECK_GE(status, compiled_class->GetStatus()) << descriptor;
- }
+ manager->GetCompiler()->RecordClassStatus(ref, klass->GetStatus());
}
// Clear any class not found or verification exceptions.
soa.Self()->ClearException();
@@ -2288,7 +2284,7 @@
Thread* self = Thread::Current();
if (compiled_method != NULL) {
MethodReference ref(&dex_file, method_idx);
- CHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
+ DCHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
{
MutexLock mu(self, compiled_methods_lock_);
compiled_methods_.Put(ref, compiled_method);
@@ -2313,6 +2309,32 @@
return it->second;
}
+void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status status) {
+ MutexLock mu(Thread::Current(), compiled_classes_lock_);
+ auto it = compiled_classes_.find(ref);
+ if (it == compiled_classes_.end() || it->second->GetStatus() != status) {
+ // An entry doesn't exist or the status is lower than the new status.
+ if (it != compiled_classes_.end()) {
+ CHECK_GT(status, it->second->GetStatus());
+ delete it->second;
+ }
+ switch (status) {
+ case mirror::Class::kStatusNotReady:
+ case mirror::Class::kStatusError:
+ case mirror::Class::kStatusRetryVerificationAtRuntime:
+ case mirror::Class::kStatusVerified:
+ case mirror::Class::kStatusInitialized:
+ break; // Expected states.
+ default:
+ LOG(FATAL) << "Unexpected class status for class "
+ << PrettyDescriptor(ref.first->GetClassDescriptor(ref.first->GetClassDef(ref.second)))
+ << " of " << status;
+ }
+ CompiledClass* compiled_class = new CompiledClass(status);
+ compiled_classes_.Overwrite(ref, compiled_class);
+ }
+}
+
CompiledMethod* CompilerDriver::GetCompiledMethod(MethodReference ref) const {
MutexLock mu(Thread::Current(), compiled_methods_lock_);
MethodTable::const_iterator it = compiled_methods_.find(ref);
@@ -2335,13 +2357,13 @@
void CompilerDriver::AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file,
size_t class_def_index) {
- MutexLock mu(self, freezing_constructor_lock_);
+ WriterMutexLock mu(self, freezing_constructor_lock_);
freezing_constructor_classes_.insert(ClassReference(dex_file, class_def_index));
}
bool CompilerDriver::RequiresConstructorBarrier(Thread* self, const DexFile* dex_file,
size_t class_def_index) {
- MutexLock mu(self, freezing_constructor_lock_);
+ ReaderMutexLock mu(self, freezing_constructor_lock_);
return freezing_constructor_classes_.count(ClassReference(dex_file, class_def_index)) != 0;
}
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index bcde178..22a510b 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -296,7 +296,8 @@
// Checks if class specified by type_idx is one of the image_classes_
bool IsImageClass(const char* descriptor) const;
- void RecordClassStatus(ClassReference ref, CompiledClass* compiled_class);
+ void RecordClassStatus(ClassReference ref, mirror::Class::Status status)
+ LOCKS_EXCLUDED(compiled_classes_lock_);
private:
// Compute constant code and method pointers when possible
@@ -362,7 +363,7 @@
InstructionSet instruction_set_;
// All class references that require
- mutable Mutex freezing_constructor_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ mutable ReaderWriterMutex freezing_constructor_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
std::set<ClassReference> freezing_constructor_classes_ GUARDED_BY(freezing_constructor_lock_);
typedef SafeMap<const ClassReference, CompiledClass*> ClassTable;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 0110b36..96c7420 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -782,8 +782,10 @@
}
~ScopedFlock() {
- int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_UN));
- CHECK_EQ(0, flock_result);
+ if (file_.get() != NULL) {
+ int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_UN));
+ CHECK_EQ(0, flock_result);
+ }
}
private:
@@ -2284,18 +2286,18 @@
}
// Verify super class.
- mirror::Class* super = klass->GetSuperClass();
- if (super != NULL) {
+ SirtRef<mirror::Class> super(self, klass->GetSuperClass());
+ if (super.get() != NULL) {
// Acquire lock to prevent races on verifying the super class.
- ObjectLock lock(self, super);
+ ObjectLock lock(self, super.get());
if (!super->IsVerified() && !super->IsErroneous()) {
- Runtime::Current()->GetClassLinker()->VerifyClass(super);
+ VerifyClass(super.get());
}
if (!super->IsCompileTimeVerified()) {
std::string error_msg(StringPrintf("Rejecting class %s that attempts to sub-class erroneous class %s",
PrettyDescriptor(klass).c_str(),
- PrettyDescriptor(super).c_str()));
+ PrettyDescriptor(super.get()).c_str()));
LOG(ERROR) << error_msg << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
SirtRef<mirror::Throwable> cause(self, self->GetException(NULL));
if (cause.get() != NULL) {
@@ -2339,7 +2341,14 @@
// Make sure all classes referenced by catch blocks are resolved.
ResolveClassExceptionHandlerTypes(dex_file, klass);
if (verifier_failure == verifier::MethodVerifier::kNoFailure) {
- klass->SetStatus(mirror::Class::kStatusVerified);
+ // Even though there were no verifier failures we need to respect whether the super-class
+ // was verified or requiring runtime reverification.
+ if (super.get() == NULL || super->IsVerified()) {
+ klass->SetStatus(mirror::Class::kStatusVerified);
+ } else {
+ CHECK_EQ(super->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
+ klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime);
+ }
} else {
CHECK_EQ(verifier_failure, verifier::MethodVerifier::kSoftFailure);
// Soft failures at compile time should be retried at runtime. Soft
@@ -2695,31 +2704,85 @@
CHECK_EQ(mh.GetReturnType(), mh2.GetReturnType());
}
-bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_statics) {
- CHECK(klass->IsResolved() || klass->IsErroneous())
- << PrettyClass(klass) << ": state=" << klass->GetStatus();
+static bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics,
+ bool can_init_parents)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (can_init_statics && can_init_statics) {
+ return true;
+ }
+ if (!can_init_statics) {
+ // Check if there's a class initializer.
+ mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
+ if (clinit != NULL) {
+ return false;
+ }
+ // Check if there are encoded static values needing initialization.
+ if (klass->NumStaticFields() != 0) {
+ ClassHelper kh(klass);
+ const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
+ DCHECK(dex_class_def != NULL);
+ if (dex_class_def->static_values_off_ != 0) {
+ return false;
+ }
+ }
+ }
+ if (!klass->IsInterface() && klass->HasSuperClass()) {
+ mirror::Class* super_class = klass->GetSuperClass();
+ if (!can_init_parents && !super_class->IsInitialized()) {
+ return false;
+ } else {
+ if (!CanWeInitializeClass(super_class, can_init_statics, true)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
+ bool can_init_parents) {
+ // see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol
+
+ // Are we already initialized and therefore done?
+ // Note: we differ from the JLS here as we don't do this under the lock, this is benign as
+ // an initialized class will never change its state.
+ if (klass->IsInitialized()) {
+ return true;
+ }
+
+ // Fast fail if initialization requires a full runtime. Not part of the JLS.
+ if (!CanWeInitializeClass(klass, can_init_statics, can_init_parents)) {
+ return false;
+ }
Thread* self = Thread::Current();
-
+ uint64_t t0;
{
- // see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol
ObjectLock lock(self, klass);
- if (klass->GetStatus() == mirror::Class::kStatusInitialized) {
+ // Re-check under the lock in case another thread initialized ahead of us.
+ if (klass->IsInitialized()) {
return true;
}
+ // Was the class already found to be erroneous? Done under the lock to match the JLS.
if (klass->IsErroneous()) {
ThrowEarlierClassFailure(klass);
return false;
}
- if (klass->GetStatus() == mirror::Class::kStatusResolved ||
- klass->GetStatus() == mirror::Class::kStatusRetryVerificationAtRuntime) {
+ CHECK(klass->IsResolved()) << PrettyClass(klass) << ": state=" << klass->GetStatus();
+
+ if (!klass->IsVerified()) {
VerifyClass(klass);
- if (klass->GetStatus() != mirror::Class::kStatusVerified) {
- if (klass->GetStatus() == mirror::Class::kStatusError) {
+ if (!klass->IsVerified()) {
+ // We failed to verify, expect either the klass to be erroneous or verification failed at
+ // compile time.
+ if (klass->IsErroneous()) {
CHECK(self->IsExceptionPending());
+ } else {
+ CHECK(Runtime::Current()->IsCompiler());
+ CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
}
return false;
}
@@ -2742,38 +2805,65 @@
if (!ValidateSuperClassDescriptors(klass)) {
klass->SetStatus(mirror::Class::kStatusError);
- lock.NotifyAll();
return false;
}
- DCHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass);
+ CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass);
+ // From here out other threads may observe that we're initializing and so changes of state
+ // require the a notification.
klass->SetClinitThreadId(self->GetTid());
klass->SetStatus(mirror::Class::kStatusInitializing);
+
+ t0 = NanoTime();
}
- uint64_t t0 = NanoTime();
-
- if (!InitializeSuperClass(klass, can_run_clinit, can_init_statics)) {
- // Super class initialization failed, this can be because we can't run
- // super-class class initializers in which case we'll be verified.
- // Otherwise this class is erroneous.
- if (!can_run_clinit) {
- CHECK(klass->IsVerified());
- } else {
- CHECK(klass->IsErroneous());
+ // Initialize super classes, must be done will initializing for the JLS.
+ if (!klass->IsInterface() && klass->HasSuperClass()) {
+ mirror::Class* super_class = klass->GetSuperClass();
+ if (!super_class->IsInitialized()) {
+ CHECK(!super_class->IsInterface());
+ CHECK(can_init_parents);
+ bool super_initialized = InitializeClass(super_class, can_init_statics, true);
+ if (!super_initialized) {
+ // The super class was verified ahead of entering initializing, we should only be here if
+ // the super class became erroneous due to initialization.
+ CHECK(super_class->IsErroneous() && self->IsExceptionPending())
+ << "Super class initialization failed for " << PrettyDescriptor(super_class)
+ << " that has unexpected status " << super_class->GetStatus()
+ << "\nPending exception:\n"
+ << (self->GetException(NULL) != NULL ? self->GetException(NULL)->Dump() : "");
+ ObjectLock lock(self, klass);
+ // Initialization failed because the super-class is erroneous.
+ klass->SetStatus(mirror::Class::kStatusError);
+ lock.NotifyAll();
+ return false;
+ }
}
- // Signal to any waiting threads that saw this class as initializing.
- ObjectLock lock(self, klass);
- lock.NotifyAll();
- return false;
}
- bool has_static_field_initializers = InitializeStaticFields(klass, can_init_statics);
+ if (klass->NumStaticFields() > 0) {
+ ClassHelper kh(klass);
+ const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
+ CHECK(dex_class_def != NULL);
+ const DexFile& dex_file = kh.GetDexFile();
+ EncodedStaticFieldValueIterator it(dex_file, kh.GetDexCache(), klass->GetClassLoader(),
+ this, *dex_class_def);
+ if (it.HasNext()) {
+ CHECK(can_init_statics);
+ // We reordered the fields, so we need to be able to map the field indexes to the right fields.
+ SafeMap<uint32_t, mirror::ArtField*> field_map;
+ ConstructFieldMap(dex_file, *dex_class_def, klass, field_map);
+ for (size_t i = 0; it.HasNext(); i++, it.Next()) {
+ it.ReadValueToField(field_map.Get(i));
+ }
+ }
+ }
mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
- if (clinit != NULL && can_run_clinit) {
- if (Runtime::Current()->IsStarted()) {
+ if (clinit != NULL) {
+ CHECK(can_init_statics);
+ if (LIKELY(Runtime::Current()->IsStarted())) {
JValue result;
clinit->Invoke(self, NULL, 0, &result, 'V');
} else {
@@ -2781,11 +2871,8 @@
}
}
- // Opportunistically set static method trampolines to their destination. Unless initialization
- // is being hindered at compile time.
- if (can_init_statics || can_run_clinit || (!has_static_field_initializers && clinit == NULL)) {
- FixupStaticTrampolines(klass);
- }
+ // Opportunistically set static method trampolines to their destination.
+ FixupStaticTrampolines(klass);
uint64_t t1 = NanoTime();
@@ -2805,14 +2892,8 @@
global_stats->class_init_time_ns += (t1 - t0);
thread_stats->class_init_time_ns += (t1 - t0);
// Set the class as initialized except if failed to initialize static fields.
- if ((!can_init_statics && has_static_field_initializers) ||
- (!can_run_clinit && clinit != NULL)) {
- klass->SetStatus(mirror::Class::kStatusVerified);
- success = false;
- } else {
- klass->SetStatus(mirror::Class::kStatusInitialized);
- }
- if (success && VLOG_IS_ON(class_linker)) {
+ klass->SetStatus(mirror::Class::kStatusInitialized);
+ if (VLOG_IS_ON(class_linker)) {
ClassHelper kh(klass);
LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation();
}
@@ -2826,6 +2907,7 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
while (true) {
self->AssertNoPendingException();
+ CHECK(!klass->IsInitialized());
lock.WaitIgnoringInterrupts();
// When we wake up, repeat the test for init-in-progress. If
@@ -2952,43 +3034,16 @@
return found1 == found2;
}
-bool ClassLinker::InitializeSuperClass(mirror::Class* klass, bool can_run_clinit, bool can_init_fields) {
- CHECK(klass != NULL);
- if (!klass->IsInterface() && klass->HasSuperClass()) {
- mirror::Class* super_class = klass->GetSuperClass();
- if (!super_class->IsInitialized()) {
- CHECK(!super_class->IsInterface());
- // Must hold lock on object when initializing and setting status.
- Thread* self = Thread::Current();
- ObjectLock lock(self, klass);
- bool super_initialized = InitializeClass(super_class, can_run_clinit, can_init_fields);
- // TODO: check for a pending exception
- if (!super_initialized) {
- if (!can_run_clinit) {
- // Don't set status to error when we can't run <clinit>.
- CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusInitializing) << PrettyClass(klass);
- klass->SetStatus(mirror::Class::kStatusVerified);
- return false;
- }
- klass->SetStatus(mirror::Class::kStatusError);
- klass->NotifyAll(self);
- return false;
- }
- }
- }
- return true;
-}
-
-bool ClassLinker::EnsureInitialized(mirror::Class* c, bool can_run_clinit, bool can_init_fields) {
+bool ClassLinker::EnsureInitialized(mirror::Class* c, bool can_init_fields, bool can_init_parents) {
DCHECK(c != NULL);
if (c->IsInitialized()) {
return true;
}
- bool success = InitializeClass(c, can_run_clinit, can_init_fields);
+ bool success = InitializeClass(c, can_init_fields, can_init_parents);
if (!success) {
Thread* self = Thread::Current();
- CHECK(self->IsExceptionPending() || !can_run_clinit) << PrettyClass(c);
+ CHECK(self->IsExceptionPending() || !can_init_fields || !can_init_parents) << PrettyClass(c);
}
return success;
}
@@ -3003,38 +3058,6 @@
}
}
-bool ClassLinker::InitializeStaticFields(mirror::Class* klass, bool can_init_statics) {
- size_t num_static_fields = klass->NumStaticFields();
- if (num_static_fields == 0) {
- return false;
- }
- mirror::DexCache* dex_cache = klass->GetDexCache();
- // TODO: this seems like the wrong check. do we really want !IsPrimitive && !IsArray?
- if (dex_cache == NULL) {
- return false;
- }
- ClassHelper kh(klass);
- const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
- CHECK(dex_class_def != NULL);
- const DexFile& dex_file = kh.GetDexFile();
- EncodedStaticFieldValueIterator it(dex_file, dex_cache, klass->GetClassLoader(),
- this, *dex_class_def);
-
- if (!it.HasNext()) {
- return false;
- } else {
- if (can_init_statics) {
- // We reordered the fields, so we need to be able to map the field indexes to the right fields.
- SafeMap<uint32_t, mirror::ArtField*> field_map;
- ConstructFieldMap(dex_file, *dex_class_def, klass, field_map);
- for (size_t i = 0; it.HasNext(); i++, it.Next()) {
- it.ReadValueToField(field_map.Get(i));
- }
- }
- return true;
- }
-}
-
bool ClassLinker::LinkClass(SirtRef<mirror::Class>& klass,
mirror::ObjectArray<mirror::Class>* interfaces) {
CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 624b7ce..5ef6d8f 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -437,16 +437,11 @@
void RegisterOatFileLocked(const OatFile& oat_file) EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
- bool InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_statics)
+ bool InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_parents)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool WaitForInitializeClass(mirror::Class* klass, Thread* self, ObjectLock& lock);
bool ValidateSuperClassDescriptors(const mirror::Class* klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool InitializeSuperClass(mirror::Class* klass, bool can_run_clinit, bool can_init_fields)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Initialize static fields, returns true if fields were initialized.
- bool InitializeStaticFields(mirror::Class* klass, bool can_init_statics)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsSameDescriptorInDifferentClassContexts(const char* descriptor,
const mirror::Class* klass1,
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index e48208d..2e6b0a8 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -41,7 +41,7 @@
soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle")));
my_klass_ = class_linker_->FindClass("LExceptionHandle;", class_loader.get());
ASSERT_TRUE(my_klass_ != NULL);
- class_linker_->EnsureInitialized(my_klass_, false, true);
+ class_linker_->EnsureInitialized(my_klass_, true, true);
dex_ = my_klass_->GetDexCache()->GetDexFile();
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 29025f2..19e134f 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -51,14 +51,20 @@
}
void Class::SetStatus(Status new_status) {
- CHECK(new_status > GetStatus() || new_status == kStatusError || !Runtime::Current()->IsStarted())
- << PrettyClass(this) << " " << GetStatus() << " -> " << new_status;
- CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this);
+ if (UNLIKELY(new_status <= GetStatus() && new_status != kStatusError)) {
+ bool class_linker_initialized = Runtime::Current()->GetClassLinker() != nullptr;
+ if (class_linker_initialized) {
+ LOG(FATAL) << "Unexpected change back of class status for " << PrettyClass(this) << " "
+ << GetStatus() << " -> " << new_status;
+ }
+ }
if (new_status > kStatusResolved) {
- CHECK_EQ(GetThinLockId(), Thread::Current()->GetThinLockId()) << PrettyClass(this);
+ CHECK_EQ(GetThinLockId(), Thread::Current()->GetThinLockId())
+ << "Attempt to change status of class while not holding its lock " << PrettyClass(this);
}
if (new_status == kStatusError) {
- CHECK_NE(GetStatus(), kStatusError) << PrettyClass(this);
+ CHECK_NE(GetStatus(), kStatusError)
+ << "Attempt to set as erroneous an already erroneous class " << PrettyClass(this);
// Stash current exception.
Thread* self = Thread::Current();
@@ -96,6 +102,7 @@
self->SetException(gc_safe_throw_location, old_exception.get());
}
+ CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this);
return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false);
}