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/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc
index 92b1230..540bd0c 100644
--- a/compiler/dex/quick_compiler_callbacks.cc
+++ b/compiler/dex/quick_compiler_callbacks.cc
@@ -38,7 +38,7 @@
   // If we don't have class unloading enabled in the compiler, we will never see class that were
   // previously verified. Return false to avoid overhead from the lookup in the compiler driver.
   if (!does_class_unloading_) {
-    return ClassStatus::kStatusNotReady;
+    return ClassStatus::kNotReady;
   }
   DCHECK(compiler_driver_ != nullptr);
   // In the case of the quicken filter: avoiding verification of quickened instructions, which the
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 68f963e..0652ea1 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1808,7 +1808,7 @@
 
 static void LoadAndUpdateStatus(const DexFile& dex_file,
                                 const DexFile::ClassDef& class_def,
-                                mirror::Class::Status status,
+                                ClassStatus status,
                                 Handle<mirror::ClassLoader> class_loader,
                                 Thread* self)
     REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1867,16 +1867,16 @@
           // Just update the compiled_classes_ map. The compiler doesn't need to resolve
           // the type.
           ClassReference ref(dex_file, i);
-          mirror::Class::Status existing = mirror::Class::kStatusNotReady;
+          ClassStatus existing = ClassStatus::kNotReady;
           DCHECK(compiled_classes_.Get(ref, &existing)) << ref.dex_file->GetLocation();
           ClassStateTable::InsertResult result =
-             compiled_classes_.Insert(ref, existing, mirror::Class::kStatusVerified);
+             compiled_classes_.Insert(ref, existing, ClassStatus::kVerified);
           CHECK_EQ(result, ClassStateTable::kInsertResultSuccess);
         } else {
           // Update the class status, so later compilation stages know they don't need to verify
           // the class.
           LoadAndUpdateStatus(
-              *dex_file, class_def, mirror::Class::kStatusVerified, class_loader, soa.Self());
+              *dex_file, class_def, ClassStatus::kVerified, class_loader, soa.Self());
           // Create `VerifiedMethod`s for each methods, the compiler expects one for
           // quickening or compiling.
           // Note that this means:
@@ -1890,7 +1890,7 @@
         // this class again.
         LoadAndUpdateStatus(*dex_file,
                             class_def,
-                            mirror::Class::kStatusRetryVerificationAtRuntime,
+                            ClassStatus::kRetryVerificationAtRuntime,
                             class_loader,
                             soa.Self());
       }
