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;
 }
diff --git a/vm/mterp/armv5te/debug.c b/vm/mterp/armv5te/debug.c
index 400bc95..9d7413c 100644
--- a/vm/mterp/armv5te/debug.c
+++ b/vm/mterp/armv5te/debug.c
@@ -29,7 +29,7 @@
     const Method* method = glue->method;
     printf("    + self is %p\n", dvmThreadSelf());
     //printf("    + currently in %s.%s %s\n",
-    //    method->clazz->descriptor, method->name, method->signature);
+    //    method->clazz->descriptor, method->name, method->shorty);
     //printf("    + dvmAsmInstructionStart = %p\n", dvmAsmInstructionStart);
     //printf("    + next handler for 0x%02x = %p\n",
     //    rINST & 0xff, dvmAsmInstructionStart + (rINST & 0xff) * 64);
diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c
index 37eaa20..5997c35 100644
--- a/vm/mterp/c/gotoTargets.c
+++ b/vm/mterp/c/gotoTargets.c
@@ -514,7 +514,7 @@
 
         ILOGV("> retval=0x%llx (leaving %s.%s %s)",
             retval.j, curMethod->clazz->descriptor, curMethod->name,
-            curMethod->signature);
+            curMethod->shorty);
         //DUMP_REGS(curMethod, fp);
 
         saveArea = SAVEAREA_FROM_FP(fp);
@@ -542,7 +542,7 @@
         methodClassDex = curMethod->clazz->pDvmDex;
         pc = saveArea->savedPc;
         ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
-            curMethod->name, curMethod->signature);
+            curMethod->name, curMethod->shorty);
 
         /* use FINISH on the caller's invoke instruction */
         //u2 invokeInstr = INST_INST(FETCH(0));
@@ -677,7 +677,7 @@
         methodClassDex = curMethod->clazz->pDvmDex;
         pc = curMethod->insns + catchRelPc;
         ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
-            curMethod->name, curMethod->signature);
+            curMethod->name, curMethod->shorty);
         DUMP_REGS(curMethod, fp, false);            // show all regs
 
         /*
@@ -726,7 +726,7 @@
         //printf("range=%d call=%p count=%d regs=0x%04x\n",
         //    methodCallRange, methodToCall, count, regs);
         //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
-        //    methodToCall->name, methodToCall->signature);
+        //    methodToCall->name, methodToCall->shorty);
 
         u4* outs;
         int i;
@@ -796,7 +796,7 @@
         ILOGV("> %s%s.%s %s",
             dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
             methodToCall->clazz->descriptor, methodToCall->name,
-            methodToCall->signature);
+            methodToCall->shorty);
 
         newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
         newSaveArea = SAVEAREA_FROM_FP(newFp);
@@ -857,7 +857,7 @@
             debugIsMethodEntry = true;              // profiling, debugging
 #endif
             ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
-                curMethod->name, curMethod->signature);
+                curMethod->name, curMethod->shorty);
             DUMP_REGS(curMethod, fp, true);         // show input args
             FINISH(0);                              // jump to method start
         } else {
@@ -879,7 +879,7 @@
 #endif
 
             ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
-                methodToCall->name, methodToCall->signature);
+                methodToCall->name, methodToCall->shorty);
 
             /*
              * Jump through native call bridge.  Because we leave no
@@ -916,7 +916,7 @@
             ILOGD("> (return from native %s.%s to %s.%s %s)",
                 methodToCall->clazz->descriptor, methodToCall->name,
                 curMethod->clazz->descriptor, curMethod->name,
-                curMethod->signature);
+                curMethod->shorty);
 
             //u2 invokeInstr = INST_INST(FETCH(0));
             if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 0769eeb..bb1d0ea 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -3547,7 +3547,7 @@
 
         ILOGV("> retval=0x%llx (leaving %s.%s %s)",
             retval.j, curMethod->clazz->descriptor, curMethod->name,
-            curMethod->signature);
+            curMethod->shorty);
         //DUMP_REGS(curMethod, fp);
 
         saveArea = SAVEAREA_FROM_FP(fp);
@@ -3575,7 +3575,7 @@
         methodClassDex = curMethod->clazz->pDvmDex;
         pc = saveArea->savedPc;
         ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
-            curMethod->name, curMethod->signature);
+            curMethod->name, curMethod->shorty);
 
         /* use FINISH on the caller's invoke instruction */
         //u2 invokeInstr = INST_INST(FETCH(0));
