Made Self Verification mode's memory interface less intrusive.
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index f5178d8..00892fa 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -151,6 +151,7 @@
     bool halveInstCount;
     bool executionCount;                // Add code to count trace executions
     bool hasLoop;
+    bool heapMemOp;                     // Mark mem ops for self verification
     int numChainingCells[kChainingCellGap];
     LIR *firstChainingLIR[kChainingCellGap];
     LIR *chainingCellBottom;
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index 347bc50..c8e8e52 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -300,7 +300,7 @@
     CompilerMethodStats *methodStats;
 
     /* If we've already compiled this trace, just return success */
-    if (dvmJitGetCodeAddr(startCodePtr)) {
+    if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
         return true;
     }
 
diff --git a/vm/compiler/codegen/arm/ArmLIR.h b/vm/compiler/codegen/arm/ArmLIR.h
index 21e2a32..b329aed 100644
--- a/vm/compiler/codegen/arm/ArmLIR.h
+++ b/vm/compiler/codegen/arm/ArmLIR.h
@@ -723,6 +723,8 @@
     ArmOpCode opCode;
     int operands[4];    // [0..3] = [dest, src1, src2, extra]
     bool isNop;         // LIR is optimized away
+    bool branchInsertSV;// mark for insertion of branch before this instruction,
+                        // used to identify mem ops for self verification mode
     int age;            // default is 0, set lazily by the optimizer
     int size;           // 16-bit unit size (1 for thumb, 1 or 2 for thumb2)
     int aliasInfo;      // For Dalvik register access disambiguation
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index c3ad957..5cb8ff6 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -1841,3 +1841,519 @@
     dvmUnlockMutex(&gDvmJit.tableLock);
     return;
 }
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * The following are used to keep compiled loads and stores from modifying
+ * memory during self verification mode.
+ *
+ * Stores do not modify memory. Instead, the address and value pair are stored
+ * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
+ * than a word, the word containing the address is loaded first before being
+ * updated.
+ *
+ * Loads check heapSpace first and return data from there if an entry exists.
+ * Otherwise, data is loaded from memory as usual.
+ */
+
+/* Used to specify sizes of memory operations */
+enum {
+    kSVByte,
+    kSVSignedByte,
+    kSVHalfword,
+    kSVSignedHalfword,
+    kSVWord,
+    kSVDoubleword,
+};
+
+/* Load the value of a decoded register from the stack */
+static int selfVerificationMemRegLoad(int* sp, int reg)
+{
+    return *(sp + reg);
+}
+
+/* Load the value of a decoded doubleword register from the stack */
+static s8 selfVerificationMemRegLoadDouble(int* sp, int reg)
+{
+    return *((s8*)(sp + reg));
+}
+
+/* Store the value of a decoded register out to the stack */
+static void selfVerificationMemRegStore(int* sp, int data, int reg)
+{
+    *(sp + reg) = data;
+}
+
+/* Store the value of a decoded doubleword register out to the stack */
+static void selfVerificationMemRegStoreDouble(int* sp, s8 data, int reg)
+{
+    *((s8*)(sp + reg)) = data;
+}
+
+/*
+ * Load the specified size of data from the specified address, checking
+ * heapSpace first if Self Verification mode wrote to it previously, and
+ * falling back to actual memory otherwise.
+ */
+static int selfVerificationLoad(int addr, int size)
+{
+    Thread *self = dvmThreadSelf();
+    ShadowSpace *shadowSpace = self->shadowSpace;
+    ShadowHeap *heapSpacePtr;
+
+    int data;
+    int maskedAddr = addr & 0xFFFFFFFC;
+    int alignment = addr & 0x3;
+
+    for (heapSpacePtr = shadowSpace->heapSpace;
+         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+        if (heapSpacePtr->addr == maskedAddr) {
+            addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
+            break;
+        }
+    }
+
+    switch (size) {
+        case kSVByte:
+            data = *((u1*) addr);
+            break;
+        case kSVSignedByte:
+            data = *((s1*) addr);
+            break;
+        case kSVHalfword:
+            data = *((u2*) addr);
+            break;
+        case kSVSignedHalfword:
+            data = *((s2*) addr);
+            break;
+        case kSVWord:
+            data = *((u4*) addr);
+    }
+
+    //LOGD("*** HEAP LOAD: Addr: 0x%x Data: 0x%x Size: %d", addr, data, size);
+    return data;
+}
+
+/* Like selfVerificationLoad, but specifically for doublewords */
+static s8 selfVerificationLoadDoubleword(int addr)
+{
+    Thread *self = dvmThreadSelf();
+    ShadowSpace* shadowSpace = self->shadowSpace;
+    ShadowHeap* heapSpacePtr;
+
+    int addr2 = addr+4;
+    unsigned int data = *((unsigned int*) addr);
+    unsigned int data2 = *((unsigned int*) addr2);
+
+    for (heapSpacePtr = shadowSpace->heapSpace;
+         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+        if (heapSpacePtr->addr == addr) {
+            data = heapSpacePtr->data;
+        } else if (heapSpacePtr->addr == addr2) {
+            data2 = heapSpacePtr->data;
+        }
+    }
+
+    //LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
+    //    addr, data, data2);
+    return (((s8) data2) << 32) | data;
+}
+
+/*
+ * Handles a store of a specified size of data to a specified address.
+ * This gets logged as an addr/data pair in heapSpace instead of modifying
+ * memory.  Addresses in heapSpace are unique, and accesses smaller than a
+ * word pull the entire word from memory first before updating.
+ */
+static void selfVerificationStore(int addr, int data, int size)
+{
+    Thread *self = dvmThreadSelf();
+    ShadowSpace *shadowSpace = self->shadowSpace;
+    ShadowHeap *heapSpacePtr;
+
+    int maskedAddr = addr & 0xFFFFFFFC;
+    int alignment = addr & 0x3;
+
+    //LOGD("*** HEAP STORE: Addr: 0x%x Data: 0x%x Size: %d", addr, data, size);
+
+    for (heapSpacePtr = shadowSpace->heapSpace;
+         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+        if (heapSpacePtr->addr == maskedAddr) break;
+    }
+
+    if (heapSpacePtr == shadowSpace->heapSpaceTail) {
+        heapSpacePtr->addr = maskedAddr;
+        heapSpacePtr->data = *((unsigned int*) maskedAddr);
+        shadowSpace->heapSpaceTail++;
+    }
+
+    addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
+    switch (size) {
+        case kSVByte:
+            *((u1*) addr) = data;
+            break;
+        case kSVSignedByte:
+            *((s1*) addr) = data;
+            break;
+        case kSVHalfword:
+            *((u2*) addr) = data;
+            break;
+        case kSVSignedHalfword:
+            *((s2*) addr) = data;
+            break;
+        case kSVWord:
+            *((u4*) addr) = data;
+    }
+}
+
+/* Like selfVerificationStore, but specifically for doublewords */
+static void selfVerificationStoreDoubleword(int addr, s8 double_data)
+{
+    Thread *self = dvmThreadSelf();
+    ShadowSpace *shadowSpace = self->shadowSpace;
+    ShadowHeap *heapSpacePtr;
+
+    int addr2 = addr+4;
+    int data = double_data;
+    int data2 = double_data >> 32;
+    bool store1 = false, store2 = false;
+
+    //LOGD("*** HEAP STORE DOUBLEWORD: Addr: 0x%x Data: 0x%x, Data2: 0x%x",
+    //    addr, data, data2);
+
+    for (heapSpacePtr = shadowSpace->heapSpace;
+         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+        if (heapSpacePtr->addr == addr) {
+            heapSpacePtr->data = data;
+            store1 = true;
+        } else if (heapSpacePtr->addr == addr2) {
+            heapSpacePtr->data = data2;
+            store2 = true;
+        }
+    }
+
+    if (!store1) {
+        shadowSpace->heapSpaceTail->addr = addr;
+        shadowSpace->heapSpaceTail->data = data;
+        shadowSpace->heapSpaceTail++;
+    }
+    if (!store2) {
+        shadowSpace->heapSpaceTail->addr = addr2;
+        shadowSpace->heapSpaceTail->data = data2;
+        shadowSpace->heapSpaceTail++;
+    }
+}
+
+/*
+ * Decodes the memory instruction at the address specified in the link
+ * register. All registers (r0-r12,lr) and fp registers (d0-d15) are stored
+ * consecutively on the stack beginning at the specified stack pointer.
+ * Calls the proper Self Verification handler for the memory instruction and
+ * updates the link register to point past the decoded memory instruction.
+ */
+void dvmSelfVerificationMemOpDecode(int lr, int* sp)
+{
+    enum {
+        kMemOpLdrPcRel = 0x09, // ldr(3)  [01001] rd[10..8] imm_8[7..0]
+        kMemOpRRR      = 0x0A, // Full opcode is 7 bits
+        kMemOp2Single  = 0x0A, // Used for Vstrs and Vldrs
+        kMemOpRRR2     = 0x0B, // Full opcode is 7 bits
+        kMemOp2Double  = 0x0B, // Used for Vstrd and Vldrd
+        kMemOpStrRRI5  = 0x0C, // str(1)  [01100] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpLdrRRI5  = 0x0D, // ldr(1)  [01101] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpStrbRRI5 = 0x0E, // strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpLdrbRRI5 = 0x0F, // ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpStrhRRI5 = 0x10, // strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpLdrhRRI5 = 0x11, // ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpLdrSpRel = 0x13, // ldr(4)  [10011] rd[10..8] imm_8[7..0]
+        kMemOpStrRRR   = 0x28, // str(2)  [0101000] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpStrhRRR  = 0x29, // strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpStrbRRR  = 0x2A, // strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpLdrsbRRR = 0x2B, // ldrsb   [0101011] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpLdrRRR   = 0x2C, // ldr(2)  [0101100] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpLdrhRRR  = 0x2D, // ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpLdrbRRR  = 0x2E, // ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpLdrshRRR = 0x2F, // ldrsh   [0101111] rm[8..6] rn[5..3] rd[2..0]
+        kMemOp2Vstr    = 0xED8, // Used for Vstrs and Vstrd
+        kMemOp2Vldr    = 0xED9, // Used for Vldrs and Vldrd
+        kMemOp2Vstr2   = 0xEDC, // Used for Vstrs and Vstrd
+        kMemOp2Vldr2   = 0xEDD, // Used for Vstrs and Vstrd
+        kMemOp2StrbRRR = 0xF80, /* str rt,[rn,rm,LSL #imm] [111110000000]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2LdrbRRR = 0xF81, /* ldrb rt,[rn,rm,LSL #imm] [111110000001]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2StrhRRR = 0xF82, /* str rt,[rn,rm,LSL #imm] [111110000010]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2LdrhRRR = 0xF83, /* ldrh rt,[rn,rm,LSL #imm] [111110000011]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2StrRRR  = 0xF84, /* str rt,[rn,rm,LSL #imm] [111110000100]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2LdrRRR  = 0xF85, /* ldr rt,[rn,rm,LSL #imm] [111110000101]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2StrbRRI12 = 0xF88, /* strb rt,[rn,#imm12] [111110001000]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2LdrbRRI12 = 0xF89, /* ldrb rt,[rn,#imm12] [111110001001]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2StrhRRI12 = 0xF8A, /* strh rt,[rn,#imm12] [111110001010]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2LdrhRRI12 = 0xF8B, /* ldrh rt,[rn,#imm12] [111110001011]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2StrRRI12 = 0xF8C, /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
+                                       rn[19..16] rt[15..12] imm12[11..0] */
+        kMemOp2LdrRRI12 = 0xF8D, /* ldr(Imm,T3) rd,[rn,#imm12] [111110001101]
+                                       rn[19..16] rt[15..12] imm12[11..0] */
+        kMemOp2LdrsbRRR = 0xF91, /* ldrsb rt,[rn,rm,LSL #imm] [111110010001]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2LdrshRRR = 0xF93, /* ldrsh rt,[rn,rm,LSL #imm] [111110010011]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2LdrsbRRI12 = 0xF99, /* ldrsb rt,[rn,#imm12] [111110011001]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2LdrshRRI12 = 0xF9B, /* ldrsh rt,[rn,#imm12] [111110011011]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2        = 0xE000, // top 3 bits set indicates Thumb2
+    };
+
+    int addr, offset, data;
+    long long double_data;
+    int size = kSVWord;
+    bool store = false;
+    unsigned int *lr_masked = (unsigned int *) (lr & 0xFFFFFFFE);
+    unsigned int insn = *lr_masked;
+
+    int old_lr;
+    old_lr = selfVerificationMemRegLoad(sp, 13);
+
+    if ((insn & kMemOp2) == kMemOp2) {
+        insn = (insn << 16) | (insn >> 16);
+        //LOGD("*** THUMB2 - Addr: 0x%x Insn: 0x%x", lr, insn);
+
+        int opcode12 = (insn >> 20) & 0xFFF;
+        int opcode6 = (insn >> 6) & 0x3F;
+        int opcode4 = (insn >> 8) & 0xF;
+        int imm2 = (insn >> 4) & 0x3;
+        int imm8 = insn & 0xFF;
+        int imm12 = insn & 0xFFF;
+        int rd = (insn >> 12) & 0xF;
+        int rm = insn & 0xF;
+        int rn = (insn >> 16) & 0xF;
+        int rt = (insn >> 12) & 0xF;
+
+        // Update the link register
+        selfVerificationMemRegStore(sp, old_lr+4, 13);
+
+        // Determine whether the mem op is a store or load
+        switch (opcode12) {
+            case kMemOp2Vstr:
+            case kMemOp2Vstr2:
+            case kMemOp2StrbRRR:
+            case kMemOp2StrhRRR:
+            case kMemOp2StrRRR:
+            case kMemOp2StrbRRI12:
+            case kMemOp2StrhRRI12:
+            case kMemOp2StrRRI12:
+                store = true;
+        }
+
+        // Determine the size of the mem access
+        switch (opcode12) {
+            case kMemOp2StrbRRR:
+            case kMemOp2LdrbRRR:
+            case kMemOp2StrbRRI12:
+            case kMemOp2LdrbRRI12:
+                size = kSVByte;
+                break;
+            case kMemOp2LdrsbRRR:
+            case kMemOp2LdrsbRRI12:
+                size = kSVSignedByte;
+                break;
+            case kMemOp2StrhRRR:
+            case kMemOp2LdrhRRR:
+            case kMemOp2StrhRRI12:
+            case kMemOp2LdrhRRI12:
+                size = kSVHalfword;
+                break;
+            case kMemOp2LdrshRRR:
+            case kMemOp2LdrshRRI12:
+                size = kSVSignedHalfword;
+                break;
+            case kMemOp2Vstr:
+            case kMemOp2Vstr2:
+            case kMemOp2Vldr:
+            case kMemOp2Vldr2:
+                if (opcode4 == kMemOp2Double) size = kSVDoubleword;
+                break;
+        }
+
+        // Load the value of the address
+        addr = selfVerificationMemRegLoad(sp, rn);
+
+        // Figure out the offset
+        switch (opcode12) {
+            case kMemOp2Vstr:
+            case kMemOp2Vstr2:
+            case kMemOp2Vldr:
+            case kMemOp2Vldr2:
+                offset = imm8 << 2;
+                if (opcode4 == kMemOp2Single) {
+                    rt = rd << 1;
+                    if (insn & 0x400000) rt |= 0x1;
+                } else if (opcode4 == kMemOp2Double) {
+                    if (insn & 0x400000) rt |= 0x10;
+                    rt = rt << 1;
+                } else {
+                    LOGD("*** ERROR: UNRECOGNIZED VECTOR MEM OP");
+                    assert(0);
+                    dvmAbort();
+                }
+                rt += 14;
+                break;
+            case kMemOp2StrbRRR:
+            case kMemOp2LdrbRRR:
+            case kMemOp2StrhRRR:
+            case kMemOp2LdrhRRR:
+            case kMemOp2StrRRR:
+            case kMemOp2LdrRRR:
+            case kMemOp2LdrsbRRR:
+            case kMemOp2LdrshRRR:
+                offset = selfVerificationMemRegLoad(sp, rm) << imm2;
+                break;
+            case kMemOp2StrbRRI12:
+            case kMemOp2LdrbRRI12:
+            case kMemOp2StrhRRI12:
+            case kMemOp2LdrhRRI12:
+            case kMemOp2StrRRI12:
+            case kMemOp2LdrRRI12:
+            case kMemOp2LdrsbRRI12:
+            case kMemOp2LdrshRRI12:
+                offset = imm12;
+                break;
+            default:
+                LOGD("*** ERROR: UNRECOGNIZED MEM OP");
+                assert(0);
+                dvmAbort();
+        }
+
+        // Handle the decoded mem op accordingly
+        if (store) {
+            if (size == kSVDoubleword) {
+                double_data = selfVerificationMemRegLoadDouble(sp, rt);
+                selfVerificationStoreDoubleword(addr+offset, double_data);
+            } else {
+                data = selfVerificationMemRegLoad(sp, rt);
+                selfVerificationStore(addr+offset, data, size);
+            }
+        } else {
+            if (size == kSVDoubleword) {
+                double_data = selfVerificationLoadDoubleword(addr+offset);
+                selfVerificationMemRegStoreDouble(sp, double_data, rt);
+            } else {
+                data = selfVerificationLoad(addr+offset, size);
+                selfVerificationMemRegStore(sp, data, rt);
+            }
+        }
+    } else {
+        //LOGD("*** THUMB - Addr: 0x%x Insn: 0x%x", lr, insn);
+
+        // Update the link register
+        selfVerificationMemRegStore(sp, old_lr+2, 13);
+
+        int opcode5 = (insn >> 11) & 0x1F;
+        int opcode7 = (insn >> 9) & 0x7F;
+        int imm = (insn >> 6) & 0x1F;
+        int rd = (insn >> 8) & 0x7;
+        int rm = (insn >> 6) & 0x7;
+        int rn = (insn >> 3) & 0x7;
+        int rt = insn & 0x7;
+
+        // Determine whether the mem op is a store or load
+        switch (opcode5) {
+            case kMemOpRRR:
+                switch (opcode7) {
+                    case kMemOpStrRRR:
+                    case kMemOpStrhRRR:
+                    case kMemOpStrbRRR:
+                        store = true;
+                }
+                break;
+            case kMemOpStrRRI5:
+            case kMemOpStrbRRI5:
+            case kMemOpStrhRRI5:
+                store = true;
+        }
+
+        // Determine the size of the mem access
+        switch (opcode5) {
+            case kMemOpRRR:
+            case kMemOpRRR2:
+                switch (opcode7) {
+                    case kMemOpStrbRRR:
+                    case kMemOpLdrbRRR:
+                        size = kSVByte;
+                        break;
+                    case kMemOpLdrsbRRR:
+                        size = kSVSignedByte;
+                        break;
+                    case kMemOpStrhRRR:
+                    case kMemOpLdrhRRR:
+                        size = kSVHalfword;
+                        break;
+                    case kMemOpLdrshRRR:
+                        size = kSVSignedHalfword;
+                        break;
+                }
+                break;
+            case kMemOpStrbRRI5:
+            case kMemOpLdrbRRI5:
+                size = kSVByte;
+                break;
+            case kMemOpStrhRRI5:
+            case kMemOpLdrhRRI5:
+                size = kSVHalfword;
+                break;
+        }
+
+        // Load the value of the address
+        if (opcode5 == kMemOpLdrPcRel)
+            addr = selfVerificationMemRegLoad(sp, 4);
+        else
+            addr = selfVerificationMemRegLoad(sp, rn);
+
+        // Figure out the offset
+        switch (opcode5) {
+            case kMemOpLdrPcRel:
+                offset = (insn & 0xFF) << 2;
+                rt = rd;
+                break;
+            case kMemOpRRR:
+            case kMemOpRRR2:
+                offset = selfVerificationMemRegLoad(sp, rm);
+                break;
+            case kMemOpStrRRI5:
+            case kMemOpLdrRRI5:
+                offset = imm << 2;
+                break;
+            case kMemOpStrhRRI5:
+            case kMemOpLdrhRRI5:
+                offset = imm << 1;
+                break;
+            case kMemOpStrbRRI5:
+            case kMemOpLdrbRRI5:
+                offset = imm;
+                break;
+            default:
+                LOGD("*** ERROR: UNRECOGNIZED MEM OP");
+                assert(0);
+                dvmAbort();
+        }
+
+        // Handle the decoded mem op accordingly
+        if (store) {
+            data = selfVerificationMemRegLoad(sp, rt);
+            selfVerificationStore(addr+offset, data, size);
+        } else {
+            data = selfVerificationLoad(addr+offset, size);
+            selfVerificationMemRegStore(sp, data, rt);
+        }
+    }
+}
+#endif
diff --git a/vm/compiler/codegen/arm/Codegen.h b/vm/compiler/codegen/arm/Codegen.h
index b148bda..0674b8b 100644
--- a/vm/compiler/codegen/arm/Codegen.h
+++ b/vm/compiler/codegen/arm/Codegen.h
@@ -45,6 +45,10 @@
 
 static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir);
 
+#if defined(WITH_SELF_VERIFICATION)
+/* Self Verification memory instruction decoder */
+void dvmSelfVerificationMemOpDecode(int lr, int* sp);
+#endif
 
 /*
  * Architecture-dependent register allocation routines implemented in
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index b0e16b8..1bf80cb 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -208,411 +208,37 @@
 }
 
 #if defined(WITH_SELF_VERIFICATION)
-/*
- * The following are used to keep compiled loads and stores from modifying
- * memory during self verification mode.
- *
- * Stores do not modify memory. Instead, the address and value pair are stored
- * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
- * than a word, the word containing the address is loaded first before being
- * updated.
- *
- * Loads check heapSpace first and return data from there if an entry exists.
- * Otherwise, data is loaded from memory as usual.
- */
-
-/* Decode contents of heapArgSpace to determine addr to load from */
-static void selfVerificationLoadDecode(HeapArgSpace* heapArgSpace, int* addr)
+static void selfVerificationBranchInsert(LIR *currentLIR, ArmOpCode opCode,
+                          int dest, int src1)
 {
-    int reg = heapArgSpace->regMap & 0xFF;
-    if (!FPREG(reg)) {
-        assert(reg < 16);
-        *addr = heapArgSpace->coreRegs[reg];
-    } else {
-        assert(!DOUBLEREG(reg));
-        *addr = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
-    }
+     ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
+     insn->opCode = opCode;
+     insn->operands[0] = dest;
+     insn->operands[1] = src1;
+     setupResourceMasks(insn);
+     dvmCompilerInsertLIRBefore(currentLIR, (LIR *) insn);
 }
 
-/* Decode contents of heapArgSpace to determine reg to load into */
-static void selfVerificationLoadDecodeData(HeapArgSpace* heapArgSpace,
-                                           int data, int reg)
+static void selfVerificationBranchInsertPass(CompilationUnit *cUnit)
 {
-    if (!FPREG(reg)) {
-        assert(reg < 16);
-        heapArgSpace->coreRegs[reg] = data;
-    } else {
-        assert(!DOUBLEREG(reg));
-        heapArgSpace->fpRegs[(reg & FP_REG_MASK)] = data;
-    }
-}
+    ArmLIR *thisLIR;
+    ArmLIR *branchLIR = dvmCompilerNew(sizeof(ArmLIR), true);
+    TemplateOpCode opCode = TEMPLATE_MEM_OP_DECODE;
 
-static void selfVerificationLoad(InterpState* interpState)
-{
-    Thread *self = dvmThreadSelf();
-    ShadowHeap *heapSpacePtr;
-    ShadowSpace *shadowSpace = self->shadowSpace;
-    HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
-
-    int addr, data;
-    selfVerificationLoadDecode(heapArgSpace, &addr);
-
-    for (heapSpacePtr = shadowSpace->heapSpace;
-         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
-        if (heapSpacePtr->addr == addr) {
-            data = heapSpacePtr->data;
-            break;
+    for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn;
+         thisLIR != (ArmLIR *) cUnit->lastLIRInsn;
+         thisLIR = NEXT_LIR(thisLIR)) {
+        if (thisLIR->branchInsertSV) {
+            /* Branch to mem op decode template */
+            selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx1,
+                       (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
+                       (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
+            selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx2,
+                       (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
+                       (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
         }
     }
-
-    if (heapSpacePtr == shadowSpace->heapSpaceTail)
-        data = *((unsigned int*) addr);
-
-    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
-
-    // LOGD("*** HEAP LOAD: Reg:%d Addr: 0x%x Data: 0x%x", reg, addr, data);
-
-    selfVerificationLoadDecodeData(heapArgSpace, data, reg);
 }
-
-static void selfVerificationLoadByte(InterpState* interpState)
-{
-    Thread *self = dvmThreadSelf();
-    ShadowHeap *heapSpacePtr;
-    ShadowSpace *shadowSpace = self->shadowSpace;
-    HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
-
-    int addr, data;
-    selfVerificationLoadDecode(heapArgSpace, &addr);
-
-    int maskedAddr = addr & 0xFFFFFFFC;
-    int alignment = addr & 0x3;
-
-    for (heapSpacePtr = shadowSpace->heapSpace;
-         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
-        if (heapSpacePtr->addr == maskedAddr) {
-            addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
-            data = *((unsigned char*) addr);
-            break;
-        }
-    }
-
-    if (heapSpacePtr == shadowSpace->heapSpaceTail)
-        data = *((unsigned char*) addr);
-
-    //LOGD("*** HEAP LOAD BYTE: Addr: 0x%x Data: 0x%x", addr, data);
-
-    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
-    selfVerificationLoadDecodeData(heapArgSpace, data, reg);
-}
-
-static void selfVerificationLoadHalfword(InterpState* interpState)
-{
-    Thread *self = dvmThreadSelf();
-    ShadowHeap *heapSpacePtr;
-    ShadowSpace *shadowSpace = self->shadowSpace;
-    HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
-
-    int addr, data;
-    selfVerificationLoadDecode(heapArgSpace, &addr);
-
-    int maskedAddr = addr & 0xFFFFFFFC;
-    int alignment = addr & 0x2;
-
-    for (heapSpacePtr = shadowSpace->heapSpace;
-         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
-        if (heapSpacePtr->addr == maskedAddr) {
-            addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
-            data = *((unsigned short*) addr);
-            break;
-        }
-    }
-
-    if (heapSpacePtr == shadowSpace->heapSpaceTail)
-        data = *((unsigned short*) addr);
-
-    //LOGD("*** HEAP LOAD kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
-
-    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
-    selfVerificationLoadDecodeData(heapArgSpace, data, reg);
-}
-
-static void selfVerificationLoadSignedByte(InterpState* interpState)
-{
-    Thread *self = dvmThreadSelf();
-    ShadowHeap* heapSpacePtr;
-    ShadowSpace* shadowSpace = self->shadowSpace;
-    HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
-
-    int addr, data;
-    selfVerificationLoadDecode(heapArgSpace, &addr);
-
-    int maskedAddr = addr & 0xFFFFFFFC;
-    int alignment = addr & 0x3;
-
-    for (heapSpacePtr = shadowSpace->heapSpace;
-         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
-        if (heapSpacePtr->addr == maskedAddr) {
-            addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
-            data = *((signed char*) addr);
-            break;
-        }
-    }
-
-    if (heapSpacePtr == shadowSpace->heapSpaceTail)
-        data = *((signed char*) addr);
-
-    //LOGD("*** HEAP LOAD SIGNED BYTE: Addr: 0x%x Data: 0x%x", addr, data);
-
-    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
-    selfVerificationLoadDecodeData(heapArgSpace, data, reg);
-}
-
-static void selfVerificationLoadSignedHalfword(InterpState* interpState)
-{
-    Thread *self = dvmThreadSelf();
-    ShadowHeap* heapSpacePtr;
-    ShadowSpace* shadowSpace = self->shadowSpace;
-    HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
-
-    int addr, data;
-    selfVerificationLoadDecode(heapArgSpace, &addr);
-
-    int maskedAddr = addr & 0xFFFFFFFC;
-    int alignment = addr & 0x2;
-
-    for (heapSpacePtr = shadowSpace->heapSpace;
-         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
-        if (heapSpacePtr->addr == maskedAddr) {
-            addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
-            data = *((signed short*) addr);
-            break;
-        }
-    }
-
-    if (heapSpacePtr == shadowSpace->heapSpaceTail)
-        data = *((signed short*) addr);
-
-    //LOGD("*** HEAP LOAD SIGNED kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
-
-    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
-    selfVerificationLoadDecodeData(heapArgSpace, data, reg);
-}
-
-static void selfVerificationLoadDoubleword(InterpState* interpState)
-{
-    Thread *self = dvmThreadSelf();
-    ShadowHeap* heapSpacePtr;
-    ShadowSpace* shadowSpace = self->shadowSpace;
-    HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
-
-    int addr;
-    selfVerificationLoadDecode(heapArgSpace, &addr);
-
-    int addr2 = addr+4;
-    unsigned int data = *((unsigned int*) addr);
-    unsigned int data2 = *((unsigned int*) addr2);
-
-    for (heapSpacePtr = shadowSpace->heapSpace;
-         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
-        if (heapSpacePtr->addr == addr) {
-            data = heapSpacePtr->data;
-        } else if (heapSpacePtr->addr == addr2) {
-            data2 = heapSpacePtr->data;
-        }
-    }
-
-    // LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
-    //    addr, data, data2);
-
-    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
-    int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
-    selfVerificationLoadDecodeData(heapArgSpace, data, reg);
-    selfVerificationLoadDecodeData(heapArgSpace, data2, reg2);
-}
-
-/* Decode contents of heapArgSpace to determine arguments to store. */
-static void selfVerificationStoreDecode(HeapArgSpace* heapArgSpace,
-                                        int* value, int reg)
-{
-    if (!FPREG(reg)) {
-        assert(reg < 16);
-        *value = heapArgSpace->coreRegs[reg];
-    } else {
-        assert(!DOUBLEREG(reg));
-        *value = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
-    }
-}
-
-static void selfVerificationStore(InterpState* interpState)
-{
-    Thread *self = dvmThreadSelf();
-    ShadowHeap *heapSpacePtr;
-    ShadowSpace *shadowSpace = self->shadowSpace;
-    HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
-
-    int addr, data;
-    int reg0 = heapArgSpace->regMap & 0xFF;
-    int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
-    selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
-    selfVerificationStoreDecode(heapArgSpace, &data, reg1);
-
-    //LOGD("*** HEAP STORE: Addr: 0x%x Data: 0x%x", addr, data);
-
-    for (heapSpacePtr = shadowSpace->heapSpace;
-         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
-        if (heapSpacePtr->addr == addr) break;
-    }
-
-    if (heapSpacePtr == shadowSpace->heapSpaceTail) {
-        heapSpacePtr->addr = addr;
-        shadowSpace->heapSpaceTail++;
-    }
-
-    heapSpacePtr->data = data;
-}
-
-static void selfVerificationStoreByte(InterpState* interpState)
-{
-    Thread *self = dvmThreadSelf();
-    ShadowHeap *heapSpacePtr;
-    ShadowSpace *shadowSpace = self->shadowSpace;
-    HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
-
-    int addr, data;
-    int reg0 = heapArgSpace->regMap & 0xFF;
-    int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
-    selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
-    selfVerificationStoreDecode(heapArgSpace, &data, reg1);
-
-    int maskedAddr = addr & 0xFFFFFFFC;
-    int alignment = addr & 0x3;
-
-    //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Data: 0x%x", addr, data);
-
-    for (heapSpacePtr = shadowSpace->heapSpace;
-         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
-        if (heapSpacePtr->addr == maskedAddr) break;
-    }
-
-    if (heapSpacePtr == shadowSpace->heapSpaceTail)  {
-        heapSpacePtr->addr = maskedAddr;
-        heapSpacePtr->data = *((unsigned int*) maskedAddr);
-        shadowSpace->heapSpaceTail++;
-    }
-
-    addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
-    *((unsigned char*) addr) = (char) data;
-
-    //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Final Data: 0x%x",
-    //    addr, heapSpacePtr->data);
-}
-
-static void selfVerificationStoreHalfword(InterpState* interpState)
-{
-    Thread *self = dvmThreadSelf();
-    ShadowHeap *heapSpacePtr;
-    ShadowSpace *shadowSpace = self->shadowSpace;
-    HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
-
-    int addr, data;
-    int reg0 = heapArgSpace->regMap & 0xFF;
-    int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
-    selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
-    selfVerificationStoreDecode(heapArgSpace, &data, reg1);
-
-    int maskedAddr = addr & 0xFFFFFFFC;
-    int alignment = addr & 0x2;
-
-    //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
-
-    for (heapSpacePtr = shadowSpace->heapSpace;
-         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
-        if (heapSpacePtr->addr == maskedAddr) break;
-    }
-
-    if (heapSpacePtr == shadowSpace->heapSpaceTail)  {
-        heapSpacePtr->addr = maskedAddr;
-        heapSpacePtr->data = *((unsigned int*) maskedAddr);
-        shadowSpace->heapSpaceTail++;
-    }
-
-    addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
-    *((unsigned short*) addr) = (short) data;
-
-    //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Final Data: 0x%x",
-    //    addr, heapSpacePtr->data);
-}
-
-static void selfVerificationStoreDoubleword(InterpState* interpState)
-{
-    Thread *self = dvmThreadSelf();
-    ShadowHeap *heapSpacePtr;
-    ShadowSpace *shadowSpace = self->shadowSpace;
-    HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
-
-    int addr, data, data2;
-    int reg0 = heapArgSpace->regMap & 0xFF;
-    int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
-    int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
-    selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
-    selfVerificationStoreDecode(heapArgSpace, &data, reg1);
-    selfVerificationStoreDecode(heapArgSpace, &data2, reg2);
-
-    int addr2 = addr+4;
-    bool store1 = false, store2 = false;
-
-    //LOGD("*** HEAP STORE DOUBLEWORD: Addr: 0x%x Data: 0x%x, Data2: 0x%x",
-    //    addr, data, data2);
-
-    for (heapSpacePtr = shadowSpace->heapSpace;
-         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
-        if (heapSpacePtr->addr == addr) {
-            heapSpacePtr->data = data;
-            store1 = true;
-        } else if (heapSpacePtr->addr == addr2) {
-            heapSpacePtr->data = data2;
-            store2 = true;
-        }
-    }
-
-    if (!store1) {
-        shadowSpace->heapSpaceTail->addr = addr;
-        shadowSpace->heapSpaceTail->data = data;
-        shadowSpace->heapSpaceTail++;
-    }
-    if (!store2) {
-        shadowSpace->heapSpaceTail->addr = addr2;
-        shadowSpace->heapSpaceTail->data = data2;
-        shadowSpace->heapSpaceTail++;
-    }
-}
-
-/* Common wrapper function for all memory operations */
-static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
-                                         void* funct)
-{
-    /* push r0 and r7 to give us a foothold */
-    newLIR1(cUnit, kThumbPush, (1 << r0) | (1 << r7));
-
-    /* Let the save handler know where the save record is */
-    loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace));
-
-    /* Load the regMap and call the save handler [note: handler pops r0/r7] */
-    loadConstant(cUnit, r7, regMap);
-    genDispatchToHandler(cUnit, TEMPLATE_SAVE_STATE);
-
-    /* Set function pointer, pass rGLUE and branch */
-    loadConstant(cUnit, r1, (int) funct);
-    newLIR2(cUnit, kThumbMovRR, r0, rGLUE);
-    newLIR1(cUnit, kThumbBlxR, r1);
-
-    /* Let the recover handler know where coreRegs[0] and restore regs */
-    loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace) +
-                            offsetof(HeapArgSpace, coreRegs));
-    genDispatchToHandler(cUnit, TEMPLATE_RESTORE_STATE);
-}
-
 #endif
 
 /* Generate a unconditional branch to go to the interpreter */
@@ -639,12 +265,12 @@
                  NULL);/* null object? */
     opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
     rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
-#if !defined(WITH_SELF_VERIFICATION)
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->heapMemOp = true;
+#endif
     loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
-#else
-    int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
-    selfVerificationMemOpWrapper(cUnit, regMap,
-        &selfVerificationLoadDoubleword);
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->heapMemOp = false;
 #endif
     freeTemp(cUnit, regPtr);
     storeValueWide(cUnit, rlDest, rlResult);
@@ -663,12 +289,12 @@
                  NULL);/* null object? */
     regPtr = allocTemp(cUnit);
     opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
