Jit: Monitor exit, possible fix for Issue 2396073

Two problems with monitor-exit:
   1.  The Jit code wasn't checking for exception thrown following
       unlocks of fat locks using dvmUnlockObject().
   2.  The mterp interpreter unlock code branched to handle exceptions
       thrown during dvmUnlockObject() with the wrong dalvik PC (the
       dPC of the unlock, rather than the instruction following the unlock).

Similar issue with the x86 interpreter fixed.  Also, deleted armv7-a
MONITOR_ENTER template, which turned out to be identical to the armv5te
one.
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index 99d392d..4048c0a 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -1276,6 +1276,15 @@
         loadConstant(cUnit, r2, (int)dvmUnlockObject);
         /* Do the call */
         opReg(cUnit, kOpBlx, r2);
+        opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */
+        ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
+        loadConstant(cUnit, r0,
+                     (int) (cUnit->method->insns + mir->offset +
+                     dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_EXIT)));
+        genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+        ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+        target->defMask = ENCODE_ALL;
+        branchOver->generic.target = (LIR *) target;
         dvmCompilerColbberCallRegs(cUnit);
     }
 }
diff --git a/vm/compiler/codegen/arm/Thumb2/Gen.c b/vm/compiler/codegen/arm/Thumb2/Gen.c
index 071964a..1390d64 100644
--- a/vm/compiler/codegen/arm/Thumb2/Gen.c
+++ b/vm/compiler/codegen/arm/Thumb2/Gen.c
@@ -253,6 +253,15 @@
                 sizeof(StackSaveArea) -
                 offsetof(StackSaveArea, xtra.currentPc));
         opReg(cUnit, kOpBlx, r7);
+        opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */
+        ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
+        loadConstant(cUnit, r0,
+                     (int) (cUnit->method->insns + mir->offset +
+                     dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_EXIT)));
+        genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+        ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+        target->defMask = ENCODE_ALL;
+        branchOver->generic.target = (LIR *) target;
         dvmCompilerColbberCallRegs(cUnit);
     }
 