@@ -2104,10 +2104,10 @@
       // Only do this if the class is resolved. If even resolution fails, quickening will go very,
       // very wrong.
       if (klass->IsResolved() && !klass->IsErroneousResolved()) {
-        if (klass->GetStatus() < mirror::Class::kStatusVerified) {
+        if (klass->GetStatus() < ClassStatus::kVerified) {
           ObjectLock<mirror::Class> lock(soa.Self(), klass);
           // Set class status to verified.
-          mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, soa.Self());
+          mirror::Class::SetStatus(klass, ClassStatus::kVerified, soa.Self());
           // Mark methods as pre-verified. If we don't do this, the interpreter will run with
           // access checks.
           klass->SetSkipAccessChecksFlagOnAllMethods(
@@ -2184,7 +2184,7 @@
     const bool is_boot_image = manager_->GetCompiler()->GetCompilerOptions().IsBootImage();
     const bool is_app_image = manager_->GetCompiler()->GetCompilerOptions().IsAppImage();
 
-    mirror::Class::Status old_status = klass->GetStatus();
+    ClassStatus old_status = klass->GetStatus();
     // Don't initialize classes in boot space when compiling app image
     if (is_app_image && klass->IsBootStrapClassLoaded()) {
       // Also return early and don't store the class status in the recorded class status.
@@ -2309,7 +2309,7 @@
         // would do so they can be skipped at runtime.
         if (!klass->IsInitialized() &&
             manager_->GetClassLinker()->ValidateSuperClassDescriptors(klass)) {
-          old_status = mirror::Class::kStatusSuperclassValidated;
+          old_status = ClassStatus::kSuperclassValidated;
         } else {
           soa.Self()->ClearException();
         }
@@ -2772,36 +2772,36 @@
   DCHECK(GetCompiledMethod(method_ref) != nullptr) << method_ref.PrettyMethod();
 }
 
-bool CompilerDriver::GetCompiledClass(const ClassReference& ref,
-                                      mirror::Class::Status* status) const {
+bool CompilerDriver::GetCompiledClass(const ClassReference& ref, ClassStatus* status) const {
   DCHECK(status != nullptr);
   // The table doesn't know if something wasn't inserted. For this case it will return
-  // kStatusNotReady. To handle this, just assume anything we didn't try to verify is not compiled.
+  // ClassStatus::kNotReady. To handle this, just assume anything we didn't try to verify
+  // is not compiled.
   if (!compiled_classes_.Get(ref, status) ||
-      *status < mirror::Class::kStatusRetryVerificationAtRuntime) {
+      *status < ClassStatus::kRetryVerificationAtRuntime) {
     return false;
   }
   return true;
 }
 
-mirror::Class::Status CompilerDriver::GetClassStatus(const ClassReference& ref) const {
-  mirror::Class::Status status = ClassStatus::kStatusNotReady;
+ClassStatus CompilerDriver::GetClassStatus(const ClassReference& ref) const {
+  ClassStatus status = ClassStatus::kNotReady;
   if (!GetCompiledClass(ref, &status)) {
     classpath_classes_.Get(ref, &status);
   }
   return status;
 }
 
-void CompilerDriver::RecordClassStatus(const ClassReference& ref, mirror::Class::Status status) {
+void CompilerDriver::RecordClassStatus(const ClassReference& ref, ClassStatus status) {
   switch (status) {
-    case mirror::Class::kStatusErrorResolved:
-    case mirror::Class::kStatusErrorUnresolved:
-    case mirror::Class::kStatusNotReady:
-    case mirror::Class::kStatusResolved:
-    case mirror::Class::kStatusRetryVerificationAtRuntime:
-    case mirror::Class::kStatusVerified:
-    case mirror::Class::kStatusSuperclassValidated:
-    case mirror::Class::kStatusInitialized:
+    case ClassStatus::kErrorResolved:
+    case ClassStatus::kErrorUnresolved:
+    case ClassStatus::kNotReady:
+    case ClassStatus::kResolved:
+    case ClassStatus::kRetryVerificationAtRuntime:
+    case ClassStatus::kVerified:
+    case ClassStatus::kSuperclassValidated:
+    case ClassStatus::kInitialized:
       break;  // Expected states.
     default:
       LOG(FATAL) << "Unexpected class status for class "
@@ -2813,7 +2813,7 @@
   ClassStateTable::InsertResult result;
   ClassStateTable* table = &compiled_classes_;
   do {
-    mirror::Class::Status existing = mirror::Class::kStatusNotReady;
+    ClassStatus existing = ClassStatus::kNotReady;
     if (!table->Get(ref, &existing)) {
       // A classpath class.
       if (kIsDebugBuild) {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index e001726..bcea853 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -31,13 +31,13 @@
 #include "base/mutex.h"
 #include "base/timing_logger.h"
 #include "class_reference.h"
+#include "class_status.h"
 #include "compiler.h"
 #include "dex_file.h"
 #include "dex_file_types.h"
 #include "driver/compiled_method_storage.h"
 #include "jit/profile_compilation_info.h"
 #include "method_reference.h"
-#include "mirror/class.h"  // For mirror::Class::Status.
 #include "os.h"
 #include "safe_map.h"
 #include "thread_pool.h"
@@ -47,6 +47,7 @@
 namespace art {
 
 namespace mirror {
+class Class;
 class DexCache;
 }  // namespace mirror
 
@@ -55,18 +56,21 @@
 class VerifierDepsTest;
 }  // namespace verifier
 
+class ArtField;
 class BitVector;
 class CompiledMethod;
 class CompilerOptions;
 class DexCompilationUnit;
+template<class T> class Handle;
 struct InlineIGetIPutData;
 class InstructionSetFeatures;
 class InternTable;
 enum InvokeType : uint32_t;
+class MemberOffset;
+template<class MirrorType> class ObjPtr;
 class ParallelCompilationManager;
 class ScopedObjectAccess;
 template <class Allocator> class SrcMap;
-template<class T> class Handle;
 class TimingLogger;
 class VdexFile;
 class VerificationResults;
@@ -152,8 +156,8 @@
   std::unique_ptr<const std::vector<uint8_t>> CreateQuickResolutionTrampoline() const;
   std::unique_ptr<const std::vector<uint8_t>> CreateQuickToInterpreterBridge() const;
 
-  mirror::Class::Status GetClassStatus(const ClassReference& ref) const;
-  bool GetCompiledClass(const ClassReference& ref, mirror::Class::Status* status) const;
+  ClassStatus GetClassStatus(const ClassReference& ref) const;
+  bool GetCompiledClass(const ClassReference& ref, ClassStatus* status) const;
 
   CompiledMethod* GetCompiledMethod(MethodReference ref) const;
   size_t GetNonRelativeLinkerPatchCount() const;
@@ -321,7 +325,7 @@
   // according to the profile file.
   bool ShouldVerifyClassBasedOnProfile(const DexFile& dex_file, uint16_t class_idx) const;
 
-  void RecordClassStatus(const ClassReference& ref, mirror::Class::Status status);
+  void RecordClassStatus(const ClassReference& ref, ClassStatus status);
 
   // Checks if the specified method has been verified without failures. Returns
   // false if the method is not in the verification results (GetVerificationResults).
@@ -476,7 +480,7 @@
       GUARDED_BY(requires_constructor_barrier_lock_);
 
   // All class references that this compiler has compiled. Indexed by class defs.
-  using ClassStateTable = AtomicDexRefMap<ClassReference, mirror::Class::Status>;
+  using ClassStateTable = AtomicDexRefMap<ClassReference, ClassStatus>;
   ClassStateTable compiled_classes_;
   // All class references that are in the classpath. Indexed by class defs.
   ClassStateTable classpath_classes_;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 278358b..2698574 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -16,11 +16,13 @@
 
 #include "driver/compiler_driver.h"
 
+#include <limits>
 #include <stdint.h>
 #include <stdio.h>
 #include <memory>
 
 #include "art_method-inl.h"
+#include "base/casts.h"
 #include "class_linker-inl.h"
 #include "common_compiler_test.h"
 #include "compiler_callbacks.h"
@@ -344,11 +346,11 @@
     ASSERT_NE(klass, nullptr);
     EXPECT_TRUE(klass->IsVerified());
 
-    mirror::Class::Status status;
+    ClassStatus status;
     bool found = compiler_driver_->GetCompiledClass(
         ClassReference(&klass->GetDexFile(), klass->GetDexTypeIndex().index_), &status);
     ASSERT_TRUE(found);
-    EXPECT_EQ(status, mirror::Class::kStatusVerified);
+    EXPECT_EQ(status, ClassStatus::kVerified);
   }
 };
 
@@ -367,8 +369,8 @@
   CheckVerifiedClass(class_loader, "LSecond;");
 }
 
-// Test that a class of status kStatusRetryVerificationAtRuntime is indeed recorded that way in the
-// driver.
+// Test that a class of status ClassStatus::kRetryVerificationAtRuntime is indeed
+// recorded that way in the driver.
 TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatusCheckVerified) {
   Thread* const self = Thread::Current();
   jobject class_loader;
@@ -386,17 +388,19 @@
   callbacks_->SetDoesClassUnloading(true, compiler_driver_.get());
   ClassReference ref(dex_file, 0u);
   // Test that the status is read from the compiler driver as expected.
-  for (size_t i = mirror::Class::kStatusRetryVerificationAtRuntime;
-      i < mirror::Class::kStatusMax;
-      ++i) {
-    const mirror::Class::Status expected_status = static_cast<mirror::Class::Status>(i);
+  static_assert(enum_cast<size_t>(ClassStatus::kLast) < std::numeric_limits<size_t>::max(),
+                "Make sure incrementing the class status does not overflow.");
+  for (size_t i = enum_cast<size_t>(ClassStatus::kRetryVerificationAtRuntime);
+       i <= enum_cast<size_t>(ClassStatus::kLast);
+       ++i) {
+    const ClassStatus expected_status = enum_cast<ClassStatus>(i);
     // Skip unsupported status that are not supposed to be ever recorded.
-    if (expected_status == mirror::Class::kStatusVerifyingAtRuntime ||
-        expected_status == mirror::Class::kStatusInitializing) {
+    if (expected_status == ClassStatus::kVerifyingAtRuntime ||
+        expected_status == ClassStatus::kInitializing) {
       continue;
     }
     compiler_driver_->RecordClassStatus(ref, expected_status);
-    mirror::Class::Status status = {};
+    ClassStatus status = {};
     ASSERT_TRUE(compiler_driver_->GetCompiledClass(ref, &status));
     EXPECT_EQ(status, expected_status);
   }
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index f9dcb5d..13886b3 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2103,9 +2103,8 @@
   // TODO(vixl): Let the MacroAssembler handle MemOperand.
   __ Add(temp, class_reg, status_offset);
   __ Ldarb(temp, HeapOperand(temp));
-  __ Cmp(temp, mirror::Class::kStatusInitialized);
-  __ B(ne, slow_path->GetEntryLabel());
-  // Use Bne instead of Blt because ARM64 doesn't have Ldarsb.
+  __ Cmp(temp, enum_cast<>(ClassStatus::kInitialized));
+  __ B(lo, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
 }
 
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index c6e1b04..7f83533 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -7173,12 +7173,12 @@
     LoadClassSlowPathARMVIXL* slow_path, vixl32::Register class_reg) {
   UseScratchRegisterScope temps(GetVIXLAssembler());
   vixl32::Register temp = temps.Acquire();
-  GetAssembler()->LoadFromOffset(kLoadSignedByte,
+  GetAssembler()->LoadFromOffset(kLoadUnsignedByte,
                                  temp,
                                  class_reg,
                                  mirror::Class::StatusOffset().Int32Value());
-  __ Cmp(temp, mirror::Class::kStatusInitialized);
-  __ B(lt, slow_path->GetEntryLabel());
+  __ Cmp(temp, enum_cast<>(ClassStatus::kInitialized));
+  __ B(lo, slow_path->GetEntryLabel());
   // Even if the initialized flag is set, we may be in a situation where caches are not synced
   // properly. Therefore, we do a memory fence.
   __ Dmb(ISH);
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index c4772ad..ebe252a 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1915,9 +1915,9 @@
 
 void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path,
                                                                     Register class_reg) {
-  __ LoadFromOffset(kLoadSignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
-  __ LoadConst32(AT, mirror::Class::kStatusInitialized);
-  __ Blt(TMP, AT, slow_path->GetEntryLabel());
+  __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
+  __ LoadConst32(AT, enum_cast<>(ClassStatus::kInitialized));
+  __ Bltu(TMP, AT, slow_path->GetEntryLabel());
   // Even if the initialized flag is set, we need to ensure consistent memory ordering.
   __ Sync(0);
   __ Bind(slow_path->GetExitLabel());
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index c8891ed..3ea7b82 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -1761,9 +1761,9 @@
 
 void InstructionCodeGeneratorMIPS64::GenerateClassInitializationCheck(SlowPathCodeMIPS64* slow_path,
                                                                       GpuRegister class_reg) {
-  __ LoadFromOffset(kLoadSignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
-  __ LoadConst32(AT, mirror::Class::kStatusInitialized);
-  __ Bltc(TMP, AT, slow_path->GetEntryLabel());
+  __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
+  __ LoadConst32(AT, enum_cast<>(ClassStatus::kInitialized));
+  __ Bltuc(TMP, AT, slow_path->GetEntryLabel());
   // Even if the initialized flag is set, we need to ensure consistent memory ordering.
   __ Sync(0);
   __ Bind(slow_path->GetExitLabel());
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index ba222fe..6853238 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -6220,8 +6220,8 @@
 void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
     SlowPathCode* slow_path, Register class_reg) {
   __ cmpb(Address(class_reg,  mirror::Class::StatusOffset().Int32Value()),
-          Immediate(mirror::Class::kStatusInitialized));
-  __ j(kLess, slow_path->GetEntryLabel());
+          Immediate(enum_cast<>(ClassStatus::kInitialized)));
+  __ j(kBelow, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
   // No need for memory fence, thanks to the X86 memory model.
 }
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index caad788..1f8d822 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -5426,8 +5426,8 @@
 void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
     SlowPathCode* slow_path, CpuRegister class_reg) {
   __ cmpb(Address(class_reg,  mirror::Class::StatusOffset().Int32Value()),
-          Immediate(mirror::Class::kStatusInitialized));
-  __ j(kLess, slow_path->GetEntryLabel());
+          Immediate(enum_cast<>(ClassStatus::kInitialized)));
+  __ j(kBelow, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
   // No need for memory fence, thanks to the x86-64 memory model.
 }
diff --git a/compiler/trampolines/trampoline_compiler.h b/compiler/trampolines/trampoline_compiler.h
index 1a10e4c..64c1eb5 100644
--- a/compiler/trampolines/trampoline_compiler.h
+++ b/compiler/trampolines/trampoline_compiler.h
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include "driver/compiler_driver.h"
+#include "offsets.h"
 
 namespace art {
 
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index ee1d7c6..d77842a 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -237,9 +237,9 @@
           CHECK(soa.Self()->IsExceptionPending());
           soa.Self()->ClearException();
         } else if (unverified_classes.find(class_def.class_idx_) == unverified_classes.end()) {
-          ASSERT_EQ(cls->GetStatus(), mirror::Class::kStatusVerified);
+          ASSERT_EQ(cls->GetStatus(), ClassStatus::kVerified);
         } else {
-          ASSERT_LT(cls->GetStatus(), mirror::Class::kStatusVerified);
+          ASSERT_LT(cls->GetStatus(), ClassStatus::kVerified);
         }
       }
     }
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 738bbf8..363cb8b 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -585,7 +585,7 @@
       if (dirty_image_objects_ != nullptr &&
           dirty_image_objects_->find(klass->PrettyDescriptor()) != dirty_image_objects_->end()) {
         bin = Bin::kKnownDirty;
-      } else if (klass->GetStatus() == Class::kStatusInitialized) {
+      } else if (klass->GetStatus() == ClassStatus::kInitialized) {
         bin = Bin::kClassInitialized;
 
         // If the class's static fields are all final, put it into a separate bin
@@ -650,7 +650,7 @@
   }
   mirror::Class* declaring_class = m->GetDeclaringClass();
   // Initialized is highly unlikely to dirty since there's no entry points to mutate.
-  return declaring_class == nullptr || declaring_class->GetStatus() != Class::kStatusInitialized;
+  return declaring_class == nullptr || declaring_class->GetStatus() != ClassStatus::kInitialized;
 }
 
 bool ImageWriter::IsImageBinSlotAssigned(mirror::Object* object) const {
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 3aceceb..a7c1439 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -62,6 +62,7 @@
 }  // namespace mirror
 
 class ClassLoaderVisitor;
+class ImTable;
 class ImtConflictTable;
 
 static constexpr int kInvalidFd = -1;
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index d261679..016a114 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -188,8 +188,8 @@
   OatClassHeader(uint32_t offset,
                  uint32_t num_non_null_compiled_methods,
                  uint32_t num_methods,
-                 mirror::Class::Status status)
-      : status_(status),
+                 ClassStatus status)
+      : status_(enum_cast<uint16_t>(status)),
         offset_(offset) {
     // We just arbitrarily say that 0 methods means kOatClassNoneCompiled and that we won't use
     // kOatClassAllCompiled unless there is at least one compiled method. This means in an
@@ -210,8 +210,8 @@
   }
 
   // Data to write.
-  static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits");
-  int16_t status_;
+  static_assert(enum_cast<>(ClassStatus::kLast) < (1 << 16), "class status won't fit in 16bits");
+  uint16_t status_;
 
   static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits");
   uint16_t type_;
@@ -931,17 +931,17 @@
 
   bool EndClass() OVERRIDE {
     ClassReference class_ref(dex_file_, class_def_index_);
-    mirror::Class::Status status;
+    ClassStatus status;
     bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
     if (!found) {
       VerificationResults* results = writer_->compiler_driver_->GetVerificationResults();
       if (results != nullptr && results->IsClassRejected(class_ref)) {
         // The oat class status is used only for verification of resolved classes,
-        // so use kStatusErrorResolved whether the class was resolved or unresolved
+        // so use ClassStatus::kErrorResolved whether the class was resolved or unresolved
         // during compile-time verification.
-        status = mirror::Class::kStatusErrorResolved;
+        status = ClassStatus::kErrorResolved;
       } else {
-        status = mirror::Class::kStatusNotReady;
+        status = ClassStatus::kNotReady;
       }
     }
 
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index e9958b1..44c2f89 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -455,7 +455,7 @@
                                                    ScopedNullHandle<mirror::ClassLoader>());
 
     const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(i);
-    CHECK_EQ(mirror::Class::Status::kStatusNotReady, oat_class.GetStatus()) << descriptor;
+    CHECK_EQ(ClassStatus::kNotReady, oat_class.GetStatus()) << descriptor;
     CHECK_EQ(kCompile ? OatClassType::kOatClassAllCompiled : OatClassType::kOatClassNoneCompiled,
              oat_class.GetType()) << descriptor;
 
diff --git a/runtime/aot_class_linker.cc b/runtime/aot_class_linker.cc
index a62cbec..93e02ef 100644
--- a/runtime/aot_class_linker.cc
+++ b/runtime/aot_class_linker.cc
@@ -44,7 +44,7 @@
   // Don't initialize klass if it's superclass is not initialized, because superclass might abort
   // the transaction and rolled back after klass's change is commited.
   if (strict_mode_ && !klass->IsInterface() && klass->HasSuperClass()) {
-    if (klass->GetSuperClass()->GetStatus() == mirror::Class::kStatusInitializing) {
+    if (klass->GetSuperClass()->GetStatus() == ClassStatus::kInitializing) {
       runtime->AbortTransactionAndThrowAbortError(self, "Can't resolve "
           + klass->PrettyTypeOf() + " because it's superclass is not initialized.");
       return false;
@@ -79,11 +79,11 @@
   ClassStatus old_status = callbacks->GetPreviousClassState(
       ClassReference(&klass->GetDexFile(), klass->GetDexClassDefIndex()));
   // Was it verified? Report no failure.
-  if (old_status >= ClassStatus::kStatusVerified) {
+  if (old_status >= ClassStatus::kVerified) {
     return verifier::FailureKind::kNoFailure;
   }
   // Does it need to be verified at runtime? Report soft failure.
-  if (old_status >= ClassStatus::kStatusRetryVerificationAtRuntime) {
+  if (old_status >= ClassStatus::kRetryVerificationAtRuntime) {
     // Error messages from here are only reported through -verbose:class. It is not worth it to
     // create a message.
     return verifier::FailureKind::kSoftFailure;
diff --git a/runtime/base/casts.h b/runtime/base/casts.h
index ac1a10c..3c6b2be 100644
--- a/runtime/base/casts.h
+++ b/runtime/base/casts.h
@@ -26,6 +26,8 @@
 
 #include <android-base/logging.h>
 
+#include "stl_util_identity.h"
+
 namespace art {
 
 // Use implicit_cast as a safe version of static_cast or const_cast
@@ -97,7 +99,7 @@
 // A version of static_cast that DCHECKs that the value can be precisely represented
 // when converting to Dest.
 template <typename Dest, typename Source>
-inline Dest dchecked_integral_cast(const Source source) {
+constexpr Dest dchecked_integral_cast(Source source) {
   DCHECK(
       // Check that the value is within the lower limit of Dest.
       (static_cast<intmax_t>(std::numeric_limits<Dest>::min()) <=
@@ -113,6 +115,33 @@
   return static_cast<Dest>(source);
 }
 
+// A version of dchecked_integral_cast casting between an integral type and an enum type.
+// When casting to an enum type, the cast does not check if the value corresponds to an enumerator.
+// When casting from an enum type, the target type can be omitted and the enum's underlying type
+// shall be used.
+
+template <typename Dest, typename Source>
+constexpr
+typename std::enable_if<!std::is_enum<Source>::value, Dest>::type
+enum_cast(Source value) {
+  return static_cast<Dest>(
+      dchecked_integral_cast<typename std::underlying_type<Dest>::type>(value));
+}
+
+template <typename Dest = void, typename Source>
+constexpr
+typename std::enable_if<std::is_enum<Source>::value,
+                        typename std::conditional<std::is_same<Dest, void>::value,
+                                                  std::underlying_type<Source>,
+                                                  Identity<Dest>>::type>::type::type
+enum_cast(Source value) {
+  using return_type = typename std::conditional<std::is_same<Dest, void>::value,
+                                                std::underlying_type<Source>,
+                                                Identity<Dest>>::type::type;
+  return dchecked_integral_cast<return_type>(
+      static_cast<typename std::underlying_type<Source>::type>(value));
+}
+
 // A version of reinterpret_cast<>() between pointers and int64_t/uint64_t
 // that goes through uintptr_t to avoid treating the pointer as "signed."
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 727dd14..7c0c68a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -445,7 +445,7 @@
   CHECK(java_lang_Object != nullptr);
   // backfill Object as the super class of Class.
   java_lang_Class->SetSuperClass(java_lang_Object.Get());
-  mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusLoaded, self);
+  mirror::Class::SetStatus(java_lang_Object, ClassStatus::kLoaded, self);
 
   java_lang_Object->SetObjectSize(sizeof(mirror::Object));
   // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been
@@ -494,14 +494,14 @@
       AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_))));
   java_lang_String->SetStringClass();
   mirror::String::SetClass(java_lang_String.Get());
-  mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusResolved, self);
+  mirror::Class::SetStatus(java_lang_String, ClassStatus::kResolved, self);
 
   // Setup java.lang.ref.Reference.
   Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize(image_pointer_size_))));
   mirror::Reference::SetClass(java_lang_ref_Reference.Get());
   java_lang_ref_Reference->SetObjectSize(mirror::Reference::InstanceSize());
-  mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusResolved, self);
+  mirror::Class::SetStatus(java_lang_ref_Reference, ClassStatus::kResolved, self);
 
   // Create storage for root classes, save away our work so far (requires descriptors).
   class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(
@@ -554,7 +554,7 @@
   SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get());
   java_lang_DexCache->SetDexCacheClass();
   java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize());
-  mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusResolved, self);
+  mirror::Class::SetStatus(java_lang_DexCache, ClassStatus::kResolved, self);
 
 
   // Setup dalvik.system.ClassExt
@@ -562,7 +562,7 @@
       AllocClass(self, java_lang_Class.Get(), mirror::ClassExt::ClassSize(image_pointer_size_))));
   SetClassRoot(kDalvikSystemClassExt, dalvik_system_ClassExt.Get());
   mirror::ClassExt::SetClass(dalvik_system_ClassExt.Get());
-  mirror::Class::SetStatus(dalvik_system_ClassExt, mirror::Class::kStatusResolved, self);
+  mirror::Class::SetStatus(dalvik_system_ClassExt, ClassStatus::kResolved, self);
 
   // Set up array classes for string, field, method
   Handle<mirror::Class> object_array_string(hs.NewHandle(
@@ -610,15 +610,15 @@
   }
 
   // Object, String, ClassExt and DexCache need to be rerun through FindSystemClass to finish init
-  mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusNotReady, self);
+  mirror::Class::SetStatus(java_lang_Object, ClassStatus::kNotReady, self);
   CheckSystemClass(self, java_lang_Object, "Ljava/lang/Object;");
   CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize());
-  mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusNotReady, self);
+  mirror::Class::SetStatus(java_lang_String, ClassStatus::kNotReady, self);
   CheckSystemClass(self, java_lang_String, "Ljava/lang/String;");
-  mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusNotReady, self);
+  mirror::Class::SetStatus(java_lang_DexCache, ClassStatus::kNotReady, self);
   CheckSystemClass(self, java_lang_DexCache, "Ljava/lang/DexCache;");
   CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize());
