Interpreter & JIT support for write barriers

In this iteration, cards are marked on either the store address or
the object head (whichever leads to faster code).  In all cases,
though, card marks are deferred until after the associated store
has completed.

Change-Id: I633d6e8c3bebdb80bde92efb4fa6fc7cc84f60fc
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index 03fc2af..d69991d 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -24,6 +24,25 @@
  * applicable directory below this one.
  */
 
+/*
+ * Mark garbage collection card. Skip if the value we're storing is null.
+ */
+static void markCard(CompilationUnit *cUnit, int valReg, int tgtAddrReg)
+{
+    int regCardBase = dvmCompilerAllocTemp(cUnit);
+    int regCardNo = dvmCompilerAllocTemp(cUnit);
+    opRegImm(cUnit, kOpCmp, valReg, 0); /* storing null? */
+    ArmLIR *branchOver = opCondBranch(cUnit, kArmCondEq);
+    loadWordDisp(cUnit, rGLUE, offsetof(InterpState, cardTable),
+                 regCardBase);
+    opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
+    storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
+                     kUnsignedByte);
+    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR *)target;
+}
+
 static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
                                      int srcSize, int tgtSize)
 {
@@ -306,7 +325,7 @@
  *
  */
 static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
-                    int fieldOffset)
+                    int fieldOffset, bool isObject)
 {
     RegisterClass regClass = dvmCompilerRegClassBySize(size);
     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
@@ -319,6 +338,10 @@
     HEAP_ACCESS_SHADOW(true);
     storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
     HEAP_ACCESS_SHADOW(false);
+    if (isObject) {
+        /* NOTE: marking card based on object head */
+        markCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
+    }
 }
 
 
@@ -528,12 +551,14 @@
     dvmCompilerLockTemp(cUnit, regPtr);   // r4PC
     dvmCompilerLockTemp(cUnit, regIndex); // r7
     dvmCompilerLockTemp(cUnit, r0);
+    dvmCompilerLockTemp(cUnit, r1);
 
     /* Bad? - roll back and re-execute if so */
     genRegImmCheck(cUnit, kArmCondEq, r0, 0, mir->offset, pcrLabel);
 
-    /* Resume here - must reload element, regPtr & index preserved */
+    /* Resume here - must reload element & array, regPtr & index preserved */
     loadValueDirectFixed(cUnit, rlSrc, r0);
+    loadValueDirectFixed(cUnit, rlArray, r1);
 
     ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
     target->defMask = ENCODE_ALL;
@@ -543,6 +568,9 @@
     storeBaseIndexed(cUnit, regPtr, regIndex, r0,
                      scale, kWord);
     HEAP_ACCESS_SHADOW(false);
+
+    /* NOTE: marking card here based on object head */
+    markCard(cUnit, r0, r1);
 }
 
 static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
@@ -1488,6 +1516,10 @@
             HEAP_ACCESS_SHADOW(true);
             storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
             HEAP_ACCESS_SHADOW(false);
+            if (mir->dalvikInsn.opCode == OP_SPUT_OBJECT) {
+                /* NOTE: marking card based on field address */
+                markCard(cUnit, rlSrc.lowReg, tReg);
+            }
 
             break;
         }
@@ -2218,16 +2250,18 @@
             genIPutWide(cUnit, mir, fieldOffset);
             break;
         case OP_IPUT:
+            genIPut(cUnit, mir, kWord, fieldOffset, false);
+            break;
         case OP_IPUT_OBJECT:
-            genIPut(cUnit, mir, kWord, fieldOffset);
+            genIPut(cUnit, mir, kWord, fieldOffset, true);
             break;
         case OP_IPUT_SHORT:
         case OP_IPUT_CHAR:
-            genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
+            genIPut(cUnit, mir, kUnsignedHalf, fieldOffset, false);
             break;
         case OP_IPUT_BYTE:
         case OP_IPUT_BOOLEAN:
-            genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
+            genIPut(cUnit, mir, kUnsignedByte, fieldOffset, false);
             break;
         case OP_IGET_WIDE_VOLATILE:
         case OP_IPUT_WIDE_VOLATILE:
@@ -2251,8 +2285,10 @@
             genIGet(cUnit, mir, kWord, fieldOffset);
             break;
         case OP_IPUT_QUICK:
+            genIPut(cUnit, mir, kWord, fieldOffset, false);
+            break;
         case OP_IPUT_OBJECT_QUICK:
-            genIPut(cUnit, mir, kWord, fieldOffset);
+            genIPut(cUnit, mir, kWord, fieldOffset, true);
             break;
         case OP_IGET_WIDE_QUICK:
             genIGetWide(cUnit, mir, fieldOffset);
diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h
index c794db2..6ba9e12 100644
--- a/vm/interp/InterpDefs.h
+++ b/vm/interp/InterpDefs.h
@@ -128,6 +128,8 @@
     const u1*       interpStackEnd;
     /* points at self->suspendCount */
     volatile int*   pSelfSuspendCount;
+    /* Biased base of GC's card table */
+    u1*             cardTable;
 #if defined(WITH_DEBUGGER)
     /* points at gDvm.debuggerActive, or NULL if debugger not enabled */
     volatile u1*    pDebuggerActive;
@@ -151,8 +153,8 @@
      */
     unsigned char*     pJitProfTable;
     JitState           jitState;
