Put wrappers on all stores of Object pointers into heap Objects.

Also:
Changed ++ loops to [i] loops where I'm touching.
Added some asserts.
Added dvmHeapSourceContainsAddress
Added dvmIsValidObjectAddress

Change-Id: I6586688246064aecabb1e22e1dca276fecee7795
diff --git a/vm/Exception.c b/vm/Exception.c
index 3cbd74d..fb3b9f8 100644
--- a/vm/Exception.c
+++ b/vm/Exception.c
@@ -1127,7 +1127,6 @@
 ArrayObject* dvmGetStackTraceRaw(const int* intVals, int stackDepth)
 {
     ArrayObject* steArray = NULL;
-    Object** stePtr;
     int i;
 
     /* init this if we haven't yet */
@@ -1139,7 +1138,6 @@
                     stackDepth, kObjectArrayRefWidth, ALLOC_DEFAULT);
     if (steArray == NULL)
         goto bail;
-    stePtr = (Object**) steArray->contents;
 
     /*
      * Allocate and initialize a StackTraceElement for each stack frame.
@@ -1196,7 +1194,7 @@
         if (dvmCheckException(dvmThreadSelf()))
             goto bail;
 
-        *stePtr++ = ste;
+        dvmSetObjectArrayElement(steArray, i, ste);
     }
 
 bail:
diff --git a/vm/Jni.c b/vm/Jni.c
index 5beefcf..9973508 100644
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -3093,7 +3093,7 @@
     //LOGV("JNI: set element %d in array %p to %p\n", index, array, value);
 
     Object* obj = dvmDecodeIndirectRef(env, jobj);
-    ((Object**) arrayObj->contents)[index] = obj;
+    dvmSetObjectArrayElement(arrayObj, index, obj);
 
 bail:
     JNI_EXIT();
diff --git a/vm/alloc/Alloc.c b/vm/alloc/Alloc.c
index 960ec93..23dc65b 100644
--- a/vm/alloc/Alloc.c
+++ b/vm/alloc/Alloc.c
@@ -227,6 +227,7 @@
 
     memcpy(copy, obj, size);
     DVM_LOCK_INIT(&copy->lock);
+    dvmWriteBarrierObject(copy);
 
     return copy;
 }
diff --git a/vm/alloc/Alloc.h b/vm/alloc/Alloc.h
index 7af68f0..1200788 100644
--- a/vm/alloc/Alloc.h
+++ b/vm/alloc/Alloc.h
@@ -91,6 +91,11 @@
 bool dvmIsValidObject(const Object* obj);
 
 /*
+ * Returns true iff <ptr> points within allocation-managed address space.
+ */
+bool dvmIsValidObjectAddress(const void *ptr);
+
+/*
  * Create a copy of an object.
  *
  * The new object will be added to the "tracked alloc" table.
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index a9c3208..bc852ca 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -541,6 +541,20 @@
     return false;
 }
 
+/*
+ * Returns true iff <obj> points to a word-aligned address within Heap
+ * address space.
+ */
+bool dvmIsValidObjectAddress(const void* ptr)
+{
+    /* Don't bother if it's not 4-byte aligned.
+     */
+    if (((uintptr_t)ptr & (4-1)) == 0) {
+        return dvmHeapSourceContainsAddress(ptr);
+    }
+    return false;
+}
+
 size_t dvmObjectSizeInHeap(const Object *obj)
 {
     return dvmHeapSourceChunkSize(obj);
diff --git a/vm/alloc/HeapSource.c b/vm/alloc/HeapSource.c
index f9234f0..0891506 100644
--- a/vm/alloc/HeapSource.c
+++ b/vm/alloc/HeapSource.c
@@ -924,6 +924,17 @@
 }
 
 /*
+ * Returns true iff <ptr> is in the heap source.
+ */
+bool
+dvmHeapSourceContainsAddress(const void *ptr)
+{
+    HS_BOILERPLATE();
+
+    return (dvmHeapBitmapCoversAddress(&gHs->liveBits, ptr));
+}
+
+/*
  * Returns true iff <ptr> was allocated from the heap source.
  */
 bool
@@ -931,7 +942,7 @@
 {
     HS_BOILERPLATE();
 
-    if (dvmHeapBitmapCoversAddress(&gHs->liveBits, ptr)) {
+    if (dvmHeapSourceContainsAddress(ptr)) {
         return dvmHeapBitmapIsObjectBitSet(&gHs->liveBits, ptr) != 0;
     }
     return false;
diff --git a/vm/alloc/HeapSource.h b/vm/alloc/HeapSource.h
index 6df3df0..465e7c9 100644
--- a/vm/alloc/HeapSource.h
+++ b/vm/alloc/HeapSource.h
@@ -104,6 +104,11 @@
 bool dvmHeapSourceContains(const void *ptr);
 
 /*
+ * Returns true iff <ptr> is within the address space managed by heap source.
+ */
+bool dvmHeapSourceContainsAddress(const void *ptr);
+
+/*
  * Returns the value of the requested flag.
  */
 enum HeapSourcePtrFlag {
diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c
index dafdbda..da8fa79 100644
--- a/vm/interp/Interp.c
+++ b/vm/interp/Interp.c
@@ -1377,6 +1377,8 @@
         }
     }
 
+    /* Never on the heap, so no write barrier needed. */
+    assert(!dvmIsValidObjectAddress(pResult));
     *pResult = interpState.retval;
 #if defined(WITH_JIT)
     dvmJitCalleeRestore(interpState.calleeSave);
diff --git a/vm/mterp/c/OP_APUT_OBJECT.c b/vm/mterp/c/OP_APUT_OBJECT.c
index cc87f5d..07e48c6 100644
--- a/vm/mterp/c/OP_APUT_OBJECT.c
+++ b/vm/mterp/c/OP_APUT_OBJECT.c
@@ -32,8 +32,9 @@
             }
         }
         ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
