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);
         }
       }
     }