-    const void*        jitResumeNPC;	// Native PC of compiled code
-    const u2*          jitResumeDPC;	// Dalvik PC corresponding to NPC
+    const void*        jitResumeNPC;    // Native PC of compiled code
+    const u2*          jitResumeDPC;    // Dalvik PC corresponding to NPC
     int                jitThreshold;
     /*
      * ppJitProfTable holds the address of gDvmJit.pJitProfTable, which
diff --git a/vm/mterp/Mterp.c b/vm/mterp/Mterp.c
index 51cef04..4b0ceb8 100644
--- a/vm/mterp/Mterp.c
+++ b/vm/mterp/Mterp.c
@@ -76,6 +76,7 @@
 
     glue->interpStackEnd = self->interpStackEnd;
     glue->pSelfSuspendCount = &self->suspendCount;
+    glue->cardTable = gDvm.biasedCardTableBase;
 #if defined(WITH_JIT)
     glue->pJitProfTable = gDvmJit.pProfTable;
     glue->ppJitProfTable = &gDvmJit.pProfTable;
diff --git a/vm/mterp/armv5te/OP_APUT_OBJECT.S b/vm/mterp/armv5te/OP_APUT_OBJECT.S
index 03477f5..e926db6 100644
--- a/vm/mterp/armv5te/OP_APUT_OBJECT.S
+++ b/vm/mterp/armv5te/OP_APUT_OBJECT.S
@@ -36,6 +36,13 @@
     bl      dvmCanPutArrayElement       @ test object type vs. array type
     cmp     r0, #0                      @ okay?
     beq     common_errArrayStore        @ no
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rGLUE, #offGlue_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r10, lsr #GC_CARD_SHIFT]    @ mark card
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 .L${opcode}_skip_check:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
diff --git a/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
index 1241c13..b9abe5a 100644
--- a/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
+++ b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
@@ -33,15 +33,15 @@
 .L${opcode}_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     $isrange
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .L${opcode}_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -49,7 +49,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -81,8 +82,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
diff --git a/vm/mterp/armv5te/OP_IPUT.S b/vm/mterp/armv5te/OP_IPUT.S
index 78d333d..53f4b4e 100644
--- a/vm/mterp/armv5te/OP_IPUT.S
+++ b/vm/mterp/armv5te/OP_IPUT.S
@@ -7,7 +7,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT.S b/vm/mterp/armv5te/OP_IPUT_OBJECT.S
index 7a4d936..5e0fe83 100644
--- a/vm/mterp/armv5te/OP_IPUT_OBJECT.S
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT.S
@@ -1,2 +1,51 @@
+%default { "barrier":"@ no-op ", "sqnum":"0" }
 %verify "executed"
-%include "armv5te/OP_IPUT.S"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * 32-bit instance field put.
+     *
+     * for: iput-object, iput-object-volatile
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .L${opcode}_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .L${opcode}_finish          @ yes, finish up
+    b       common_exceptionThrown
+%break
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.L${opcode}_finish:
+    @bl      common_squeak${sqnum}
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    $barrier                            @ releasing store
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S b/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S
index 6838faf..648a69c 100644
--- a/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S
@@ -1,2 +1,19 @@
 %verify "executed"
-%include "armv5te/OP_IPUT_QUICK.S"
+%verify "null object"
+    /* For: iput-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    cmp     r3, #0                      @ check object for null
+    mov     r2, rINST, lsr #8           @ r2<- A(+)
+    beq     common_errNullObject        @ object was null
+    and     r2, r2, #15
+    GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE.S b/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE.S
index ba3f615..b4d24e7 100644
--- a/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE.S
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE.S
@@ -1,2 +1,2 @@
 %verify "executed"
-%include "armv5te/OP_IPUT.S" {"barrier":"SMP_DMB"}
+%include "armv5te/OP_IPUT_OBJECT.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IPUT_QUICK.S b/vm/mterp/armv5te/OP_IPUT_QUICK.S
index c15da2b..ad76eca 100644
--- a/vm/mterp/armv5te/OP_IPUT_QUICK.S
+++ b/vm/mterp/armv5te/OP_IPUT_QUICK.S
@@ -1,6 +1,6 @@
 %verify "executed"
 %verify "null object"
-    /* For: iput-quick, iput-object-quick */
+    /* For: iput-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
diff --git a/vm/mterp/armv5te/OP_SPUT.S b/vm/mterp/armv5te/OP_SPUT.S
index c9919ba..e709b22 100644
--- a/vm/mterp/armv5te/OP_SPUT.S
+++ b/vm/mterp/armv5te/OP_SPUT.S
@@ -6,7 +6,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
diff --git a/vm/mterp/armv5te/OP_SPUT_OBJECT.S b/vm/mterp/armv5te/OP_SPUT_OBJECT.S
index 1048982..54a04fc 100644
--- a/vm/mterp/armv5te/OP_SPUT_OBJECT.S
+++ b/vm/mterp/armv5te/OP_SPUT_OBJECT.S
@@ -1,2 +1,38 @@
+%default { "barrier":"@ no-op " }
 %verify "executed"
-%include "armv5te/OP_SPUT.S"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * 32-bit SPUT handler for objects
+     *
+     * for: sput-object, sput-object-volatile
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .L${opcode}_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .L${opcode}_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+%break
+.L${opcode}_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    $barrier                            @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE.S b/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE.S
index cfb2b27..fe12b9e 100644
--- a/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE.S
+++ b/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE.S
@@ -1,2 +1,2 @@
 %verify "executed"
-%include "armv5te/OP_SPUT.S" {"barrier":"SMP_DMB"}
+%include "armv5te/OP_SPUT_OBJECT.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/common/asm-constants.h b/vm/mterp/common/asm-constants.h
index dde675e..bcff8f0 100644
--- a/vm/mterp/common/asm-constants.h
+++ b/vm/mterp/common/asm-constants.h
@@ -97,8 +97,33 @@
 MTERP_OFFSET(offGlue_bailPtr,           MterpGlue, bailPtr, 28)
 MTERP_OFFSET(offGlue_interpStackEnd,    MterpGlue, interpStackEnd, 32)
 MTERP_OFFSET(offGlue_pSelfSuspendCount, MterpGlue, pSelfSuspendCount, 36)
+MTERP_OFFSET(offGlue_cardTable,         MterpGlue, cardTable, 40)
 #if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
-MTERP_OFFSET(offGlue_pDebuggerActive,   MterpGlue, pDebuggerActive, 40)
+MTERP_OFFSET(offGlue_pDebuggerActive,   MterpGlue, pDebuggerActive, 44)
+MTERP_OFFSET(offGlue_pActiveProfilers,  MterpGlue, pActiveProfilers, 48)
+MTERP_OFFSET(offGlue_entryPoint,        MterpGlue, entryPoint, 52)
+#if defined(WITH_JIT)
+MTERP_OFFSET(offGlue_pJitProfTable,     MterpGlue, pJitProfTable, 60)
+MTERP_OFFSET(offGlue_jitState,          MterpGlue, jitState, 64)
+MTERP_OFFSET(offGlue_jitResumeNPC,      MterpGlue, jitResumeNPC, 68)
+MTERP_OFFSET(offGlue_jitResumeDPC,      MterpGlue, jitResumeDPC, 72)
+MTERP_OFFSET(offGlue_jitThreshold,      MterpGlue, jitThreshold, 76)
+MTERP_OFFSET(offGlue_ppJitProfTable,    MterpGlue, ppJitProfTable, 80)
+MTERP_OFFSET(offGlue_icRechainCount,    MterpGlue, icRechainCount, 84)
+#endif
+#elif defined(WITH_DEBUGGER)
+MTERP_OFFSET(offGlue_pDebuggerActive,   MterpGlue, pDebuggerActive, 44)
+MTERP_OFFSET(offGlue_entryPoint,        MterpGlue, entryPoint, 48)
+#if defined(WITH_JIT)
+MTERP_OFFSET(offGlue_pJitProfTable,     MterpGlue, pJitProfTable, 56)
+MTERP_OFFSET(offGlue_jitState,          MterpGlue, jitState, 60)
+MTERP_OFFSET(offGlue_jitResumeNPC,      MterpGlue, jitResumeNPC, 64)
+MTERP_OFFSET(offGlue_jitResumeDPC,      MterpGlue, jitResumeDPC, 68)
+MTERP_OFFSET(offGlue_jitThreshold,      MterpGlue, jitThreshold, 72)
+MTERP_OFFSET(offGlue_ppJitProfTable,    MterpGlue, ppJitProfTable, 76)
+MTERP_OFFSET(offGlue_icRechainCount,    MterpGlue, icRechainCount, 80)
+#endif
+#elif defined(WITH_PROFILER)
 MTERP_OFFSET(offGlue_pActiveProfilers,  MterpGlue, pActiveProfilers, 44)
 MTERP_OFFSET(offGlue_entryPoint,        MterpGlue, entryPoint, 48)
 #if defined(WITH_JIT)
@@ -110,40 +135,16 @@
 MTERP_OFFSET(offGlue_ppJitProfTable,    MterpGlue, ppJitProfTable, 76)
 MTERP_OFFSET(offGlue_icRechainCount,    MterpGlue, icRechainCount, 80)
 #endif
-#elif defined(WITH_DEBUGGER)
-MTERP_OFFSET(offGlue_pDebuggerActive,   MterpGlue, pDebuggerActive, 40)
-MTERP_OFFSET(offGlue_entryPoint,        MterpGlue, entryPoint, 44)
-#if defined(WITH_JIT)
-MTERP_OFFSET(offGlue_pJitProfTable,     MterpGlue, pJitProfTable, 52)
-MTERP_OFFSET(offGlue_jitState,          MterpGlue, jitState, 56)
-MTERP_OFFSET(offGlue_jitResumeNPC,      MterpGlue, jitResumeNPC, 60)
-MTERP_OFFSET(offGlue_jitResumeDPC,      MterpGlue, jitResumeDPC, 64)
-MTERP_OFFSET(offGlue_jitThreshold,      MterpGlue, jitThreshold, 68)
-MTERP_OFFSET(offGlue_ppJitProfTable,    MterpGlue, ppJitProfTable, 72)
-MTERP_OFFSET(offGlue_icRechainCount,    MterpGlue, icRechainCount, 76)
-#endif
-#elif defined(WITH_PROFILER)
-MTERP_OFFSET(offGlue_pActiveProfilers,  MterpGlue, pActiveProfilers, 40)
-MTERP_OFFSET(offGlue_entryPoint,        MterpGlue, entryPoint, 44)
-#if defined(WITH_JIT)
-MTERP_OFFSET(offGlue_pJitProfTable,     MterpGlue, pJitProfTable, 52)
-MTERP_OFFSET(offGlue_jitState,          MterpGlue, jitState, 56)
-MTERP_OFFSET(offGlue_jitResumeNPC,      MterpGlue, jitResumeNPC, 60)
-MTERP_OFFSET(offGlue_jitResumeDPC,      MterpGlue, jitResumeDPC, 64)
-MTERP_OFFSET(offGlue_jitThreshold,      MterpGlue, jitThreshold, 68)
-MTERP_OFFSET(offGlue_ppJitProfTable,    MterpGlue, ppJitProfTable, 72)
-MTERP_OFFSET(offGlue_icRechainCount,    MterpGlue, icRechainCount, 76)
-#endif
 #else
-MTERP_OFFSET(offGlue_entryPoint,        MterpGlue, entryPoint, 40)
+MTERP_OFFSET(offGlue_entryPoint,        MterpGlue, entryPoint, 44)
 #if defined(WITH_JIT)
-MTERP_OFFSET(offGlue_pJitProfTable,     MterpGlue, pJitProfTable, 48)
-MTERP_OFFSET(offGlue_jitState,          MterpGlue, jitState, 52)
-MTERP_OFFSET(offGlue_jitResumeNPC,      MterpGlue, jitResumeNPC, 56)
-MTERP_OFFSET(offGlue_jitResumeDPC,      MterpGlue, jitResumeDPC, 60)
-MTERP_OFFSET(offGlue_jitThreshold,      MterpGlue, jitThreshold, 64)
-MTERP_OFFSET(offGlue_ppJitProfTable,    MterpGlue, ppJitProfTable, 68)
-MTERP_OFFSET(offGlue_icRechainCount,    MterpGlue, icRechainCount, 72)
+MTERP_OFFSET(offGlue_pJitProfTable,     MterpGlue, pJitProfTable, 52)
+MTERP_OFFSET(offGlue_jitState,          MterpGlue, jitState, 56)
+MTERP_OFFSET(offGlue_jitResumeNPC,      MterpGlue, jitResumeNPC, 60)
+MTERP_OFFSET(offGlue_jitResumeDPC,      MterpGlue, jitResumeDPC, 64)
+MTERP_OFFSET(offGlue_jitThreshold,      MterpGlue, jitThreshold, 68)
+MTERP_OFFSET(offGlue_ppJitProfTable,    MterpGlue, ppJitProfTable, 72)
+MTERP_OFFSET(offGlue_icRechainCount,    MterpGlue, icRechainCount, 76)
 #endif
 #endif
 /* make sure all JValue union members are stored at the same offset */