-        ((u4*) arrayObj->contents)[GET_REGISTER(vsrc2)] =
-            GET_REGISTER(vdst);
+        dvmSetObjectArrayElement(arrayObj,
+                                 GET_REGISTER(vsrc2),
+                                 (Object *)GET_REGISTER(vdst));
     }
     FINISH(2);
 OP_END
diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c
index acbde1c..c6c118b 100644
--- a/vm/mterp/c/gotoTargets.c
+++ b/vm/mterp/c/gotoTargets.c
@@ -94,6 +94,9 @@
                 vdst >>= 4;
             }
         }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
 
         retval.l = newArray;
     }
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 6a50b64..39cd6ba 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -2100,8 +2100,9 @@
             }
         }
         ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
-        ((u4*) arrayObj->contents)[GET_REGISTER(vsrc2)] =
-            GET_REGISTER(vdst);
+        dvmSetObjectArrayElement(arrayObj,
+                                 GET_REGISTER(vsrc2),
+                                 (Object *)GET_REGISTER(vdst));
     }
     FINISH(2);
 OP_END
@@ -3227,6 +3228,9 @@
                 vdst >>= 4;
             }
         }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
 
         retval.l = newArray;
     }
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index 18433f8..9468b24 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -2466,8 +2466,9 @@
             }
         }
         ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
-        ((u4*) arrayObj->contents)[GET_REGISTER(vsrc2)] =
-            GET_REGISTER(vdst);
+        dvmSetObjectArrayElement(arrayObj,
+                                 GET_REGISTER(vsrc2),
+                                 (Object *)GET_REGISTER(vdst));
     }
     FINISH(2);
 OP_END
@@ -3511,6 +3512,9 @@
                 vdst >>= 4;
             }
         }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
 
         retval.l = newArray;
     }
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index a4c4b54..5b0d45b 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -2205,8 +2205,9 @@
             }
         }
         ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
-        ((u4*) arrayObj->contents)[GET_REGISTER(vsrc2)] =
-            GET_REGISTER(vdst);
+        dvmSetObjectArrayElement(arrayObj,
+                                 GET_REGISTER(vsrc2),
+                                 (Object *)GET_REGISTER(vdst));
     }
     FINISH(2);
 OP_END
@@ -3250,6 +3251,9 @@
                 vdst >>= 4;
             }
         }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
 
         retval.l = newArray;
     }
diff --git a/vm/mterp/out/InterpC-x86-atom.c b/vm/mterp/out/InterpC-x86-atom.c
index 9d208a3..7da241c 100644
--- a/vm/mterp/out/InterpC-x86-atom.c
+++ b/vm/mterp/out/InterpC-x86-atom.c
@@ -1422,6 +1422,9 @@
                 vdst >>= 4;
             }
         }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
 
         retval.l = newArray;
     }
diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c
index d9e599e..86fe972 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -1391,6 +1391,9 @@
                 vdst >>= 4;
             }
         }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
 
         retval.l = newArray;
     }
diff --git a/vm/native/dalvik_system_DexFile.c b/vm/native/dalvik_system_DexFile.c
index e031289..25c9dfb 100644
--- a/vm/native/dalvik_system_DexFile.c
+++ b/vm/native/dalvik_system_DexFile.c
@@ -335,6 +335,7 @@
     DvmDex* pDvmDex;
     DexFile* pDexFile;
     ArrayObject* stringArray;
+    Thread* self = dvmThreadSelf();
 
     if (!validateCookie(cookie))
         RETURN_VOID();
@@ -349,10 +350,13 @@
     int count = pDexFile->pHeader->classDefsSize;
     stringArray = dvmAllocObjectArray(gDvm.classJavaLangString, count,
                     ALLOC_DEFAULT);
-    if (stringArray == NULL)
-        RETURN_VOID();          // should be an OOM pending
+    if (stringArray == NULL) {
+        /* probably OOM */
+        LOGD("Failed allocating array of %d strings\n", count);
+        assert(dvmCheckException(self));
+        RETURN_VOID();
+    }
 
-    StringObject** contents = (StringObject**) stringArray->contents;
     int i;
     for (i = 0; i < count; i++) {
         const DexClassDef* pClassDef = dexGetClassDef(pDexFile, i);
@@ -360,12 +364,13 @@
             dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
 
         char* className = dvmDescriptorToDot(descriptor);
-        contents[i] = dvmCreateStringFromCstr(className);
-        dvmReleaseTrackedAlloc((Object*) contents[i], NULL);
+        StringObject* str = dvmCreateStringFromCstr(className);
+        dvmSetObjectArrayElement(stringArray, i, (Object *)str);
+        dvmReleaseTrackedAlloc((Object *)str, self);
         free(className);
     }
 
