Merge "Add class flags to class to help GC scanning"
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_