-#if !defined(WITH_SELF_VERIFICATION)
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->heapMemOp = true;
+#endif
     storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
-#else
-    int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
-    selfVerificationMemOpWrapper(cUnit, regMap,
-        &selfVerificationStoreDoubleword);
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->heapMemOp = false;
 #endif
     freeTemp(cUnit, regPtr);
 }
@@ -689,17 +315,13 @@
     rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
                  NULL);/* null object? */
-#if !defined(WITH_SELF_VERIFICATION)
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->heapMemOp = true;
+#endif
     loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
                  size, rlObj.sRegLow);
-#else
-    /* Combine address and offset */
-    regPtr = allocTemp(cUnit);
-    opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
-
-    int regMap = rlResult.lowReg << 8 | regPtr;
-    selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
-    freeTemp(cUnit, regPtr);
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->heapMemOp = false;
 #endif
     storeValue(cUnit, rlDest, rlResult);
 }
@@ -719,15 +341,12 @@
     int regPtr;
     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
                  NULL);/* null object? */
-#if !defined(WITH_SELF_VERIFICATION)
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->heapMemOp = true;
+#endif
     storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
-#else
-    /* Combine address and offset */
-    regPtr = allocTemp(cUnit);
-    opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
-
-    int regMap = rlSrc.lowReg << 8 | regPtr;
-    selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->heapMemOp = false;
 #endif
 }
 
