Add class flags to class to help GC scanning

Reduces GC time and pauses by reducing the number of loads required
to scan an object.

Average total GC time before on EvaluateAndApplyChanges (EAAC): 7.452s
After: 7.144s

Average GC pause times before on EAAC: 860.67us
After: 722.75us

Adding the class flags field cause a memory increase of ~24k system
wide on low memory devices.

Change-Id: I3f04212d5787bfbf5e55026584d149f55476105e
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 35acd42..084c88e 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -141,10 +141,10 @@
 #define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (36 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_ACCESS_FLAGS_OFFSET,
             art::mirror::Class::AccessFlagsOffset().Int32Value())
-#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (96 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (100 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET,
             art::mirror::Class::ObjectSizeOffset().Int32Value())
-#define MIRROR_CLASS_STATUS_OFFSET (108 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_STATUS_OFFSET (112 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_STATUS_OFFSET,
             art::mirror::Class::StatusOffset().Int32Value())
 
@@ -153,7 +153,7 @@
             static_cast<uint32_t>(art::mirror::Class::kStatusInitialized))
 #define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000
 ADD_TEST_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE),
-            static_cast<uint32_t>(kAccClassIsFinalizable))
+            static_cast<uint32_t>(art::kAccClassIsFinalizable))
 
 // Array offsets.
 #define MIRROR_ARRAY_LENGTH_OFFSET      MIRROR_OBJECT_HEADER_SIZE
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c179c64..b547d07 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -358,9 +358,9 @@
   // Setup String.
   Handle<mirror::Class> java_lang_String(hs.NewHandle(
       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);
-  java_lang_String->SetStringClass();
 
   // Setup java.lang.ref.Reference.
   Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle(
@@ -570,16 +570,13 @@
   CHECK_EQ(java_lang_ref_Reference->GetClassSize(),
            mirror::Reference::ClassSize(image_pointer_size_));
   class_root = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;");
-  class_root->SetAccessFlags(class_root->GetAccessFlags() |
-                             kAccClassIsReference | kAccClassIsFinalizerReference);
+  class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagFinalizerReference);
   class_root = FindSystemClass(self, "Ljava/lang/ref/PhantomReference;");
-  class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference |
-                             kAccClassIsPhantomReference);
+  class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagPhantomReference);
   class_root = FindSystemClass(self, "Ljava/lang/ref/SoftReference;");
-  class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference);
+  class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagSoftReference);
   class_root = FindSystemClass(self, "Ljava/lang/ref/WeakReference;");
-  class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference |
-                             kAccClassIsWeakReference);
+  class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagWeakReference);
 
   // Setup the ClassLoader, verifying the object_size_.
   class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;");
@@ -2701,6 +2698,11 @@
   new_class->SetVTable(java_lang_Object->GetVTable());
   new_class->SetPrimitiveType(Primitive::kPrimNot);
   new_class->SetClassLoader(component_type->GetClassLoader());
+  if (component_type->IsPrimitive()) {
+    new_class->SetClassFlags(mirror::kClassFlagNoReferenceFields);
+  } else {
+    new_class->SetClassFlags(mirror::kClassFlagObjectArray);
+  }
   mirror::Class::SetStatus(new_class, mirror::Class::kStatusLoaded, self);
   {
     ArtMethod* imt[mirror::Class::kImtSize];
@@ -4385,9 +4387,9 @@
   }
 
   // Inherit reference flags (if any) from the superclass.