@@ -342,5 +343,8 @@
 /* flags for dvmMalloc */
 MTERP_CONSTANT(ALLOC_DONT_TRACK,    0x01)
 
+/* for GC */
+MTERP_CONSTANT(GC_CARD_SHIFT, 7)
+
 /* opcode number */
 MTERP_CONSTANT(OP_MOVE_EXCEPTION,   0x0d)
diff --git a/vm/mterp/out/InterpAsm-armv4t.S b/vm/mterp/out/InterpAsm-armv4t.S
index 2e7dcc6..d82272f 100644
--- a/vm/mterp/out/InterpAsm-armv4t.S
+++ b/vm/mterp/out/InterpAsm-armv4t.S
@@ -2612,7 +2612,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2656,11 +2656,10 @@
     .balign 64
 .L_OP_IPUT_OBJECT: /* 0x5b */
 /* File: armv5te/OP_IPUT_OBJECT.S */
-/* File: armv5te/OP_IPUT.S */
     /*
-     * General 32-bit instance field put.
+     * 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput-object, iput-object-volatile
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2679,7 +2678,6 @@
     bne     .LOP_IPUT_OBJECT_finish          @ yes, finish up
     b       common_exceptionThrown
 
-
 /* ------------------------------ */
     .balign 64
 .L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2689,7 +2687,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2718,7 +2716,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2747,7 +2745,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2776,7 +2774,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2991,7 +2989,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3041,11 +3039,10 @@
     .balign 64
 .L_OP_SPUT_OBJECT: /* 0x69 */
 /* File: armv5te/OP_SPUT_OBJECT.S */