@@ -769,7 +388,6 @@
         /* regPtr -> array data */
         opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
     }
-#if !defined(WITH_SELF_VERIFICATION)
     if ((size == kLong) || (size == kDouble)) {
         if (scale) {
             int rNewIndex = allocTemp(cUnit);
@@ -780,63 +398,28 @@
             opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
         }
         rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
+#if defined(WITH_SELF_VERIFICATION)
+        cUnit->heapMemOp = true;
+#endif
         loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
+#if defined(WITH_SELF_VERIFICATION)
+        cUnit->heapMemOp = false;
+#endif
         freeTemp(cUnit, regPtr);
         storeValueWide(cUnit, rlDest, rlResult);
     } else {
         rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
+#if defined(WITH_SELF_VERIFICATION)
+        cUnit->heapMemOp = true;
+#endif
         loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
                         scale, size);
+#if defined(WITH_SELF_VERIFICATION)
+        cUnit->heapMemOp = false;
+#endif
         freeTemp(cUnit, regPtr);
         storeValue(cUnit, rlDest, rlResult);
     }
-#else
-    //TODO: probably want to move this into loadBaseIndexed
-    void *funct = NULL;
-    switch(size) {
-        case kLong:
-        case kDouble:
-            funct = (void*) &selfVerificationLoadDoubleword;
-            break;
-        case kWord:
-            funct = (void*) &selfVerificationLoad;
-            break;
-        case kUnsignedHalf:
-            funct = (void*) &selfVerificationLoadHalfword;
-            break;
-        case kSignedHalf:
-            funct = (void*) &selfVerificationLoadSignedHalfword;
-            break;
-        case kUnsignedByte:
-            funct = (void*) &selfVerificationLoadByte;
-            break;
-        case kSignedByte:
-            funct = (void*) &selfVerificationLoadSignedByte;
-            break;
-        default:
-            assert(0);
-            dvmAbort();
-    }
-    /* Combine address and index */
-    if (scale) {
-        int regTmp = allocTemp(cUnit);
-        opRegRegImm(cUnit, kOpLsl, regTmp, rlIndex.lowReg, scale);
-        opRegReg(cUnit, kOpAdd, regPtr, regTmp);
-        freeTemp(cUnit, regTmp);
-    } else {
-        opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
-    }
-
-    rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
-    int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
-    selfVerificationMemOpWrapper(cUnit, regMap, funct);
-
-    freeTemp(cUnit, regPtr);
-    if ((size == kLong) || (size == kDouble))
-        storeValueWide(cUnit, rlDest, rlResult);
-    else
-        storeValue(cUnit, rlDest, rlResult);
-#endif
 }
 
 /*
@@ -885,7 +468,6 @@
         opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
     }
     /* at this point, regPtr points to array, 2 live temps */