@@ -3710,7 +3710,7 @@
         methodClassDex = curMethod->clazz->pDvmDex;
         pc = curMethod->insns + catchRelPc;
         ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
-            curMethod->name, curMethod->signature);
+            curMethod->name, curMethod->shorty);
         DUMP_REGS(curMethod, fp, false);            // show all regs
 
         /*
@@ -3759,7 +3759,7 @@
         //printf("range=%d call=%p count=%d regs=0x%04x\n",
         //    methodCallRange, methodToCall, count, regs);
         //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
-        //    methodToCall->name, methodToCall->signature);
+        //    methodToCall->name, methodToCall->shorty);
 
         u4* outs;
         int i;
@@ -3829,7 +3829,7 @@
         ILOGV("> %s%s.%s %s",
             dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
             methodToCall->clazz->descriptor, methodToCall->name,
-            methodToCall->signature);
+            methodToCall->shorty);
 
         newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
         newSaveArea = SAVEAREA_FROM_FP(newFp);
@@ -3890,7 +3890,7 @@
             debugIsMethodEntry = true;              // profiling, debugging
 #endif
             ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
-                curMethod->name, curMethod->signature);
+                curMethod->name, curMethod->shorty);
             DUMP_REGS(curMethod, fp, true);         // show input args
             FINISH(0);                              // jump to method start
         } else {
@@ -3912,7 +3912,7 @@
 #endif
 
             ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
-                methodToCall->name, methodToCall->signature);
+                methodToCall->name, methodToCall->shorty);
 
             /*
              * Jump through native call bridge.  Because we leave no
@@ -3949,7 +3949,7 @@
             ILOGD("> (return from native %s.%s to %s.%s %s)",
                 methodToCall->clazz->descriptor, methodToCall->name,
                 curMethod->clazz->descriptor, curMethod->name,
-                curMethod->signature);
+                curMethod->shorty);
 
             //u2 invokeInstr = INST_INST(FETCH(0));
             if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
diff --git a/vm/mterp/out/InterpC-armv4t.c b/vm/mterp/out/InterpC-armv4t.c
index bdfffe3..6b82bc8 100644
--- a/vm/mterp/out/InterpC-armv4t.c
+++ b/vm/mterp/out/InterpC-armv4t.c
@@ -1228,7 +1228,7 @@
     const Method* method = glue->method;
     printf("    + self is %p\n", dvmThreadSelf());
     //printf("    + currently in %s.%s %s\n",
-    //    method->clazz->descriptor, method->name, method->signature);
+    //    method->clazz->descriptor, method->name, method->shorty);
     //printf("    + dvmAsmInstructionStart = %p\n", dvmAsmInstructionStart);
     //printf("    + next handler for 0x%02x = %p\n",
     //    rINST & 0xff, dvmAsmInstructionStart + (rINST & 0xff) * 64);
diff --git a/vm/mterp/out/InterpC-armv5te-vfp.c b/vm/mterp/out/InterpC-armv5te-vfp.c
index 7840920..7312700 100644
--- a/vm/mterp/out/InterpC-armv5te-vfp.c
+++ b/vm/mterp/out/InterpC-armv5te-vfp.c
@@ -1228,7 +1228,7 @@
     const Method* method = glue->method;
     printf("    + self is %p\n", dvmThreadSelf());
     //printf("    + currently in %s.%s %s\n",
-    //    method->clazz->descriptor, method->name, method->signature);
+    //    method->clazz->descriptor, method->name, method->shorty);
     //printf("    + dvmAsmInstructionStart = %p\n", dvmAsmInstructionStart);
     //printf("    + next handler for 0x%02x = %p\n",
     //    rINST & 0xff, dvmAsmInstructionStart + (rINST & 0xff) * 64);
diff --git a/vm/mterp/out/InterpC-armv5te.c b/vm/mterp/out/InterpC-armv5te.c
index 4849423..ea11551 100644
--- a/vm/mterp/out/InterpC-armv5te.c
+++ b/vm/mterp/out/InterpC-armv5te.c
@@ -1228,7 +1228,7 @@
     const Method* method = glue->method;
     printf("    + self is %p\n", dvmThreadSelf());
     //printf("    + currently in %s.%s %s\n",
-    //    method->clazz->descriptor, method->name, method->signature);
+    //    method->clazz->descriptor, method->name, method->shorty);
     //printf("    + dvmAsmInstructionStart = %p\n", dvmAsmInstructionStart);
     //printf("    + next handler for 0x%02x = %p\n",
     //    rINST & 0xff, dvmAsmInstructionStart + (rINST & 0xff) * 64);
diff --git a/vm/mterp/out/InterpC-armv7-a.c b/vm/mterp/out/InterpC-armv7-a.c
index a4413bb..97799ec 100644
--- a/vm/mterp/out/InterpC-armv7-a.c
+++ b/vm/mterp/out/InterpC-armv7-a.c
@@ -1228,7 +1228,7 @@
     const Method* method = glue->method;
     printf("    + self is %p\n", dvmThreadSelf());
     //printf("    + currently in %s.%s %s\n",
-    //    method->clazz->descriptor, method->name, method->signature);
+    //    method->clazz->descriptor, method->name, method->shorty);
     //printf("    + dvmAsmInstructionStart = %p\n", dvmAsmInstructionStart);
     //printf("    + next handler for 0x%02x = %p\n",
     //    rINST & 0xff, dvmAsmInstructionStart + (rINST & 0xff) * 64);
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index c8f428c..90b2a75 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -1395,7 +1395,7 @@
         if (/*gDvm.debuggerActive &&*/
             strcmp(method->clazz->descriptor, cd) == 0 &&
             strcmp(method->name, mn) == 0 &&
