summaryrefslogtreecommitdiff
path: root/runtime/mirror/class.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/mirror/class.cc')
-rw-r--r--runtime/mirror/class.cc72
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