-  mirror::Class::SetStatus(dalvik_system_ClassExt, mirror::Class::kStatusNotReady, self);
+  mirror::Class::SetStatus(dalvik_system_ClassExt, ClassStatus::kNotReady, self);
   CheckSystemClass(self, dalvik_system_ClassExt, "Ldalvik/system/ClassExt;");
   CHECK_EQ(dalvik_system_ClassExt->GetObjectSize(), mirror::ClassExt::InstanceSize());
 
@@ -772,7 +772,7 @@
 
   // java.lang.ref classes need to be specially flagged, but otherwise are normal classes
   // finish initializing Reference class
-  mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self);
+  mirror::Class::SetStatus(java_lang_ref_Reference, ClassStatus::kNotReady, self);
   CheckSystemClass(self, java_lang_ref_Reference, "Ljava/lang/ref/Reference;");
   CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize());
   CHECK_EQ(java_lang_ref_Reference->GetClassSize(),
@@ -2309,7 +2309,7 @@
         // Check for circular dependencies between classes, the lock is required for SetStatus.
         if (!h_class->IsResolved() && h_class->GetClinitThreadId() == self->GetTid()) {
           ThrowClassCircularityError(h_class.Get());
-          mirror::Class::SetStatus(h_class, mirror::Class::kStatusErrorUnresolved, self);
+          mirror::Class::SetStatus(h_class, ClassStatus::kErrorUnresolved, self);
           return nullptr;
         }
       }
