Do not commingle application and zygote references when sweeping.

When garbage objects are identified references to these objects are
passed to a function which, in the case of an application heap,
releases their storage to the mspace or, in the case of a zygote heap,
counts their freed memory without touching the underlying heap.

This freeing process is performed in bulk.  To attenuate the cost of
calling and to allow for more efficient merging of adjacent unused
blocks of memory, a buffer is filled with adjacent references to free.
The freeing mechanism is chosen based on the first reference in the
buffer.  If the first reference is an application heap object all
objects in the buffer have their storage released to the underlying
mspace.  If the first object is a zygote object, only the free space
counting is performed.  Assertions check if this assumption is sound.

The previous change to the sweep did not treat the various regions of
the heap specially and therefore allowed the freeing buffer to have
its contained pointers span both heaps.  This change restores some of
the functionality which kept references from either heap separate.

Change-Id: Ibc563dcf46ff1681596664f04a2a85a4d29eb5e1
diff --git a/vm/alloc/HeapSource.c b/vm/alloc/HeapSource.c
index 010774b..10a3c79 100644
--- a/vm/alloc/HeapSource.c
+++ b/vm/alloc/HeapSource.c
@@ -731,6 +731,20 @@
     return total;
 }
 
+void dvmHeapSourceGetRegions(uintptr_t *base, uintptr_t *max, size_t numHeaps)
+{
+    HeapSource *hs = gHs;
+    size_t i;
+
+    HS_BOILERPLATE();
+
+    assert(numHeaps <= hs->numHeaps);
+    for (i = 0; i < numHeaps; ++i) {
+        base[i] = (uintptr_t)hs->heaps[i].base;
+        max[i] = MIN((uintptr_t)hs->heaps[i].limit - 1, hs->markBits.max);
+    }
+}
+
 /*
  * Get the bitmap representing all live objects.
  */
diff --git a/vm/alloc/HeapSource.h b/vm/alloc/HeapSource.h
index b182409..ce61a78 100644
--- a/vm/alloc/HeapSource.h
+++ b/vm/alloc/HeapSource.h
@@ -61,6 +61,12 @@
  */
 void dvmHeapSourceShutdown(GcHeap **gcHeap);
 
+/*
+ * Returns the base and inclusive max addresses of the heap source
+ * heaps.  The base and max values are suitable for passing directly
+ * to the bitmap sweeping routine.
+ */
+void dvmHeapSourceGetRegions(uintptr_t *base, uintptr_t *max, size_t numHeaps);
 
 /*
  * Get the bitmap representing all live objects.
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index 13ca89e..4f36d82 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -1066,24 +1066,29 @@
 void dvmHeapSweepUnmarkedObjects(GcMode mode, bool isConcurrent,
                                  size_t *numObjects, size_t *numBytes)
 {
+    uintptr_t base[HEAP_SOURCE_MAX_HEAP_COUNT];
+    uintptr_t max[HEAP_SOURCE_MAX_HEAP_COUNT];
     SweepContext ctx;
     HeapBitmap *prevLive, *prevMark;
-    uintptr_t base, max;
+    size_t numHeaps, numSweepHeaps;
+    size_t i;
 
-    prevLive = dvmHeapSourceGetMarkBits();
-    prevMark = dvmHeapSourceGetLiveBits();
+    numHeaps = dvmHeapSourceGetNumHeaps();
+    dvmHeapSourceGetRegions(base, max, numHeaps);
     if (mode == GC_PARTIAL) {
-        assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == prevMark->base);
-        base = (uintptr_t)dvmHeapSourceGetImmuneLimit(mode);
+        assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == base[0]);
+        numSweepHeaps = 1;
     } else {
-        base = prevLive->base;
+        numSweepHeaps = numHeaps;
     }
-    max = prevLive->max;
     ctx.numObjects = ctx.numBytes = 0;
     ctx.isConcurrent = isConcurrent;
-    dvmHeapBitmapSweepWalk(prevLive, prevMark,
-                           base, max,
-                           sweepBitmapCallback, &ctx);
+    prevLive = dvmHeapSourceGetMarkBits();
+    prevMark = dvmHeapSourceGetLiveBits();
+    for (i = 0; i < numSweepHeaps; ++i) {
+        dvmHeapBitmapSweepWalk(prevLive, prevMark, base[i], max[i],
+                               sweepBitmapCallback, &ctx);
+    }
     *numObjects = ctx.numObjects;
     *numBytes = ctx.numBytes;
     if (gDvm.allocProf.enabled) {