-  int reference_flags = (super->GetAccessFlags() & kAccReferenceFlagsMask);
+  int reference_flags = (super->GetClassFlags() & mirror::kClassFlagReference);
   if (reference_flags != 0) {
-    klass->SetAccessFlags(klass->GetAccessFlags() | reference_flags);
+    klass->SetClassFlags(klass->GetClassFlags() | reference_flags);
   }
   // Disallow custom direct subclasses of java.lang.ref.Reference.
   if (init_done_ && super == GetClassRoot(kJavaLangRefReference)) {
@@ -5227,6 +5229,22 @@
     *class_size = size;
   } else {
     klass->SetNumReferenceInstanceFields(num_reference_fields);
+    mirror::Class* super_class = klass->GetSuperClass();
+    if (num_reference_fields == 0 || super_class == nullptr) {
+      // object has one reference field, klass, but we ignore it since we always visit the class.
+      // If the super_class is null then we are java.lang.Object.
+      if (super_class == nullptr ||
+          (super_class->GetClassFlags() & mirror::kClassFlagNoReferenceFields) != 0) {
+        klass->SetClassFlags(klass->GetClassFlags() | mirror::kClassFlagNoReferenceFields);
+      } else if (kIsDebugBuild) {
+        size_t total_reference_instance_fields = 0;
+        while (super_class != nullptr) {
+          total_reference_instance_fields += super_class->NumReferenceInstanceFields();
+          super_class = super_class->GetSuperClass();
+        }
+        CHECK_GT(total_reference_instance_fields, 1u);
+      }
+    }
     if (!klass->IsVariableSize()) {
       std::string temp;
       DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor(&temp);
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 3c84d8f..0d1c875 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -488,6 +488,7 @@
 struct ClassOffsets : public CheckOffsets<mirror::Class> {
   ClassOffsets() : CheckOffsets<mirror::Class>(false, "Ljava/lang/Class;") {
     addOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags");
+    addOffset(OFFSETOF_MEMBER(mirror::Class, class_flags_), "classFlags");
     addOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_), "classLoader");
     addOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize");
     addOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId");
diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h
index a3cc831..56edcc9 100644
--- a/runtime/gc/collector/mark_sweep-inl.h
+++ b/runtime/gc/collector/mark_sweep-inl.h
@@ -35,10 +35,17 @@
   obj->VisitReferences(visitor, ref_visitor);
   if (kCountScannedTypes) {
     mirror::Class* klass = obj->GetClass<kVerifyNone>();
-    if (UNLIKELY(klass == mirror::Class::GetJavaLangClass())) {
+    uint32_t class_flags = klass->GetClassFlags();
+    if ((class_flags & mirror::kClassFlagNoReferenceFields) != 0) {
+      ++no_reference_class_count_;
+    } else if (class_flags == mirror::kClassFlagNormal) {
+      ++normal_count_;
+    } else if (class_flags == mirror::kClassFlagObjectArray) {
+      ++object_array_count_;
+    } else if (class_flags == mirror::kClassFlagClass) {
       ++class_count_;
-    } else if (UNLIKELY(klass->IsArrayClass<kVerifyNone>())) {
-      ++array_count_;
+    } else if ((class_flags & mirror::kClassFlagReference) != 0) {
+      ++reference_count_;
     } else {
       ++other_count_;
     }
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index b0a8a5b..7ddc7cc 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -70,7 +70,6 @@
 static constexpr bool kProfileLargeObjects = false;
 static constexpr bool kMeasureOverhead = false;
 static constexpr bool kCountTasks = false;
-static constexpr bool kCountJavaLangRefs = false;
 static constexpr bool kCountMarkedObjects = false;
 
 // Turn off kCheckLocks when profiling the GC since it slows the GC down by up to 40%.
@@ -114,15 +113,17 @@
   mark_stack_ = heap_->GetMarkStack();
   DCHECK(mark_stack_ != nullptr);
   immune_region_.Reset();
+  no_reference_class_count_.StoreRelaxed(0);
+  normal_count_.StoreRelaxed(0);
   class_count_.StoreRelaxed(0);
-  array_count_.StoreRelaxed(0);
+  object_array_count_.StoreRelaxed(0);
   other_count_.StoreRelaxed(0);
+  reference_count_.StoreRelaxed(0);
   large_object_test_.StoreRelaxed(0);
   large_object_mark_.StoreRelaxed(0);
   overhead_time_ .StoreRelaxed(0);
   work_chunks_created_.StoreRelaxed(0);
   work_chunks_deleted_.StoreRelaxed(0);
-  reference_count_.StoreRelaxed(0);
   mark_null_count_.StoreRelaxed(0);
   mark_immune_count_.StoreRelaxed(0);
   mark_fastpath_count_.StoreRelaxed(0);
@@ -1265,9 +1266,6 @@
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
 // marked, put it on the appropriate list in the heap for later processing.
 void MarkSweep::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref) {
-  if (kCountJavaLangRefs) {
-    ++reference_count_;
-  }
   heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, ref, this);
 }
 
@@ -1386,8 +1384,14 @@
 void MarkSweep::FinishPhase() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   if (kCountScannedTypes) {
-    VLOG(gc) << "MarkSweep scanned classes=" << class_count_.LoadRelaxed()
-        << " arrays=" << array_count_.LoadRelaxed() << " other=" << other_count_.LoadRelaxed();
+    VLOG(gc)
+        << "MarkSweep scanned"
+        << " no reference objects=" << no_reference_class_count_.LoadRelaxed()
+        << " normal objects=" << normal_count_.LoadRelaxed()
+        << " classes=" << class_count_.LoadRelaxed()
+        << " object arrays=" << object_array_count_.LoadRelaxed()
+        << " references=" << reference_count_.LoadRelaxed()
+        << " other=" << other_count_.LoadRelaxed();
   }
   if (kCountTasks) {
     VLOG(gc) << "Total number of work chunks allocated: " << work_chunks_created_.LoadRelaxed();
@@ -1399,9 +1403,6 @@
     VLOG(gc) << "Large objects tested " << large_object_test_.LoadRelaxed()
         << " marked " << large_object_mark_.LoadRelaxed();
   }
-  if (kCountJavaLangRefs) {
-    VLOG(gc) << "References scanned " << reference_count_.LoadRelaxed();
-  }
   if (kCountMarkedObjects) {
     VLOG(gc) << "Marked: null=" << mark_null_count_.LoadRelaxed()
         << " immune=" <<  mark_immune_count_.LoadRelaxed()
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 8bd1dc7..371bba5 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -245,7 +245,7 @@
   void RevokeAllThreadLocalBuffers();
 
   // Whether or not we count how many of each type of object were scanned.
-  static const bool kCountScannedTypes = false;
+  static constexpr bool kCountScannedTypes = false;
 
   // Current space, we check this space first to avoid searching for the appropriate space for an
   // object.
@@ -260,18 +260,23 @@
 
   // Parallel finger.
   AtomicInteger atomic_finger_;
+
+  AtomicInteger no_reference_class_count_;
+  AtomicInteger normal_count_;
   // Number of classes scanned, if kCountScannedTypes.
   AtomicInteger class_count_;
-  // Number of arrays scanned, if kCountScannedTypes.
-  AtomicInteger array_count_;
+  // Number of object arrays scanned, if kCountScannedTypes.
+  AtomicInteger object_array_count_;
   // Number of non-class/arrays scanned, if kCountScannedTypes.
   AtomicInteger other_count_;
+  // Number of java.lang.ref.Reference instances.
+  AtomicInteger reference_count_;
+
   AtomicInteger large_object_test_;
   AtomicInteger large_object_mark_;
   AtomicInteger overhead_time_;
   AtomicInteger work_chunks_created_;
   AtomicInteger work_chunks_deleted_;
-  AtomicInteger reference_count_;
   AtomicInteger mark_null_count_;
   AtomicInteger mark_immune_count_;
   AtomicInteger mark_fastpath_count_;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index d7f918b..b8c4478 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -3707,7 +3707,7 @@
 
 void Heap::CheckPreconditionsForAllocObject(mirror::Class* c, size_t byte_count) {
   CHECK(c == nullptr || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) ||
-        (c->IsVariableSize() || c->GetObjectSize() == byte_count));
+        (c->IsVariableSize() || c->GetObjectSize() == byte_count)) << c->GetClassFlags();
   CHECK_GE(byte_count, sizeof(mirror::Object));
 }
 
diff --git a/runtime/image.cc b/runtime/image.cc
index 2586959..8df17c6 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,7 +24,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '1', '9', '\0' };
+const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '0', '\0' };
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index cd678f6..b2c6e4d 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -547,6 +547,7 @@
 inline String* Class::GetName() {
   return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Class, name_));
 }