@@ -2771,7 +2771,7 @@
     // An exception occured during load, set status to erroneous while holding klass' lock in case
     // notification is necessary.
     if (!klass->IsErroneous()) {
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
     }
     return nullptr;
   }
@@ -2781,7 +2781,7 @@
   if (!LoadSuperAndInterfaces(klass, *new_dex_file)) {
     // Loading failed.
     if (!klass->IsErroneous()) {
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
     }
     return nullptr;
   }
@@ -2800,7 +2800,7 @@
   if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) {
     // Linking failed.
     if (!klass->IsErroneous()) {
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
     }
     return nullptr;
   }
@@ -3087,7 +3087,7 @@
                              ObjPtr<mirror::ClassLoader> class_loader) {
   CHECK(klass != nullptr);
   CHECK(klass->GetDexCache() != nullptr);
-  CHECK_EQ(mirror::Class::kStatusNotReady, klass->GetStatus());
+  CHECK_EQ(ClassStatus::kNotReady, klass->GetStatus());
   const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
   CHECK(descriptor != nullptr);
 
@@ -3097,7 +3097,7 @@
   klass->SetAccessFlags(access_flags);
   klass->SetClassLoader(class_loader);
   DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
-  mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, nullptr);
+  mirror::Class::SetStatus(klass, ClassStatus::kIdx, nullptr);
 
   klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
   klass->SetDexTypeIndex(dex_class_def.class_idx_);
@@ -3623,7 +3623,7 @@
   h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
   h_class->SetPrimitiveType(type);
   h_class->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
-  mirror::Class::SetStatus(h_class, mirror::Class::kStatusInitialized, self);
+  mirror::Class::SetStatus(h_class, ClassStatus::kInitialized, self);
   const char* descriptor = Primitive::Descriptor(type);
   ObjPtr<mirror::Class> existing = InsertClass(descriptor,
                                                h_class.Get(),
@@ -3738,11 +3738,11 @@
   } else {
     new_class->SetClassFlags(mirror::kClassFlagObjectArray);
   }
-  mirror::Class::SetStatus(new_class, mirror::Class::kStatusLoaded, self);
+  mirror::Class::SetStatus(new_class, ClassStatus::kLoaded, self);
   new_class->PopulateEmbeddedVTable(image_pointer_size_);
   ImTable* object_imt = java_lang_Object->GetImt(image_pointer_size_);
   new_class->SetImt(object_imt, image_pointer_size_);
