diff options
Diffstat (limited to 'runtime/mirror/class.cc')
-rw-r--r-- | runtime/mirror/class.cc | 72 |
1 files changed, 55 insertions, 17 deletions
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index b7429ddb4b..e57cc982a3 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -188,28 +188,57 @@ ObjPtr<ClassExt> Class::EnsureExtDataPresent(Handle<Class> h_this, Thread* self) } } +template <typename T> +static void CheckSetStatus(Thread* self, T thiz, ClassStatus new_status, ClassStatus old_status) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (UNLIKELY(new_status <= old_status && new_status != ClassStatus::kErrorUnresolved && + new_status != ClassStatus::kErrorResolved && new_status != ClassStatus::kRetired)) { + LOG(FATAL) << "Unexpected change back of class status for " << thiz->PrettyClass() << " " + << old_status << " -> " << new_status; + } + if (old_status == ClassStatus::kInitialized) { + // We do not hold the lock for making the class visibly initialized + // as this is unnecessary and could lead to deadlocks. + CHECK_EQ(new_status, ClassStatus::kVisiblyInitialized); + } else if ((new_status >= ClassStatus::kResolved || old_status >= ClassStatus::kResolved) && + !Locks::mutator_lock_->IsExclusiveHeld(self)) { + // When classes are being resolved the resolution code should hold the + // lock or have everything else suspended + CHECK_EQ(thiz->GetLockOwnerThreadId(), self->GetThreadId()) + << "Attempt to change status of class while not holding its lock: " << thiz->PrettyClass() + << " " << old_status << " -> " << new_status; + } + if (UNLIKELY(Locks::mutator_lock_->IsExclusiveHeld(self))) { + CHECK(!Class::IsErroneous(new_status)) + << "status " << new_status + << " cannot be set while suspend-all is active. Would require allocations."; + CHECK(thiz->IsResolved()) + << thiz->PrettyClass() + << " not resolved during suspend-all status change. Waiters might be missed!"; + } +} + +void Class::SetStatusLocked(ClassStatus new_status) { + ClassStatus old_status = GetStatus(); + CheckSetStatus(Thread::Current(), this, new_status, old_status); + if (kBitstringSubtypeCheckEnabled) { + // FIXME: This looks broken with respect to aborted transactions. + SubtypeCheck<ObjPtr<mirror::Class>>::WriteStatus(this, new_status); + } else { + // The ClassStatus is always in the 4 most-significant bits of status_. + static_assert(sizeof(status_) == sizeof(uint32_t), "Size of status_ not equal to uint32"); + uint32_t new_status_value = static_cast<uint32_t>(new_status) << (32 - kClassStatusBitSize); + DCHECK(!Runtime::Current()->IsActiveTransaction()); + SetField32Volatile<false>(StatusOffset(), new_status_value); + } +} + void Class::SetStatus(Handle<Class> h_this, ClassStatus new_status, Thread* self) { ClassStatus old_status = h_this->GetStatus(); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); bool class_linker_initialized = class_linker != nullptr && class_linker->IsInitialized(); if (LIKELY(class_linker_initialized)) { - if (UNLIKELY(new_status <= old_status && - new_status != ClassStatus::kErrorUnresolved && - new_status != ClassStatus::kErrorResolved && - new_status != ClassStatus::kRetired)) { - LOG(FATAL) << "Unexpected change back of class status for " << h_this->PrettyClass() - << " " << old_status << " -> " << new_status; - } - if (old_status == ClassStatus::kInitialized) { - // We do not hold the lock for making the class visibly initialized - // as this is unnecessary and could lead to deadlocks. - CHECK_EQ(new_status, ClassStatus::kVisiblyInitialized); - } else if (new_status >= ClassStatus::kResolved || old_status >= ClassStatus::kResolved) { - // When classes are being resolved the resolution code should hold the lock. - CHECK_EQ(h_this->GetLockOwnerThreadId(), self->GetThreadId()) - << "Attempt to change status of class while not holding its lock: " - << h_this->PrettyClass() << " " << old_status << " -> " << new_status; - } + CheckSetStatus(self, h_this, new_status, old_status); } if (UNLIKELY(IsErroneous(new_status))) { CHECK(!h_this->IsErroneous()) @@ -336,6 +365,15 @@ void Class::SetClassSize(uint32_t new_class_size) { SetField32Transaction(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size); } +ObjPtr<Class> Class::GetObsoleteClass() { + ObjPtr<ClassExt> ext(GetExtData()); + if (ext.IsNull()) { + return nullptr; + } else { + return ext->GetObsoleteClass(); + } +} + // Return the class' name. The exact format is bizarre, but it's the specified behavior for // Class.getName: keywords for primitive types, regular "[I" form for primitive arrays (so "int" // but "[I"), and arrays of reference types written between "L" and ";" but with dots rather than |