-#if !defined(WITH_SELF_VERIFICATION)
     if ((size == kLong) || (size == kDouble)) {
         //TODO: need specific wide routine that can handle fp regs
         if (scale) {
@@ -897,57 +479,25 @@
             opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
         }
         rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+#if defined(WITH_SELF_VERIFICATION)
+        cUnit->heapMemOp = true;
+#endif
         storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
+#if defined(WITH_SELF_VERIFICATION)
+        cUnit->heapMemOp = false;
+#endif
         freeTemp(cUnit, regPtr);
     } else {
         rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+#if defined(WITH_SELF_VERIFICATION)
+        cUnit->heapMemOp = true;
+#endif
         storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
                          scale, size);
-    }
-#else
-    //TODO: probably want to move this into storeBaseIndexed
-    void *funct = NULL;
-    switch(size) {
-        case kLong:
-        case kDouble:
-            funct = (void*) &selfVerificationStoreDoubleword;
-            break;
-        case kWord:
-            funct = (void*) &selfVerificationStore;
-            break;
-        case kSignedHalf:
-        case kUnsignedHalf:
-            funct = (void*) &selfVerificationStoreHalfword;
-            break;
-        case kSignedByte:
-        case kUnsignedByte:
-            funct = (void*) &selfVerificationStoreByte;
-            break;
-        default:
-            assert(0);
-            dvmAbort();
-    }
-
-    if (scale) {
-        int regTmpIndex = allocTemp(cUnit);
-        // 3 live temps
-        opRegRegImm(cUnit, kOpLsl, regTmpIndex, rlIndex.lowReg, scale);
-        opRegReg(cUnit, kOpAdd, regPtr, regTmpIndex);
-        freeTemp(cUnit, regTmpIndex);
-    } else {
-        opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
-    }
-    /* Combine address and index */
-    if ((size == kLong) || (size == kDouble)) {
-        rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
-    } else {
-        rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
-    }
-
-    int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
-    selfVerificationMemOpWrapper(cUnit, regMap, funct);
-
+#if defined(WITH_SELF_VERIFICATION)
+        cUnit->heapMemOp = false;
 #endif