-    dvmReleaseTrackedAlloc((Object*)stringArray, NULL);
+    dvmReleaseTrackedAlloc((Object*)stringArray, self);
     RETURN_PTR(stringArray);
 }
 
diff --git a/vm/native/dalvik_system_VMDebug.c b/vm/native/dalvik_system_VMDebug.c
index dd6ac8a..d27926c 100644
--- a/vm/native/dalvik_system_VMDebug.c
+++ b/vm/native/dalvik_system_VMDebug.c
@@ -30,6 +30,8 @@
  */
 static ArrayObject* convertStringArray(char** strings, size_t count)
 {
+    Thread* self = dvmThreadSelf();
+
     /*
      * Allocate an array to hold the String objects.
      */
@@ -46,27 +48,26 @@
     if (stringArray == NULL) {
         /* probably OOM */
         LOGD("Failed allocating array of %d strings\n", count);
+        assert(dvmCheckException(self));
         return NULL;
     }
 
-    Thread* self = dvmThreadSelf();
-
     /*
      * Create the individual String objects and add them to the array.
      */
-    StringObject** contents = (StringObject**) stringArray->contents;
     size_t i;
     for (i = 0; i < count; i++) {
-        contents[i] = dvmCreateStringFromCstr(strings[i]);
-        if (contents[i] == NULL) {
+        Object *str =
+            (Object *)dvmCreateStringFromCstr(strings[i]);
+        if (str == NULL) {
             /* probably OOM; drop out now */
             assert(dvmCheckException(self));
             dvmReleaseTrackedAlloc((Object*)stringArray, self);
             return NULL;
         }
-
+        dvmSetObjectArrayElement(stringArray, i, str);
         /* stored in tracked array, okay to release */
-        dvmReleaseTrackedAlloc((Object*)contents[i], self);
+        dvmReleaseTrackedAlloc(str, self);
     }
 
     dvmReleaseTrackedAlloc((Object*)stringArray, self);
diff --git a/vm/native/dalvik_system_VMStack.c b/vm/native/dalvik_system_VMStack.c
index 4a1ce53..8db4a6b 100644
--- a/vm/native/dalvik_system_VMStack.c
+++ b/vm/native/dalvik_system_VMStack.c
@@ -150,18 +150,16 @@
     /*
      * Fill in the array.
      */
-    ClassObject** objects = (ClassObject**) classes->contents;
-
-    unsigned int sidx = 0;
-    for (idx = kSkip; (int) idx < methodCount && sidx < size; idx++) {
-        const Method* meth = methods[idx];
-
-        if (dvmIsReflectionMethod(meth))
+    unsigned int objCount = 0;
+    for (idx = kSkip; (int) idx < methodCount; idx++) {
+        if (dvmIsReflectionMethod(methods[idx])) {
             continue;
-
-        *objects++ = meth->clazz;
-        sidx++;
+        }
+        dvmSetObjectArrayElement(classes, objCount,
+                                 (Object *)methods[idx]->clazz);
+        objCount++;
     }
+    assert(objCount == classes->length);
 
 bail:
     free(methods);
diff --git a/vm/native/java_lang_Class.c b/vm/native/java_lang_Class.c
index b873466..1bb9241 100644
--- a/vm/native/java_lang_Class.c
+++ b/vm/native/java_lang_Class.c
@@ -191,12 +191,13 @@
                         0, ALLOC_DEFAULT);
         }
     } else if (publicOnly) {
-        int i, newIdx, publicCount = 0;
+        u4 count, newIdx, publicCount = 0;
         ClassObject** pSource = (ClassObject**) classes->contents;
+        u4 length = classes->length;
 
         /* count up public classes */
-        for (i = 0; i < (int)classes->length; i++) {
-            if (dvmIsPublicClass(pSource[i]))
+        for (count = 0; count < length; count++) {
+            if (dvmIsPublicClass(pSource[count]))
                 publicCount++;
         }
 
@@ -206,12 +207,13 @@
                         publicCount, ALLOC_DEFAULT);
 
         /* copy them over */
-        ClassObject** pDest = (ClassObject**) newClasses->contents;
-        for (i = newIdx = 0; i < (int)classes->length; i++) {
-            if (dvmIsPublicClass(pSource[i]))
-                pDest[newIdx++] = pSource[i];
+        for (count = newIdx = 0; count < length; count++) {
+            if (dvmIsPublicClass(pSource[count])) {
+                dvmSetObjectArrayElement(newClasses, newIdx,
+                                         (Object *)pSource[count]);
+                newIdx++;
+            }
         }
-
         assert(newIdx == publicCount);
         dvmReleaseTrackedAlloc((Object*) classes, NULL);
         classes = newClasses;
diff --git a/vm/native/java_lang_System.c b/vm/native/java_lang_System.c
index 82b93d2..064d6da 100644
--- a/vm/native/java_lang_System.c
+++ b/vm/native/java_lang_System.c
@@ -148,6 +148,7 @@
             (*copyFunc)((u1*)dstArray->contents + dstPos * width,
                     (const u1*)srcArray->contents + srcPos * width,
                     length * width);
+            dvmWriteBarrierArray(dstArray, dstPos, dstPos+length);
         } else {
             /*
              * The arrays are not fundamentally compatible.  However, we may
@@ -194,7 +195,7 @@
             (*copyFunc)((u1*)dstArray->contents + dstPos * width,
                     (const u1*)srcArray->contents + srcPos * width,
                     copyCount * width);
-
+            dvmWriteBarrierArray(dstArray, 0, copyCount);
             if (copyCount != length) {
                 dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",
                     "source[%d] of type %s cannot be stored in destination array of type %s",
diff --git a/vm/native/java_lang_reflect_Field.c b/vm/native/java_lang_reflect_Field.c
index 65879f4..cb9f2bf 100644
--- a/vm/native/java_lang_reflect_Field.c
+++ b/vm/native/java_lang_reflect_Field.c
@@ -231,6 +231,17 @@
         fieldType->primitiveType == PRIM_DOUBLE)
     {
         fieldPtr->j = value.j;
+    } else if (fieldType->primitiveType == PRIM_NOT) {
+        if (slot < 0) {
+            StaticField *sfield;
+            sfield = (StaticField *)dvmSlotToField(declaringClass, slot);
+            assert(fieldPtr == &sfield->value);
+            dvmSetStaticFieldObject(sfield, value.l);
+        } else {
+            int offset = declaringClass->ifields[slot].byteOffset;
+            assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset));
+            dvmSetFieldObject(obj, offset, value.l);
+        }
     } else {
         fieldPtr->i = value.i;
     }
diff --git a/vm/native/java_security_AccessController.c b/vm/native/java_security_AccessController.c
index 1c35b0e..378fb94 100644
--- a/vm/native/java_security_AccessController.c
+++ b/vm/native/java_security_AccessController.c
@@ -121,9 +121,8 @@
     }
 
     /* copy the ProtectionDomain objects out */
-    Object** objects = (Object**) domains->contents;
-    for (idx = 0; idx < subIdx; idx++)
-        *objects++ = subSet[idx];
+    memcpy(domains->contents, subSet, subIdx * sizeof(Object *));
+    dvmWriteBarrierArray(domains, 0, subIdx);
 
 bail:
     free(subSet);
diff --git a/vm/native/sun_misc_Unsafe.c b/vm/native/sun_misc_Unsafe.c
index b3c7141..7a64c46 100644
--- a/vm/native/sun_misc_Unsafe.c
+++ b/vm/native/sun_misc_Unsafe.c
@@ -128,7 +128,7 @@
     // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
     int result = android_atomic_release_cas((int32_t) expectedValue,
             (int32_t) newValue, address);
-
+    dvmWriteBarrierField(obj, address);
     RETURN_BOOLEAN(result == 0);
 }
 
@@ -221,6 +221,7 @@
     volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
 
     android_atomic_release_store((int32_t)value, address);
+    dvmWriteBarrierField(obj, (void *)address);
     RETURN_VOID();
 }
 