+
 inline void Class::SetName(String* name) {
   if (Runtime::Current()->IsActiveTransaction()) {
     SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, name_), name);
@@ -784,9 +785,17 @@
 inline void Class::SetAccessFlags(uint32_t new_access_flags) {
   // Called inside a transaction when setting pre-verified flag during boot image compilation.
   if (Runtime::Current()->IsActiveTransaction()) {
-    SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+    SetField32<true>(AccessFlagsOffset(), new_access_flags);
   } else {
-    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+    SetField32<false>(AccessFlagsOffset(), new_access_flags);
+  }
+}
+
+inline void Class::SetClassFlags(uint32_t new_flags) {
+  if (Runtime::Current()->IsActiveTransaction()) {
+    SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_), new_flags);
+  } else {
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_), new_flags);
   }
 }
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 055b3e5..228fd27 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -44,6 +44,7 @@
       << java_lang_Class_.Read()
       << " " << java_lang_Class;
   CHECK(java_lang_Class != nullptr);
+  java_lang_Class->SetClassFlags(java_lang_Class->GetClassFlags() | mirror::kClassFlagClass);
   java_lang_Class_ = GcRoot<Class>(java_lang_Class);
 }
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 3f375be..cbcb517 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -19,6 +19,7 @@
 
 #include "base/iteration_range.h"
 #include "dex_file.h"