-            strcmp(method->signature, sg) == 0)
+            strcmp(method->shorty, sg) == 0)
         {
             LOGW("Reached %s.%s, enabling verbose mode\n",
                 method->clazz->descriptor, method->name);
@@ -3838,7 +3838,7 @@
 
         ILOGV("> retval=0x%llx (leaving %s.%s %s)",
             retval.j, curMethod->clazz->descriptor, curMethod->name,
-            curMethod->signature);
+            curMethod->shorty);
         //DUMP_REGS(curMethod, fp);
 
         saveArea = SAVEAREA_FROM_FP(fp);
@@ -3866,7 +3866,7 @@
         methodClassDex = curMethod->clazz->pDvmDex;
         pc = saveArea->savedPc;
         ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
-            curMethod->name, curMethod->signature);
+            curMethod->name, curMethod->shorty);
 
         /* use FINISH on the caller's invoke instruction */
         //u2 invokeInstr = INST_INST(FETCH(0));
@@ -4001,7 +4001,7 @@
         methodClassDex = curMethod->clazz->pDvmDex;
         pc = curMethod->insns + catchRelPc;
         ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
-            curMethod->name, curMethod->signature);
+            curMethod->name, curMethod->shorty);
         DUMP_REGS(curMethod, fp, false);            // show all regs
 
         /*
@@ -4050,7 +4050,7 @@
         //printf("range=%d call=%p count=%d regs=0x%04x\n",
         //    methodCallRange, methodToCall, count, regs);
         //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
-        //    methodToCall->name, methodToCall->signature);
+        //    methodToCall->name, methodToCall->shorty);
 
         u4* outs;
         int i;
@@ -4120,7 +4120,7 @@
         ILOGV("> %s%s.%s %s",
             dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
             methodToCall->clazz->descriptor, methodToCall->name,
-            methodToCall->signature);
+            methodToCall->shorty);
 
         newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
         newSaveArea = SAVEAREA_FROM_FP(newFp);
@@ -4181,7 +4181,7 @@
             debugIsMethodEntry = true;              // profiling, debugging
 #endif
             ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
-                curMethod->name, curMethod->signature);
+                curMethod->name, curMethod->shorty);
             DUMP_REGS(curMethod, fp, true);         // show input args
             FINISH(0);                              // jump to method start
         } else {
@@ -4203,7 +4203,7 @@
 #endif
 
             ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
-                methodToCall->name, methodToCall->signature);
+                methodToCall->name, methodToCall->shorty);
 
             /*
              * Jump through native call bridge.  Because we leave no
@@ -4240,7 +4240,7 @@
             ILOGD("> (return from native %s.%s to %s.%s %s)",
                 methodToCall->clazz->descriptor, methodToCall->name,
                 curMethod->clazz->descriptor, curMethod->name,
-                curMethod->signature);
+                curMethod->shorty);
 
             //u2 invokeInstr = INST_INST(FETCH(0));
             if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index baf7a86..c28bf5b 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -3552,7 +3552,7 @@
 
         ILOGV("> retval=0x%llx (leaving %s.%s %s)",
             retval.j, curMethod->clazz->descriptor, curMethod->name,
-            curMethod->signature);
+            curMethod->shorty);
         //DUMP_REGS(curMethod, fp);
 
         saveArea = SAVEAREA_FROM_FP(fp);
@@ -3580,7 +3580,7 @@
         methodClassDex = curMethod->clazz->pDvmDex;
         pc = saveArea->savedPc;
         ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
-            curMethod->name, curMethod->signature);
+            curMethod->name, curMethod->shorty);
 
         /* use FINISH on the caller's invoke instruction */
         //u2 invokeInstr = INST_INST(FETCH(0));