@@ -305,6 +306,7 @@
     Object** address = (Object**) (((u1*) obj) + offset);
 
     *address = value;
+    dvmWriteBarrierField(obj, address);
     RETURN_VOID();
 }
 
diff --git a/vm/oo/Array.c b/vm/oo/Array.c
index 6e706ef..9749f77 100644
--- a/vm/oo/Array.c
+++ b/vm/oo/Array.c
@@ -246,7 +246,6 @@
         }
     } else {
         ClassObject* subArrayClass;
-        Object** contents;
         int i;
 
         /* if we have X[][], find X[] */
@@ -269,19 +268,16 @@
         /*
          * Create a new sub-array in every element of the array.
          */
-        contents = (Object**) newArray->contents;
         for (i = 0; i < *dimensions; i++) {
-            ArrayObject* newSubArray;
-
-            newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1,
-                            dimensions+1);
+          ArrayObject* newSubArray;
+          newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1,
+                          dimensions+1);
             if (newSubArray == NULL) {
                 dvmReleaseTrackedAlloc((Object*) newArray, NULL);
                 assert(dvmCheckException(dvmThreadSelf()));
                 return NULL;
             }
-
-            *contents++ = (Object*) newSubArray;
+            dvmSetObjectArrayElement(newArray, i, (Object *)newSubArray);
             dvmReleaseTrackedAlloc((Object*) newSubArray, NULL);
         }
     }
@@ -427,12 +423,18 @@
     dvmSetClassSerialNumber(newClass);
     newClass->descriptorAlloc = strdup(descriptor);
     newClass->descriptor = newClass->descriptorAlloc;
-    newClass->super = gDvm.classJavaLangObject;
+    dvmSetFieldObject((Object *)newClass,
+                      offsetof(ClassObject, super),
+                      (Object *)gDvm.classJavaLangObject);
     newClass->vtableCount = gDvm.classJavaLangObject->vtableCount;
     newClass->vtable = gDvm.classJavaLangObject->vtable;
     newClass->primitiveType = PRIM_NOT;
-    newClass->elementClass = elementClass;
-    newClass->classLoader = elementClass->classLoader;
+    dvmSetFieldObject((Object *)newClass,
+                      offsetof(ClassObject, elementClass),
+                      (Object *)elementClass);
+    dvmSetFieldObject((Object *)newClass,
+                      offsetof(ClassObject, classLoader),
+                      (Object *)elementClass->classLoader);
     newClass->arrayDim = arrayDim;
     newClass->status = CLASS_INITIALIZED;
 #if WITH_HPROF && WITH_HPROF_STACK
@@ -530,9 +532,6 @@
         assert(newClass != NULL);
         return newClass;
     }