+    }
 }
 
 static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
@@ -1881,12 +1431,12 @@
             rlDest = getDestLoc(cUnit, mir, 0);
             rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
-#if !defined(WITH_SELF_VERIFICATION)
+#if defined(WITH_SELF_VERIFICATION)
+            cUnit->heapMemOp = true;
+#endif
             loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
-#else
-            int regMap = rlResult.lowReg << 8 | tReg;
-            selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
-
+#if defined(WITH_SELF_VERIFICATION)
+            cUnit->heapMemOp = false;
 #endif
             storeValue(cUnit, rlDest, rlResult);
             break;
@@ -1900,14 +1450,12 @@
             rlDest = getDestLocWide(cUnit, mir, 0, 1);
             rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
-#if !defined(WITH_SELF_VERIFICATION)
+#if defined(WITH_SELF_VERIFICATION)
+            cUnit->heapMemOp = true;
+#endif
             loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
-#else
-            int regMap = rlResult.highReg << 16 |
-                         rlResult.lowReg << 8 | tReg;
-            selfVerificationMemOpWrapper(cUnit, regMap,
-                &selfVerificationLoadDoubleword);
-
+#if defined(WITH_SELF_VERIFICATION)
+            cUnit->heapMemOp = false;
 #endif
             storeValueWide(cUnit, rlDest, rlResult);
             break;