@@ -3715,7 +3715,7 @@
         methodClassDex = curMethod->clazz->pDvmDex;
         pc = curMethod->insns + catchRelPc;
         ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
-            curMethod->name, curMethod->signature);
+            curMethod->name, curMethod->shorty);
         DUMP_REGS(curMethod, fp, false);            // show all regs
 
         /*
@@ -3764,7 +3764,7 @@
         //printf("range=%d call=%p count=%d regs=0x%04x\n",
         //    methodCallRange, methodToCall, count, regs);
         //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
-        //    methodToCall->name, methodToCall->signature);
+        //    methodToCall->name, methodToCall->shorty);
 
         u4* outs;
         int i;
@@ -3834,7 +3834,7 @@
         ILOGV("> %s%s.%s %s",
             dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
             methodToCall->clazz->descriptor, methodToCall->name,
-            methodToCall->signature);
+            methodToCall->shorty);
 
         newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
         newSaveArea = SAVEAREA_FROM_FP(newFp);
@@ -3895,7 +3895,7 @@
             debugIsMethodEntry = true;              // profiling, debugging
 #endif
             ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
-                curMethod->name, curMethod->signature);
+                curMethod->name, curMethod->shorty);
             DUMP_REGS(curMethod, fp, true);         // show input args
             FINISH(0);                              // jump to method start
         } else {
@@ -3917,7 +3917,7 @@
 #endif
 
             ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
-                methodToCall->name, methodToCall->signature);
+                methodToCall->name, methodToCall->shorty);
 
             /*
              * Jump through native call bridge.  Because we leave no
@@ -3954,7 +3954,7 @@
             ILOGD("> (return from native %s.%s to %s.%s %s)",
                 methodToCall->clazz->descriptor, methodToCall->name,
                 curMethod->clazz->descriptor, curMethod->name,
-                curMethod->signature);
+                curMethod->shorty);
 
             //u2 invokeInstr = INST_INST(FETCH(0));
             if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c
index fe261c7..9bb70d1 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -1702,7 +1702,7 @@
 
         ILOGV("> retval=0x%llx (leaving %s.%s %s)",
             retval.j, curMethod->clazz->descriptor, curMethod->name,
-            curMethod->signature);
+            curMethod->shorty);
         //DUMP_REGS(curMethod, fp);
 
         saveArea = SAVEAREA_FROM_FP(fp);
@@ -1730,7 +1730,7 @@
         methodClassDex = curMethod->clazz->pDvmDex;
         pc = saveArea->savedPc;
         ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
-            curMethod->name, curMethod->signature);
+            curMethod->name, curMethod->shorty);
 
         /* use FINISH on the caller's invoke instruction */
         //u2 invokeInstr = INST_INST(FETCH(0));
@@ -1865,7 +1865,7 @@
         methodClassDex = curMethod->clazz->pDvmDex;
         pc = curMethod->insns + catchRelPc;
         ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
-            curMethod->name, curMethod->signature);
+            curMethod->name, curMethod->shorty);
         DUMP_REGS(curMethod, fp, false);            // show all regs
 
         /*
@@ -1914,7 +1914,7 @@
         //printf("range=%d call=%p count=%d regs=0x%04x\n",
         //    methodCallRange, methodToCall, count, regs);
         //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
-        //    methodToCall->name, methodToCall->signature);
+        //    methodToCall->name, methodToCall->shorty);
 
         u4* outs;
         int i;
@@ -1984,7 +1984,7 @@
         ILOGV("> %s%s.%s %s",
             dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
             methodToCall->clazz->descriptor, methodToCall->name,
-            methodToCall->signature);
+            methodToCall->shorty);
 
         newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
         newSaveArea = SAVEAREA_FROM_FP(newFp);
@@ -2045,7 +2045,7 @@
             debugIsMethodEntry = true;              // profiling, debugging
 #endif
             ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
-                curMethod->name, curMethod->signature);
+                curMethod->name, curMethod->shorty);
             DUMP_REGS(curMethod, fp, true);         // show input args
             FINISH(0);                              // jump to method start
         } else {
@@ -2067,7 +2067,7 @@
 #endif
 
             ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
-                methodToCall->name, methodToCall->signature);
+                methodToCall->name, methodToCall->shorty);
 
             /*
              * Jump through native call bridge.  Because we leave no
@@ -2104,7 +2104,7 @@
             ILOGD("> (return from native %s.%s to %s.%s %s)",
                 methodToCall->clazz->descriptor, methodToCall->name,
                 curMethod->clazz->descriptor, curMethod->name,
-                curMethod->signature);
+                curMethod->shorty);
 
             //u2 invokeInstr = INST_INST(FETCH(0));
             if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
diff --git a/vm/mterp/portable/debug.c b/vm/mterp/portable/debug.c
index 38b55ae..449d49b 100644
--- a/vm/mterp/portable/debug.c
+++ b/vm/mterp/portable/debug.c
@@ -223,7 +223,7 @@
         if (/*gDvm.debuggerActive &&*/
             strcmp(method->clazz->descriptor, cd) == 0 &&
             strcmp(method->name, mn) == 0 &&