+#include "class_flags.h"
 #include "gc_root.h"
 #include "gc/allocator_type.h"
 #include "invoke_type.h"
@@ -201,6 +202,12 @@
     return OFFSET_OF_OBJECT_MEMBER(Class, access_flags_);
   }
 
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  ALWAYS_INLINE uint32_t GetClassFlags() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_));
+  }
+  void SetClassFlags(uint32_t new_flags) SHARED_REQUIRES(Locks::mutator_lock_);
+
   void SetAccessFlags(uint32_t new_access_flags) SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Returns true if the class is an interface.
@@ -228,21 +235,19 @@
   }
 
   ALWAYS_INLINE bool IsStringClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetField32(AccessFlagsOffset()) & kAccClassIsStringClass) != 0;
+    return (GetClassFlags() & kClassFlagString) != 0;
   }
 
   ALWAYS_INLINE void SetStringClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
-    SetAccessFlags(flags | kAccClassIsStringClass);
+    SetClassFlags(GetClassFlags() | kClassFlagString | kClassFlagNoReferenceFields);
   }
 
   ALWAYS_INLINE bool IsClassLoaderClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetField32(AccessFlagsOffset()) & kAccClassIsClassLoaderClass) != 0;
+    return (GetClassFlags() & kClassFlagClassLoader) != 0;
   }
 
   ALWAYS_INLINE void SetClassLoaderClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
-    SetAccessFlags(flags | kAccClassIsClassLoaderClass);
+    SetClassFlags(GetClassFlags() | kClassFlagClassLoader);
   }
 
   // Returns true if the class is abstract.
@@ -272,27 +277,27 @@
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsTypeOfReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags<kVerifyFlags>() & kAccClassIsReference) != 0;
+    return (GetClassFlags<kVerifyFlags>() & kClassFlagReference) != 0;
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsWeakReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags<kVerifyFlags>() & kAccClassIsWeakReference) != 0;
+    return (GetClassFlags<kVerifyFlags>() & kClassFlagWeakReference) != 0;
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsSoftReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags<kVerifyFlags>() & kAccReferenceFlagsMask) == kAccClassIsReference;
+    return (GetClassFlags<kVerifyFlags>() & kClassFlagSoftReference) != 0;
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsFinalizerReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags<kVerifyFlags>() & kAccClassIsFinalizerReference) != 0;
+    return (GetClassFlags<kVerifyFlags>() & kClassFlagFinalizerReference) != 0;
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsPhantomReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags<kVerifyFlags>() & kAccClassIsPhantomReference) != 0;
+    return (GetClassFlags<kVerifyFlags>() & kClassFlagPhantomReference) != 0;
   }
 
   // Can references of this type be assigned to by things of another type? For non-array types
@@ -862,7 +867,8 @@
   uint32_t NumInstanceFields() SHARED_REQUIRES(Locks::mutator_lock_);
   ArtField* GetInstanceField(uint32_t i) SHARED_REQUIRES(Locks::mutator_lock_);
 
-  // Returns the number of instance fields containing reference types.
+  // Returns the number of instance fields containing reference types not counting fields in the
+  // super class.
   uint32_t NumReferenceInstanceFields() SHARED_REQUIRES(Locks::mutator_lock_) {
     DCHECK(IsResolved() || IsErroneous());
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_));
@@ -1225,6 +1231,9 @@
   // length-prefixed array.
   uint64_t virtual_methods_;
 