-/* File: armv5te/OP_SPUT.S */
     /*
-     * General 32-bit SPUT handler.
+     * 32-bit SPUT handler for objects
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput-object, sput-object-volatile
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3053,15 +3050,14 @@
     ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
     ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
     cmp     r0, #0                      @ is resolved entry null?
-    beq     .LOP_SPUT_OBJECT_resolve         @ yes, do resolve
-.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
-    mov     r2, rINST, lsr #8           @ r2<- AA
-    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
-    GET_VREG(r1, r2)                    @ r1<- fp[AA]
-    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    @ no-op                             @ releasing store
-    str     r1, [r0, #offStaticField_value] @ field<- vAA
-    GOTO_OPCODE(ip)                     @ jump to next instruction
+    bne     .LOP_SPUT_OBJECT_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
 
 
 /* ------------------------------ */
@@ -3072,7 +3068,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3099,7 +3095,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3126,7 +3122,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3153,7 +3149,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7455,7 +7451,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -7510,7 +7506,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7833,7 +7829,7 @@
     .balign 64
 .L_OP_IPUT_QUICK: /* 0xf5 */
 /* File: armv5te/OP_IPUT_QUICK.S */
-    /* For: iput-quick, iput-object-quick */
+    /* For: iput-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
@@ -7872,8 +7868,7 @@
     .balign 64
 .L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
 /* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
-/* File: armv5te/OP_IPUT_QUICK.S */
-    /* For: iput-quick, iput-object-quick */
+    /* For: iput-object-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
@@ -7883,12 +7878,14 @@
     beq     common_errNullObject        @ object was null
     and     r2, r2, #15
     GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
-
 /* ------------------------------ */
     .balign 64
 .L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -8001,11 +7998,11 @@
     .balign 64
 .L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
 /* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
-/* File: armv5te/OP_IPUT.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
     /*
-     * General 32-bit instance field put.
+     * 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput-object, iput-object-volatile
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -8056,11 +8053,11 @@
     .balign 64
 .L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
 /* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
-/* File: armv5te/OP_SPUT.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
     /*
-     * General 32-bit SPUT handler.
+     * 32-bit SPUT handler for objects
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput-object, sput-object-volatile
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -8068,15 +8065,15 @@
     ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
     ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
     cmp     r0, #0                      @ is resolved entry null?
-    beq     .LOP_SPUT_OBJECT_VOLATILE_resolve         @ yes, do resolve
-.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
-    mov     r2, rINST, lsr #8           @ r2<- AA
-    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
-    GET_VREG(r1, r2)                    @ r1<- fp[AA]
-    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    SMP_DMB                            @ releasing store
-    str     r1, [r0, #offStaticField_value] @ field<- vAA
-    GOTO_OPCODE(ip)                     @ jump to next instruction
+    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
 
 
 /* ------------------------------ */
@@ -8352,15 +8349,15 @@
 .LOP_FILLED_NEW_ARRAY_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     0
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .LOP_FILLED_NEW_ARRAY_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -8368,7 +8365,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -8400,8 +8398,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
@@ -8430,15 +8433,15 @@
 .LOP_FILLED_NEW_ARRAY_RANGE_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     1
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .LOP_FILLED_NEW_ARRAY_RANGE_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -8446,7 +8449,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -8478,8 +8482,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
@@ -8711,6 +8720,13 @@
     bl      dvmCanPutArrayElement       @ test object type vs. array type
     cmp     r0, #0                      @ okay?
     beq     common_errArrayStore        @ no
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rGLUE, #offGlue_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r10, lsr #GC_CARD_SHIFT]    @ mark card
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 .LOP_APUT_OBJECT_skip_check:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
@@ -8929,11 +8945,15 @@
     and     r1, r1, #15                 @ r1<- A
     cmp     r9, #0                      @ check object for null
     GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     beq     common_errNullObject        @ object was null
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     @ no-op                             @ releasing store
-    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_IPUT_BOOLEAN */
@@ -9162,19 +9182,18 @@
     b       common_exceptionThrown      @ no, handle exception
 
 /* continuation for OP_SPUT_OBJECT */
-
-    /*
-     * Continuation if the field has not yet been resolved.
-     *  r1: BBBB field ref
-     */
-.LOP_SPUT_OBJECT_resolve:
-    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
-    EXPORT_PC()                         @ resolve() could throw, so export now
-    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
-    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
-    cmp     r0, #0                      @ success?
-    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
-    b       common_exceptionThrown      @ no, handle exception
+.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    @ no-op                             @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_SPUT_BOOLEAN */
 
@@ -9769,11 +9788,15 @@
     and     r1, r1, #15                 @ r1<- A
     cmp     r9, #0                      @ check object for null
     GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     beq     common_errNullObject        @ object was null
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     SMP_DMB                            @ releasing store
-    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_SGET_OBJECT_VOLATILE */
@@ -9792,19 +9815,18 @@
     b       common_exceptionThrown      @ no, handle exception
 
 /* continuation for OP_SPUT_OBJECT_VOLATILE */
-
-    /*
-     * Continuation if the field has not yet been resolved.
-     *  r1: BBBB field ref
-     */
-.LOP_SPUT_OBJECT_VOLATILE_resolve:
-    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
-    EXPORT_PC()                         @ resolve() could throw, so export now
-    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
-    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
-    cmp     r0, #0                      @ success?
-    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ yes, finish
-    b       common_exceptionThrown      @ no, handle exception
+.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    SMP_DMB                            @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 
     .size   dvmAsmSisterStart, .-dvmAsmSisterStart
     .global dvmAsmSisterEnd
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
index 2e86a7f..633a32d 100644
--- a/vm/mterp/out/InterpAsm-armv5te-vfp.S
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -2592,7 +2592,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2636,11 +2636,10 @@
     .balign 64
 .L_OP_IPUT_OBJECT: /* 0x5b */
 /* File: armv5te/OP_IPUT_OBJECT.S */
-/* File: armv5te/OP_IPUT.S */
     /*
-     * General 32-bit instance field put.
+     * 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput-object, iput-object-volatile
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2659,7 +2658,6 @@
     bne     .LOP_IPUT_OBJECT_finish          @ yes, finish up
     b       common_exceptionThrown
 
-
 /* ------------------------------ */
     .balign 64
 .L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2669,7 +2667,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2698,7 +2696,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2727,7 +2725,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2756,7 +2754,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2971,7 +2969,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3021,11 +3019,10 @@
     .balign 64
 .L_OP_SPUT_OBJECT: /* 0x69 */
 /* File: armv5te/OP_SPUT_OBJECT.S */
