Merge "Update to allow x86-atom build for FI on Gingerbread"
diff --git a/libdex/CmdUtils.c b/libdex/CmdUtils.c
index 35696f9..8ce0d4b 100644
--- a/libdex/CmdUtils.c
+++ b/libdex/CmdUtils.c
@@ -160,7 +160,7 @@
     /*
      * Pop open the (presumed) DEX file.
      */
-    fd = open(fileName, O_RDONLY);
+    fd = open(fileName, O_RDONLY | O_BINARY);
     if (fd < 0) {
         if (!quiet) {
             fprintf(stderr, "ERROR: unable to open '%s': %s\n",
diff --git a/libdex/ZipArchive.c b/libdex/ZipArchive.c
index 756f488..efe9f79 100644
--- a/libdex/ZipArchive.c
+++ b/libdex/ZipArchive.c
@@ -341,7 +341,7 @@
 
     memset(pArchive, 0, sizeof(ZipArchive));
 
-    fd = open(fileName, O_RDONLY, 0);
+    fd = open(fileName, O_RDONLY | O_BINARY, 0);
     if (fd < 0) {
         err = errno ? errno : -1;
         LOGV("Unable to open '%s': %s\n", fileName, strerror(err));
diff --git a/vm/alloc/Alloc.c b/vm/alloc/Alloc.c
index 4dcd91c..7b56a35 100644
--- a/vm/alloc/Alloc.c
+++ b/vm/alloc/Alloc.c
@@ -305,11 +305,11 @@
 typedef struct {
     const ClassObject *clazz;
     size_t count;
-} CountInstancesOfClassContext;
+} CountContext;
 
 static void countInstancesOfClassCallback(void *ptr, void *arg)
 {
-    CountInstancesOfClassContext *ctx = arg;
+    CountContext *ctx = arg;
     const Object *obj = ptr;
 
     assert(ctx != NULL);
@@ -320,10 +320,31 @@
 
 size_t dvmCountInstancesOfClass(const ClassObject *clazz)
 {
-    CountInstancesOfClassContext ctx = { clazz, 0 };
+    CountContext ctx = { clazz, 0 };
     HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
     dvmLockHeap();
     dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
     dvmUnlockHeap();
     return ctx.count;
 }
+
+static void countAssignableInstancesOfClassCallback(void *ptr, void *arg)
+{
+    CountContext *ctx = arg;
+    const Object *obj = ptr;
+
+    assert(ctx != NULL);
+    if (dvmInstanceof(obj->clazz, ctx->clazz)) {
+        ctx->count += 1;
+    }
+}
+
+size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
+{
+    CountContext ctx = { clazz, 0 };
+    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
+    dvmLockHeap();
+    dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);
+    dvmUnlockHeap();
+    return ctx.count;
+}
diff --git a/vm/alloc/Alloc.h b/vm/alloc/Alloc.h
index aeed9c3..fd9c633 100644
--- a/vm/alloc/Alloc.h
+++ b/vm/alloc/Alloc.h
@@ -180,8 +180,13 @@
 size_t dvmGetExternalBytesAllocated(void);
 
 /*
- * Returns a count of the extant instances of a class.
+ * Returns a count of the direct instances of a class.
  */
 size_t dvmCountInstancesOfClass(const ClassObject *clazz);
 
+/*
+ * Returns a count of the instances of a class and its subclasses.
+ */
+size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz);
+
 #endif /*_DALVIK_ALLOC_ALLOC*/
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index bde1b49..62a4ccc 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -722,7 +722,10 @@
     while (*list != NULL) {
         ref = dequeuePendingReference(list);
         referent = dvmGetFieldObject(ref, referentOffset);
-        assert(referent != NULL);
+        if (referent == NULL) {
+            /* Referent was cleared by the user during marking. */
+            continue;
+        }
         marked = isMarked(referent, ctx);
         if (!marked && ((++counter) & 1)) {
             /* Referent is white and biased toward saving, mark it. */
@@ -760,8 +763,7 @@
     while (*list != NULL) {
         ref = dequeuePendingReference(list);
         referent = dvmGetFieldObject(ref, referentOffset);
-        assert(referent != NULL);
-        if (!isMarked(referent, ctx)) {
+        if (referent != NULL && !isMarked(referent, ctx)) {
             /* Referent is white, clear it. */
             clearReference(ref);
             if (isEnqueuable(ref)) {
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index 657533b..011679b 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -1219,7 +1219,6 @@
     /* r0 = dalvik pc */
     dvmCompilerFlushAllRegs(cUnit);
     loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
-    loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                  jitToInterpEntries.dvmJitToInterpPunt), r1);
     opReg(cUnit, kOpBlx, r1);
diff --git a/vm/native/dalvik_system_VMDebug.c b/vm/native/dalvik_system_VMDebug.c
index b9f3610..192a8f2 100644
--- a/vm/native/dalvik_system_VMDebug.c
+++ b/vm/native/dalvik_system_VMDebug.c
@@ -889,8 +889,13 @@
     JValue* pResult)
 {
     ClassObject* clazz = (ClassObject*)args[0];
+    bool countAssignable = args[1];
     if (clazz == NULL) {
         RETURN_LONG(0);
+    }
+    if (countAssignable) {
+        size_t count = dvmCountAssignableInstancesOfClass(clazz);
+        RETURN_LONG((long long)count);
     } else {
         size_t count = dvmCountInstancesOfClass(clazz);
         RETURN_LONG((long long)count);
@@ -954,7 +959,7 @@
         Dalvik_dalvik_system_VMDebug_crash },
     { "infopoint",                 "(I)V",
         Dalvik_dalvik_system_VMDebug_infopoint },
-    { "countInstancesOfClass",     "(Ljava/lang/Class;)J",
+    { "countInstancesOfClass",     "(Ljava/lang/Class;Z)J",
         Dalvik_dalvik_system_VMDebug_countInstancesOfClass },
     { NULL, NULL, NULL },
 };
diff --git a/vm/native/java_lang_System.c b/vm/native/java_lang_System.c
index 96cc144..4af0dfa 100644
--- a/vm/native/java_lang_System.c
+++ b/vm/native/java_lang_System.c
@@ -20,6 +20,33 @@
 #include "Dalvik.h"
 #include "native/InternalNativePriv.h"
 
+/*
+ * Call the appropriate copy function given the circumstances.
+ */
+static void copy(void *dest, const void *src, size_t n, bool sameArray,
+        size_t elemSize)
+{
+    if (sameArray) {
+        /* Might overlap. */
+        if (elemSize == sizeof(Object*)) {
+            /*
+             * In addition to handling overlap properly, bcopy()
+             * guarantees atomic treatment of words. This is needed so
+             * that concurrent threads never see half-formed pointers
+             * or ints. The former is required for proper gc behavior,
+             * and the latter is also required for proper high-level
+             * language support.
+             *
+             * Note: bcopy()'s argument order is different than memcpy().
+             */
+            bcopy(src, dest, n);
+        } else {
+            memmove(dest, src, n);
+        }
+    } else {
+        memcpy(dest, src, n); /* Can't overlap; use faster function. */
+    }
+}
 
 /*
  * public static void arraycopy(Object src, int srcPos, Object dest,
@@ -30,7 +57,6 @@
  */
 static void Dalvik_java_lang_System_arraycopy(const u4* args, JValue* pResult)
 {
-    void* (*copyFunc)(void *dest, const void *src, size_t n);
     ArrayObject* srcArray;
     ArrayObject* dstArray;
     ClassObject* srcClass;
@@ -38,6 +64,7 @@
     int srcPos, dstPos, length;
     char srcType, dstType;
     bool srcPrim, dstPrim;
+    bool sameArray;
 
     srcArray = (ArrayObject*) args[0];
     srcPos = args[1];
@@ -45,10 +72,7 @@
     dstPos = args[3];
     length = args[4];
 
-    if (srcArray == dstArray)
-        copyFunc = memmove;         /* might overlap */
-    else
-        copyFunc = memcpy;          /* can't overlap, use faster func */
+    sameArray = (srcArray == dstArray);
 
     /* check for null or bad pointer */
     if (!dvmValidateObject((Object*)srcArray) ||
@@ -126,9 +150,10 @@
                 dstArray->contents, dstPos * width,
                 srcArray->contents, srcPos * width,
                 length * width);
-        (*copyFunc)((u1*)dstArray->contents + dstPos * width,
+        copy((u1*)dstArray->contents + dstPos * width,
                 (const u1*)srcArray->contents + srcPos * width,
-                length * width);
+                length * width,
+                sameArray, width);
     } else {
         /*
          * Neither class is primitive.  See if elements in "src" are instances
@@ -147,9 +172,10 @@
                 dstArray->contents, dstPos * width,
                 srcArray->contents, srcPos * width,
                 length * width);
-            (*copyFunc)((u1*)dstArray->contents + dstPos * width,
+            copy((u1*)dstArray->contents + dstPos * width,
                     (const u1*)srcArray->contents + srcPos * width,
-                    length * width);
+                    length * width,
+                    sameArray, width);
             dvmWriteBarrierArray(dstArray, dstPos, dstPos+length);
         } else {
             /*
@@ -194,9 +220,10 @@
                 dstArray->contents, dstPos * width,
                 srcArray->contents, srcPos * width,
                 copyCount, length);
-            (*copyFunc)((u1*)dstArray->contents + dstPos * width,
+            copy((u1*)dstArray->contents + dstPos * width,
                     (const u1*)srcArray->contents + srcPos * width,
-                    copyCount * width);
+                    copyCount * width,
+                    sameArray, width);
             dvmWriteBarrierArray(dstArray, 0, copyCount);
             if (copyCount != length) {
                 dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",