-
-    /* make it available to the GC */
-    newClass->obj.clazz = gDvm.classJavaLangClass;
     dvmReleaseTrackedAlloc((Object*) newClass, NULL);
 
     LOGV("Created array class '%s' %p (access=0x%04x.%04x)\n",
@@ -664,21 +663,21 @@
     ClassObject* dstElemClass)
 {
     Object** src = (Object**)srcArray->contents;
-    Object** dst = (Object**)dstArray->contents;
-    u4 count = dstArray->length;
+    u4 length, count;
 
     assert(srcArray->length == dstArray->length);
     assert(dstArray->obj.clazz->elementClass == dstElemClass ||
         (dstArray->obj.clazz->elementClass == dstElemClass->elementClass &&
          dstArray->obj.clazz->arrayDim == dstElemClass->arrayDim+1));
 
-    while (count--) {
-        if (!dvmInstanceof((*src)->clazz, dstElemClass)) {
+    length = dstArray->length;
+    for (count = 0; count < length; count++) {
+        if (!dvmInstanceof(src[count]->clazz, dstElemClass)) {
             LOGW("dvmCopyObjectArray: can't store %s in %s\n",
-                (*src)->clazz->descriptor, dstElemClass->descriptor);
+                src[count]->clazz->descriptor, dstElemClass->descriptor);
             return false;
         }
-        *dst++ = *src++;
+        dvmSetObjectArrayElement(dstArray, count, src[count]);
     }
 
     return true;
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index 40535cc..feb4fdb 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -1695,7 +1695,9 @@
     newClass->descriptor = descriptor;
     assert(newClass->descriptorAlloc == NULL);
     newClass->accessFlags = pClassDef->accessFlags;
-    newClass->classLoader = classLoader;
+    dvmSetFieldObject((Object *)newClass,
+                      offsetof(ClassObject, classLoader),
+                      (Object *)classLoader);
     newClass->pDvmDex = pDvmDex;
     newClass->primitiveType = PRIM_NOT;
     newClass->status = CLASS_IDX;
@@ -2506,8 +2508,8 @@
         clazz->status = CLASS_LOADED;
 
         if (superclassIdx != kDexNoIndex) {
-            clazz->super = dvmResolveClass(clazz, superclassIdx, false);
-            if (clazz->super == NULL) {
+            ClassObject* super = dvmResolveClass(clazz, superclassIdx, false);
+            if (super == NULL) {
                 assert(dvmCheckException(dvmThreadSelf()));
                 if (gDvm.optimizing) {
                     /* happens with "external" libs */
@@ -2519,6 +2521,9 @@
                 }
                 goto bail;
             }
+            dvmSetFieldObject((Object *)clazz,
+                              offsetof(ClassObject, super),
+                              (Object *)super);
         }
 
         if (clazz->interfaceCount > 0) {
@@ -3825,7 +3830,7 @@
         bool parsed = dvmEncodedArrayIteratorGetNext(&iterator, &value);
         StaticField* sfield = &clazz->sfields[i];
         const char* descriptor = sfield->field.signature;
-        bool needRelease = false;
+        bool isObj = false;
 
         if (! parsed) {
             /*
@@ -3859,13 +3864,13 @@
                     case kDexAnnotationString: {
                         parsed =
                             (strcmp(descriptor, "Ljava/lang/String;") == 0);
-                        needRelease = true;
+                        isObj = true;
                         break;
                     }
                     case kDexAnnotationType: {
                         parsed =
                             (strcmp(descriptor, "Ljava/lang/Class;") == 0);
-                        needRelease = true;
+                        isObj = true;
                         break;
                     }
                     default: {
@@ -3883,13 +3888,18 @@
 
         if (parsed) {
             /*
-             * All's well, so store the value. Note: This always
-             * stores the full width of a JValue, even though most of
-             * the time only the first word is needed.
+             * All's well, so store the value.
              */
-            sfield->value = value.value;
-            if (needRelease) {
+            if (isObj) {
+                dvmSetStaticFieldObject(sfield, value.value.l);
                 dvmReleaseTrackedAlloc(value.value.l, self);
+            } else {
+                /*
+                 * Note: This always stores the full width of a
+                 * JValue, even though most of the time only the first
+                 * word is needed.
+                 */
+                sfield->value = value.value;
             }
         } else {
             /*
@@ -4279,7 +4289,9 @@
 verify_failed:
             dvmThrowExceptionWithClassMessage("Ljava/lang/VerifyError;",
                 clazz->descriptor);
-            clazz->verifyErrorClass = dvmGetException(self)->clazz;
+            dvmSetFieldObject((Object *)clazz,
+                              offsetof(ClassObject, verifyErrorClass),
+                              (Object *)dvmGetException(self)->clazz);
             clazz->status = CLASS_ERROR;
             goto bail_unlock;
         }
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index 041e1e8..935f670 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -255,8 +255,12 @@
  * Properly initialize an Object.
  * void DVM_OBJECT_INIT(Object *obj, ClassObject *clazz_)
  */
-#define DVM_OBJECT_INIT(obj, clazz_) \
-    do { (obj)->clazz = (clazz_); DVM_LOCK_INIT(&(obj)->lock); } while (0)
+#define DVM_OBJECT_INIT(obj, clazz_)                                    \
+    do {                                                                \
+        dvmSetFieldObject((Object *)obj, offsetof(Object, clazz),       \
+                          (Object *)clazz_);                            \
+        DVM_LOCK_INIT(&(obj)->lock);                                    \
+    } while (0)
 
 /*
  * Data objects have an Object header followed by their instance data.
@@ -673,6 +677,26 @@
 }
 
 /*
+ * Note writes to the heap.
+ */
+INLINE void dvmWriteBarrierField(Object *obj, void *addr) {
+}
+INLINE void dvmWriteBarrierObject(Object *obj) {
+}
+INLINE void dvmWriteBarrierArray(const ArrayObject* obj,
+                                 size_t start, size_t end) {
+}
+/*
+ * Store a single value in the array, and note in the write barrier.
+ */
+INLINE void dvmSetObjectArrayElement(const ArrayObject* obj, int index,
+                                     Object* val) {
+    ((Object **)(obj)->contents)[index] = val;
+    dvmWriteBarrierArray(obj, index, index+1);
+}
+
+
+/*
  * Field access functions.  Pass in the word offset from Field->byteOffset.
  *
  * We guarantee that long/double field data is 64-bit aligned, so it's safe
@@ -754,7 +778,9 @@
     ((JValue*)BYTE_OFFSET(obj, offset))->d = val;
 }
 INLINE void dvmSetFieldObject(Object* obj, int offset, Object* val) {
-    ((JValue*)BYTE_OFFSET(obj, offset))->l = val;
+    JValue* lhs = BYTE_OFFSET(obj, offset);
+    lhs->l = val;
+    dvmWriteBarrierField(obj, &lhs->l);
 }
 INLINE void dvmSetFieldIntVolatile(Object* obj, int offset, s4 val) {
     s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i;
@@ -763,6 +789,7 @@
 INLINE void dvmSetFieldObjectVolatile(Object* obj, int offset, Object* val) {
     void** ptr = &((JValue*)BYTE_OFFSET(obj, offset))->l;
     android_atomic_release_store((int32_t)val, (int32_t*)ptr);
+    dvmWriteBarrierField(obj, ptr);
 }
 INLINE void dvmSetFieldLongVolatile(Object* obj, int offset, s8 val) {
     s8* addr = BYTE_OFFSET(obj, offset);
@@ -845,6 +872,7 @@
 }
 INLINE void dvmSetStaticFieldObject(StaticField* sfield, Object* val) {
     sfield->value.l = val;
+    dvmWriteBarrierField((Object *)sfield->field.clazz, &sfield->value.l);
 }
 INLINE void dvmSetStaticFieldIntVolatile(StaticField* sfield, s4 val) {
     s4* ptr = &(sfield->value.i);
@@ -853,6 +881,7 @@
 INLINE void dvmSetStaticFieldObjectVolatile(StaticField* sfield, Object* val) {
     void** ptr = &(sfield->value.l);
     android_atomic_release_store((int32_t)val, (int32_t*)ptr);
+    dvmWriteBarrierField((Object *)sfield->field.clazz, &sfield->value.l);
 }
 INLINE void dvmSetStaticFieldLongVolatile(StaticField* sfield, s8 val) {
     s8* addr = &sfield->value.j;
diff --git a/vm/reflect/Annotation.c b/vm/reflect/Annotation.c
index 86f800e..a5007ba 100644
--- a/vm/reflect/Annotation.c
+++ b/vm/reflect/Annotation.c
@@ -544,8 +544,7 @@
             return false;
         } else {
             ArrayObject* newArray;
-            Object** pObj;
-            u4 size;
+            u4 size, count;
 
             size = readUleb128(&ptr);
             LOGVV("--- annotation array, size is %u at %p\n", size, ptr);
@@ -555,18 +554,17 @@
                 LOGE("annotation element array alloc failed (%d)\n", size);
                 return false;
             }
-            pObj = (Object**)newArray->contents;
 
             AnnotationValue avalue;
-            while (size--) {
+            for (count = 0; count < size; count++) {
                 if (!processAnnotationValue(clazz, &ptr, &avalue,
                                 kAllObjects)) {
                     dvmReleaseTrackedAlloc((Object*)newArray, self);
                     return false;
                 }
                 Object* obj = avalue.value.l;
+                dvmSetObjectArrayElement(newArray, count, obj);
                 dvmReleaseTrackedAlloc(obj, self);
-                *pObj++ = obj;
             }
 
             elemObj = (Object*) newArray;
@@ -807,7 +805,7 @@
     ArrayObject* elementArray = NULL;
     const ClassObject* annoClass;
     const u1* ptr;
-    u4 typeIdx, size;
+    u4 typeIdx, size, count;
 
     ptr = *pPtr;
     typeIdx = readUleb128(&ptr);
@@ -836,7 +834,6 @@
      * default values get merged in later.
      */
     JValue result;
-    Object** pElement = NULL;
 
     if (size > 0) {
         elementArray = dvmAllocArrayByClass(
@@ -847,20 +844,19 @@
                 size);
             goto bail;
         }
-        pElement = (Object**) elementArray->contents;
     }
 
     /*
      * "ptr" points to a byte stream with "size" occurrences of
      * annotation_element.
      */
-    while (size--) {
+    for (count = 0; count < size; count++) {
         Object* newMember = createAnnotationMember(clazz, annoClass, &ptr);
         if (newMember == NULL)
             goto bail;
 
         /* add it to the array */
-        *pElement++ = newMember;
+        dvmSetObjectArrayElement(elementArray, count, newMember);
     }
 
     dvmCallMethod(self,
@@ -898,8 +894,8 @@
     DexFile* pDexFile = clazz->pDvmDex->pDexFile;
     const DexAnnotationItem* pAnnoItem;
     ArrayObject* annoArray;
-    Object** pContents;
     int i, count;
+    u4 dstIndex;
 
     /* we need these later; make sure they're initialized */
     if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory))
@@ -914,27 +910,29 @@
             count++;
     }
 
-    annoArray =dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArray,
-        count, ALLOC_DEFAULT);
+    annoArray =
+        dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArray,
+                             count, ALLOC_DEFAULT);
     if (annoArray == NULL)
         return NULL;
-    pContents = (Object**) annoArray->contents;
 
     /*
      * Generate Annotation objects.  We must put them into the array
      * immediately (or add them to the tracked ref table).
      */
+    dstIndex = 0;
     for (i = 0; i < (int) pAnnoSet->size; i++) {
         pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i);
         if (pAnnoItem->visibility != visibility)
             continue;
         const u1* ptr = pAnnoItem->annotation;
-        *pContents = processEncodedAnnotation(clazz, &ptr);
-        if (*pContents == NULL) {
+        Object *anno = processEncodedAnnotation(clazz, &ptr);
+        if (anno == NULL) {
             dvmReleaseTrackedAlloc((Object*) annoArray, NULL);
             return NULL;
         }
-        pContents++;
+        dvmSetObjectArrayElement(annoArray, dstIndex, anno);
+        ++dstIndex;
     }
 
     return annoArray;
@@ -1987,7 +1985,6 @@
 {
     DexFile* pDexFile = clazz->pDvmDex->pDexFile;
     ArrayObject* annoArrayArray = NULL;
-    ArrayObject** pContents;
     u4 idx;
 
     /* allocate an array of Annotation arrays to hold results */
@@ -1998,24 +1995,24 @@
         goto bail;
     }
 
-    pContents = (ArrayObject**) annoArrayArray->contents;
-
     for (idx = 0; idx < count; idx++) {
         Thread* self = dvmThreadSelf();
         const DexAnnotationSetRefItem* pItem;
         const DexAnnotationSetItem* pAnnoSet;
+        Object *annoSet;
 
         pItem = dexGetParameterAnnotationSetRef(pAnnoSetList, idx);
         pAnnoSet = dexGetSetRefItemItem(pDexFile, pItem);
-        *pContents = processAnnotationSet(clazz, pAnnoSet,
-                        kDexVisibilityRuntime);
-        if (*pContents == NULL) {
+        annoSet = (Object *)processAnnotationSet(clazz,
+                                                 pAnnoSet,
+                                                 kDexVisibilityRuntime);
+        if (annoSet == NULL) {
             LOGW("processAnnotationSet failed\n");
             annoArrayArray = NULL;
             goto bail;
         }
-        dvmReleaseTrackedAlloc((Object*) *pContents, self);
-        pContents++;
+        dvmSetObjectArrayElement(annoArrayArray, idx, annoSet);
+        dvmReleaseTrackedAlloc((Object*) annoSet, self);
     }
 
 bail:
diff --git a/vm/reflect/Proxy.c b/vm/reflect/Proxy.c
index 4984b12..eef658d 100644
--- a/vm/reflect/Proxy.c
+++ b/vm/reflect/Proxy.c
@@ -188,9 +188,13 @@
     newClass->descriptorAlloc = dvmNameToDescriptor(nameStr);
     newClass->descriptor = newClass->descriptorAlloc;
     newClass->accessFlags = ACC_PUBLIC | ACC_FINAL;
-    newClass->super = gDvm.classJavaLangReflectProxy;
+    dvmSetFieldObject((Object *)newClass,
+                      offsetof(ClassObject, super),
+                      (Object *)gDvm.classJavaLangReflectProxy);
     newClass->primitiveType = PRIM_NOT;
-    newClass->classLoader = loader;
+    dvmSetFieldObject((Object *)newClass,
+                      offsetof(ClassObject, classLoader),
+                      (Object *)loader);
 #if WITH_HPROF && WITH_HPROF_STACK
     hprofFillInStackTrace(newClass);
 #endif
diff --git a/vm/reflect/Reflect.c b/vm/reflect/Reflect.c
index 8e128b7..cf63462 100644
--- a/vm/reflect/Reflect.c
+++ b/vm/reflect/Reflect.c
@@ -240,7 +240,6 @@
     ClassObject* defClass)
 {
     ArrayObject* classArray;
-    ClassObject** classes;
     char* signature = *pSignature;
     char* cp;
     int i, count;
@@ -273,7 +272,6 @@
         return NULL;
 
     /* fill it in */
-    classes = (ClassObject**) classArray->contents;
     cp = signature;
     for (i = 0; i < count; i++) {
         ClassObject* clazz;
@@ -284,8 +282,7 @@
             return NULL;
         }
         LOGVV("REFLECT  %d: '%s'\n", i, clazz->descriptor);
-
-        *classes++ = clazz;
+        dvmSetObjectArrayElement(classArray, i, (Object *)clazz);
     }
 
     *pSignature = cp;
@@ -395,7 +392,6 @@
 ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly)
 {
     ArrayObject* fieldArray = NULL;
-    Object** fields;
     int i, count;
 
     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
@@ -421,34 +417,38 @@
                     kObjectArrayRefWidth, ALLOC_DEFAULT);
     if (fieldArray == NULL)
         return NULL;
-    fields = (Object**) fieldArray->contents;
 
     /* populate */
+    size_t fieldCount = 0;
     for (i = 0; i < clazz->sfieldCount; i++) {
         if (!publicOnly ||
             (clazz->sfields[i].field.accessFlags & ACC_PUBLIC) != 0)
         {
-            *fields = createFieldObject(&clazz->sfields[i].field, clazz);
-            if (*fields == NULL)
+            Object* field = createFieldObject(&clazz->sfields[i].field, clazz);
+            if (field == NULL) {
                 goto fail;
-            dvmReleaseTrackedAlloc(*fields, NULL);
-            fields++;
-            count--;
+            }
+            dvmSetObjectArrayElement(fieldArray, fieldCount, field);
+            dvmReleaseTrackedAlloc(field, NULL);
+            ++fieldCount;
         }
     }
     for (i = 0; i < clazz->ifieldCount; i++) {
         if (!publicOnly ||
             (clazz->ifields[i].field.accessFlags & ACC_PUBLIC) != 0)
         {
-            *fields = createFieldObject(&clazz->ifields[i].field, clazz);
-            if (*fields == NULL)
+            Object* field = createFieldObject(&clazz->ifields[i].field, clazz);
+            if (field == NULL) {
                 goto fail;
-            dvmReleaseTrackedAlloc(*fields, NULL);
-            fields++;
-            count--;
+            }
+            dvmSetObjectArrayElement(fieldArray, fieldCount, field);
+            dvmReleaseTrackedAlloc(field, NULL);
+            ++fieldCount;
         }
     }
 
+    assert(fieldCount == fieldArray->length);
+
     /* caller must call dvmReleaseTrackedAlloc */
     return fieldArray;
 
@@ -575,7 +575,6 @@
 ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly)
 {
     ArrayObject* consArray;
-    Object** consObjPtr;
     Method* meth;
     int i, count;
 
@@ -610,12 +609,11 @@
     if (consArray == NULL)
         return NULL;
 
-    consObjPtr = (Object**) consArray->contents;
-
     /*
      * Fill out the array.
      */
     meth = clazz->directMethods;
+    size_t consObjCount = 0;
     for (i = 0; i < clazz->directMethodCount; i++, meth++) {
         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
             dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
@@ -623,12 +621,13 @@
             Object* consObj = createConstructorObject(meth);
             if (consObj == NULL)
                 goto fail;
-            *consObjPtr++ = consObj;
+            dvmSetObjectArrayElement(consArray, consObjCount, consObj);
+            ++consObjCount;
             dvmReleaseTrackedAlloc(consObj, NULL);
         }
     }
 