-/* File: armv5te/OP_SPUT.S */
     /*
-     * General 32-bit SPUT handler.
+     * 32-bit SPUT handler for objects
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput-object, sput-object-volatile
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3033,15 +3030,14 @@
     ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
     ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
     cmp     r0, #0                      @ is resolved entry null?
-    beq     .LOP_SPUT_OBJECT_resolve         @ yes, do resolve
-.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
-    mov     r2, rINST, lsr #8           @ r2<- AA
-    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
-    GET_VREG(r1, r2)                    @ r1<- fp[AA]
-    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    @ no-op                             @ releasing store
-    str     r1, [r0, #offStaticField_value] @ field<- vAA
-    GOTO_OPCODE(ip)                     @ jump to next instruction
+    bne     .LOP_SPUT_OBJECT_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
 
 
 /* ------------------------------ */
@@ -3052,7 +3048,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3079,7 +3075,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3106,7 +3102,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3133,7 +3129,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7135,7 +7131,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -7190,7 +7186,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7512,7 +7508,7 @@
     .balign 64
 .L_OP_IPUT_QUICK: /* 0xf5 */
 /* File: armv5te/OP_IPUT_QUICK.S */
-    /* For: iput-quick, iput-object-quick */
+    /* For: iput-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
@@ -7550,8 +7546,7 @@
     .balign 64
 .L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
 /* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
-/* File: armv5te/OP_IPUT_QUICK.S */
-    /* For: iput-quick, iput-object-quick */
+    /* For: iput-object-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
@@ -7561,12 +7556,14 @@
     beq     common_errNullObject        @ object was null
     and     r2, r2, #15
     GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
-
 /* ------------------------------ */
     .balign 64
 .L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -7679,11 +7676,11 @@
     .balign 64
 .L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
 /* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
-/* File: armv5te/OP_IPUT.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
     /*
-     * General 32-bit instance field put.
+     * 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput-object, iput-object-volatile
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -7734,11 +7731,11 @@
     .balign 64
 .L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
 /* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
-/* File: armv5te/OP_SPUT.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
     /*
-     * General 32-bit SPUT handler.
+     * 32-bit SPUT handler for objects
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput-object, sput-object-volatile
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7746,15 +7743,15 @@
     ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
     ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
     cmp     r0, #0                      @ is resolved entry null?
-    beq     .LOP_SPUT_OBJECT_VOLATILE_resolve         @ yes, do resolve
-.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
-    mov     r2, rINST, lsr #8           @ r2<- AA
-    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
-    GET_VREG(r1, r2)                    @ r1<- fp[AA]
-    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    SMP_DMB                            @ releasing store
-    str     r1, [r0, #offStaticField_value] @ field<- vAA
-    GOTO_OPCODE(ip)                     @ jump to next instruction
+    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
 
 
 /* ------------------------------ */
@@ -8030,15 +8027,15 @@
 .LOP_FILLED_NEW_ARRAY_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     0
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .LOP_FILLED_NEW_ARRAY_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -8046,7 +8043,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -8078,8 +8076,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
@@ -8108,15 +8111,15 @@
 .LOP_FILLED_NEW_ARRAY_RANGE_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     1
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .LOP_FILLED_NEW_ARRAY_RANGE_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -8124,7 +8127,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -8156,8 +8160,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
@@ -8251,6 +8260,13 @@
     bl      dvmCanPutArrayElement       @ test object type vs. array type
     cmp     r0, #0                      @ okay?
     beq     common_errArrayStore        @ no
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rGLUE, #offGlue_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r10, lsr #GC_CARD_SHIFT]    @ mark card
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 .LOP_APUT_OBJECT_skip_check:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
@@ -8468,11 +8484,15 @@
     and     r1, r1, #15                 @ r1<- A
     cmp     r9, #0                      @ check object for null
     GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     beq     common_errNullObject        @ object was null
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     @ no-op                             @ releasing store
-    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_IPUT_BOOLEAN */
@@ -8701,19 +8721,18 @@
     b       common_exceptionThrown      @ no, handle exception
 
 /* continuation for OP_SPUT_OBJECT */
-
-    /*
-     * Continuation if the field has not yet been resolved.
-     *  r1: BBBB field ref
-     */
-.LOP_SPUT_OBJECT_resolve:
-    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
-    EXPORT_PC()                         @ resolve() could throw, so export now
-    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
-    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
-    cmp     r0, #0                      @ success?
-    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
-    b       common_exceptionThrown      @ no, handle exception
+.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    @ no-op                             @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_SPUT_BOOLEAN */
 
@@ -9307,11 +9326,15 @@
     and     r1, r1, #15                 @ r1<- A
     cmp     r9, #0                      @ check object for null
     GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     beq     common_errNullObject        @ object was null
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     SMP_DMB                            @ releasing store
-    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_SGET_OBJECT_VOLATILE */
@@ -9330,19 +9353,18 @@
     b       common_exceptionThrown      @ no, handle exception
 
 /* continuation for OP_SPUT_OBJECT_VOLATILE */
-
-    /*
-     * Continuation if the field has not yet been resolved.
-     *  r1: BBBB field ref
-     */
-.LOP_SPUT_OBJECT_VOLATILE_resolve:
-    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
-    EXPORT_PC()                         @ resolve() could throw, so export now
-    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
-    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
-    cmp     r0, #0                      @ success?
-    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ yes, finish
-    b       common_exceptionThrown      @ no, handle exception
+.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    SMP_DMB                            @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 
     .size   dvmAsmSisterStart, .-dvmAsmSisterStart
     .global dvmAsmSisterEnd
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index feb908c..66f3a3d 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -2614,7 +2614,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2658,11 +2658,10 @@
     .balign 64
 .L_OP_IPUT_OBJECT: /* 0x5b */
 /* File: armv5te/OP_IPUT_OBJECT.S */
-/* File: armv5te/OP_IPUT.S */
     /*
-     * General 32-bit instance field put.
+     * 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput-object, iput-object-volatile
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2681,7 +2680,6 @@
     bne     .LOP_IPUT_OBJECT_finish          @ yes, finish up
     b       common_exceptionThrown
 
-
 /* ------------------------------ */
     .balign 64
 .L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2691,7 +2689,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2720,7 +2718,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2749,7 +2747,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2778,7 +2776,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2993,7 +2991,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3043,11 +3041,10 @@
     .balign 64
 .L_OP_SPUT_OBJECT: /* 0x69 */
 /* File: armv5te/OP_SPUT_OBJECT.S */
-/* File: armv5te/OP_SPUT.S */
     /*
-     * General 32-bit SPUT handler.
+     * 32-bit SPUT handler for objects
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput-object, sput-object-volatile
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3055,15 +3052,14 @@
     ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
     ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
     cmp     r0, #0                      @ is resolved entry null?
-    beq     .LOP_SPUT_OBJECT_resolve         @ yes, do resolve
-.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
-    mov     r2, rINST, lsr #8           @ r2<- AA
-    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
-    GET_VREG(r1, r2)                    @ r1<- fp[AA]
-    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    @ no-op                             @ releasing store
-    str     r1, [r0, #offStaticField_value] @ field<- vAA
-    GOTO_OPCODE(ip)                     @ jump to next instruction
+    bne     .LOP_SPUT_OBJECT_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
 
 
 /* ------------------------------ */