@@ -1927,11 +1475,12 @@
             rlSrc = getSrcLoc(cUnit, mir, 0);
             rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
-#if !defined(WITH_SELF_VERIFICATION)
+#if defined(WITH_SELF_VERIFICATION)
+            cUnit->heapMemOp = true;
+#endif
             storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
-#else
-            int regMap = rlSrc.lowReg << 8 | tReg;
-            selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
+#if defined(WITH_SELF_VERIFICATION)
+            cUnit->heapMemOp = false;
 #endif
             break;
         }
@@ -1945,12 +1494,12 @@
             rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
             rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
-#if !defined(WITH_SELF_VERIFICATION)
+#if defined(WITH_SELF_VERIFICATION)
+            cUnit->heapMemOp = true;
+#endif
             storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
-#else
-            int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | tReg;
-            selfVerificationMemOpWrapper(cUnit, regMap,
-                &selfVerificationStoreDoubleword);
+#if defined(WITH_SELF_VERIFICATION)
+            cUnit->heapMemOp = false;
 #endif
             break;
         }
@@ -4114,6 +3663,10 @@
     }
 
     dvmCompilerApplyGlobalOptimizations(cUnit);
+
+#if defined(WITH_SELF_VERIFICATION)
+    selfVerificationBranchInsertPass(cUnit);
+#endif
 }
 
 /* Accept the work and start compiling */
diff --git a/vm/compiler/codegen/arm/Thumb/Factory.c b/vm/compiler/codegen/arm/Thumb/Factory.c
index 2348b3a..586e640 100644
--- a/vm/compiler/codegen/arm/Thumb/Factory.c
+++ b/vm/compiler/codegen/arm/Thumb/Factory.c
@@ -457,6 +457,10 @@
             assert(0);
     }
     res = newLIR3(cUnit, opCode, rDest, rBase, rNewIndex);
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        res->branchInsertSV = true;
+#endif
     if (scale)
         freeTemp(cUnit, rNewIndex);
     return (first) ? first : res;
@@ -490,6 +494,10 @@
             assert(0);
     }
     res = newLIR3(cUnit, opCode, rSrc, rBase, rNewIndex);
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        res->branchInsertSV = true;
+#endif
     if (scale)
         freeTemp(cUnit, rNewIndex);
     return (first) ? first : res;
@@ -625,7 +633,12 @@
                 freeTemp(cUnit, rTmp);
         }
     }
-
+#if defined(WITH_SELF_VERIFICATION)
+    if (load != NULL && cUnit->heapMemOp)
+        load->branchInsertSV = true;
+    if (load2 != NULL && cUnit->heapMemOp)
+        load2->branchInsertSV = true;
+#endif
     return res;
 }
 
@@ -726,6 +739,12 @@
         }
         freeTemp(cUnit, rScratch);
     }
+#if defined(WITH_SELF_VERIFICATION)
+    if (store != NULL && cUnit->heapMemOp)
+        store->branchInsertSV = true;
+    if (store2 != NULL && cUnit->heapMemOp)
+        store2->branchInsertSV = true;
+#endif
     return res;
 }
 
diff --git a/vm/compiler/codegen/arm/Thumb2/Factory.c b/vm/compiler/codegen/arm/Thumb2/Factory.c
index ea93bbf..433953e 100644
--- a/vm/compiler/codegen/arm/Thumb2/Factory.c
+++ b/vm/compiler/codegen/arm/Thumb2/Factory.c
@@ -660,6 +660,7 @@
                                int rIndex, int rDest, int scale, OpSize size)
 {
     bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
+    ArmLIR *load;
     ArmOpCode opCode = kThumbBkpt;
     bool thumbForm = (allLowRegs && (scale == 0));
     int regPtr;
@@ -683,7 +684,12 @@
             } else {
                 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
             }
-            return newLIR3(cUnit, opCode, rDest, regPtr, 0);
+            load = newLIR3(cUnit, opCode, rDest, regPtr, 0);
+#if defined(WITH_SELF_VERIFICATION)
+            if (cUnit->heapMemOp)
+                load->branchInsertSV = true;
+#endif
+            return load;
         case kWord:
             opCode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
             break;
@@ -703,15 +709,22 @@
             assert(0);
     }
     if (thumbForm)
-        return newLIR3(cUnit, opCode, rDest, rBase, rIndex);
+        load = newLIR3(cUnit, opCode, rDest, rBase, rIndex);
     else
