OSDN Git Service

Add support for bump pointer spaces to DdmSendHeapSegments.
authorMathieu Chartier <mathieuc@google.com>
Wed, 30 Jul 2014 21:59:56 +0000 (14:59 -0700)
committerMathieu Chartier <mathieuc@google.com>
Thu, 31 Jul 2014 00:18:37 +0000 (17:18 -0700)
Added support for bump pointer spaces as well as
differentiating between DlMallocSpaces and RosAllocSpaces.
Added logic to reset the start of next chunk to prevent
inbetween space regions counted as free.

Fixed a debug build bug where we were doing an mprotect after
creating a rosalloc space. In debug builds, this writes a magic
value in the page. This was faulting since it was set to PROT_NONE.
The fix moves the mprotect before the RosAlloc space creation.

Bug: 16408851

(cherry picked from commit 36dab3607e77505ce139eacef1c62a1c4bc4affd)

Change-Id: I5095feb01fa7e248178a2833da7f821f4fd52c89

runtime/debugger.cc
runtime/gc/heap.cc

index 0d906f1..7ee406b 100644 (file)
@@ -3948,7 +3948,8 @@ class HeapChunkContext {
   HeapChunkContext(bool merge, bool native)
       : buf_(16384 - 16),
         type_(0),
-        merge_(merge) {
+        merge_(merge),
+        chunk_overhead_(0) {
     Reset();
     if (native) {
       type_ = CHUNK_TYPE("NHSG");
@@ -3963,6 +3964,14 @@ class HeapChunkContext {
     }
   }
 
+  void SetChunkOverhead(size_t chunk_overhead) {
+    chunk_overhead_ = chunk_overhead;
+  }
+
+  void ResetStartOfNextChunk() {
+    startOfNextMemoryChunk_ = nullptr;
+  }
+
   void EnsureHeader(const void* chunk_ptr) {
     if (!needHeader_) {
       return;
@@ -4007,7 +4016,7 @@ class HeapChunkContext {
 
   void Reset() {
     p_ = &buf_[0];
-    startOfNextMemoryChunk_ = NULL;
+    ResetStartOfNextChunk();
     totalAllocationUnits_ = 0;
     needHeader_ = true;
     pieceLenField_ = NULL;
@@ -4034,6 +4043,8 @@ class HeapChunkContext {
      */
     bool native = type_ == CHUNK_TYPE("NHSG");
 
+    // TODO: I'm not sure using start of next chunk works well with multiple spaces. We shouldn't
+    // count gaps inbetween spaces as free memory.
     if (startOfNextMemoryChunk_ != NULL) {
         // Transmit any pending free memory. Native free memory of
         // over kMaxFreeLen could be because of the use of mmaps, so
@@ -4060,11 +4071,8 @@ class HeapChunkContext {
     // OLD-TODO: if context.merge, see if this chunk is different from the last chunk.
     // If it's the same, we should combine them.
     uint8_t state = ExamineObject(obj, native);
-    // dlmalloc's chunk header is 2 * sizeof(size_t), but if the previous chunk is in use for an
-    // allocation then the first sizeof(size_t) may belong to it.
-    const size_t dlMallocOverhead = sizeof(size_t);
-    AppendChunk(state, start, used_bytes + dlMallocOverhead);
-    startOfNextMemoryChunk_ = reinterpret_cast<char*>(start) + used_bytes + dlMallocOverhead;
+    AppendChunk(state, start, used_bytes + chunk_overhead_);
+    startOfNextMemoryChunk_ = reinterpret_cast<char*>(start) + used_bytes + chunk_overhead_;
   }
 
   void AppendChunk(uint8_t state, void* ptr, size_t length)
@@ -4153,10 +4161,18 @@ class HeapChunkContext {
   uint32_t type_;
   bool merge_;
   bool needHeader_;
+  size_t chunk_overhead_;
 
   DISALLOW_COPY_AND_ASSIGN(HeapChunkContext);
 };
 
+static void BumpPointerSpaceCallback(mirror::Object* obj, void* arg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+  const size_t size = RoundUp(obj->SizeOf(), kObjectAlignment);
+  HeapChunkContext::HeapChunkCallback(
+      obj, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(obj) + size), size, arg);
+}
+
 void Dbg::DdmSendHeapSegments(bool native) {
   Dbg::HpsgWhen when;
   Dbg::HpsgWhat what;
@@ -4197,14 +4213,27 @@ void Dbg::DdmSendHeapSegments(bool native) {
 #endif
   } else {
     gc::Heap* heap = Runtime::Current()->GetHeap();
-    const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
-    typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
-    for (It cur = spaces.begin(), end = spaces.end(); cur != end; ++cur) {
-      if ((*cur)->IsMallocSpace()) {
-        (*cur)->AsMallocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+    for (const auto& space : heap->GetContinuousSpaces()) {
+      if (space->IsDlMallocSpace()) {
+        // dlmalloc's chunk header is 2 * sizeof(size_t), but if the previous chunk is in use for an
+        // allocation then the first sizeof(size_t) may belong to it.
+        context.SetChunkOverhead(sizeof(size_t));
+        space->AsDlMallocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+      } else if (space->IsRosAllocSpace()) {
+        context.SetChunkOverhead(0);
+        space->AsRosAllocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+      } else if (space->IsBumpPointerSpace()) {
+        context.SetChunkOverhead(0);
+        ReaderMutexLock mu(self, *Locks::mutator_lock_);
+        WriterMutexLock mu2(self, *Locks::heap_bitmap_lock_);
+        space->AsBumpPointerSpace()->Walk(BumpPointerSpaceCallback, &context);
+      } else {
+        UNIMPLEMENTED(WARNING) << "Not counting objects in space " << *space;
       }
+      context.ResetStartOfNextChunk();
     }
     // Walk the large objects, these are not in the AllocSpace.
+    context.SetChunkOverhead(0);
     heap->GetLargeObjectsSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
   }
 
index f7c7080..66cdd08 100644 (file)
@@ -1624,12 +1624,12 @@ void Heap::TransitionCollector(CollectorType collector_type) {
         std::unique_ptr<MemMap> mem_map(temp_space_->ReleaseMemMap());
         RemoveSpace(temp_space_);
         temp_space_ = nullptr;
+        mem_map->Protect(PROT_READ | PROT_WRITE);
         CreateMainMallocSpace(mem_map.get(), kDefaultInitialSize, mem_map->Size(),
                               mem_map->Size());
         mem_map.release();
         // Compact to the main space from the bump pointer space, don't need to swap semispaces.
         AddSpace(main_space_);
-        main_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
         Compact(main_space_, bump_pointer_space_, kGcCauseCollectorTransition);
         mem_map.reset(bump_pointer_space_->ReleaseMemMap());
         RemoveSpace(bump_pointer_space_);