@@ -3074,7 +3070,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3101,7 +3097,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3128,7 +3124,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3155,7 +3151,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7457,7 +7453,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -7512,7 +7508,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7834,7 +7830,7 @@
     .balign 64
 .L_OP_IPUT_QUICK: /* 0xf5 */
 /* File: armv5te/OP_IPUT_QUICK.S */
-    /* For: iput-quick, iput-object-quick */
+    /* For: iput-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
@@ -7872,8 +7868,7 @@
     .balign 64
 .L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
 /* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
-/* File: armv5te/OP_IPUT_QUICK.S */
-    /* For: iput-quick, iput-object-quick */
+    /* For: iput-object-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
@@ -7883,12 +7878,14 @@
     beq     common_errNullObject        @ object was null
     and     r2, r2, #15
     GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
-
 /* ------------------------------ */
     .balign 64
 .L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -8001,11 +7998,11 @@
     .balign 64
 .L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
 /* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
-/* File: armv5te/OP_IPUT.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
     /*
-     * General 32-bit instance field put.
+     * 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput-object, iput-object-volatile
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -8056,11 +8053,11 @@
     .balign 64
 .L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
 /* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
-/* File: armv5te/OP_SPUT.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
     /*
-     * General 32-bit SPUT handler.
+     * 32-bit SPUT handler for objects
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput-object, sput-object-volatile
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -8068,15 +8065,15 @@
     ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
     ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
     cmp     r0, #0                      @ is resolved entry null?
-    beq     .LOP_SPUT_OBJECT_VOLATILE_resolve         @ yes, do resolve
-.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
-    mov     r2, rINST, lsr #8           @ r2<- AA
-    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
-    GET_VREG(r1, r2)                    @ r1<- fp[AA]
-    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    SMP_DMB                            @ releasing store
-    str     r1, [r0, #offStaticField_value] @ field<- vAA
-    GOTO_OPCODE(ip)                     @ jump to next instruction
+    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
 
 
 /* ------------------------------ */
@@ -8352,15 +8349,15 @@
 .LOP_FILLED_NEW_ARRAY_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     0
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .LOP_FILLED_NEW_ARRAY_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -8368,7 +8365,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -8400,8 +8398,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
@@ -8430,15 +8433,15 @@
 .LOP_FILLED_NEW_ARRAY_RANGE_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     1
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .LOP_FILLED_NEW_ARRAY_RANGE_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -8446,7 +8449,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -8478,8 +8482,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
@@ -8709,6 +8718,13 @@
     bl      dvmCanPutArrayElement       @ test object type vs. array type
     cmp     r0, #0                      @ okay?
     beq     common_errArrayStore        @ no
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rGLUE, #offGlue_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r10, lsr #GC_CARD_SHIFT]    @ mark card
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 .LOP_APUT_OBJECT_skip_check:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
@@ -8926,11 +8942,15 @@
     and     r1, r1, #15                 @ r1<- A
     cmp     r9, #0                      @ check object for null
     GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     beq     common_errNullObject        @ object was null
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     @ no-op                             @ releasing store
-    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_IPUT_BOOLEAN */
@@ -9159,19 +9179,18 @@
     b       common_exceptionThrown      @ no, handle exception
 
 /* continuation for OP_SPUT_OBJECT */
-
-    /*
-     * Continuation if the field has not yet been resolved.
-     *  r1: BBBB field ref
-     */
-.LOP_SPUT_OBJECT_resolve:
-    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
-    EXPORT_PC()                         @ resolve() could throw, so export now
-    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
-    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
-    cmp     r0, #0                      @ success?
-    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
-    b       common_exceptionThrown      @ no, handle exception
+.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    @ no-op                             @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_SPUT_BOOLEAN */
 
@@ -9765,11 +9784,15 @@
     and     r1, r1, #15                 @ r1<- A
     cmp     r9, #0                      @ check object for null
     GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     beq     common_errNullObject        @ object was null
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     SMP_DMB                            @ releasing store
-    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_SGET_OBJECT_VOLATILE */
@@ -9788,19 +9811,18 @@
     b       common_exceptionThrown      @ no, handle exception
 
 /* continuation for OP_SPUT_OBJECT_VOLATILE */
-
-    /*
-     * Continuation if the field has not yet been resolved.
-     *  r1: BBBB field ref
-     */
-.LOP_SPUT_OBJECT_VOLATILE_resolve:
-    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
-    EXPORT_PC()                         @ resolve() could throw, so export now
-    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
-    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
-    cmp     r0, #0                      @ success?
-    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ yes, finish
-    b       common_exceptionThrown      @ no, handle exception
+.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    SMP_DMB                            @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 
     .size   dvmAsmSisterStart, .-dvmAsmSisterStart
     .global dvmAsmSisterEnd
diff --git a/vm/mterp/out/InterpAsm-armv7-a-neon.S b/vm/mterp/out/InterpAsm-armv7-a-neon.S
index f573a40..e837dda 100644
--- a/vm/mterp/out/InterpAsm-armv7-a-neon.S
+++ b/vm/mterp/out/InterpAsm-armv7-a-neon.S
@@ -2636,11 +2636,10 @@
     .balign 64
 .L_OP_IPUT_OBJECT: /* 0x5b */
 /* File: armv5te/OP_IPUT_OBJECT.S */
-/* File: armv5te/OP_IPUT.S */
     /*
-     * General 32-bit instance field put.
+     * 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput-object, iput-object-volatile
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2659,7 +2658,6 @@
     bne     .LOP_IPUT_OBJECT_finish          @ yes, finish up
     b       common_exceptionThrown
 
-
 /* ------------------------------ */
     .balign 64
 .L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2669,7 +2667,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2698,7 +2696,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2727,7 +2725,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2756,7 +2754,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2971,7 +2969,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3021,11 +3019,10 @@
     .balign 64
 .L_OP_SPUT_OBJECT: /* 0x69 */
 /* File: armv5te/OP_SPUT_OBJECT.S */
-/* File: armv5te/OP_SPUT.S */
     /*
-     * General 32-bit SPUT handler.
+     * 32-bit SPUT handler for objects
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput-object, sput-object-volatile
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3033,15 +3030,14 @@
     ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
     ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
     cmp     r0, #0                      @ is resolved entry null?
-    beq     .LOP_SPUT_OBJECT_resolve         @ yes, do resolve
-.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
-    mov     r2, rINST, lsr #8           @ r2<- AA
-    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
-    GET_VREG(r1, r2)                    @ r1<- fp[AA]
-    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    @ no-op                             @ releasing store
-    str     r1, [r0, #offStaticField_value] @ field<- vAA
-    GOTO_OPCODE(ip)                     @ jump to next instruction
+    bne     .LOP_SPUT_OBJECT_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
 
 
 /* ------------------------------ */
