Merge "Change ClassStatus to fit into 4 bits."
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 5d4ed46..b35a8e9 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1809,7 +1809,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_) {
@@ -1868,16 +1868,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:
@@ -1891,7 +1891,7 @@
         // this class again.
         LoadAndUpdateStatus(*dex_file,
                             class_def,
-                            mirror::Class::kStatusRetryVerificationAtRuntime,
+                            ClassStatus::kRetryVerificationAtRuntime,
                             class_loader,
                             soa.Self());
       }
@@ -2105,10 +2105,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(
@@ -2185,7 +2185,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.
@@ -2310,7 +2310,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();
         }
@@ -2771,36 +2771,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 "
@@ -2812,7 +2812,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.