+  // Class flags to help speed up visiting object references.
+  uint32_t class_flags_;
+
   // Total size of the Class instance; used when allocating storage on gc heap.
   // See also object_size_.
   uint32_t class_size_;
diff --git a/runtime/mirror/class_flags.h b/runtime/mirror/class_flags.h
new file mode 100644
index 0000000..6c15639
--- /dev/null
+++ b/runtime/mirror/class_flags.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MIRROR_CLASS_FLAGS_H_
+#define ART_RUNTIME_MIRROR_CLASS_FLAGS_H_
+
+#include <stdint.h>
+
+namespace art {
+namespace mirror {
+
+// Object types stored in class to help GC with faster object marking.
+static constexpr uint32_t kClassFlagNormal             = 0x00000000;
+// Only normal objects which have no reference fields, e.g. string or primitive array or normal
+// class instance.
+static constexpr uint32_t kClassFlagNoReferenceFields  = 0x00000001;
+static constexpr uint32_t kClassFlagString             = 0x00000004;
+static constexpr uint32_t kClassFlagObjectArray        = 0x00000008;
+static constexpr uint32_t kClassFlagClass              = 0x00000010;
+
+// class is ClassLoader or one of its subclasses
+static constexpr uint32_t kClassFlagClassLoader        = 0x00000020;
+
+// class is a soft/weak/phantom ref
+static constexpr uint32_t kClassFlagSoftReference      = 0x00000040;
+// class is a weak reference
+static constexpr uint32_t kClassFlagWeakReference      = 0x00000080;
+// class is a finalizer reference
+static constexpr uint32_t kClassFlagFinalizerReference = 0x00000100;
+// class is a phantom reference
+static constexpr uint32_t kClassFlagPhantomReference   = 0x00000200;
+
+static constexpr uint32_t kClassFlagReference =
+    kClassFlagSoftReference |
+    kClassFlagWeakReference |
+    kClassFlagFinalizerReference |
+    kClassFlagPhantomReference;
+
+}  // namespace mirror
+}  // namespace art
+
+#endif  // ART_RUNTIME_MIRROR_CLASS_FLAGS_H_
+
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 586ae30..702a0f4 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -24,6 +24,7 @@
 #include "atomic.h"
 #include "array-inl.h"
 #include "class.h"
+#include "class_flags.h"
 #include "class_linker.h"
 #include "class_loader-inl.h"
 #include "lock_word-inl.h"
