merge from open-source master
diff --git a/vm/alloc/HeapSource.c b/vm/alloc/HeapSource.c
index d97290f..830e5d7 100644
--- a/vm/alloc/HeapSource.c
+++ b/vm/alloc/HeapSource.c
@@ -787,6 +787,82 @@
}
/*
+ * Frees the first numPtrs objects in the ptrs list. The list must
+ * contain addresses all in the same mspace, and must be in increasing
+ * order. This implies that there are no duplicates, and no entries
+ * are NULL.
+ */
+void
+dvmHeapSourceFreeList(size_t numPtrs, void **ptrs)
+{
+ Heap *heap;
+
+ HS_BOILERPLATE();
+
+ if (numPtrs == 0) {
+ return;
+ }
+
+ assert(ptrs != NULL);
+ assert(*ptrs != NULL);
+ heap = ptr2heap(gHs, *ptrs);
+ if (heap != NULL) {
+ mspace *msp = heap->msp;
+ // Calling mspace_free on shared heaps disrupts sharing too
+ // much. For heap[0] -- the 'active heap' -- we call
+ // mspace_free, but on the other heaps we only do some
+ // accounting.
+ if (heap == gHs->heaps) {
+ // mspace_merge_objects takes two allocated objects, and
+ // if the second immediately follows the first, will merge
+ // them, returning a larger object occupying the same
+ // memory. This is a local operation, and doesn't require
+ // dlmalloc to manipulate any freelists. It's pretty
+ // inexpensive compared to free().
+
+ // ptrs is an array of objects all in memory order, and if
+ // client code has been allocating lots of short-lived
+ // objects, this is likely to contain runs of objects all
+ // now garbage, and thus highly amenable to this optimization.
+
+ // Unroll the 0th iteration around the loop below,
+ // countFree ptrs[0] and initializing merged.
+ assert(ptrs[0] != NULL);
+ assert(ptr2heap(gHs, ptrs[0]) == heap);
+ countFree(heap, ptrs[0], true);
+ void *merged = ptrs[0];
+
+ size_t i;
+ for (i = 1; i < numPtrs; i++) {
+ assert(merged != NULL);
+ assert(ptrs[i] != NULL);
+ assert((intptr_t)merged < (intptr_t)ptrs[i]);
+ assert(ptr2heap(gHs, ptrs[i]) == heap);
+ countFree(heap, ptrs[i], true);
+ // Try to merge. If it works, merged now includes the
+ // memory of ptrs[i]. If it doesn't, free merged, and
+ // see if ptrs[i] starts a new run of adjacent
+ // objects to merge.
+ if (mspace_merge_objects(msp, merged, ptrs[i]) == NULL) {
+ mspace_free(msp, merged);
+ merged = ptrs[i];
+ }
+ }
+ assert(merged != NULL);
+ mspace_free(msp, merged);
+ } else {
+ // This is not an 'active heap'. Only do the accounting.
+ size_t i;
+ for (i = 0; i < numPtrs; i++) {
+ assert(ptrs[i] != NULL);
+ assert(ptr2heap(gHs, ptrs[i]) == heap);
+ countFree(heap, ptrs[i], true);
+ }
+ }
+ }
+}
+
+/*
* Returns true iff <ptr> was allocated from the heap source.
*/
bool
diff --git a/vm/alloc/HeapSource.h b/vm/alloc/HeapSource.h
index 3007d4f..fdaf119 100644
--- a/vm/alloc/HeapSource.h
+++ b/vm/alloc/HeapSource.h
@@ -105,6 +105,14 @@
void dvmHeapSourceFree(void *ptr);
/*
+ * Frees the first numPtrs objects in the ptrs list. The list must
+ * contain addresses all in the same mspace, and must be in increasing
+ * order. This implies that there are no duplicates, and no entries
+ * are NULL.
+ */
+void dvmHeapSourceFreeList(size_t numPtrs, void **ptrs);
+
+/*
* Returns true iff <ptr> was allocated from the heap source.
*/
bool dvmHeapSourceContains(const void *ptr);
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index b8da3a3..09cc25f 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -15,6 +15,7 @@
*/
#include "Dalvik.h"
+#include "alloc/clz.h"
#include "alloc/HeapBitmap.h"
#include "alloc/HeapInternal.h"
#include "alloc/HeapSource.h"
@@ -435,30 +436,39 @@
static void scanInstanceFields(const DataObject *obj, ClassObject *clazz,
GcMarkContext *ctx)
{
-//TODO: Optimize this by avoiding walking the superclass chain
- while (clazz != NULL) {
- InstField *f;
- int i;
-
- /* All of the fields that contain object references
- * are guaranteed to be at the beginning of the ifields list.
- */
- f = clazz->ifields;
- for (i = 0; i < clazz->ifieldRefCount; i++) {
- /* Mark the array or object reference.
- * May be NULL.
- *
- * Note that, per the comment on struct InstField,
- * f->byteOffset is the offset from the beginning of
- * obj, not the offset into obj->instanceData.
- */
- markObject(dvmGetFieldObject((Object*)obj, f->byteOffset), ctx);
- f++;
+ if (false && clazz->refOffsets != CLASS_WALK_SUPER) {
+ unsigned int refOffsets = clazz->refOffsets;
+ while (refOffsets != 0) {
+ const int rshift = CLZ(refOffsets);
+ refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
+ markObject(dvmGetFieldObject((Object*)obj,
+ CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
}
+ } else {
+ while (clazz != NULL) {
+ InstField *f;
+ int i;
- /* This will be NULL when we hit java.lang.Object
- */
- clazz = clazz->super;
+ /* All of the fields that contain object references
+ * are guaranteed to be at the beginning of the ifields list.
+ */
+ f = clazz->ifields;
+ for (i = 0; i < clazz->ifieldRefCount; i++) {
+ /* Mark the array or object reference.
+ * May be NULL.
+ *
+ * Note that, per the comment on struct InstField,
+ * f->byteOffset is the offset from the beginning of
+ * obj, not the offset into obj->instanceData.
+ */
+ markObject(dvmGetFieldObject((Object*)obj, f->byteOffset), ctx);
+ f++;
+ }
+
+ /* This will be NULL when we hit java.lang.Object
+ */
+ clazz = clazz->super;
+ }
}
}
@@ -1203,6 +1213,7 @@
{
const ClassObject *const classJavaLangClass = gDvm.classJavaLangClass;
size_t i;
+ void **origPtrs = ptrs;
for (i = 0; i < numPtrs; i++) {
DvmHeapChunk *hc;
@@ -1265,11 +1276,10 @@
#endif
}
#endif
-
-//TODO: provide a heapsource function that takes a list of pointers to free
-// and call it outside of this loop.
- dvmHeapSourceFree(hc);
}
+ // TODO: dvmHeapSourceFreeList has a loop, just like the above
+ // does. Consider collapsing the two loops to save overhead.
+ dvmHeapSourceFreeList(numPtrs, origPtrs);
return true;
}