Merge "Catch references to unused regions in art::gc::ConcurrentCopying::Mark."
am: 3c18f4e9dc

Change-Id: Idb9816c4631d0faeee12a19a3d94ebb6f2e89c90
diff --git a/runtime/gc/collector/concurrent_copying-inl.h b/runtime/gc/collector/concurrent_copying-inl.h
index d739ed2..56983be 100644
--- a/runtime/gc/collector/concurrent_copying-inl.h
+++ b/runtime/gc/collector/concurrent_copying-inl.h
@@ -23,6 +23,7 @@
 #include "gc/accounting/space_bitmap-inl.h"
 #include "gc/heap.h"
 #include "gc/space/region_space.h"
+#include "gc/verification.h"
 #include "lock_word.h"
 #include "mirror/object-readbarrier-inl.h"
 
@@ -123,34 +124,39 @@
     return from_ref;
   }
   DCHECK(region_space_ != nullptr) << "Read barrier slow path taken when CC isn't running?";
-  space::RegionSpace::RegionType rtype = region_space_->GetRegionType(from_ref);
-  switch (rtype) {
-    case space::RegionSpace::RegionType::kRegionTypeToSpace:
-      // It's already marked.
-      return from_ref;
-    case space::RegionSpace::RegionType::kRegionTypeFromSpace: {
-      mirror::Object* to_ref = GetFwdPtr(from_ref);
-      if (to_ref == nullptr) {
-        // It isn't marked yet. Mark it by copying it to the to-space.
-        to_ref = Copy(from_ref, holder, offset);
+  if (region_space_->HasAddress(from_ref)) {
+    space::RegionSpace::RegionType rtype = region_space_->GetRegionTypeUnsafe(from_ref);
+    switch (rtype) {
+      case space::RegionSpace::RegionType::kRegionTypeToSpace:
+        // It's already marked.
+        return from_ref;
+      case space::RegionSpace::RegionType::kRegionTypeFromSpace: {
+        mirror::Object* to_ref = GetFwdPtr(from_ref);
+        if (to_ref == nullptr) {
+          // It isn't marked yet. Mark it by copying it to the to-space.
+          to_ref = Copy(from_ref, holder, offset);
+        }
+        // The copy should either be in a to-space region, or in the
+        // non-moving space, if it could not fit in a to-space region.
+        DCHECK(region_space_->IsInToSpace(to_ref) || heap_->non_moving_space_->HasAddress(to_ref))
+            << "from_ref=" << from_ref << " to_ref=" << to_ref;
+        return to_ref;
       }
-      // The copy should either be in a to-space region, or in the
-      // non-moving space, if it could not fit in a to-space region.
-      DCHECK(region_space_->IsInToSpace(to_ref) || heap_->non_moving_space_->HasAddress(to_ref))
-          << "from_ref=" << from_ref << " to_ref=" << to_ref;
-      return to_ref;
+      case space::RegionSpace::RegionType::kRegionTypeUnevacFromSpace:
+        return MarkUnevacFromSpaceRegion(from_ref, region_space_bitmap_);
+      default:
+        // The reference is in an unused region.
+        region_space_->DumpNonFreeRegions(LOG_STREAM(FATAL_WITHOUT_ABORT));
+        LOG(FATAL_WITHOUT_ABORT) << DumpHeapReference(holder, offset, from_ref);
+        heap_->GetVerification()->LogHeapCorruption(holder, offset, from_ref, /* fatal */ true);
+        UNREACHABLE();
     }
-    case space::RegionSpace::RegionType::kRegionTypeUnevacFromSpace: {
-      return MarkUnevacFromSpaceRegion(from_ref, region_space_bitmap_);
+  } else {
+    if (immune_spaces_.ContainsObject(from_ref)) {
+      return MarkImmuneSpace<kGrayImmuneObject>(from_ref);
+    } else {
+      return MarkNonMoving(from_ref, holder, offset);
     }
-    case space::RegionSpace::RegionType::kRegionTypeNone:
-      if (immune_spaces_.ContainsObject(from_ref)) {
-        return MarkImmuneSpace<kGrayImmuneObject>(from_ref);
-      } else {
-        return MarkNonMoving(from_ref, holder, offset);
-      }
-    default:
-      UNREACHABLE();
   }
 }
 
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 7304697..a78813b 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -1857,7 +1857,7 @@
     if (region_space_->HasAddress(ref)) {
       // Check to-space invariant in region space (moving space).
       using RegionType = space::RegionSpace::RegionType;
-      space::RegionSpace::RegionType type = region_space_->GetRegionType(ref);
+      space::RegionSpace::RegionType type = region_space_->GetRegionTypeUnsafe(ref);
       if (type == RegionType::kRegionTypeToSpace) {
         // OK.
         return;
@@ -1935,7 +1935,7 @@
     if (region_space_->HasAddress(ref)) {
       // Check to-space invariant in region space (moving space).
       using RegionType = space::RegionSpace::RegionType;
-      space::RegionSpace::RegionType type = region_space_->GetRegionType(ref);
+      space::RegionSpace::RegionType type = region_space_->GetRegionTypeUnsafe(ref);
       if (type == RegionType::kRegionTypeToSpace) {
         // OK.
         return;
diff --git a/runtime/gc/space/region_space.h b/runtime/gc/space/region_space.h
index c3b7ff7..d63257d 100644
--- a/runtime/gc/space/region_space.h
+++ b/runtime/gc/space/region_space.h
@@ -231,14 +231,23 @@
     return false;
   }
 
+  // If `ref` is in the region space, return the type of its region;
+  // otherwise, return `RegionType::kRegionTypeNone`.
   RegionType GetRegionType(mirror::Object* ref) {
     if (HasAddress(ref)) {
-      Region* r = RefToRegionUnlocked(ref);
-      return r->Type();
+      return GetRegionTypeUnsafe(ref);
     }
     return RegionType::kRegionTypeNone;
   }
 
+  // Unsafe version of RegionSpace::GetRegionType.
+  // Precondition: `ref` is in the region space.
+  RegionType GetRegionTypeUnsafe(mirror::Object* ref) {
+    DCHECK(HasAddress(ref)) << ref;
+    Region* r = RefToRegionUnlocked(ref);
+    return r->Type();
+  }
+
   // Determine which regions to evacuate and tag them as
   // from-space. Tag the rest as unevacuated from-space.
   void SetFromSpace(accounting::ReadBarrierTable* rb_table, bool force_evacuate_all)
@@ -530,8 +539,8 @@
   // Return the object location following `obj` in the region space
   // (i.e., the object location at `obj + obj->SizeOf()`).
   //
-  // Note that
-  // - unless the region containing `obj` is fully used; and
+  // Note that unless
+  // - the region containing `obj` is fully used; and
   // - `obj` is not the last object of that region;
   // the returned location is not guaranteed to be a valid object.
   mirror::Object* GetNextObject(mirror::Object* obj)