-  mirror::Class::SetStatus(new_class, mirror::Class::kStatusInitialized, self);
+  mirror::Class::SetStatus(new_class, ClassStatus::kInitialized, self);
   // don't need to set new_class->SetObjectSize(..)
   // because Object::SizeOf delegates to Array::SizeOf
 
@@ -4000,7 +4000,7 @@
   }
   // Need to grab the lock to change status.
   ObjectLock<mirror::Class> super_lock(self, klass);
-  mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+  mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
   return false;
 }
 
@@ -4022,9 +4022,9 @@
     ObjectLock<mirror::Class> lock(self, klass);
 
     // Is somebody verifying this now?
-    mirror::Class::Status old_status = klass->GetStatus();
-    while (old_status == mirror::Class::kStatusVerifying ||
-        old_status == mirror::Class::kStatusVerifyingAtRuntime) {
+    ClassStatus old_status = klass->GetStatus();
+    while (old_status == ClassStatus::kVerifying ||
+        old_status == ClassStatus::kVerifyingAtRuntime) {
       lock.WaitIgnoringInterrupts();
       // WaitIgnoringInterrupts can still receive an interrupt and return early, in this
       // case we may see the same status again. b/62912904. This is why the check is
@@ -4055,18 +4055,18 @@
       return verifier::FailureKind::kSoftFailure;
     }
 
-    if (klass->GetStatus() == mirror::Class::kStatusResolved) {
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifying, self);
+    if (klass->GetStatus() == ClassStatus::kResolved) {
+      mirror::Class::SetStatus(klass, ClassStatus::kVerifying, self);
     } else {
-      CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime)
+      CHECK_EQ(klass->GetStatus(), ClassStatus::kRetryVerificationAtRuntime)
           << klass->PrettyClass();
       CHECK(!Runtime::Current()->IsAotCompiler());
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifyingAtRuntime, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kVerifyingAtRuntime, self);
     }
 
     // Skip verification if disabled.
     if (!Runtime::Current()->IsVerificationEnabled()) {
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kVerified, self);
       EnsureSkipAccessChecksMethods(klass, image_pointer_size_);
       return verifier::FailureKind::kNoFailure;
     }
@@ -4128,7 +4128,7 @@
 
   // Try to use verification information from the oat file, otherwise do runtime verification.
   const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
-  mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady);
+  ClassStatus oat_file_class_status(ClassStatus::kNotReady);
   bool preverified = VerifyClassUsingOatFile(dex_file, klass.Get(), oat_file_class_status);
 
   VLOG(class_linker) << "Class preverified status for class "
@@ -4165,10 +4165,10 @@
       // Even though there were no verifier failures we need to respect whether the super-class and
       // super-default-interfaces were verified or requiring runtime reverification.
       if (supertype == nullptr || supertype->IsVerified()) {
-        mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
+        mirror::Class::SetStatus(klass, ClassStatus::kVerified, self);
       } else {
-        CHECK_EQ(supertype->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
-        mirror::Class::SetStatus(klass, mirror::Class::kStatusRetryVerificationAtRuntime, self);
+        CHECK_EQ(supertype->GetStatus(), ClassStatus::kRetryVerificationAtRuntime);
+        mirror::Class::SetStatus(klass, ClassStatus::kRetryVerificationAtRuntime, self);
         // Pretend a soft failure occurred so that we don't consider the class verified below.
         verifier_failure = verifier::FailureKind::kSoftFailure;
       }
@@ -4178,9 +4178,9 @@
       // failures at runtime will be handled by slow paths in the generated
       // code. Set status accordingly.
       if (Runtime::Current()->IsAotCompiler()) {
-        mirror::Class::SetStatus(klass, mirror::Class::kStatusRetryVerificationAtRuntime, self);
+        mirror::Class::SetStatus(klass, ClassStatus::kRetryVerificationAtRuntime, self);
       } else {
-        mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
+        mirror::Class::SetStatus(klass, ClassStatus::kVerified, self);
         // As this is a fake verified status, make sure the methods are _not_ marked
         // kAccSkipAccessChecks later.
         klass->SetVerificationAttempted();
@@ -4192,7 +4192,7 @@
                   << " because: " << error_msg;
     self->AssertNoPendingException();
     ThrowVerifyError(klass.Get(), "%s", error_msg.c_str());
-    mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+    mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
   }
   if (preverified || verifier_failure == verifier::FailureKind::kNoFailure) {
     // Class is verified so we don't need to do any access check on its methods.
@@ -4234,7 +4234,7 @@
 
 bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file,
                                           ObjPtr<mirror::Class> klass,
-                                          mirror::Class::Status& oat_file_class_status) {
+                                          ClassStatus& oat_file_class_status) {
   // If we're compiling, we can only verify the class using the oat file if
   // we are not compiling the image or if the class we're verifying is not part of
   // the app.  In other words, we will only check for preverification of bootclasspath
@@ -4260,15 +4260,15 @@
 
   uint16_t class_def_index = klass->GetDexClassDefIndex();
   oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus();
-  if (oat_file_class_status >= mirror::Class::kStatusVerified) {
+  if (oat_file_class_status >= ClassStatus::kVerified) {
     return true;
   }
   // If we only verified a subset of the classes at compile time, we can end up with classes that
   // were resolved by the verifier.
-  if (oat_file_class_status == mirror::Class::kStatusResolved) {
+  if (oat_file_class_status == ClassStatus::kResolved) {
     return false;
   }
-  if (oat_file_class_status == mirror::Class::kStatusRetryVerificationAtRuntime) {
+  if (oat_file_class_status == ClassStatus::kRetryVerificationAtRuntime) {
     // Compile time verification failed with a soft error. Compile time verification can fail
     // because we have incomplete type information. Consider the following:
     // class ... {
@@ -4293,7 +4293,7 @@
     // in the class. These errors are unrecoverable.
     return false;
   }
-  if (oat_file_class_status == mirror::Class::kStatusNotReady) {
+  if (oat_file_class_status == ClassStatus::kNotReady) {
     // Status is uninitialized if we couldn't determine the status at compile time, for example,
     // not loading the class.
     // TODO: when the verifier doesn't rely on Class-es failing to resolve/load the type hierarchy
@@ -4366,7 +4366,7 @@
   temp_klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
   // Object has an empty iftable, copy it for that reason.
   temp_klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
-  mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusIdx, self);
+  mirror::Class::SetStatus(temp_klass, ClassStatus::kIdx, self);
   std::string descriptor(GetDescriptorForProxy(temp_klass.Get()));
   const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str());
 
@@ -4434,7 +4434,7 @@
   // The super class is java.lang.reflect.Proxy
   temp_klass->SetSuperClass(GetClassRoot(kJavaLangReflectProxy));
   // Now effectively in the loaded state.
-  mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusLoaded, self);
+  mirror::Class::SetStatus(temp_klass, ClassStatus::kLoaded, self);
   self->AssertNoPendingException();
 
   // At this point the class is loaded. Publish a ClassLoad event.
@@ -4450,7 +4450,7 @@
     Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
         hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)));
     if (!LinkClass(self, descriptor.c_str(), temp_klass, h_interfaces, &klass)) {
-      mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusErrorUnresolved, self);
+      mirror::Class::SetStatus(temp_klass, ClassStatus::kErrorUnresolved, self);
       return nullptr;
     }
   }
@@ -4471,7 +4471,7 @@
   {
     // Lock on klass is released. Lock new class object.
     ObjectLock<mirror::Class> initialization_lock(self, klass);
-    mirror::Class::SetStatus(klass, mirror::Class::kStatusInitialized, self);
+    mirror::Class::SetStatus(klass, ClassStatus::kInitialized, self);
   }
 
   // sanity checks
@@ -4687,7 +4687,7 @@
           VlogClassInitializationFailure(klass);
         } else {
           CHECK(Runtime::Current()->IsAotCompiler());
-          CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
+          CHECK_EQ(klass->GetStatus(), ClassStatus::kRetryVerificationAtRuntime);
         }
         return false;
       } else {
@@ -4703,12 +4703,12 @@
       }
     }
 