@@ -3052,7 +3048,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3079,7 +3075,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3106,7 +3102,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3133,7 +3129,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7089,7 +7085,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -7144,7 +7140,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7500,8 +7496,7 @@
     .balign 64
 .L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
 /* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
-/* File: armv5te/OP_IPUT_QUICK.S */
-    /* For: iput-quick, iput-object-quick */
+    /* For: iput-object-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
@@ -7511,12 +7506,14 @@
     beq     common_errNullObject        @ object was null
     and     r2, r2, #15
     GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
-
 /* ------------------------------ */
     .balign 64
 .L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -7629,11 +7626,11 @@
     .balign 64
 .L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
 /* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
-/* File: armv5te/OP_IPUT.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
     /*
-     * General 32-bit instance field put.
+     * 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput-object, iput-object-volatile
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -7684,11 +7681,11 @@
     .balign 64
 .L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
 /* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
-/* File: armv5te/OP_SPUT.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
     /*
-     * General 32-bit SPUT handler.
+     * 32-bit SPUT handler for objects
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput-object, sput-object-volatile
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7696,15 +7693,15 @@
     ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
     ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
     cmp     r0, #0                      @ is resolved entry null?
-    beq     .LOP_SPUT_OBJECT_VOLATILE_resolve         @ yes, do resolve
-.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
-    mov     r2, rINST, lsr #8           @ r2<- AA
-    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
-    GET_VREG(r1, r2)                    @ r1<- fp[AA]
-    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    SMP_DMB                            @ releasing store
-    str     r1, [r0, #offStaticField_value] @ field<- vAA
-    GOTO_OPCODE(ip)                     @ jump to next instruction
+    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
 
 
 /* ------------------------------ */
@@ -7980,15 +7977,15 @@
 .LOP_FILLED_NEW_ARRAY_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     0
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .LOP_FILLED_NEW_ARRAY_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -7996,7 +7993,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -8028,8 +8026,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
@@ -8058,15 +8061,15 @@
 .LOP_FILLED_NEW_ARRAY_RANGE_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     1
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .LOP_FILLED_NEW_ARRAY_RANGE_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -8074,7 +8077,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -8106,8 +8110,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
@@ -8201,6 +8210,13 @@
     bl      dvmCanPutArrayElement       @ test object type vs. array type
     cmp     r0, #0                      @ okay?
     beq     common_errArrayStore        @ no
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rGLUE, #offGlue_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r10, lsr #GC_CARD_SHIFT]    @ mark card
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 .LOP_APUT_OBJECT_skip_check:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
@@ -8402,11 +8418,15 @@
     and     r1, r1, #15                 @ r1<- A
     cmp     r9, #0                      @ check object for null
     GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     beq     common_errNullObject        @ object was null
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     @ no-op                             @ releasing store
-    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_IPUT_BOOLEAN */
@@ -8635,19 +8655,18 @@
     b       common_exceptionThrown      @ no, handle exception
 
 /* continuation for OP_SPUT_OBJECT */
-
-    /*
-     * Continuation if the field has not yet been resolved.
-     *  r1: BBBB field ref
-     */
-.LOP_SPUT_OBJECT_resolve:
-    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
-    EXPORT_PC()                         @ resolve() could throw, so export now
-    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
-    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
-    cmp     r0, #0                      @ success?
-    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
-    b       common_exceptionThrown      @ no, handle exception
+.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    @ no-op                             @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_SPUT_BOOLEAN */
 
@@ -9241,11 +9260,15 @@
     and     r1, r1, #15                 @ r1<- A
     cmp     r9, #0                      @ check object for null
     GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     beq     common_errNullObject        @ object was null
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     SMP_DMB                            @ releasing store
-    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_SGET_OBJECT_VOLATILE */
@@ -9264,19 +9287,18 @@
     b       common_exceptionThrown      @ no, handle exception
 
 /* continuation for OP_SPUT_OBJECT_VOLATILE */
-
-    /*
-     * Continuation if the field has not yet been resolved.
-     *  r1: BBBB field ref
-     */
-.LOP_SPUT_OBJECT_VOLATILE_resolve:
-    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
-    EXPORT_PC()                         @ resolve() could throw, so export now
-    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
-    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
-    cmp     r0, #0                      @ success?
-    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ yes, finish
-    b       common_exceptionThrown      @ no, handle exception
+.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    SMP_DMB                            @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 
     .size   dvmAsmSisterStart, .-dvmAsmSisterStart
     .global dvmAsmSisterEnd
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
index 32484e2..dc33638 100644
--- a/vm/mterp/out/InterpAsm-armv7-a.S
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -2636,11 +2636,10 @@
     .balign 64
 .L_OP_IPUT_OBJECT: /* 0x5b */
 /* File: armv5te/OP_IPUT_OBJECT.S */
-/* File: armv5te/OP_IPUT.S */
     /*
-     * General 32-bit instance field put.
+     * 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput-object, iput-object-volatile
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2659,7 +2658,6 @@
     bne     .LOP_IPUT_OBJECT_finish          @ yes, finish up
     b       common_exceptionThrown
 
-
 /* ------------------------------ */
     .balign 64
 .L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2669,7 +2667,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2698,7 +2696,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2727,7 +2725,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2756,7 +2754,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -2971,7 +2969,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3021,11 +3019,10 @@
     .balign 64
 .L_OP_SPUT_OBJECT: /* 0x69 */
 /* File: armv5te/OP_SPUT_OBJECT.S */
-/* File: armv5te/OP_SPUT.S */
     /*
-     * General 32-bit SPUT handler.
+     * 32-bit SPUT handler for objects
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput-object, sput-object-volatile
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3033,15 +3030,14 @@
     ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
     ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
     cmp     r0, #0                      @ is resolved entry null?
-    beq     .LOP_SPUT_OBJECT_resolve         @ yes, do resolve
-.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
-    mov     r2, rINST, lsr #8           @ r2<- AA
-    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
-    GET_VREG(r1, r2)                    @ r1<- fp[AA]
-    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    @ no-op                             @ releasing store
-    str     r1, [r0, #offStaticField_value] @ field<- vAA
-    GOTO_OPCODE(ip)                     @ jump to next instruction
+    bne     .LOP_SPUT_OBJECT_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
 
 
 /* ------------------------------ */