-        return newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
+        load = newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
+
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        load->branchInsertSV = true;
+#endif
+    return load;
 }
 
 static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
                                 int rIndex, int rSrc, int scale, OpSize size)
 {
     bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
+    ArmLIR *store;
     ArmOpCode opCode = kThumbBkpt;
     bool thumbForm = (allLowRegs && (scale == 0));
     int regPtr;
@@ -735,7 +748,12 @@
             } else {
                 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
             }
-            return newLIR3(cUnit, opCode, rSrc, regPtr, 0);
+            store = newLIR3(cUnit, opCode, rSrc, regPtr, 0);
+#if defined(WITH_SELF_VERIFICATION)
+            if (cUnit->heapMemOp)
+                store->branchInsertSV = true;
+#endif
+            return store;
         case kWord:
             opCode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
             break;
@@ -751,9 +769,15 @@
             assert(0);
     }
     if (thumbForm)
-        return newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
+        store = newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
     else
-        return newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
+        store = newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
+
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        store->branchInsertSV = true;
+#endif
+    return store;
 }
 
 /*
@@ -872,6 +896,10 @@
     if (rBase == rFP) {
         annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
     }
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        load->branchInsertSV = true;
+#endif
     return res;
 }
 
@@ -982,6 +1010,10 @@
     if (rBase == rFP) {
         annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
     }
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        store->branchInsertSV = true;
+#endif
     return res;
 }
 
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S
new file mode 100644
index 0000000..21e23a9
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S
@@ -0,0 +1,19 @@
+#if defined(WITH_SELF_VERIFICATION)
+    /*
+     * This handler encapsulates heap memory ops for selfVerification mode.
+     *
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
+     */
+    vpush   {d0-d15}                    @ save out all fp registers
+    push    {r0-r12,lr}                 @ save out all registers
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    vpop    {d0-d15}                    @ restore all fp registers
+    bx      lr                          @ return to compiled code
+#endif
diff --git a/vm/compiler/template/armv5te-vfp/TemplateOpList.h b/vm/compiler/template/armv5te-vfp/TemplateOpList.h
index 8855d46..d991bed 100644
--- a/vm/compiler/template/armv5te-vfp/TemplateOpList.h
+++ b/vm/compiler/template/armv5te-vfp/TemplateOpList.h
@@ -51,8 +51,7 @@
 JIT_TEMPLATE(CMPL_FLOAT_VFP)
 JIT_TEMPLATE(SQRT_DOUBLE_VFP)
 JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
-JIT_TEMPLATE(SAVE_STATE)
-JIT_TEMPLATE(RESTORE_STATE)
+JIT_TEMPLATE(MEM_OP_DECODE)
 JIT_TEMPLATE(STRING_COMPARETO)
 JIT_TEMPLATE(STRING_INDEXOF)
 JIT_TEMPLATE(INTERPRET)
diff --git a/vm/compiler/template/armv5te/TEMPLATE_MEM_OP_DECODE.S b/vm/compiler/template/armv5te/TEMPLATE_MEM_OP_DECODE.S
new file mode 100644
index 0000000..ecd4eaa
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_MEM_OP_DECODE.S
@@ -0,0 +1,17 @@
+#if defined(WITH_SELF_VERIFICATION)
+    /*
+     * This handler encapsulates heap memory ops for selfVerification mode.
+     *
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
+     */
+    push    {r0-r12,lr}                 @ save out all registers
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    bx      lr                          @ return to compiled code
+#endif
diff --git a/vm/compiler/template/armv5te/TemplateOpList.h b/vm/compiler/template/armv5te/TemplateOpList.h
index c7ae80a..e81383c 100644
--- a/vm/compiler/template/armv5te/TemplateOpList.h
+++ b/vm/compiler/template/armv5te/TemplateOpList.h
@@ -36,8 +36,7 @@
 JIT_TEMPLATE(SHR_LONG)
 JIT_TEMPLATE(USHR_LONG)
 JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
-JIT_TEMPLATE(SAVE_STATE)
-JIT_TEMPLATE(RESTORE_STATE)
+JIT_TEMPLATE(MEM_OP_DECODE)
 JIT_TEMPLATE(STRING_COMPARETO)
 JIT_TEMPLATE(STRING_INDEXOF)
 JIT_TEMPLATE(INTERPRET)
diff --git a/vm/compiler/template/armv5te/footer.S b/vm/compiler/template/armv5te/footer.S
index 0e817a6..1709bf3 100644
--- a/vm/compiler/template/armv5te/footer.S
+++ b/vm/compiler/template/armv5te/footer.S
@@ -79,6 +79,10 @@
     .word   dvmMterpCommonExceptionThrown
 .LdvmLockObject:
     .word   dvmLockObject
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+    .word   dvmSelfVerificationMemOpDecode
+#endif
 .L__aeabi_cdcmple:
     .word   __aeabi_cdcmple
 .L__aeabi_cfcmple:
diff --git a/vm/compiler/template/armv7-a/TemplateOpList.h b/vm/compiler/template/armv7-a/TemplateOpList.h
index 8855d46..d991bed 100644
--- a/vm/compiler/template/armv7-a/TemplateOpList.h
+++ b/vm/compiler/template/armv7-a/TemplateOpList.h
@@ -51,8 +51,7 @@
 JIT_TEMPLATE(CMPL_FLOAT_VFP)
 JIT_TEMPLATE(SQRT_DOUBLE_VFP)
 JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
-JIT_TEMPLATE(SAVE_STATE)
-JIT_TEMPLATE(RESTORE_STATE)
+JIT_TEMPLATE(MEM_OP_DECODE)
 JIT_TEMPLATE(STRING_COMPARETO)
 JIT_TEMPLATE(STRING_INDEXOF)
 JIT_TEMPLATE(INTERPRET)
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
index 3090a17..7ecad39 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
@@ -1056,49 +1056,28 @@
 
 /* ------------------------------ */
     .balign 4
-    .global dvmCompiler_TEMPLATE_SAVE_STATE
-dvmCompiler_TEMPLATE_SAVE_STATE:
-/* File: armv5te-vfp/TEMPLATE_SAVE_STATE.S */
+    .global dvmCompiler_TEMPLATE_MEM_OP_DECODE
+dvmCompiler_TEMPLATE_MEM_OP_DECODE:
+/* File: armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S */
+#if defined(WITH_SELF_VERIFICATION)
     /*
-     * This handler performs a register save for selfVerification mode.
-     * On entry:
-     *    Top of stack + 4: r7 value to save
-     *    Top of stack + 0: r0 value to save
-     *    r0 - offset from rGLUE to the beginning of the heapArgSpace record
-     *    r7 - the value of regMap
+     * This handler encapsulates heap memory ops for selfVerification mode.
      *
-     * The handler must save regMap, r0-r12 and then return with r0-r12
-     * with their original values (note that this means r0 and r7 must take
-     * the values on the stack - not the ones in those registers on entry.
-     * Finally, the two registers previously pushed must be popped.
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
      */