@@ -1010,20 +1011,43 @@
                                     const JavaLangRefVisitor& ref_visitor) {
   mirror::Class* klass = GetClass<kVerifyFlags>();
   visitor(this, ClassOffset(), false);
-  if (klass == Class::GetJavaLangClass()) {
-    AsClass<kVerifyNone>()->VisitReferences(klass, visitor);
-  } else if (klass->IsArrayClass() || klass->IsStringClass()) {
-    if (klass->IsObjectArrayClass<kVerifyNone>()) {
-      AsObjectArray<mirror::Object, kVerifyNone>()->VisitReferences(visitor);
-    }
-  } else if (klass->IsClassLoaderClass()) {
-    mirror::ClassLoader* class_loader = AsClassLoader<kVerifyFlags>();
-    class_loader->VisitReferences<kVerifyFlags>(klass, visitor);
-  } else {
+  const uint32_t class_flags = klass->GetClassFlags<kVerifyNone>();
+  if (LIKELY(class_flags == kClassFlagNormal)) {
     DCHECK(!klass->IsVariableSize());
     VisitInstanceFieldsReferences(klass, visitor);
-    if (UNLIKELY(klass->IsTypeOfReferenceClass<kVerifyNone>())) {
-      ref_visitor(klass, AsReference());
+    DCHECK(!klass->IsClassClass());
+  } else {
+    if ((class_flags & kClassFlagNoReferenceFields) == 0) {
+      DCHECK(!klass->IsStringClass());
+      if (class_flags == kClassFlagClass) {
+        DCHECK(klass->IsClassClass());
+        AsClass<kVerifyNone>()->VisitReferences(klass, visitor);
+      } else if (class_flags == kClassFlagObjectArray) {
+        DCHECK(klass->IsObjectArrayClass());
+        AsObjectArray<mirror::Object, kVerifyNone>()->VisitReferences(visitor);
+      } else if ((class_flags & kClassFlagReference) != 0) {
+        VisitInstanceFieldsReferences(klass, visitor);
+        ref_visitor(klass, AsReference());
+      } else {
+        mirror::ClassLoader* const class_loader = AsClassLoader<kVerifyFlags>();
+        class_loader->VisitReferences<kVerifyFlags>(klass, visitor);
+      }
+    } else if (kIsDebugBuild) {
+      CHECK(!klass->IsClassClass());
+      CHECK(!klass->IsObjectArrayClass());
+      // String still has instance fields for reflection purposes but these don't exist in
+      // actual string instances.
+      if (!klass->IsStringClass()) {
+        size_t total_reference_instance_fields = 0;
+        mirror::Class* super_class = klass;
+        do {
+          total_reference_instance_fields += super_class->NumReferenceInstanceFields();
+          super_class = super_class->GetSuperClass();
+        } while (super_class != nullptr);
+        // The only reference field should be the object's class. This field is handled at the
+        // beginning of the function.
+        CHECK_EQ(total_reference_instance_fields, 1u);
+      }
     }
   }
 }
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index b6236b1..45610dc 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -55,6 +55,7 @@
 void String::SetClass(Class* java_lang_String) {
   CHECK(java_lang_String_.IsNull());
   CHECK(java_lang_String != nullptr);
+  CHECK(java_lang_String->IsStringClass());
   java_lang_String_ = GcRoot<Class>(java_lang_String);
 }
 
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index eb2e1f6..fbee2d7 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -157,10 +157,9 @@
     return java_lang_String_.Read();
   }
 
-  static void SetClass(Class* java_lang_String);
-  static void ResetClass();
-  static void VisitRoots(RootVisitor* visitor)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+  static void SetClass(Class* java_lang_String) SHARED_REQUIRES(Locks::mutator_lock_);
+  static void ResetClass() SHARED_REQUIRES(Locks::mutator_lock_);
+  static void VisitRoots(RootVisitor* visitor) SHARED_REQUIRES(Locks::mutator_lock_);
 
  private:
   void SetHashCode(int32_t new_hash_code) SHARED_REQUIRES(Locks::mutator_lock_) {
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 0d9ec29..f7ab10b 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -19,6 +19,8 @@
 
 #include <stdint.h>
 
+namespace art {
+
 static constexpr uint32_t kAccPublic =       0x0001;  // class, field, method, ic
 static constexpr uint32_t kAccPrivate =      0x0002;  // field, method, ic
 static constexpr uint32_t kAccProtected =    0x0004;  // field, method, ic
@@ -49,28 +51,8 @@
 static constexpr uint32_t kAccMiranda =              0x00200000;  // method (dex only)
 
 // Special runtime-only flags.
-// Note: if only kAccClassIsReference is set, we have a soft reference.
-
-// class is ClassLoader or one of its subclasses
-static constexpr uint32_t kAccClassIsClassLoaderClass   = 0x10000000;
-
 // class/ancestor overrides finalize()
 static constexpr uint32_t kAccClassIsFinalizable        = 0x80000000;
-// class is a soft/weak/phantom ref
-static constexpr uint32_t kAccClassIsReference          = 0x08000000;
-// class is a weak reference
-static constexpr uint32_t kAccClassIsWeakReference      = 0x04000000;
-// class is a finalizer reference
-static constexpr uint32_t kAccClassIsFinalizerReference = 0x02000000;
-// class is a phantom reference
-static constexpr uint32_t kAccClassIsPhantomReference   = 0x01000000;
-// class is the string class
-static constexpr uint32_t kAccClassIsStringClass        = 0x00800000;
-
-static constexpr uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
-                                                  | kAccClassIsWeakReference
-                                                  | kAccClassIsFinalizerReference
-                                                  | kAccClassIsPhantomReference);
 
 // Valid (meaningful) bits for a field.
 static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected |
@@ -95,5 +77,7 @@
 static constexpr uint32_t kAccValidInterfaceFlags = kAccPublic | kAccInterface |
     kAccAbstract | kAccSynthetic | kAccAnnotation;
 
+}  // namespace art
+
 #endif  // ART_RUNTIME_MODIFIERS_H_