-    // If the class is kStatusInitializing, either this thread is
+    // If the class is ClassStatus::kInitializing, either this thread is
     // initializing higher up the stack or another thread has beat us
     // to initializing and we need to wait. Either way, this
     // invocation of InitializeClass will not be responsible for
     // running <clinit> and will return.
-    if (klass->GetStatus() == mirror::Class::kStatusInitializing) {
+    if (klass->GetStatus() == ClassStatus::kInitializing) {
       // Could have got an exception during verification.
       if (self->IsExceptionPending()) {
         VlogClassInitializationFailure(klass);
@@ -4733,20 +4733,20 @@
     const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler())
         ? OatFile::FindOatClass(klass->GetDexFile(), klass->GetDexClassDefIndex(), &has_oat_class)
         : OatFile::OatClass::Invalid();
-    if (oat_class.GetStatus() < mirror::Class::kStatusSuperclassValidated &&
+    if (oat_class.GetStatus() < ClassStatus::kSuperclassValidated &&
         !ValidateSuperClassDescriptors(klass)) {
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
       return false;
     }
     self->AllowThreadSuspension();
 
-    CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << klass->PrettyClass()
+    CHECK_EQ(klass->GetStatus(), ClassStatus::kVerified) << klass->PrettyClass()
         << " self.tid=" << self->GetTid() << " clinit.tid=" << klass->GetClinitThreadId();
 
     // From here out other threads may observe that we're initializing and so changes of state
     // require the a notification.
     klass->SetClinitThreadId(self->GetTid());
-    mirror::Class::SetStatus(klass, mirror::Class::kStatusInitializing, self);
+    mirror::Class::SetStatus(klass, ClassStatus::kInitializing, self);
 
     t0 = NanoTime();
   }
@@ -4773,7 +4773,7 @@
             << (self->GetException() != nullptr ? self->GetException()->Dump() : "");
         ObjectLock<mirror::Class> lock(self, klass);
         // Initialization failed because the super-class is erroneous.
-        mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+        mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
         return false;
       }
     }
@@ -4804,7 +4804,7 @@
         if (!iface_initialized) {
           ObjectLock<mirror::Class> lock(self, klass);
           // Initialization failed because one of our interfaces with default methods is erroneous.
-          mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+          mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
           return false;
         }
       }
@@ -4876,7 +4876,7 @@
 
     if (self->IsExceptionPending()) {
       WrapExceptionInInitializer(klass);
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
       success = false;
     } else if (Runtime::Current()->IsTransactionAborted()) {
       // The exception thrown when the transaction aborted has been caught and cleared
@@ -4885,7 +4885,7 @@
                      << mirror::Class::PrettyDescriptor(klass.Get())
                      << " without exception while transaction was aborted: re-throw it now.";
       Runtime::Current()->ThrowTransactionAbortError(self);
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
       success = false;
     } else {
       RuntimeStats* global_stats = Runtime::Current()->GetStats();
@@ -4895,7 +4895,7 @@
       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.
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusInitialized, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kInitialized, self);
       if (VLOG_IS_ON(class_linker)) {
         std::string temp;
         LOG(INFO) << "Initialized class " << klass->GetDescriptor(&temp) << " from " <<
@@ -4969,14 +4969,14 @@
     // we were not using WaitIgnoringInterrupts), bail out.
     if (self->IsExceptionPending()) {
       WrapExceptionInInitializer(klass);
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
       return false;
     }
     // Spurious wakeup? Go back to waiting.
-    if (klass->GetStatus() == mirror::Class::kStatusInitializing) {
+    if (klass->GetStatus() == ClassStatus::kInitializing) {
       continue;
     }
-    if (klass->GetStatus() == mirror::Class::kStatusVerified &&
+    if (klass->GetStatus() == ClassStatus::kVerified &&
         Runtime::Current()->IsAotCompiler()) {
       // Compile time initialization failed.
       return false;
@@ -5309,7 +5309,7 @@
                             Handle<mirror::Class> klass,
                             Handle<mirror::ObjectArray<mirror::Class>> interfaces,
                             MutableHandle<mirror::Class>* h_new_class_out) {
-  CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
+  CHECK_EQ(ClassStatus::kLoaded, klass->GetStatus());
 
   if (!LinkSuperClass(klass)) {
     return false;
@@ -5329,7 +5329,7 @@
     return false;
   }
   CreateReferenceInstanceOffsets(klass);
-  CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
+  CHECK_EQ(ClassStatus::kLoaded, klass->GetStatus());
 
   ImTable* imt = nullptr;
   if (klass->ShouldHaveImt()) {
@@ -5382,7 +5382,7 @@
 
     // This will notify waiters on klass that saw the not yet resolved
     // class in the class_table_ during EnsureResolved.
-    mirror::Class::SetStatus(klass, mirror::Class::kStatusResolved, self);
+    mirror::Class::SetStatus(klass, ClassStatus::kResolved, self);
     h_new_class_out->Assign(klass.Get());
   } else {
     CHECK(!klass->IsResolved());
@@ -5398,7 +5398,7 @@
     klass->SetIFieldsPtrUnchecked(nullptr);
     if (UNLIKELY(h_new_class == nullptr)) {
       self->AssertPendingOOMException();
-      mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
+      mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
       return false;
     }
 
@@ -5432,12 +5432,12 @@
 
     // This will notify waiters on temp class that saw the not yet resolved class in the
     // class_table_ during EnsureResolved.
-    mirror::Class::SetStatus(klass, mirror::Class::kStatusRetired, self);
+    mirror::Class::SetStatus(klass, ClassStatus::kRetired, self);
 
-    CHECK_EQ(h_new_class->GetStatus(), mirror::Class::kStatusResolving);
+    CHECK_EQ(h_new_class->GetStatus(), ClassStatus::kResolving);
     // This will notify waiters on new_class that saw the not yet resolved
     // class in the class_table_ during EnsureResolved.
-    mirror::Class::SetStatus(h_new_class, mirror::Class::kStatusResolved, self);
+    mirror::Class::SetStatus(h_new_class, ClassStatus::kResolved, self);
     // Return the new class.
     h_new_class_out->Assign(h_new_class.Get());
   }
@@ -5445,7 +5445,7 @@
 }
 
 bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) {
-  CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus());
+  CHECK_EQ(ClassStatus::kIdx, klass->GetStatus());
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
   dex::TypeIndex super_class_idx = class_def.superclass_idx_;
   if (super_class_idx.IsValid()) {
@@ -5498,7 +5498,7 @@
     }
   }
   // Mark the class as loaded.
-  mirror::Class::SetStatus(klass, mirror::Class::kStatusLoaded, nullptr);
+  mirror::Class::SetStatus(klass, ClassStatus::kLoaded, nullptr);
   return true;
 }
 
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 10562f0..b4e2937 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -478,7 +478,7 @@
       REQUIRES(!Locks::dex_lock_);
   bool VerifyClassUsingOatFile(const DexFile& dex_file,
                                ObjPtr<mirror::Class> klass,
-                               mirror::Class::Status& oat_file_class_status)
+                               ClassStatus& oat_file_class_status)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_);
   void ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass)
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 3dca2f9..c386883 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -86,7 +86,7 @@
     EXPECT_TRUE(primitive->GetSuperClass() == nullptr);
     EXPECT_FALSE(primitive->HasSuperClass());
     EXPECT_TRUE(primitive->GetClassLoader() == nullptr);
-    EXPECT_EQ(mirror::Class::kStatusInitialized, primitive->GetStatus());
+    EXPECT_EQ(ClassStatus::kInitialized, primitive->GetStatus());
     EXPECT_FALSE(primitive->IsErroneous());
     EXPECT_TRUE(primitive->IsLoaded());
     EXPECT_TRUE(primitive->IsResolved());
@@ -125,7 +125,7 @@
     EXPECT_TRUE(JavaLangObject->GetSuperClass() == nullptr);
     EXPECT_FALSE(JavaLangObject->HasSuperClass());
     EXPECT_TRUE(JavaLangObject->GetClassLoader() == nullptr);
