Change BumpPointerSpace main block header to not be in space data.

Changed the bump pointer space main block to be in the space and not
the space data. This lets us access the main block header when the
space is protected and lets us walk a protected space as long as it
is empty.

Bug: 12966354
Change-Id: Id53bf59224926718af7356dd9fc1205ff91cc5d1
diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc
index 2e07bd3..f7bdc4c 100644
--- a/runtime/gc/space/bump_pointer_space.cc
+++ b/runtime/gc/space/bump_pointer_space.cc
@@ -44,9 +44,8 @@
       growth_end_(limit),
       objects_allocated_(0), bytes_allocated_(0),
       block_lock_("Block lock"),
+      main_block_size_(0),
       num_blocks_(0) {
-  CHECK_GE(Capacity(), sizeof(BlockHeader));
-  end_ += sizeof(BlockHeader);
 }
 
 BumpPointerSpace::BumpPointerSpace(const std::string& name, MemMap* mem_map)
@@ -55,9 +54,8 @@
       growth_end_(mem_map->End()),
       objects_allocated_(0), bytes_allocated_(0),
       block_lock_("Block lock"),
+      main_block_size_(0),
       num_blocks_(0) {
-  CHECK_GE(Capacity(), sizeof(BlockHeader));
-  end_ += sizeof(BlockHeader);
 }
 
 mirror::Object* BumpPointerSpace::Alloc(Thread*, size_t num_bytes, size_t* bytes_allocated) {
@@ -78,13 +76,14 @@
   CHECK_NE(madvise(Begin(), Limit() - Begin(), MADV_DONTNEED), -1) << "madvise failed";
   // Reset the end of the space back to the beginning, we move the end forward as we allocate
   // objects.
-  SetEnd(Begin() + sizeof(BlockHeader));
+  SetEnd(Begin());
   objects_allocated_ = 0;
   bytes_allocated_ = 0;
   growth_end_ = Limit();
   {
     MutexLock mu(Thread::Current(), block_lock_);
     num_blocks_ = 0;
+    main_block_size_ = 0;
   }
 }
 
@@ -115,9 +114,8 @@
 }
 
 void BumpPointerSpace::UpdateMainBlock() {
-  BlockHeader* header = reinterpret_cast<BlockHeader*>(Begin());
-  header->size_ = Size() - sizeof(BlockHeader);
   DCHECK_EQ(num_blocks_, 0U);
+  main_block_size_ = Size();
 }
 
 // Returns the start of the storage.
@@ -139,7 +137,7 @@
 
 void BumpPointerSpace::Walk(ObjectCallback* callback, void* arg) {
   byte* pos = Begin();
-
+  byte* main_end = pos;
   {
     MutexLock mu(Thread::Current(), block_lock_);
     // If we have 0 blocks then we need to update the main header since we have bump pointer style
@@ -147,8 +145,15 @@
     if (num_blocks_ == 0) {
       UpdateMainBlock();
     }
+    main_end += main_block_size_;
   }
-
+  // Walk all of the objects in the main block first.
+  while (pos < main_end) {
+    mirror::Object* obj = reinterpret_cast<mirror::Object*>(pos);
+    callback(obj, arg);
+    pos = reinterpret_cast<byte*>(GetNextObject(obj));
+  }
+  // Walk the other blocks (currently only TLABs).
   while (pos < End()) {
     BlockHeader* header = reinterpret_cast<BlockHeader*>(pos);
     size_t block_size = header->size_;
@@ -167,7 +172,7 @@
 }
 
 bool BumpPointerSpace::IsEmpty() const {
-  return Size() == sizeof(BlockHeader);
+  return Begin() == End();
 }
 
 uint64_t BumpPointerSpace::GetBytesAllocated() {
diff --git a/runtime/gc/space/bump_pointer_space.h b/runtime/gc/space/bump_pointer_space.h
index ddd17be..d7e6f5b 100644
--- a/runtime/gc/space/bump_pointer_space.h
+++ b/runtime/gc/space/bump_pointer_space.h
@@ -139,15 +139,16 @@
 
   // The main block is an unbounded block where objects go when there are no other blocks. This
   // enables us to maintain tightly packed objects when you are not using thread local buffers for
-  // allocation.
-  // The main block is also the block which starts at address 0.
+  // allocation. The main block starts at the space Begin().
   void UpdateMainBlock() EXCLUSIVE_LOCKS_REQUIRED(block_lock_);
 
   byte* growth_end_;
   AtomicInteger objects_allocated_;  // Accumulated from revoked thread local regions.
   AtomicInteger bytes_allocated_;  // Accumulated from revoked thread local regions.
   Mutex block_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-
+  // The objects at the start of the space are stored in the main block. The main block doesn't
+  // have a header, this lets us walk empty spaces which are mprotected.
+  size_t main_block_size_ GUARDED_BY(block_lock_);
   // The number of blocks in the space, if it is 0 then the space has one long continuous block
   // which doesn't have an updated header.
   size_t num_blocks_ GUARDED_BY(block_lock_);