diff --git a/vm/compiler/template/armv7-a/TEMPLATE_MONITOR_ENTER.S b/vm/compiler/template/armv7-a/TEMPLATE_MONITOR_ENTER.S
deleted file mode 100644
index 114bbdc..0000000
--- a/vm/compiler/template/armv7-a/TEMPLATE_MONITOR_ENTER.S
+++ /dev/null
@@ -1,32 +0,0 @@
-    /*
-     * thumb2 specific.
-     *
-     * In this variant of the MONITOR_ENTER handler, we assume that
-     * the test for the simple thin lock case has already been done.
-     * So, we'll just call dvmLockObject(), refresh the
-     * jit's on/off switch on return and then bail out to the interpreter.
-     * We have to bail to the interpreter because the translation cache
-     * may have been cleared while we were blocked on a monitor in
-     * dvmLockObject.
-     *
-     * On entry:
-     *    r0 - self pointer
-     *    r1 - the object (which has already been null-checked by the caller
-     *    r4 - the Dalvik PC of the following instruction.
-     *
-     */
-    ldr     r2, .LdvmLockObject
-    mov     r3, #0                       @ Record that we're not returning
-    str     r3, [r0, #offThread_inJitCodeCache]
-    blx     r2                           @ dvmLockObject(self, obj)
-    @ refresh Jit's on/off status
-    ldr     r0, [rGLUE, #offGlue_ppJitProfTable]
-    ldr     r0, [r0]
-    ldr     r2, .LdvmJitToInterpNoChain
-    str     r0, [rGLUE, #offGlue_pJitProfTable]
-    @ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(EXIT_STATS)
-    mov     r0, #kHeavyweightMonitor
-#endif
-    bx      r2
-
diff --git a/vm/compiler/template/config-armv7-a b/vm/compiler/template/config-armv7-a
index 29d9019..be7af31 100644
--- a/vm/compiler/template/config-armv7-a
+++ b/vm/compiler/template/config-armv7-a
@@ -46,7 +46,7 @@
     op TEMPLATE_STRING_COMPARETO armv5te
     op TEMPLATE_STRING_INDEXOF armv5te
     op TEMPLATE_INTERPRET armv5te
-    op TEMPLATE_MONITOR_ENTER armv7-a
+    op TEMPLATE_MONITOR_ENTER armv5te
     op TEMPLATE_MONITOR_ENTER_DEBUG armv5te
 op-end
 
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
index 6d9b7f0..e83e773 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
@@ -1371,23 +1371,17 @@
     .balign 4
     .global dvmCompiler_TEMPLATE_MONITOR_ENTER
 dvmCompiler_TEMPLATE_MONITOR_ENTER:
-/* File: armv7-a/TEMPLATE_MONITOR_ENTER.S */
+/* File: armv5te/TEMPLATE_MONITOR_ENTER.S */
     /*
-     * thumb2 specific.
-     *
-     * In this variant of the MONITOR_ENTER handler, we assume that
-     * the test for the simple thin lock case has already been done.
-     * So, we'll just call dvmLockObject(), refresh the
-     * jit's on/off switch on return and then bail out to the interpreter.
-     * We have to bail to the interpreter because the translation cache
-     * may have been cleared while we were blocked on a monitor in
-     * dvmLockObject.
+     * Call out to the runtime to lock an object.  Because this thread
+     * may have been suspended in THREAD_MONITOR state and the Jit's
+     * translation cache subsequently cleared, we cannot return directly.
+     * Instead, unconditionally transition to the interpreter to resume.
      *
      * On entry:
      *    r0 - self pointer
      *    r1 - the object (which has already been null-checked by the caller
      *    r4 - the Dalvik PC of the following instruction.
-     *
      */
     ldr     r2, .LdvmLockObject
     mov     r3, #0                       @ Record that we're not returning
diff --git a/vm/mterp/armv5te/OP_MONITOR_EXIT.S b/vm/mterp/armv5te/OP_MONITOR_EXIT.S
index b334ae9..c9aedf0 100644
--- a/vm/mterp/armv5te/OP_MONITOR_EXIT.S
+++ b/vm/mterp/armv5te/OP_MONITOR_EXIT.S
@@ -13,12 +13,15 @@
     EXPORT_PC()                         @ before fetch: export the PC
     GET_VREG(r1, r2)                    @ r1<- vAA (object)
     cmp     r1, #0                      @ null object?
-    beq     common_errNullObject        @ yes
+    beq     1f                          @ yes
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
     bl      dvmUnlockObject             @ r0<- success for unlock(self, obj)
     cmp     r0, #0                      @ failed?
-    beq     common_exceptionThrown      @ yes, exception is pending
     FETCH_ADVANCE_INST(1)               @ before throw: advance rPC, load rINST
+    beq     common_exceptionThrown      @ yes, exception is pending
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     GOTO_OPCODE(ip)                     @ jump to next instruction
+1:
+    FETCH_ADVANCE_INST(1)               @ advance before throw
+    b      common_errNullObject
 
diff --git a/vm/mterp/out/InterpAsm-armv4t.S b/vm/mterp/out/InterpAsm-armv4t.S
index 2b1897e..c3cebb7 100644
--- a/vm/mterp/out/InterpAsm-armv4t.S
+++ b/vm/mterp/out/InterpAsm-armv4t.S
@@ -908,14 +908,17 @@
     EXPORT_PC()                         @ before fetch: export the PC
     GET_VREG(r1, r2)                    @ r1<- vAA (object)
     cmp     r1, #0                      @ null object?
-    beq     common_errNullObject        @ yes
+    beq     1f                          @ yes
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
     bl      dvmUnlockObject             @ r0<- success for unlock(self, obj)
     cmp     r0, #0                      @ failed?
-    beq     common_exceptionThrown      @ yes, exception is pending
     FETCH_ADVANCE_INST(1)               @ before throw: advance rPC, load rINST
+    beq     common_exceptionThrown      @ yes, exception is pending
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     GOTO_OPCODE(ip)                     @ jump to next instruction
+1:
+    FETCH_ADVANCE_INST(1)               @ advance before throw
+    b      common_errNullObject
 
 
 /* ------------------------------ */
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
index 0e82c92..2064668 100644
--- a/vm/mterp/out/InterpAsm-armv5te-vfp.S
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -908,14 +908,17 @@
     EXPORT_PC()                         @ before fetch: export the PC
     GET_VREG(r1, r2)                    @ r1<- vAA (object)
     cmp     r1, #0                      @ null object?
-    beq     common_errNullObject        @ yes
+    beq     1f                          @ yes
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
     bl      dvmUnlockObject             @ r0<- success for unlock(self, obj)
     cmp     r0, #0                      @ failed?
-    beq     common_exceptionThrown      @ yes, exception is pending
     FETCH_ADVANCE_INST(1)               @ before throw: advance rPC, load rINST
+    beq     common_exceptionThrown      @ yes, exception is pending
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     GOTO_OPCODE(ip)                     @ jump to next instruction
+1:
+    FETCH_ADVANCE_INST(1)               @ advance before throw
+    b      common_errNullObject
 
 
 /* ------------------------------ */
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index 73bf602..3a41054 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -908,14 +908,17 @@
     EXPORT_PC()                         @ before fetch: export the PC
     GET_VREG(r1, r2)                    @ r1<- vAA (object)
     cmp     r1, #0                      @ null object?
-    beq     common_errNullObject        @ yes
+    beq     1f                          @ yes
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
     bl      dvmUnlockObject             @ r0<- success for unlock(self, obj)
     cmp     r0, #0                      @ failed?
-    beq     common_exceptionThrown      @ yes, exception is pending
     FETCH_ADVANCE_INST(1)               @ before throw: advance rPC, load rINST
+    beq     common_exceptionThrown      @ yes, exception is pending
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     GOTO_OPCODE(ip)                     @ jump to next instruction
+1:
+    FETCH_ADVANCE_INST(1)               @ advance before throw
+    b      common_errNullObject
 
 
 /* ------------------------------ */
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
index ccd02b3..bc3b7eb 100644
--- a/vm/mterp/out/InterpAsm-armv7-a.S
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -905,14 +905,17 @@
     EXPORT_PC()                         @ before fetch: export the PC
     GET_VREG(r1, r2)                    @ r1<- vAA (object)
     cmp     r1, #0                      @ null object?
-    beq     common_errNullObject        @ yes
+    beq     1f                          @ yes
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
     bl      dvmUnlockObject             @ r0<- success for unlock(self, obj)
     cmp     r0, #0                      @ failed?
-    beq     common_exceptionThrown      @ yes, exception is pending
     FETCH_ADVANCE_INST(1)               @ before throw: advance rPC, load rINST
+    beq     common_exceptionThrown      @ yes, exception is pending
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
     GOTO_OPCODE(ip)                     @ jump to next instruction
+1:
+    FETCH_ADVANCE_INST(1)               @ advance before throw
+    b      common_errNullObject
 
 
 /* ------------------------------ */
diff --git a/vm/mterp/out/InterpAsm-x86.S b/vm/mterp/out/InterpAsm-x86.S
index 3783abe..1d9f36b 100644
--- a/vm/mterp/out/InterpAsm-x86.S
+++ b/vm/mterp/out/InterpAsm-x86.S
@@ -703,7 +703,7 @@
     GET_GLUE(%ecx)
     EXPORT_PC()
     testl   %eax,%eax                   # null object?
-    je      common_errNullObject        # go if so
+    je      .LOP_MONITOR_EXIT_errNullObject   # go if so
     movl    offGlue_self(%ecx),%ecx     # ecx<- glue->self
     movl    %eax,OUT_ARG1(%esp)
     SPILL(rPC)
@@ -6281,9 +6281,12 @@
     UNSPILL(rPC)
     FETCH_INST_WORD(1)
     testl   %eax,%eax                   # success?
-    je      common_exceptionThrown      # no, exception pending
     ADVANCE_PC(1)
+    je      common_exceptionThrown      # no, exception pending
     GOTO_NEXT
+.LOP_MONITOR_EXIT_errNullObject:
+    ADVANCE_PC(1)                       # advance before throw
+    jmp     common_errNullObject
 
 /* continuation for OP_CHECK_CAST */
 
diff --git a/vm/mterp/x86/OP_MONITOR_EXIT.S b/vm/mterp/x86/OP_MONITOR_EXIT.S
index b360a3e..788b7a7 100644
--- a/vm/mterp/x86/OP_MONITOR_EXIT.S
+++ b/vm/mterp/x86/OP_MONITOR_EXIT.S
@@ -14,7 +14,7 @@
     GET_GLUE(%ecx)
     EXPORT_PC()
     testl   %eax,%eax                   # null object?
-    je      common_errNullObject        # go if so
+    je      .L${opcode}_errNullObject   # go if so
     movl    offGlue_self(%ecx),%ecx     # ecx<- glue->self
     movl    %eax,OUT_ARG1(%esp)
     SPILL(rPC)
@@ -27,6 +27,9 @@
     UNSPILL(rPC)
     FETCH_INST_WORD(1)
     testl   %eax,%eax                   # success?
-    je      common_exceptionThrown      # no, exception pending
     ADVANCE_PC(1)
+    je      common_exceptionThrown      # no, exception pending
     GOTO_NEXT
+.L${opcode}_errNullObject:
+    ADVANCE_PC(1)                       # advance before throw
+    jmp     common_errNullObject