(Experimental) Add Brooks pointers.

This feature is disabled by default.

Verified that the Brooks pointers are installed correctly by using the
CMS/SS collectors.

Change-Id: Ia9be9814ab6e29169ac85edc4792ce8c81d552a9
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index cc34689..736dcb1 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -439,6 +439,12 @@
 
 inline void MarkSweep::UnMarkObjectNonNull(const Object* obj) {
   DCHECK(!IsImmune(obj));
+
+  if (kUseBrooksPointer) {
+    // Verify all the objects have the correct Brooks pointer installed.
+    obj->AssertSelfBrooksPointer();
+  }
+
   // Try to take advantage of locality of references within a space, failing this find the space
   // the hard way.
   accounting::SpaceBitmap* object_bitmap = current_mark_bitmap_;
@@ -459,6 +465,11 @@
 inline void MarkSweep::MarkObjectNonNull(const Object* obj) {
   DCHECK(obj != NULL);
 
+  if (kUseBrooksPointer) {
+    // Verify all the objects have the correct Brooks pointer installed.
+    obj->AssertSelfBrooksPointer();
+  }
+
   if (IsImmune(obj)) {
     DCHECK(IsMarked(obj));
     return;
@@ -521,6 +532,11 @@
 inline bool MarkSweep::MarkObjectParallel(const Object* obj) {
   DCHECK(obj != NULL);
 
+  if (kUseBrooksPointer) {
+    // Verify all the objects have the correct Brooks pointer installed.
+    obj->AssertSelfBrooksPointer();
+  }
+
   if (IsImmune(obj)) {
     DCHECK(IsMarked(obj));
     return false;
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index fe8c253..d639db5 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -517,6 +517,12 @@
   // references.
   saved_bytes_ +=
       CopyAvoidingDirtyingPages(reinterpret_cast<void*>(forward_address), obj, object_size);
+  if (kUseBrooksPointer) {
+    obj->AssertSelfBrooksPointer();
+    DCHECK_EQ(forward_address->GetBrooksPointer(), obj);
+    forward_address->SetBrooksPointer(forward_address);
+    forward_address->AssertSelfBrooksPointer();
+  }
   if (to_space_live_bitmap_ != nullptr) {
     to_space_live_bitmap_->Set(forward_address);
   }
@@ -529,6 +535,12 @@
 // the to-space and have their forward address updated. Objects which have been newly marked are
 // pushed on the mark stack.
 Object* SemiSpace::MarkObject(Object* obj) {
+  if (kUseBrooksPointer) {
+    // Verify all the objects have the correct forward pointer installed.
+    if (obj != nullptr) {
+      obj->AssertSelfBrooksPointer();
+    }
+  }
   Object* forward_address = obj;
   if (obj != nullptr && !IsImmune(obj)) {
     if (from_space_->HasAddress(obj)) {
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 3d591f0..2e47a02 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -65,6 +65,10 @@
     }
   }
   obj->SetClass(klass);
+  if (kUseBrooksPointer) {
+    obj->SetBrooksPointer(obj);
+    obj->AssertSelfBrooksPointer();
+  }
   pre_fence_visitor(obj);
   DCHECK_GT(bytes_allocated, 0u);
   const size_t new_num_bytes_allocated =
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 58db7a8..4435d98 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1402,6 +1402,12 @@
     }
     // Copy the object over to its new location.
     memcpy(reinterpret_cast<void*>(forward_address), obj, object_size);
+    if (kUseBrooksPointer) {
+      obj->AssertSelfBrooksPointer();
+      DCHECK_EQ(forward_address->GetBrooksPointer(), obj);
+      forward_address->SetBrooksPointer(forward_address);
+      forward_address->AssertSelfBrooksPointer();
+    }
     return forward_address;
   }
 };
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 12c5451..76c4d25 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -133,6 +133,11 @@
     mirror::Object* obj = reinterpret_cast<mirror::Object*>(current);
     CHECK(live_bitmap_->Test(obj));
     CHECK(obj->GetClass() != nullptr) << "Image object at address " << obj << " has null class";
+    if (kUseBrooksPointer) {
+      CHECK(obj->GetBrooksPointer() == obj)
+          << "Bad Brooks pointer: obj=" << reinterpret_cast<void*>(obj)
+          << " brooks_ptr=" << reinterpret_cast<void*>(obj->GetBrooksPointer());
+    }
     current += RoundUp(obj->SizeOf(), kObjectAlignment);
   }
 }
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index 093967e..41077f3 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -49,6 +49,9 @@
                                                                                       null_loader);
     EXPECT_TRUE(byte_array_class != nullptr);
     o->SetClass(byte_array_class);
+    if (kUseBrooksPointer) {
+      o->SetBrooksPointer(o.get());
+    }
     mirror::Array* arr = o->AsArray<kVerifyNone>();
     size_t header_size = SizeOfZeroLengthByteArray();
     int32_t length = size - header_size;