-    EXPECT_EQ(mirror::Class::kStatusInitialized, JavaLangObject->GetStatus());
+    EXPECT_EQ(ClassStatus::kInitialized, JavaLangObject->GetStatus());
     EXPECT_FALSE(JavaLangObject->IsErroneous());
     EXPECT_TRUE(JavaLangObject->IsLoaded());
     EXPECT_TRUE(JavaLangObject->IsResolved());
@@ -200,7 +200,7 @@
     EXPECT_TRUE(array->HasSuperClass());
     ASSERT_TRUE(array->GetComponentType() != nullptr);
     ASSERT_GT(strlen(array->GetComponentType()->GetDescriptor(&temp)), 0U);
-    EXPECT_EQ(mirror::Class::kStatusInitialized, array->GetStatus());
+    EXPECT_EQ(ClassStatus::kInitialized, array->GetStatus());
     EXPECT_FALSE(array->IsErroneous());
     EXPECT_TRUE(array->IsLoaded());
     EXPECT_TRUE(array->IsResolved());
@@ -919,7 +919,7 @@
   EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
   EXPECT_TRUE(MyClass->HasSuperClass());
   EXPECT_EQ(class_loader.Get(), MyClass->GetClassLoader());
-  EXPECT_EQ(mirror::Class::kStatusResolved, MyClass->GetStatus());
+  EXPECT_EQ(ClassStatus::kResolved, MyClass->GetStatus());
   EXPECT_FALSE(MyClass->IsErroneous());
   EXPECT_TRUE(MyClass->IsLoaded());
   EXPECT_TRUE(MyClass->IsResolved());
diff --git a/runtime/class_status.h b/runtime/class_status.h
index 7f2ef6a..ada2863 100644
--- a/runtime/class_status.h
+++ b/runtime/class_status.h
@@ -24,70 +24,70 @@
 
 // Class Status
 //
-// kStatusRetired: Class that's temporarily used till class linking time
+// kRetired: Class that's temporarily used till class linking time
 // has its (vtable) size figured out and has been cloned to one with the
 // right size which will be the one used later. The old one is retired and
 // will be gc'ed once all refs to the class point to the newly
 // cloned version.
 //
-// kStatusErrorUnresolved, kStatusErrorResolved: Class is erroneous. We need
+// kErrorUnresolved, kErrorResolved: Class is erroneous. We need
 // to distinguish between classes that have been resolved and classes that
 // have not. This is important because the const-class instruction needs to
 // return a previously resolved class even if its subsequent initialization
 // failed. We also need this to decide whether to wrap a previous
 // initialization failure in ClassDefNotFound error or not.
 //
-// kStatusNotReady: If a Class cannot be found in the class table by
+// kNotReady: If a Class cannot be found in the class table by
 // FindClass, it allocates an new one with AllocClass in the
-// kStatusNotReady and calls LoadClass. Note if it does find a
-// class, it may not be kStatusResolved and it will try to push it
-// forward toward kStatusResolved.
+// kNotReady and calls LoadClass. Note if it does find a
+// class, it may not be kResolved and it will try to push it
+// forward toward kResolved.
 //
-// kStatusIdx: LoadClass populates with Class with information from
-// the DexFile, moving the status to kStatusIdx, indicating that the
+// kIdx: LoadClass populates with Class with information from
+// the DexFile, moving the status to kIdx, indicating that the
 // Class value in super_class_ has not been populated. The new Class
 // can then be inserted into the classes table.
 //
-// kStatusLoaded: After taking a lock on Class, the ClassLinker will
-// attempt to move a kStatusIdx class forward to kStatusLoaded by
+// kLoaded: After taking a lock on Class, the ClassLinker will
+// attempt to move a kIdx class forward to kLoaded by
 // using ResolveClass to initialize the super_class_ and ensuring the
 // interfaces are resolved.
 //
-// kStatusResolving: Class is just cloned with the right size from
+// kResolving: Class is just cloned with the right size from
 // temporary class that's acting as a placeholder for linking. The old
 // class will be retired. New class is set to this status first before
 // moving on to being resolved.
 //
-// kStatusResolved: Still holding the lock on Class, the ClassLinker
+// kResolved: Still holding the lock on Class, the ClassLinker
 // shows linking is complete and fields of the Class populated by making
-// it kStatusResolved. Java allows circularities of the form where a super
+// it kResolved. Java allows circularities of the form where a super
 // class has a field that is of the type of the sub class. We need to be able
 // to fully resolve super classes while resolving types for fields.
 //
-// kStatusRetryVerificationAtRuntime: The verifier sets a class to
+// kRetryVerificationAtRuntime: The verifier sets a class to
 // this state if it encounters a soft failure at compile time. This
 // often happens when there are unresolved classes in other dex
 // files, and this status marks a class as needing to be verified
 // again at runtime.
 //
 // TODO: Explain the other states
-enum ClassStatus : int8_t {
-  kStatusRetired = -3,  // Retired, should not be used. Use the newly cloned one instead.
-  kStatusErrorResolved = -2,
-  kStatusErrorUnresolved = -1,
-  kStatusNotReady = 0,
-  kStatusIdx = 1,  // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_.
-  kStatusLoaded = 2,  // DEX idx values resolved.
-  kStatusResolving = 3,  // Just cloned from temporary class object.
-  kStatusResolved = 4,  // Part of linking.
-  kStatusVerifying = 5,  // In the process of being verified.
-  kStatusRetryVerificationAtRuntime = 6,  // Compile time verification failed, retry at runtime.
-  kStatusVerifyingAtRuntime = 7,  // Retrying verification at runtime.
-  kStatusVerified = 8,  // Logically part of linking; done pre-init.
-  kStatusSuperclassValidated = 9,  // Superclass validation part of init done.
-  kStatusInitializing = 10,  // Class init in progress.
-  kStatusInitialized = 11,  // Ready to go.
-  kStatusMax = 12,
+enum class ClassStatus : uint8_t {
+  kNotReady = 0,  // Zero-initialized Class object starts in this state.
+  kRetired = 1,  // Retired, should not be used. Use the newly cloned one instead.
+  kErrorResolved = 2,
+  kErrorUnresolved = 3,
+  kIdx = 4,  // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_.
+  kLoaded = 5,  // DEX idx values resolved.
+  kResolving = 6,  // Just cloned from temporary class object.
+  kResolved = 7,  // Part of linking.
+  kVerifying = 8,  // In the process of being verified.
+  kRetryVerificationAtRuntime = 9,  // Compile time verification failed, retry at runtime.
+  kVerifyingAtRuntime = 10,  // Retrying verification at runtime.
+  kVerified = 11,  // Logically part of linking; done pre-init.
+  kSuperclassValidated = 12,  // Superclass validation part of init done.
+  kInitializing = 13,  // Class init in progress.
+  kInitialized = 14,  // Ready to go.
+  kLast = kInitialized
 };
 
 std::ostream& operator<<(std::ostream& os, const ClassStatus& rhs);
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index c45bbe5..e313ec5 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -79,7 +79,7 @@
   mirror::Class* const existing = existing_it->Read();
   CHECK_NE(existing, klass) << descriptor;
   CHECK(!existing->IsResolved()) << descriptor;
-  CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusResolving) << descriptor;
+  CHECK_EQ(klass->GetStatus(), ClassStatus::kResolving) << descriptor;
   CHECK(!klass->IsTemp()) << descriptor;
   VerifyObject(klass);
   // Update the element in the hash set with the new class. This is safe to do since the descriptor
diff --git a/runtime/compiler_callbacks.h b/runtime/compiler_callbacks.h
index 9041df9..4560bca 100644
--- a/runtime/compiler_callbacks.h
+++ b/runtime/compiler_callbacks.h
@@ -55,7 +55,7 @@
   // Return the class status of a previous stage of the compilation. This can be used, for example,
   // when class unloading is enabled during multidex compilation.
   virtual ClassStatus GetPreviousClassState(ClassReference ref ATTRIBUTE_UNUSED) {
-    return ClassStatus::kStatusNotReady;
+    return ClassStatus::kNotReady;
   }
 
   virtual void SetDoesClassUnloading(bool does_class_unloading ATTRIBUTE_UNUSED,
diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h
index e158212..46630db 100644
--- a/runtime/generated/asm_support_gen.h
+++ b/runtime/generated/asm_support_gen.h
@@ -54,8 +54,6 @@
 DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_OBJECT_CLASS_OFFSET), (static_cast<int32_t>(art::mirror::Object::ClassOffset().Int32Value())))
 #define MIRROR_OBJECT_LOCK_WORD_OFFSET 4
 DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_OBJECT_LOCK_WORD_OFFSET), (static_cast<int32_t>(art::mirror::Object::MonitorOffset().Int32Value())))