-    assert(consObjPtr - (Object**) consArray->contents == count);
+    assert(consObjCount == consArray->length);
 
     /* caller must call dvmReleaseTrackedAlloc */
     return consArray;
@@ -740,7 +739,6 @@
 ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly)
 {
     ArrayObject* methodArray;
-    Object** methObjPtr;
     Method* meth;
     int i, count;
 
@@ -778,12 +776,12 @@
     if (methodArray == NULL)
         return NULL;
 
-    methObjPtr = (Object**) methodArray->contents;
 
     /*
      * Fill out the array.
      */
     meth = clazz->virtualMethods;
+    size_t methObjCount = 0;
     for (i = 0; i < clazz->virtualMethodCount; i++, meth++) {
         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
             !dvmIsMirandaMethod(meth))
@@ -791,7 +789,8 @@
             Object* methObj = dvmCreateReflectMethodObject(meth);
             if (methObj == NULL)
                 goto fail;
-            *methObjPtr++ = methObj;
+            dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
+            ++methObjCount;
             dvmReleaseTrackedAlloc(methObj, NULL);
         }
     }
@@ -803,12 +802,13 @@
             Object* methObj = dvmCreateReflectMethodObject(meth);
             if (methObj == NULL)
                 goto fail;
-            *methObjPtr++ = methObj;
+            dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
+            ++methObjCount;
             dvmReleaseTrackedAlloc(methObj, NULL);
         }
     }
 
-    assert(methObjPtr - (Object**) methodArray->contents == count);
+    assert(methObjCount == methodArray->length);
 
     /* caller must call dvmReleaseTrackedAlloc */
     return methodArray;
@@ -841,11 +841,9 @@
     /*
      * Fill out the array.
      */
-    Object** interfaceObjPtr = (Object**) interfaceArray->contents;
-    int i;
-    for (i = 0; i < count; i++) {
-        *interfaceObjPtr++ = (Object*) clazz->interfaces[i];
-    }
+    memcpy(interfaceArray->contents, clazz->interfaces,
+           count * sizeof(Object *));
+    dvmWriteBarrierArray(interfaceArray, 0, count);
 
     /* caller must call dvmReleaseTrackedAlloc */
     return interfaceArray;
@@ -1102,6 +1100,8 @@
                 value->clazz->descriptor, returnType->descriptor);
             return false;
         }
+        /* Never on the heap, so no write barrier needed. */
+        assert(!dvmIsValidObjectAddress(pResult));
         pResult->l = value;
         return true;
     } else if (typeIndex == PRIM_VOID) {