diff options
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 126 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.h | 5 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 247 | ||||
| -rw-r--r-- | runtime/class_linker.h | 7 | ||||
| -rw-r--r-- | runtime/exception_test.cc | 2 | ||||
| -rw-r--r-- | runtime/mirror/class.cc | 17 |
6 files changed, 226 insertions, 178 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index bf541c6e04..d265ed1c0d 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -758,11 +758,6 @@ void CompilerDriver::UpdateImageClasses(base::TimingLogger& timings) { } } -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 bool SkipClass(ClassLinker* class_linker, jobject class_loader, const Dex 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 const char* class_initializer_black_list[] = { 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 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl 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, can_init_static_fields); + 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); + } } - soa.Self()->AssertNoPendingException(); } } + soa.Self()->AssertNoPendingException(); } // If successfully initialized place in SSB array. if (klass->IsInitialized()) { @@ -2105,15 +2108,8 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl } } // 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 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t 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 @@ CompiledClass* CompilerDriver::GetCompiledClass(ClassReference ref) const { 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::SetBitcodeFileName(std::string const& filename) { 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 bcde178b76..22a510b86b 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -296,7 +296,8 @@ class CompilerDriver { // 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 @@ class CompilerDriver { 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 0110b366d6..96c74203e6 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -782,8 +782,10 @@ class ScopedFlock { } ~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 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { } // 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 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { // 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 @@ static void CheckProxyMethod(mirror::ArtMethod* method, 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 - Thread* self = Thread::Current(); + // 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 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, boo 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); - } - uint64_t t0 = NanoTime(); + 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 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, boo } } - // 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 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, boo 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 @@ bool ClassLinker::WaitForInitializeClass(mirror::Class* klass, Thread* self, Obj 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 @@ bool ClassLinker::IsSameDescriptorInDifferentClassContexts(const char* descripto 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 @@ void ClassLinker::ConstructFieldMap(const DexFile& dex_file, const DexFile::Clas } } -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 624b7cecec..5ef6d8f006 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -437,16 +437,11 @@ class ClassLinker { 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 e48208d771..2e6b0a8f56 100644 --- a/runtime/exception_test.cc +++ b/runtime/exception_test.cc @@ -41,7 +41,7 @@ class ExceptionTest : public CommonTest { 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 29025f26c8..19e134fdfe 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -51,14 +51,20 @@ void Class::ResetClass() { } 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 @@ void Class::SetStatus(Status new_status) { 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); } |