-    add     r0, r0, rGLUE               @ pointer to heapArgSpace
-    stmia   r0!, {r7}                   @ save regMap
-    ldr     r7, [r13, #0]               @ recover r0 value
-    stmia   r0!, {r7}                   @ save r0
-    ldr     r7, [r13, #4]               @ recover r7 value
-    stmia   r0!, {r1-r12}
-    add     r0, #12                     @ move to start of FP save regio
-    vstmia  r0, {d0-d15}
-    pop     {r0, r7}                    @ recover r0, r7
-    bx      lr
-
-/* ------------------------------ */
-    .balign 4
-    .global dvmCompiler_TEMPLATE_RESTORE_STATE
-dvmCompiler_TEMPLATE_RESTORE_STATE:
-/* File: armv5te-vfp/TEMPLATE_RESTORE_STATE.S */
-    /*
-     * This handler restores state following a selfVerification memory access.
-     * On entry:
-     *    r0 - offset from rGLUE to the 1st element of the coreRegs save array.
-     */
-    add     r0, r0, rGLUE               @ pointer to heapArgSpace.coreRegs[0]
-    add     r0, #64                     @ pointer to heapArgSpace.fpRegs[0]
-    vldmia  r0, {d0-d15}
-    sub     r0, #64                     @ pointer to heapArgSpace.coreRegs[0]
-    ldmia   r0, {r0-r12}
-    bx      lr
+    vpush   {d0-d15}                    @ save out all fp registers
+    push    {r0-r12,lr}                 @ save out all registers
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    vpop    {d0-d15}                    @ restore all fp registers
+    bx      lr                          @ return to compiled code
+#endif
 
 /* ------------------------------ */
     .balign 4
@@ -1535,6 +1514,10 @@
     .word   dvmMterpCommonExceptionThrown
 .LdvmLockObject:
     .word   dvmLockObject
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+    .word   dvmSelfVerificationMemOpDecode
+#endif
 .L__aeabi_cdcmple:
     .word   __aeabi_cdcmple
 .L__aeabi_cfcmple:
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
index ffb9786..173cec0 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
@@ -786,44 +786,26 @@
 
 /* ------------------------------ */
     .balign 4
-    .global dvmCompiler_TEMPLATE_SAVE_STATE
-dvmCompiler_TEMPLATE_SAVE_STATE:
-/* File: armv5te/TEMPLATE_SAVE_STATE.S */
+    .global dvmCompiler_TEMPLATE_MEM_OP_DECODE
+dvmCompiler_TEMPLATE_MEM_OP_DECODE:
+/* File: armv5te/TEMPLATE_MEM_OP_DECODE.S */
+#if defined(WITH_SELF_VERIFICATION)
     /*
-     * This handler performs a register save for selfVerification mode.
-     * On entry:
-     *    Top of stack + 4: r7 value to save
-     *    Top of stack + 0: r0 value to save
-     *    r0 - offset from rGLUE to the beginning of the heapArgSpace record
-     *    r7 - the value of regMap
+     * This handler encapsulates heap memory ops for selfVerification mode.
      *
-     * The handler must save regMap, r0-r12 and then return with r0-r12
-     * with their original values (note that this means r0 and r7 must take
-     * the values on the stack - not the ones in those registers on entry.
-     * Finally, the two registers previously pushed must be popped.
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
      */
-    add     r0, r0, rGLUE               @ pointer to heapArgSpace
-    stmia   r0!, {r7}                   @ save regMap
-    ldr     r7, [r13, #0]               @ recover r0 value
-    stmia   r0!, {r7}                   @ save r0
-    ldr     r7, [r13, #4]               @ recover r7 value
-    stmia   r0!, {r1-r12}
-    pop     {r0, r7}                    @ recover r0, r7
-    bx      lr
-
-/* ------------------------------ */
-    .balign 4
-    .global dvmCompiler_TEMPLATE_RESTORE_STATE
-dvmCompiler_TEMPLATE_RESTORE_STATE:
-/* File: armv5te/TEMPLATE_RESTORE_STATE.S */
-    /*
-     * This handler restores state following a selfVerification memory access.
-     * On entry:
-     *    r0 - offset from rGLUE to the 1st element of the coreRegs save array.
-     */
-    add     r0, r0, rGLUE               @ pointer to heapArgSpace.coreRegs[0]
-    ldmia   r0, {r0-r12}
-    bx      lr
+    push    {r0-r12,lr}                 @ save out all registers
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    bx      lr                          @ return to compiled code
+#endif
 
 /* ------------------------------ */
     .balign 4
@@ -1260,6 +1242,10 @@
     .word   dvmMterpCommonExceptionThrown
 .LdvmLockObject:
     .word   dvmLockObject
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+    .word   dvmSelfVerificationMemOpDecode
+#endif
 .L__aeabi_cdcmple:
     .word   __aeabi_cdcmple
 .L__aeabi_cfcmple:
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
index b157ff3..872a1df 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
@@ -1056,49 +1056,28 @@
 
 /* ------------------------------ */
     .balign 4
-    .global dvmCompiler_TEMPLATE_SAVE_STATE
-dvmCompiler_TEMPLATE_SAVE_STATE:
-/* File: armv5te-vfp/TEMPLATE_SAVE_STATE.S */
+    .global dvmCompiler_TEMPLATE_MEM_OP_DECODE
+dvmCompiler_TEMPLATE_MEM_OP_DECODE:
+/* File: armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S */
+#if defined(WITH_SELF_VERIFICATION)
     /*
-     * This handler performs a register save for selfVerification mode.
-     * On entry:
-     *    Top of stack + 4: r7 value to save
-     *    Top of stack + 0: r0 value to save
-     *    r0 - offset from rGLUE to the beginning of the heapArgSpace record
-     *    r7 - the value of regMap
+     * This handler encapsulates heap memory ops for selfVerification mode.
      *
-     * The handler must save regMap, r0-r12 and then return with r0-r12
-     * with their original values (note that this means r0 and r7 must take
-     * the values on the stack - not the ones in those registers on entry.
-     * Finally, the two registers previously pushed must be popped.
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
      */
-    add     r0, r0, rGLUE               @ pointer to heapArgSpace
-    stmia   r0!, {r7}                   @ save regMap
-    ldr     r7, [r13, #0]               @ recover r0 value
-    stmia   r0!, {r7}                   @ save r0
-    ldr     r7, [r13, #4]               @ recover r7 value
-    stmia   r0!, {r1-r12}
-    add     r0, #12                     @ move to start of FP save regio
-    vstmia  r0, {d0-d15}
-    pop     {r0, r7}                    @ recover r0, r7
-    bx      lr
-
-/* ------------------------------ */
-    .balign 4
-    .global dvmCompiler_TEMPLATE_RESTORE_STATE
-dvmCompiler_TEMPLATE_RESTORE_STATE:
-/* File: armv5te-vfp/TEMPLATE_RESTORE_STATE.S */
-    /*
-     * This handler restores state following a selfVerification memory access.
-     * On entry:
-     *    r0 - offset from rGLUE to the 1st element of the coreRegs save array.
-     */
-    add     r0, r0, rGLUE               @ pointer to heapArgSpace.coreRegs[0]
-    add     r0, #64                     @ pointer to heapArgSpace.fpRegs[0]
-    vldmia  r0, {d0-d15}
-    sub     r0, #64                     @ pointer to heapArgSpace.coreRegs[0]
-    ldmia   r0, {r0-r12}
-    bx      lr
+    vpush   {d0-d15}                    @ save out all fp registers
+    push    {r0-r12,lr}                 @ save out all registers
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    vpop    {d0-d15}                    @ restore all fp registers
+    bx      lr                          @ return to compiled code
+#endif
 
 /* ------------------------------ */
     .balign 4
@@ -1541,6 +1520,10 @@
     .word   dvmMterpCommonExceptionThrown
 .LdvmLockObject:
     .word   dvmLockObject
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+    .word   dvmSelfVerificationMemOpDecode
+#endif
 .L__aeabi_cdcmple:
     .word   __aeabi_cdcmple
 .L__aeabi_cfcmple:
diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h
index 3231968..67d005e 100644
--- a/vm/interp/InterpDefs.h
+++ b/vm/interp/InterpDefs.h
@@ -38,19 +38,6 @@
 } InterpEntry;
 
 #if defined(WITH_JIT)
-#if defined(WITH_SELF_VERIFICATION)
-/*
- * Note: layout is important.  This record hold saved state information
- * and is used by both C, generated code in the cache, and assembler handlers.
- */
-typedef struct HeapArgSpace {
-//FIXME: This is arm-specific.  Need to be able to redefine this by target
-    int regMap;
-    int coreRegs[16];
-    int fpRegs[32];
-} HeapArgSpace;
-#endif
-
 /*
  * There are six entry points from the compiled code to the interpreter:
  * 1) dvmJitToInterpNormal: find if there is a corresponding compilation for
@@ -186,9 +173,6 @@
     int currRunLen;           // Length of run in 16-bit words
     int lastThreshFilter;
     const u2* lastPC;         // Stage the PC first for the threaded interpreter
-#if defined(WITH_SELF_VERIFICATION)
-    struct HeapArgSpace heapArgSpace;
-#endif
     const u2* threshFilter[JIT_TRACE_THRESH_FILTER_SIZE];
     JitTraceRun trace[MAX_JIT_RUN_LEN];
     double calleeSave[JIT_CALLEE_SAVE_DOUBLE_COUNT];