Clean up enums in RegionSpace.

Split enum RegionState into two enums, RegionState and
RegionType. Merge the latter with SubSpaceType.

Use RefToRegionUnlocked in RegionSpace::AddLiveBytes.

Turn some CHECKs into DCHECKs.

Improve the Ritz EAAC run time and the GC time by ~20%.

Bug: 12687968
Change-Id: Icdb8ab3e9ec2a1eefc8c9a2e4bb19befcf2562a6
diff --git a/runtime/gc/space/region_space.h b/runtime/gc/space/region_space.h
index b4a043f..4160547 100644
--- a/runtime/gc/space/region_space.h
+++ b/runtime/gc/space/region_space.h
@@ -17,9 +17,10 @@
 #ifndef ART_RUNTIME_GC_SPACE_REGION_SPACE_H_
 #define ART_RUNTIME_GC_SPACE_REGION_SPACE_H_
 
+#include "gc/accounting/read_barrier_table.h"
 #include "object_callbacks.h"
 #include "space.h"
-#include "gc/accounting/read_barrier_table.h"
+#include "thread.h"
 
 namespace art {
 namespace gc {
@@ -94,32 +95,40 @@
   void AssertAllThreadLocalBuffersAreRevoked() LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_,
                                                               Locks::thread_list_lock_);
 
-  enum SubSpaceType {
-    kAllSpaces,        // All spaces.
-    kFromSpace,        // From-space. To be evacuated.
-    kUnevacFromSpace,  // Unevacuated from-space. Not to be evacuated.
-    kToSpace,          // To-space.
+  enum class RegionType : uint8_t {
+    kRegionTypeAll,              // All types.
+    kRegionTypeFromSpace,        // From-space. To be evacuated.
+    kRegionTypeUnevacFromSpace,  // Unevacuated from-space. Not to be evacuated.
+    kRegionTypeToSpace,          // To-space.
+    kRegionTypeNone,             // None.
   };
 
-  template<SubSpaceType kSubSpaceType> uint64_t GetBytesAllocatedInternal();
-  template<SubSpaceType kSubSpaceType> uint64_t GetObjectsAllocatedInternal();
+  enum class RegionState : uint8_t {
+    kRegionStateFree,            // Free region.
+    kRegionStateAllocated,       // Allocated region.
+    kRegionStateLarge,           // Large allocated (allocation larger than the region size).
+    kRegionStateLargeTail,       // Large tail (non-first regions of a large allocation).
+  };
+
+  template<RegionType kRegionType> uint64_t GetBytesAllocatedInternal();
+  template<RegionType kRegionType> uint64_t GetObjectsAllocatedInternal();
   uint64_t GetBytesAllocated() {
-    return GetBytesAllocatedInternal<kAllSpaces>();
+    return GetBytesAllocatedInternal<RegionType::kRegionTypeAll>();
   }
   uint64_t GetObjectsAllocated() {
-    return GetObjectsAllocatedInternal<kAllSpaces>();
+    return GetObjectsAllocatedInternal<RegionType::kRegionTypeAll>();
   }
   uint64_t GetBytesAllocatedInFromSpace() {
-    return GetBytesAllocatedInternal<kFromSpace>();
+    return GetBytesAllocatedInternal<RegionType::kRegionTypeFromSpace>();
   }
   uint64_t GetObjectsAllocatedInFromSpace() {
-    return GetObjectsAllocatedInternal<kFromSpace>();
+    return GetObjectsAllocatedInternal<RegionType::kRegionTypeFromSpace>();
   }
   uint64_t GetBytesAllocatedInUnevacFromSpace() {
-    return GetBytesAllocatedInternal<kUnevacFromSpace>();
+    return GetBytesAllocatedInternal<RegionType::kRegionTypeUnevacFromSpace>();
   }
   uint64_t GetObjectsAllocatedInUnevacFromSpace() {
-    return GetObjectsAllocatedInternal<kUnevacFromSpace>();
+    return GetObjectsAllocatedInternal<RegionType::kRegionTypeUnevacFromSpace>();
   }
 
   bool CanMoveObjects() const OVERRIDE {
@@ -181,6 +190,14 @@
     return false;
   }
 
+  RegionType GetRegionType(mirror::Object* ref) {
+    if (HasAddress(ref)) {
+      Region* r = RefToRegionUnlocked(ref);
+      return r->Type();
+    }
+    return RegionType::kRegionTypeNone;
+  }
+
   void SetFromSpace(accounting::ReadBarrierTable* rb_table, bool force_evacuate_all)
       LOCKS_EXCLUDED(region_lock_);
 
@@ -190,7 +207,7 @@
   void ClearFromSpace();
 
   void AddLiveBytes(mirror::Object* ref, size_t alloc_size) {
-    Region* reg = RefToRegion(ref);
+    Region* reg = RefToRegionUnlocked(ref);
     reg->AddLiveBytes(alloc_size);
   }
 
@@ -209,38 +226,36 @@
   template<bool kToSpaceOnly>
   void WalkInternal(ObjectCallback* callback, void* arg) NO_THREAD_SAFETY_ANALYSIS;
 
-  enum RegionState {
-    kRegionFree,                      // Free region.
-    kRegionToSpace,                   // To-space region.
-    kRegionFromSpace,                 // From-space region. To be evacuated.
-    kRegionUnevacFromSpace,           // Unevacuated from-space region. Not to be evacuated.
-    kRegionLargeToSpace,              // Large (allocation larger than the region size) to-space.
-    kRegionLargeFromSpace,            // Large from-space. To be evacuated.
-    kRegionLargeUnevacFromSpace,      // Large unevacuated from-space.
-    kRegionLargeTailToSpace,          // Large tail (non-first regions of a large allocation).
-    kRegionLargeTailFromSpace,        // Large tail from-space.
-    kRegionLargeTailUnevacFromSpace,  // Large tail unevacuated from-space.
-  };
-
   class Region {
    public:
     Region()
         : idx_(static_cast<size_t>(-1)),
-          begin_(nullptr), top_(nullptr), end_(nullptr), state_(kRegionToSpace),
+          begin_(nullptr), top_(nullptr), end_(nullptr),
+          state_(RegionState::kRegionStateAllocated), type_(RegionType::kRegionTypeToSpace),
           objects_allocated_(0), alloc_time_(0), live_bytes_(static_cast<size_t>(-1)),
           is_newly_allocated_(false), is_a_tlab_(false), thread_(nullptr) {}
 
     Region(size_t idx, uint8_t* begin, uint8_t* end)
-        : idx_(idx), begin_(begin), top_(begin), end_(end), state_(kRegionFree),
+        : idx_(idx), begin_(begin), top_(begin), end_(end),
+          state_(RegionState::kRegionStateFree), type_(RegionType::kRegionTypeNone),
           objects_allocated_(0), alloc_time_(0), live_bytes_(static_cast<size_t>(-1)),
           is_newly_allocated_(false), is_a_tlab_(false), thread_(nullptr) {
       DCHECK_LT(begin, end);
       DCHECK_EQ(static_cast<size_t>(end - begin), kRegionSize);
     }
 
+    RegionState State() const {
+      return state_;
+    }
+
+    RegionType Type() const {
+      return type_;
+    }
+
     void Clear() {
       top_ = begin_;
-      state_ = kRegionFree;
+      state_ = RegionState::kRegionStateFree;
+      type_ = RegionType::kRegionTypeNone;
       objects_allocated_ = 0;
       alloc_time_ = 0;
       live_bytes_ = static_cast<size_t>(-1);
@@ -257,8 +272,9 @@
                                         size_t* usable_size);
 
     bool IsFree() const {
-      bool is_free = state_ == kRegionFree;
+      bool is_free = state_ == RegionState::kRegionStateFree;
       if (is_free) {
+        DCHECK(IsInNoSpace());
         DCHECK_EQ(begin_, top_);
         DCHECK_EQ(objects_allocated_, 0U);
       }
@@ -268,19 +284,22 @@
     // Given a free region, declare it non-free (allocated).
     void Unfree(uint32_t alloc_time) {
       DCHECK(IsFree());
-      state_ = kRegionToSpace;
+      state_ = RegionState::kRegionStateAllocated;
+      type_ = RegionType::kRegionTypeToSpace;
       alloc_time_ = alloc_time;
     }
 
     void UnfreeLarge(uint32_t alloc_time) {
       DCHECK(IsFree());
-      state_ = kRegionLargeToSpace;
+      state_ = RegionState::kRegionStateLarge;
+      type_ = RegionType::kRegionTypeToSpace;
       alloc_time_ = alloc_time;
     }
 
     void UnfreeLargeTail(uint32_t alloc_time) {
       DCHECK(IsFree());
-      state_ = kRegionLargeTailToSpace;
+      state_ = RegionState::kRegionStateLargeTail;
+      type_ = RegionType::kRegionTypeToSpace;
       alloc_time_ = alloc_time;
     }
 
@@ -288,25 +307,23 @@
       is_newly_allocated_ = true;
     }
 
-    // Non-large, non-large-tail.
-    bool IsNormal() const {
-      return state_ == kRegionToSpace || state_ == kRegionFromSpace ||
-          state_ == kRegionUnevacFromSpace;
+    // Non-large, non-large-tail allocated.
+    bool IsAllocated() const {
+      return state_ == RegionState::kRegionStateAllocated;
     }
 
+    // Large allocated.
     bool IsLarge() const {
-      bool is_large = state_ == kRegionLargeToSpace || state_ == kRegionLargeFromSpace ||
-          state_ == kRegionLargeUnevacFromSpace;
+      bool is_large = state_ == RegionState::kRegionStateLarge;
       if (is_large) {
         DCHECK_LT(begin_ + 1 * MB, top_);
       }
       return is_large;
     }
 
+    // Large-tail allocated.
     bool IsLargeTail() const {
-      bool is_large_tail = state_ == kRegionLargeTailToSpace ||
-          state_ == kRegionLargeTailFromSpace ||
-          state_ == kRegionLargeTailUnevacFromSpace;
+      bool is_large_tail = state_ == RegionState::kRegionStateLargeTail;
       if (is_large_tail) {
         DCHECK_EQ(begin_, top_);
       }
@@ -318,71 +335,36 @@
     }
 
     bool IsInFromSpace() const {
-      return state_ == kRegionFromSpace || state_ == kRegionLargeFromSpace ||
-          state_ == kRegionLargeTailFromSpace;
+      return type_ == RegionType::kRegionTypeFromSpace;
     }
 
     bool IsInToSpace() const {
-      return state_ == kRegionToSpace || state_ == kRegionLargeToSpace ||
-          state_ == kRegionLargeTailToSpace;
+      return type_ == RegionType::kRegionTypeToSpace;
     }
 
     bool IsInUnevacFromSpace() const {
-      return state_ == kRegionUnevacFromSpace || state_ == kRegionLargeUnevacFromSpace ||
-          state_ == kRegionLargeTailUnevacFromSpace;
+      return type_ == RegionType::kRegionTypeUnevacFromSpace;
+    }
+
+    bool IsInNoSpace() const {
+      return type_ == RegionType::kRegionTypeNone;
     }
 
     void SetAsFromSpace() {
-      switch (state_) {
-        case kRegionToSpace:
-          state_ = kRegionFromSpace;
-          break;
-        case kRegionLargeToSpace:
-          state_ = kRegionLargeFromSpace;
-          break;
-        case kRegionLargeTailToSpace:
-          state_ = kRegionLargeTailFromSpace;
-          break;
-        default:
-          LOG(FATAL) << "Unexpected region state : " << static_cast<uint>(state_)
-                     << " idx=" << idx_;
-      }
+      DCHECK(!IsFree() && IsInToSpace());
+      type_ = RegionType::kRegionTypeFromSpace;
       live_bytes_ = static_cast<size_t>(-1);
     }
 
     void SetAsUnevacFromSpace() {
-      switch (state_) {
-        case kRegionToSpace:
-          state_ = kRegionUnevacFromSpace;
-          break;
-        case kRegionLargeToSpace:
-          state_ = kRegionLargeUnevacFromSpace;
-          break;
-        case kRegionLargeTailToSpace:
-          state_ = kRegionLargeTailUnevacFromSpace;
-          break;
-        default:
-          LOG(FATAL) << "Unexpected region state : " << static_cast<uint>(state_)
-                     << " idx=" << idx_;
-      }
+      DCHECK(!IsFree() && IsInToSpace());
+      type_ = RegionType::kRegionTypeUnevacFromSpace;
       live_bytes_ = 0U;
     }
 
     void SetUnevacFromSpaceAsToSpace() {
-      switch (state_) {
-        case kRegionUnevacFromSpace:
-          state_ = kRegionToSpace;
-          break;
-        case kRegionLargeUnevacFromSpace:
-          state_ = kRegionLargeToSpace;
-          break;
-        case kRegionLargeTailUnevacFromSpace:
-          state_ = kRegionLargeTailToSpace;
-          break;
-        default:
-          LOG(FATAL) << "Unexpected region state : " << static_cast<uint>(state_)
-                     << " idx=" << idx_;
-      }
+      DCHECK(!IsFree() && IsInUnevacFromSpace());
+      type_ = RegionType::kRegionTypeToSpace;
     }
 
     ALWAYS_INLINE bool ShouldBeEvacuated();
@@ -419,7 +401,7 @@
         DCHECK_EQ(begin_, top_);
         return 0;
       } else {
-        DCHECK(IsNormal()) << static_cast<uint>(state_);
+        DCHECK(IsAllocated()) << static_cast<uint>(state_);
         DCHECK_LE(begin_, top_);
         size_t bytes = static_cast<size_t>(top_ - begin_);
         DCHECK_LE(bytes, kRegionSize);
@@ -437,7 +419,7 @@
         DCHECK_EQ(objects_allocated_, 0U);
         return 0;
       } else {
-        DCHECK(IsNormal()) << static_cast<uint>(state_);
+        DCHECK(IsAllocated()) << static_cast<uint>(state_);
         return objects_allocated_;
       }
     }
@@ -465,7 +447,7 @@
     void Dump(std::ostream& os) const;
 
     void RecordThreadLocalAllocations(size_t num_objects, size_t num_bytes) {
-      DCHECK(IsNormal());
+      DCHECK(IsAllocated());
       DCHECK_EQ(objects_allocated_, 0U);
       DCHECK_EQ(top_, end_);
       objects_allocated_ = num_objects;
@@ -479,7 +461,8 @@
     // Can't use Atomic<uint8_t*> as Atomic's copy operator is implicitly deleted.
     uint8_t* top_;                 // The current position of the allocation.
     uint8_t* end_;                 // The end address of the region.
-    uint8_t state_;                // The region state (see RegionState).
+    RegionState state_;            // The region state (see RegionState).
+    RegionType type_;              // The region type (see RegionType).
     uint64_t objects_allocated_;   // The number of objects allocated.
     uint32_t alloc_time_;          // The allocation time of the region.
     size_t live_bytes_;            // The live bytes. Used to compute the live percent.
@@ -534,6 +517,9 @@
   DISALLOW_COPY_AND_ASSIGN(RegionSpace);
 };
 
+std::ostream& operator<<(std::ostream& os, const RegionSpace::RegionState& value);
+std::ostream& operator<<(std::ostream& os, const RegionSpace::RegionType& value);
+
 }  // namespace space
 }  // namespace gc
 }  // namespace art