-#define MIRROR_CLASS_STATUS_INITIALIZED 0xb
-DEFINE_CHECK_EQ(static_cast<uint32_t>(MIRROR_CLASS_STATUS_INITIALIZED), (static_cast<uint32_t>((art::mirror::Class::kStatusInitialized))))
 #define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000
 DEFINE_CHECK_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE), (static_cast<uint32_t>((art::kAccClassIsFinalizable))))
 #define ACCESS_FLAGS_CLASS_IS_INTERFACE 0x200
diff --git a/runtime/image.cc b/runtime/image.cc
index 8f35d84..b9d955c 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '1', '\0' };  // @FastNative access flags.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '2', '\0' };  // 4-bit ClassStatus.
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
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.
diff --git a/runtime/oat.h b/runtime/oat.h
index 9d21180..7d1bf85 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  // Last oat version changed reason: .bss index mapping change.
-  static constexpr uint8_t kOatVersion[] = { '1', '3', '5', '\0' };
+  // Last oat version changed reason: 4-bit ClassStatus.
+  static constexpr uint8_t kOatVersion[] = { '1', '3', '6', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index f437db2..7a3014e 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1654,9 +1654,8 @@
 
   const uint8_t* status_pointer = oat_class_pointer;
   CHECK_LT(status_pointer, oat_file_->End()) << oat_file_->GetLocation();
-  mirror::Class::Status status =
-      static_cast<mirror::Class::Status>(*reinterpret_cast<const int16_t*>(status_pointer));
-  CHECK_LT(status, mirror::Class::kStatusMax);
+  ClassStatus status = enum_cast<ClassStatus>(*reinterpret_cast<const int16_t*>(status_pointer));
+  CHECK_LE(status, ClassStatus::kLast);
 
   const uint8_t* type_pointer = status_pointer + sizeof(uint16_t);
   CHECK_LT(type_pointer, oat_file_->End()) << oat_file_->GetLocation();
@@ -1737,7 +1736,7 @@
 }
 
 OatFile::OatClass::OatClass(const OatFile* oat_file,
-                            mirror::Class::Status status,
+                            ClassStatus status,
                             OatClassType type,
                             uint32_t bitmap_size,
                             const uint32_t* bitmap_pointer,
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 1fb17a4..2ed1c82 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -24,11 +24,12 @@
 #include "base/array_ref.h"
 #include "base/mutex.h"
 #include "base/stringpiece.h"
+#include "class_status.h"
 #include "compiler_filter.h"
 #include "dex_file.h"
 #include "dex_file_layout.h"
 #include "index_bss_mapping.h"
-#include "mirror/class.h"
+#include "mirror/object.h"
 #include "oat.h"
 #include "os.h"
 #include "type_lookup_table.h"
@@ -196,7 +197,7 @@
 
   class OatClass FINAL {
    public:
-    mirror::Class::Status GetStatus() const {
+    ClassStatus GetStatus() const {
       return status_;
     }
 
@@ -224,7 +225,7 @@
     // See FindOatClass().
     static OatClass Invalid() {
       return OatClass(/* oat_file */ nullptr,
-                      mirror::Class::kStatusErrorUnresolved,
+                      ClassStatus::kErrorUnresolved,
                       kOatClassNoneCompiled,
                       /* bitmap_size */ 0,
                       /* bitmap_pointer */ nullptr,
@@ -233,7 +234,7 @@
 
    private:
     OatClass(const OatFile* oat_file,
-             mirror::Class::Status status,
+             ClassStatus status,
              OatClassType type,
              uint32_t bitmap_size,
              const uint32_t* bitmap_pointer,
@@ -241,7 +242,7 @@
 
     const OatFile* const oat_file_;
 
-    const mirror::Class::Status status_;
+    const ClassStatus status_;
 
     const OatClassType type_;
 
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 304017e..0bad548 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -66,7 +66,7 @@
     class_linker_->VerifyClass(soa.Self(), h_klass);
     ASSERT_TRUE(h_klass->IsVerified());
 
-    mirror::Class::Status old_status = h_klass->GetStatus();
+    ClassStatus old_status = h_klass->GetStatus();
     LockWord old_lock_word = h_klass->GetLockWord(false);
 
     Runtime::Current()->EnterTransactionMode();
diff --git a/test/008-exceptions/src/Main.java b/test/008-exceptions/src/Main.java
index 89fe016..008576a 100644
--- a/test/008-exceptions/src/Main.java
+++ b/test/008-exceptions/src/Main.java
@@ -158,8 +158,8 @@
             t.printStackTrace(System.out);
         }
         try {
-            // Before splitting mirror::Class::kStatusError into
-            // kStatusErrorUnresolved and kStatusErrorResolved,
+            // Before splitting ClassStatus::kError into
+            // ClassStatus::kErrorUnresolved and ClassStatus::kErrorResolved,
             // this would trigger a
             //     CHECK(super_class->IsResolved())
             // failure in
@@ -188,8 +188,8 @@
         } catch (Throwable t) {
             t.printStackTrace(System.out);
         }
-        // Before splitting mirror::Class::kStatusError into
-        // kStatusErrorUnresolved and kStatusErrorResolved,
+        // Before splitting ClassStatus::kError into
+        // ClassStatus::kErrorUnresolved and ClassStatus::kErrorResolved,
         // the exception from wrapper 1 would have been
         // wrapped in NoClassDefFoundError but the exception
         // from wrapper 2 would have been unwrapped.
diff --git a/test/626-const-class-linking/clear_dex_cache_types.cc b/test/626-const-class-linking/clear_dex_cache_types.cc
index e1af02e..96ef266 100644
--- a/test/626-const-class-linking/clear_dex_cache_types.cc
+++ b/test/626-const-class-linking/clear_dex_cache_types.cc
@@ -36,10 +36,10 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::Class> klass = hs.NewHandle(soa.Decode<mirror::Class>(cls));
-  mirror::Class::Status status = klass->GetStatus();
-  if (status == mirror::Class::kStatusResolved) {
+  ClassStatus status = klass->GetStatus();
+  if (status == ClassStatus::kResolved) {
     ObjectLock<mirror::Class> lock(soa.Self(), klass);
-    klass->SetStatus(klass, mirror::Class::kStatusVerified, soa.Self());
+    klass->SetStatus(klass, ClassStatus::kVerified, soa.Self());
   } else {
     LOG(ERROR) << klass->PrettyClass() << " has unexpected status: " << status;
   }
diff --git a/tools/cpp-define-generator/constant_class.def b/tools/cpp-define-generator/constant_class.def
index f46cd33..4f1d875 100644
--- a/tools/cpp-define-generator/constant_class.def
+++ b/tools/cpp-define-generator/constant_class.def
@@ -15,7 +15,6 @@
  */
 
 #if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "mirror/class.h"         // kStatusInitialized
 #include "modifiers.h"            // kAccClassIsFinalizable
 #include "base/bit_utils.h"       // MostSignificantBit
 #endif
@@ -23,7 +22,6 @@
 #define DEFINE_FLAG_OFFSET(type_name, field_name, expr) \
   DEFINE_EXPR(type_name ## _ ## field_name, uint32_t, (expr))
 
-DEFINE_FLAG_OFFSET(MIRROR_CLASS, STATUS_INITIALIZED,       art::mirror::Class::kStatusInitialized)
 DEFINE_FLAG_OFFSET(ACCESS_FLAGS, CLASS_IS_FINALIZABLE,     art::kAccClassIsFinalizable)
 DEFINE_FLAG_OFFSET(ACCESS_FLAGS, CLASS_IS_INTERFACE,       art::kAccInterface)
 // TODO: We should really have a BitPosition which also checks it's a power of 2.