@@ -3052,7 +3048,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3079,7 +3075,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3106,7 +3102,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -3133,7 +3129,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7089,7 +7085,7 @@
     /*
      * General 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -7144,7 +7140,7 @@
     /*
      * General 32-bit SPUT handler.
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7500,8 +7496,7 @@
     .balign 64
 .L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
 /* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
-/* File: armv5te/OP_IPUT_QUICK.S */
-    /* For: iput-quick, iput-object-quick */
+    /* For: iput-object-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
@@ -7511,12 +7506,14 @@
     beq     common_errNullObject        @ object was null
     and     r2, r2, #15
     GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
-
 /* ------------------------------ */
     .balign 64
 .L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -7629,11 +7626,11 @@
     .balign 64
 .L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
 /* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
-/* File: armv5te/OP_IPUT.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
     /*
-     * General 32-bit instance field put.
+     * 32-bit instance field put.
      *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * for: iput-object, iput-object-volatile
      */
     /* op vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
@@ -7684,11 +7681,11 @@
     .balign 64
 .L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
 /* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
-/* File: armv5te/OP_SPUT.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
     /*
-     * General 32-bit SPUT handler.
+     * 32-bit SPUT handler for objects
      *
-     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     * for: sput-object, sput-object-volatile
      */
     /* op vAA, field@BBBB */
     ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
@@ -7696,15 +7693,15 @@
     ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
     ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
     cmp     r0, #0                      @ is resolved entry null?
-    beq     .LOP_SPUT_OBJECT_VOLATILE_resolve         @ yes, do resolve
-.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
-    mov     r2, rINST, lsr #8           @ r2<- AA
-    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
-    GET_VREG(r1, r2)                    @ r1<- fp[AA]
-    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    SMP_DMB                            @ releasing store
-    str     r1, [r0, #offStaticField_value] @ field<- vAA
-    GOTO_OPCODE(ip)                     @ jump to next instruction
+    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ no, continue
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
 
 
 /* ------------------------------ */
@@ -7980,15 +7977,15 @@
 .LOP_FILLED_NEW_ARRAY_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     0
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .LOP_FILLED_NEW_ARRAY_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -7996,7 +7993,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -8028,8 +8026,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
@@ -8058,15 +8061,15 @@
 .LOP_FILLED_NEW_ARRAY_RANGE_continue:
     ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
     mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
-    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
     .if     1
     mov     r1, r10                     @ r1<- AA (length)
     .else
     mov     r1, r10, lsr #4             @ r1<- B (length)
     .endif
-    cmp     r3, #'I'                    @ array of ints?
-    cmpne   r3, #'L'                    @ array of objects?
-    cmpne   r3, #'['                    @ array of arrays?
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
     mov     r9, r1                      @ save length in r9
     bne     .LOP_FILLED_NEW_ARRAY_RANGE_notimpl         @ no, not handled yet
     bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
@@ -8074,7 +8077,8 @@
     beq     common_exceptionThrown      @ alloc failed, handle exception
 
     FETCH(r1, 2)                        @ r1<- FEDC or CCCC
-    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    str     r0, [rGLUE, #offGlue_retval]      @ retval.l <- new array
+    str     rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
     add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
     subs    r9, r9, #1                  @ length--, check for neg
     FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
@@ -8106,8 +8110,13 @@
     .endif
 
 2:
-    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
-    GOTO_OPCODE(ip)                     @ execute it
+    ldr     r0, [rGLUE, #offGlue_retval]     @ r0<- object
+    ldr     r1, [rGLUE, #offGlue_retval+4]   @ r1<- type
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+    GOTO_OPCODE(ip)                          @ execute it
 
     /*
      * Throw an exception indicating that we have not implemented this
@@ -8201,6 +8210,13 @@
     bl      dvmCanPutArrayElement       @ test object type vs. array type
     cmp     r0, #0                      @ okay?
     beq     common_errArrayStore        @ no
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rGLUE, #offGlue_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r10, lsr #GC_CARD_SHIFT]    @ mark card
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 .LOP_APUT_OBJECT_skip_check:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
@@ -8402,11 +8418,15 @@
     and     r1, r1, #15                 @ r1<- A
     cmp     r9, #0                      @ check object for null
     GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     beq     common_errNullObject        @ object was null
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     @ no-op                             @ releasing store
-    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_IPUT_BOOLEAN */
@@ -8635,19 +8655,18 @@
     b       common_exceptionThrown      @ no, handle exception
 
 /* continuation for OP_SPUT_OBJECT */
-
-    /*
-     * Continuation if the field has not yet been resolved.
-     *  r1: BBBB field ref
-     */
-.LOP_SPUT_OBJECT_resolve:
-    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
-    EXPORT_PC()                         @ resolve() could throw, so export now
-    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
-    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
-    cmp     r0, #0                      @ success?
-    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
-    b       common_exceptionThrown      @ no, handle exception
+.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    @ no-op                             @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_SPUT_BOOLEAN */
 
@@ -9241,11 +9260,15 @@
     and     r1, r1, #15                 @ r1<- A
     cmp     r9, #0                      @ check object for null
     GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
     beq     common_errNullObject        @ object was null
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r9, r3                      @ r9<- direct ptr to target location
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     SMP_DMB                            @ releasing store
-    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    str     r0, [r9]                    @ obj.field (8/16/32 bits)<- r0
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
     GOTO_OPCODE(ip)                     @ jump to next instruction
 
 /* continuation for OP_SGET_OBJECT_VOLATILE */
@@ -9264,19 +9287,18 @@
     b       common_exceptionThrown      @ no, handle exception
 
 /* continuation for OP_SPUT_OBJECT_VOLATILE */
-
-    /*
-     * Continuation if the field has not yet been resolved.
-     *  r1: BBBB field ref
-     */
-.LOP_SPUT_OBJECT_VOLATILE_resolve:
-    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
-    EXPORT_PC()                         @ resolve() could throw, so export now
-    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
-    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
-    cmp     r0, #0                      @ success?
-    bne     .LOP_SPUT_OBJECT_VOLATILE_finish          @ yes, finish
-    b       common_exceptionThrown      @ no, handle exception
+.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rGLUE, #offGlue_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    add     r0, #offStaticField_value   @ r0<- pointer to store target
+    SMP_DMB                            @ releasing store
+    str     r1, [r0]                    @ field<- vAA
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
 
     .size   dvmAsmSisterStart, .-dvmAsmSisterStart
     .global dvmAsmSisterEnd
diff --git a/vm/mterp/x86-atom/TODO.txt b/vm/mterp/x86-atom/TODO.txt
index 5b89db9..abeee31 100644
--- a/vm/mterp/x86-atom/TODO.txt
+++ b/vm/mterp/x86-atom/TODO.txt
@@ -1,5 +1,6 @@
 Items requiring attention:
 
+(hi) Add gc card marking to aput/iput/sput/new_filled_array
 (hi) Correct stack overflow handling (dvmCleanupStackOverflow takes an
      additional argument now)
 (hi) "debugger active" test in common_periodicChecks must handle