Change ClassStatus to fit into 4 bits.
In preparation for extending the type check bit string from
24 to 28 bits, rewrite ClassStatus to fit into 4 bits. Also
perform a proper cleanup of the ClassStatus, i.e. change it
to an enum class, remove the "Status" word from enumerator
names, replace "Max" with "Last" in line with other
enumerations and remove aliases from mirror::Class.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: Pixel 2 XL boots.
Test: testrunner.py --target --optimizing
Bug: 64692057
Bug: 65318848
Change-Id: Iec1610ba5dac2c527b36c12819f132e1a77f2d45
diff --git a/runtime/mirror/class-refvisitor-inl.h b/runtime/mirror/class-refvisitor-inl.h
index 3d52ead..263b774 100644
--- a/runtime/mirror/class-refvisitor-inl.h
+++ b/runtime/mirror/class-refvisitor-inl.h
@@ -32,12 +32,12 @@
inline void Class::VisitReferences(ObjPtr<Class> klass, const Visitor& visitor) {
VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass.Ptr(), visitor);
// Right after a class is allocated, but not yet loaded
- // (kStatusNotReady, see ClassLinker::LoadClass()), GC may find it
+ // (ClassStatus::kNotReady, see ClassLinker::LoadClass()), GC may find it
// and scan it. IsTemp() may call Class::GetAccessFlags() but may
// fail in the DCHECK in Class::GetAccessFlags() because the class
- // status is kStatusNotReady. To avoid it, rely on IsResolved()
+ // status is ClassStatus::kNotReady. To avoid it, rely on IsResolved()
// only. This is fine because a temp class never goes into the
- // kStatusResolved state.
+ // ClassStatus::kResolved state.
if (IsResolved<kVerifyFlags>()) {
// Temp classes don't ever populate imt/vtable or static fields and they are not even
// allocated with the right size for those. Also, unresolved classes don't have fields
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 10daebb..6bee3cf 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -54,23 +54,6 @@
GcRoot<Class> Class::java_lang_Class_;
-constexpr Class::Status Class::kStatusRetired;
-constexpr Class::Status Class::kStatusErrorResolved;
-constexpr Class::Status Class::kStatusErrorUnresolved;
-constexpr Class::Status Class::kStatusNotReady;
-constexpr Class::Status Class::kStatusIdx;
-constexpr Class::Status Class::kStatusLoaded;
-constexpr Class::Status Class::kStatusResolving;
-constexpr Class::Status Class::kStatusResolved;
-constexpr Class::Status Class::kStatusVerifying;
-constexpr Class::Status Class::kStatusRetryVerificationAtRuntime;
-constexpr Class::Status Class::kStatusVerifyingAtRuntime;
-constexpr Class::Status Class::kStatusVerified;
-constexpr Class::Status Class::kStatusSuperclassValidated;
-constexpr Class::Status Class::kStatusInitializing;
-constexpr Class::Status Class::kStatusInitialized;
-constexpr Class::Status Class::kStatusMax;
-
void Class::SetClassClass(ObjPtr<Class> java_lang_Class) {
CHECK(java_lang_Class_.IsNull())
<< java_lang_Class_.Read()
@@ -131,19 +114,19 @@
}
}
-void Class::SetStatus(Handle<Class> h_this, Status new_status, Thread* self) {
- Status old_status = h_this->GetStatus();
+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 != kStatusErrorUnresolved &&
- new_status != kStatusErrorResolved &&
- new_status != kStatusRetired)) {
+ 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 (new_status >= kStatusResolved || old_status >= kStatusResolved) {
+ 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: "
@@ -155,7 +138,7 @@
<< "Attempt to set as erroneous an already erroneous class "
<< h_this->PrettyClass()
<< " old_status: " << old_status << " new_status: " << new_status;
- CHECK_EQ(new_status == kStatusErrorResolved, old_status >= kStatusResolved);
+ CHECK_EQ(new_status == ClassStatus::kErrorResolved, old_status >= ClassStatus::kResolved);
if (VLOG_IS_ON(class_linker)) {
LOG(ERROR) << "Setting " << h_this->PrettyDescriptor() << " to erroneous.";
if (self->IsExceptionPending()) {
@@ -181,7 +164,7 @@
// Setting the object size alloc fast path needs to be after the status write so that if the
// alloc path sees a valid object size, we would know that it's initialized as long as it has a
// load-acquire/fake dependency.
- if (new_status == kStatusInitialized && !h_this->IsVariableSize()) {
+ if (new_status == ClassStatus::kInitialized && !h_this->IsVariableSize()) {
DCHECK_EQ(h_this->GetObjectSizeAllocFastPath(), std::numeric_limits<uint32_t>::max());
// Finalizable objects must always go slow path.
if (!h_this->IsFinalizable()) {
@@ -199,13 +182,13 @@
if (h_this->IsTemp()) {
// Class is a temporary one, ensure that waiters for resolution get notified of retirement
// so that they can grab the new version of the class from the class linker's table.
- CHECK_LT(new_status, kStatusResolved) << h_this->PrettyDescriptor();
- if (new_status == kStatusRetired || new_status == kStatusErrorUnresolved) {
+ CHECK_LT(new_status, ClassStatus::kResolved) << h_this->PrettyDescriptor();
+ if (new_status == ClassStatus::kRetired || new_status == ClassStatus::kErrorUnresolved) {
h_this->NotifyAll(self);
}
} else {
- CHECK_NE(new_status, kStatusRetired);
- if (old_status >= kStatusResolved || new_status >= kStatusResolved) {
+ CHECK_NE(new_status, ClassStatus::kRetired);
+ if (old_status >= ClassStatus::kResolved || new_status >= ClassStatus::kResolved) {
h_this->NotifyAll(self);
}
}
@@ -1154,7 +1137,7 @@
StackHandleScope<1> hs(self_);
Handle<mirror::Class> h_new_class_obj(hs.NewHandle(obj->AsClass()));
Object::CopyObject(h_new_class_obj.Get(), orig_->Get(), copy_bytes_);
- Class::SetStatus(h_new_class_obj, Class::kStatusResolving, self_);
+ Class::SetStatus(h_new_class_obj, ClassStatus::kResolving, self_);
h_new_class_obj->PopulateEmbeddedVTable(pointer_size_);
h_new_class_obj->SetImt(imt_, pointer_size_);
h_new_class_obj->SetClassSize(new_length_);
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index c545a9b..95fc35d 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_MIRROR_CLASS_H_
#include "base/bit_utils.h"
+#include "base/casts.h"
#include "base/enums.h"
#include "base/iteration_range.h"
#include "class_flags.h"
@@ -77,38 +78,16 @@
static constexpr uint32_t kPrimitiveTypeSizeShiftShift = 16;
static constexpr uint32_t kPrimitiveTypeMask = (1u << kPrimitiveTypeSizeShiftShift) - 1;
- // Make ClassStatus available as Class::Status.
- using Status = ClassStatus;
-
- // Required for a minimal change. Fix up and remove in a future change.
- static constexpr Status kStatusRetired = Status::kStatusRetired;
- static constexpr Status kStatusErrorResolved = Status::kStatusErrorResolved;
- static constexpr Status kStatusErrorUnresolved = Status::kStatusErrorUnresolved;
- static constexpr Status kStatusNotReady = Status::kStatusNotReady;
- static constexpr Status kStatusIdx = Status::kStatusIdx;
- static constexpr Status kStatusLoaded = Status::kStatusLoaded;
- static constexpr Status kStatusResolving = Status::kStatusResolving;
- static constexpr Status kStatusResolved = Status::kStatusResolved;
- static constexpr Status kStatusVerifying = Status::kStatusVerifying;
- static constexpr Status kStatusRetryVerificationAtRuntime =
- Status::kStatusRetryVerificationAtRuntime;
- static constexpr Status kStatusVerifyingAtRuntime = Status::kStatusVerifyingAtRuntime;
- static constexpr Status kStatusVerified = Status::kStatusVerified;
- static constexpr Status kStatusSuperclassValidated = Status::kStatusSuperclassValidated;
- static constexpr Status kStatusInitializing = Status::kStatusInitializing;
- static constexpr Status kStatusInitialized = Status::kStatusInitialized;
- static constexpr Status kStatusMax = Status::kStatusMax;
-
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- Status GetStatus() REQUIRES_SHARED(Locks::mutator_lock_) {
+ ClassStatus GetStatus() REQUIRES_SHARED(Locks::mutator_lock_) {
// Avoid including "subtype_check_bits_and_status.h" to get the field.
// The ClassStatus is always in the least-significant bits of status_.
- return static_cast<Status>(static_cast<uint8_t>(
- static_cast<uint32_t>(GetField32Volatile<kVerifyFlags>(StatusOffset())) & 0xff));
+ return enum_cast<ClassStatus>(
+ static_cast<uint32_t>(GetField32Volatile<kVerifyFlags>(StatusOffset())) & 0xff);
}
// This is static because 'this' may be moved by GC.
- static void SetStatus(Handle<Class> h_this, Status new_status, Thread* self)
+ static void SetStatus(Handle<Class> h_this, ClassStatus new_status, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
static MemberOffset StatusOffset() {
@@ -118,24 +97,24 @@
// Returns true if the class has been retired.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsRetired() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() == kStatusRetired;
+ return GetStatus<kVerifyFlags>() == ClassStatus::kRetired;
}
// Returns true if the class has failed to link.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsErroneousUnresolved() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() == kStatusErrorUnresolved;
+ return GetStatus<kVerifyFlags>() == ClassStatus::kErrorUnresolved;
}
// Returns true if the class has failed to initialize.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsErroneousResolved() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() == kStatusErrorResolved;
+ return GetStatus<kVerifyFlags>() == ClassStatus::kErrorResolved;
}
// Returns true if the class status indicets that the class has failed to link or initialize.
- static bool IsErroneous(Status status) {
- return status == kStatusErrorUnresolved || status == kStatusErrorResolved;
+ static bool IsErroneous(ClassStatus status) {
+ return status == ClassStatus::kErrorUnresolved || status == ClassStatus::kErrorResolved;
}
// Returns true if the class has failed to link or initialize.
@@ -147,44 +126,44 @@
// Returns true if the class has been loaded.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsIdxLoaded() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() >= kStatusIdx;
+ return GetStatus<kVerifyFlags>() >= ClassStatus::kIdx;
}
// Returns true if the class has been loaded.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsLoaded() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() >= kStatusLoaded;
+ return GetStatus<kVerifyFlags>() >= ClassStatus::kLoaded;
}
// Returns true if the class has been linked.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsResolved() REQUIRES_SHARED(Locks::mutator_lock_) {
- Status status = GetStatus<kVerifyFlags>();
- return status >= kStatusResolved || status == kStatusErrorResolved;
+ ClassStatus status = GetStatus<kVerifyFlags>();
+ return status >= ClassStatus::kResolved || status == ClassStatus::kErrorResolved;
}
// Returns true if the class should be verified at runtime.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool ShouldVerifyAtRuntime() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() == kStatusRetryVerificationAtRuntime;
+ return GetStatus<kVerifyFlags>() == ClassStatus::kRetryVerificationAtRuntime;
}
// Returns true if the class has been verified.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsVerified() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() >= kStatusVerified;
+ return GetStatus<kVerifyFlags>() >= ClassStatus::kVerified;
}
// Returns true if the class is initializing.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsInitializing() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() >= kStatusInitializing;
+ return GetStatus<kVerifyFlags>() >= ClassStatus::kInitializing;
}
// Returns true if the class is initialized.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsInitialized() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() == kStatusInitialized;
+ return GetStatus<kVerifyFlags>() == ClassStatus::kInitialized;
}
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -333,8 +312,10 @@
// Returns true if this class is the placeholder and should retire and
// be replaced with a class with the right size for embedded imt/vtable.
bool IsTemp() REQUIRES_SHARED(Locks::mutator_lock_) {
- Status s = GetStatus();
- return s < Status::kStatusResolving && s != kStatusErrorResolved && ShouldHaveEmbeddedVTable();
+ ClassStatus s = GetStatus();
+ return s < ClassStatus::kResolving &&
+ s != ClassStatus::kErrorResolved &&
+ ShouldHaveEmbeddedVTable();
}
String* GetName() REQUIRES_SHARED(Locks::mutator_lock_); // Returns the cached name.