-            strcmp(method->signature, sg) == 0)
+            strcmp(method->shorty, sg) == 0)
         {
             LOGW("Reached %s.%s, enabling verbose mode\n",
                 method->clazz->descriptor, method->name);
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index a2c485f..50ef961 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -4421,6 +4421,44 @@
         dvmCallMethod(self, method, NULL, &unused);
     }
 
+    /* Set the bitmap of reference offsets. Except for class Object,
+     * start with the superclass offsets.
+     */
+    if (clazz->super != NULL) {
+        clazz->refOffsets = clazz->super->refOffsets;
+    } else {
+        clazz->refOffsets = 0;
+    }
+    /*
+     * If our superclass overflowed, we don't stand a chance.
+     */
+    if (clazz->refOffsets != CLASS_WALK_SUPER) {
+        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++) {
+            /*
+             * Note that, per the comment on struct InstField,
+             * f->byteOffset is the offset from the beginning of
+             * obj, not the offset into obj->instanceData.
+             */
+            assert(f->byteOffset >= CLASS_SMALLEST_OFFSET);
+            assert((f->byteOffset & (CLASS_OFFSET_ALIGNMENT - 1)) == 0);
+            u4 newBit = CLASS_BIT_FROM_OFFSET(f->byteOffset);
+            if (newBit != 0) {
+                clazz->refOffsets |= newBit;
+            } else {
+                clazz->refOffsets = CLASS_WALK_SUPER;
+                break;
+            }
+            f++;
+        }
+    }
+
     if (dvmCheckException(self)) {
         /*
          * We've had an exception thrown during static initialization.  We
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index b8236db..3e724f4 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -173,6 +173,34 @@
 #define PRIM_TYPE_TO_LETTER "ZCFDBSIJV"     /* must match order in enum */
 
 /*
+ * Definitions for packing refOffsets in ClassObject.
+ */
+/*
+ * A magic value for refOffsets. Ignore the bits and walk the super
+ * chain when this is the value.
+ * [This is an unlikely "natural" value, since it would be 30 non-ref instance
+ * fields followed by 2 ref instance fields.]
+ */
+#define CLASS_WALK_SUPER ((unsigned int)(3))
+#define CLASS_SMALLEST_OFFSET (sizeof(struct Object))
+#define CLASS_BITS_PER_WORD (sizeof(unsigned long int) * 8)
+#define CLASS_OFFSET_ALIGNMENT 4
+#define CLASS_HIGH_BIT ((unsigned int)1 << (CLASS_BITS_PER_WORD - 1))
+/*
+ * Return a single bit, or zero if the encoding can't encode the offset.
+ */
+#define CLASS_BIT_FROM_OFFSET(byteOffset) \
+    (CLASS_HIGH_BIT >> \
+      (((unsigned int)(byteOffset) - CLASS_SMALLEST_OFFSET) / \
+       CLASS_OFFSET_ALIGNMENT))
+/*
+ * Return an offset, given a bit number as returned from CLZ.
+ */
+#define CLASS_OFFSET_FROM_CLZ(rshift) \
+    (((int)(rshift) * CLASS_OFFSET_ALIGNMENT) + CLASS_SMALLEST_OFFSET)
+
+
+/*
  * Used for iftable in ClassObject.
  */
 typedef struct InterfaceEntry {
@@ -423,6 +451,9 @@
     int             ifieldRefCount; // number of fields that are object refs
     InstField*      ifields;
 
+    /* bitmap of offsets of ifields */
+    u4 refOffsets;
+
     /* source file name, if known */
     const char*     sourceFile;
 };