Merge "MIPS: HRor clean-up"
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 0691f2a..699ab3e 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -1312,7 +1312,114 @@
 .endm
 
 // Generate the allocation entrypoints for each allocator.
-GENERATE_ALL_ALLOC_ENTRYPOINTS
+GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
+ENTRY art_quick_alloc_object_rosalloc
+
+    # Fast path rosalloc allocation
+    # a0: type_idx
+    # a1: ArtMethod*
+    # s1: Thread::Current
+    # -----------------------------
+    # t0: class
+    # t1: object size
+    # t2: rosalloc run
+    # t3: thread stack top offset
+    # t4: thread stack bottom offset
+    # v0: free list head
+    #
+    # t5, t6 : temps
+
+    lw    $t0, ART_METHOD_DEX_CACHE_TYPES_OFFSET_32($a1)       # Load dex cache resolved types
+                                                               # array.
+
+    sll   $t5, $a0, COMPRESSED_REFERENCE_SIZE_SHIFT            # Shift the value.
+    addu  $t5, $t0, $t5                                        # Compute the index.
+    lw    $t0, 0($t5)                                          # Load class (t0).
+    beqz  $t0, .Lart_quick_alloc_object_rosalloc_slow_path
+
+    li    $t6, MIRROR_CLASS_STATUS_INITIALIZED
+    lw    $t5, MIRROR_CLASS_STATUS_OFFSET($t0)                 # Check class status.
+    bne   $t5, $t6, .Lart_quick_alloc_object_rosalloc_slow_path
+
+    # Add a fake dependence from the following access flag and size loads to the status load. This
+    # is to prevent those loads from being reordered above the status load and reading wrong values.
+    xor   $t5, $t5, $t5
+    addu  $t0, $t0, $t5
+
+    lw    $t5, MIRROR_CLASS_ACCESS_FLAGS_OFFSET($t0)           # Check if access flags has
+    li    $t6, ACCESS_FLAGS_CLASS_IS_FINALIZABLE               # kAccClassIsFinalizable.
+    and   $t6, $t5, $t6
+    bnez  $t6, .Lart_quick_alloc_object_rosalloc_slow_path
+
+    lw    $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1)        # Check if thread local allocation
+    lw    $t4, THREAD_LOCAL_ALLOC_STACK_END_OFFSET($s1)        # stack has any room left.
+    bgeu  $t3, $t4, .Lart_quick_alloc_object_rosalloc_slow_path
+
+    lw    $t1, MIRROR_CLASS_OBJECT_SIZE_OFFSET($t0)            # Load object size (t1).
+    li    $t5, ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE          # Check if size is for a thread local
+                                                               # allocation.
+    bgtu  $t1, $t5, .Lart_quick_alloc_object_rosalloc_slow_path
+
+    # Compute the rosalloc bracket index from the size. Allign up the size by the rosalloc bracket
+    # quantum size and divide by the quantum size and subtract by 1.
+
+    addiu $t1, $t1, -1                                         # Decrease obj size and shift right
+    srl   $t1, $t1, ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT        # by quantum.
+
+    sll   $t2, $t1, POINTER_SIZE_SHIFT
+    addu  $t2, $t2, $s1
+    lw    $t2, THREAD_ROSALLOC_RUNS_OFFSET($t2)                # Load rosalloc run (t2).
+
+    # Load the free list head (v0).
+    # NOTE: this will be the return val.
+
+    lw    $v0, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
+    beqz  $v0, .Lart_quick_alloc_object_rosalloc_slow_path
+    nop
+
+    # Load the next pointer of the head and update the list head with the next pointer.
+
+    lw    $t5, ROSALLOC_SLOT_NEXT_OFFSET($v0)
+    sw    $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
+
+    # Store the class pointer in the header. This also overwrites the first pointer. The offsets are
+    # asserted to match.
+
+#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
+#error "Class pointer needs to overwrite next pointer."
+#endif
+
+    POISON_HEAP_REF $t0
+    sw    $t0, MIRROR_OBJECT_CLASS_OFFSET($v0)
+
+    # Push the new object onto the thread local allocation stack and increment the thread local
+    # allocation stack top.
+
+    sw    $v0, 0($t3)
+    addiu $t3, $t3, COMPRESSED_REFERENCE_SIZE
+    sw    $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1)
+
+    # Decrement the size of the free list.
+
+    lw    $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
+    addiu $t5, $t5, -1
+    sw    $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
+
+    sync                                                          # Fence.
+
+    jalr  $zero, $ra
+    nop
+
+  .Lart_quick_alloc_object_rosalloc_slow_path:
+
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
+    jal   artAllocObjectFromCodeRosAlloc
+    move  $a2 ,$s1                                                # Pass self as argument.
+    RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+
+END art_quick_alloc_object_rosalloc
 
     /*
      * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
diff --git a/runtime/interpreter/mterp/arm/footer.S b/runtime/interpreter/mterp/arm/footer.S
index 75e0037..617f572 100644
--- a/runtime/interpreter/mterp/arm/footer.S
+++ b/runtime/interpreter/mterp/arm/footer.S
@@ -128,9 +128,11 @@
  */
 MterpFallback:
     EXPORT_PC
+#if MTERP_LOGGING
     mov  r0, rSELF
     add  r1, rFP, #OFF_FP_SHADOWFRAME
     bl MterpLogFallback
+#endif
 MterpCommonFallback:
     mov     r0, #0                                  @ signal retry with reference interpreter.
     b       MterpDone
@@ -144,9 +146,6 @@
  *  uint32_t* rFP  (should still be live, pointer to base of vregs)
  */
 MterpExceptionReturn:
-    ldr     r2, [rFP, #OFF_FP_RESULT_REGISTER]
-    str     r0, [r2]
-    str     r1, [r2, #4]
     mov     r0, #1                                  @ signal return to caller.
     b MterpDone
 MterpReturn:
diff --git a/runtime/interpreter/mterp/arm/op_aget.S b/runtime/interpreter/mterp/arm/op_aget.S
index 2cc4d66..11f7079 100644
--- a/runtime/interpreter/mterp/arm/op_aget.S
+++ b/runtime/interpreter/mterp/arm/op_aget.S
@@ -1,11 +1,11 @@
-%default { "load":"ldr", "shift":"2", "is_object":"0", "data_offset":"MIRROR_INT_ARRAY_DATA_OFFSET" }
+%default { "load":"ldr", "shift":"2", "data_offset":"MIRROR_INT_ARRAY_DATA_OFFSET" }
     /*
      * Array get, 32 bits or less.  vAA <- vBB[vCC].
      *
      * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
      * instructions.  We use a pair of FETCH_Bs instead.
      *
-     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     * for: aget, aget-boolean, aget-byte, aget-char, aget-short
      *
      * NOTE: assumes data offset for arrays is the same for all non-wide types.
      * If this changes, specialize.
@@ -25,9 +25,5 @@
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     $load   r2, [r0, #$data_offset]     @ r2<- vBB[vCC]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
-    .if $is_object
-    SET_VREG_OBJECT r2, r9              @ vAA<- r2
-    .else
     SET_VREG r2, r9                     @ vAA<- r2
-    .endif
     GOTO_OPCODE ip                      @ jump to next instruction
diff --git a/runtime/interpreter/mterp/arm/op_iget_object_quick.S b/runtime/interpreter/mterp/arm/op_iget_object_quick.S
index 1f8dc5a..fe29106 100644
--- a/runtime/interpreter/mterp/arm/op_iget_object_quick.S
+++ b/runtime/interpreter/mterp/arm/op_iget_object_quick.S
@@ -1 +1,17 @@
-%include "arm/op_iget_quick.S" {"is_object":"1"}
+    /* For: iget-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    FETCH r1, 1                         @ r1<- field byte offset
+    GET_VREG r0, r2                     @ r0<- object we're operating on
+    cmp     r0, #0                      @ check object for null
+    beq     common_errNullObject        @ object was null
+    bl      artIGetObjectFromMterp      @ (obj, offset)
+    ldr     r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    PREFETCH_INST 2
+    cmp     r3, #0
+    bne     MterpPossibleException      @ bail out
+    SET_VREG_OBJECT r0, r2              @ fp[A]<- r0
+    ADVANCE 2                           @ advance rPC
+    GET_INST_OPCODE ip                  @ extract opcode from rINST
+    GOTO_OPCODE ip                      @ jump to next instruction
diff --git a/runtime/interpreter/mterp/arm/op_iget_quick.S b/runtime/interpreter/mterp/arm/op_iget_quick.S
index 9229afc..0eaf364 100644
--- a/runtime/interpreter/mterp/arm/op_iget_quick.S
+++ b/runtime/interpreter/mterp/arm/op_iget_quick.S
@@ -1,5 +1,5 @@
-%default { "load":"ldr", "is_object":"0" }
-    /* For: iget-quick, iget-object-quick */
+%default { "load":"ldr" }
+    /* For: iget-quick, iget-boolean-quick, iget-byte-quick, iget-char-quick, iget-short-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     FETCH r1, 1                         @ r1<- field byte offset
@@ -9,10 +9,6 @@
     beq     common_errNullObject        @ object was null
     $load   r0, [r3, r1]                @ r0<- obj.field
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    .if $is_object
-    SET_VREG_OBJECT r0, r2              @ fp[A]<- r0
-    .else
     SET_VREG r0, r2                     @ fp[A]<- r0
-    .endif
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 060fe76..9975458 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -607,5 +607,14 @@
   }
 }
 
+extern "C" mirror::Object* artIGetObjectFromMterp(mirror::Object* obj, uint32_t field_offset)
+  SHARED_REQUIRES(Locks::mutator_lock_) {
+  if (UNLIKELY(obj == nullptr)) {
+    ThrowNullPointerExceptionFromInterpreter();
+    return nullptr;
+  }
+  return obj->GetFieldObject<mirror::Object>(MemberOffset(field_offset));
+}
+
 }  // namespace interpreter
 }  // namespace art
diff --git a/runtime/interpreter/mterp/out/mterp_arm.S b/runtime/interpreter/mterp/out/mterp_arm.S
index 33036e6..2d6f057 100644
--- a/runtime/interpreter/mterp/out/mterp_arm.S
+++ b/runtime/interpreter/mterp/out/mterp_arm.S
@@ -2013,7 +2013,7 @@
      * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
      * instructions.  We use a pair of FETCH_Bs instead.
      *
-     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     * for: aget, aget-boolean, aget-byte, aget-char, aget-short
      *
      * NOTE: assumes data offset for arrays is the same for all non-wide types.
      * If this changes, specialize.
@@ -2033,11 +2033,7 @@
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     ldr   r2, [r0, #MIRROR_INT_ARRAY_DATA_OFFSET]     @ r2<- vBB[vCC]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
-    .if 0
-    SET_VREG_OBJECT r2, r9              @ vAA<- r2
-    .else
     SET_VREG r2, r9                     @ vAA<- r2
-    .endif
     GOTO_OPCODE ip                      @ jump to next instruction
 
 /* ------------------------------ */
@@ -2106,7 +2102,7 @@
      * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
      * instructions.  We use a pair of FETCH_Bs instead.
      *
-     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     * for: aget, aget-boolean, aget-byte, aget-char, aget-short
      *
      * NOTE: assumes data offset for arrays is the same for all non-wide types.
      * If this changes, specialize.
@@ -2126,11 +2122,7 @@
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     ldrb   r2, [r0, #MIRROR_BOOLEAN_ARRAY_DATA_OFFSET]     @ r2<- vBB[vCC]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
-    .if 0
-    SET_VREG_OBJECT r2, r9              @ vAA<- r2
-    .else
     SET_VREG r2, r9                     @ vAA<- r2
-    .endif
     GOTO_OPCODE ip                      @ jump to next instruction
 
 
@@ -2145,7 +2137,7 @@
      * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
      * instructions.  We use a pair of FETCH_Bs instead.
      *
-     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     * for: aget, aget-boolean, aget-byte, aget-char, aget-short
      *
      * NOTE: assumes data offset for arrays is the same for all non-wide types.
      * If this changes, specialize.
@@ -2165,11 +2157,7 @@
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     ldrsb   r2, [r0, #MIRROR_BYTE_ARRAY_DATA_OFFSET]     @ r2<- vBB[vCC]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
-    .if 0
-    SET_VREG_OBJECT r2, r9              @ vAA<- r2
-    .else
     SET_VREG r2, r9                     @ vAA<- r2
-    .endif
     GOTO_OPCODE ip                      @ jump to next instruction
 
 
@@ -2184,7 +2172,7 @@
      * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
      * instructions.  We use a pair of FETCH_Bs instead.
      *
-     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     * for: aget, aget-boolean, aget-byte, aget-char, aget-short
      *
      * NOTE: assumes data offset for arrays is the same for all non-wide types.
      * If this changes, specialize.
@@ -2204,11 +2192,7 @@
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     ldrh   r2, [r0, #MIRROR_CHAR_ARRAY_DATA_OFFSET]     @ r2<- vBB[vCC]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
-    .if 0
-    SET_VREG_OBJECT r2, r9              @ vAA<- r2
-    .else
     SET_VREG r2, r9                     @ vAA<- r2
-    .endif
     GOTO_OPCODE ip                      @ jump to next instruction
 
 
@@ -2223,7 +2207,7 @@
      * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
      * instructions.  We use a pair of FETCH_Bs instead.
      *
-     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     * for: aget, aget-boolean, aget-byte, aget-char, aget-short
      *
      * NOTE: assumes data offset for arrays is the same for all non-wide types.
      * If this changes, specialize.
@@ -2243,11 +2227,7 @@
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     ldrsh   r2, [r0, #MIRROR_SHORT_ARRAY_DATA_OFFSET]     @ r2<- vBB[vCC]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
-    .if 0
-    SET_VREG_OBJECT r2, r9              @ vAA<- r2
-    .else
     SET_VREG r2, r9                     @ vAA<- r2
-    .endif
     GOTO_OPCODE ip                      @ jump to next instruction
 
 
@@ -7127,7 +7107,7 @@
     .balign 128
 .L_op_iget_quick: /* 0xe3 */
 /* File: arm/op_iget_quick.S */
-    /* For: iget-quick, iget-object-quick */
+    /* For: iget-quick, iget-boolean-quick, iget-byte-quick, iget-char-quick, iget-short-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     FETCH r1, 1                         @ r1<- field byte offset
@@ -7137,11 +7117,7 @@
     beq     common_errNullObject        @ object was null
     ldr   r0, [r3, r1]                @ r0<- obj.field
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    .if 0
-    SET_VREG_OBJECT r0, r2              @ fp[A]<- r0
-    .else
     SET_VREG r0, r2                     @ fp[A]<- r0
-    .endif
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
 
@@ -7167,26 +7143,24 @@
     .balign 128
 .L_op_iget_object_quick: /* 0xe5 */
 /* File: arm/op_iget_object_quick.S */
-/* File: arm/op_iget_quick.S */
-    /* For: iget-quick, iget-object-quick */
+    /* For: iget-object-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     FETCH r1, 1                         @ r1<- field byte offset
-    GET_VREG r3, r2                     @ r3<- object we're operating on
-    ubfx    r2, rINST, #8, #4           @ r2<- A
-    cmp     r3, #0                      @ check object for null
+    GET_VREG r0, r2                     @ r0<- object we're operating on
+    cmp     r0, #0                      @ check object for null
     beq     common_errNullObject        @ object was null
-    ldr   r0, [r3, r1]                @ r0<- obj.field
-    FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    .if 1
+    bl      artIGetObjectFromMterp      @ (obj, offset)
+    ldr     r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    PREFETCH_INST 2
+    cmp     r3, #0
+    bne     MterpPossibleException      @ bail out
     SET_VREG_OBJECT r0, r2              @ fp[A]<- r0
-    .else
-    SET_VREG r0, r2                     @ fp[A]<- r0
-    .endif
+    ADVANCE 2                           @ advance rPC
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
 
-
 /* ------------------------------ */
     .balign 128
 .L_op_iput_quick: /* 0xe6 */
@@ -7373,7 +7347,7 @@
 .L_op_iget_boolean_quick: /* 0xef */
 /* File: arm/op_iget_boolean_quick.S */
 /* File: arm/op_iget_quick.S */
-    /* For: iget-quick, iget-object-quick */
+    /* For: iget-quick, iget-boolean-quick, iget-byte-quick, iget-char-quick, iget-short-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     FETCH r1, 1                         @ r1<- field byte offset
@@ -7383,11 +7357,7 @@
     beq     common_errNullObject        @ object was null
     ldrb   r0, [r3, r1]                @ r0<- obj.field
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    .if 0
-    SET_VREG_OBJECT r0, r2              @ fp[A]<- r0
-    .else
     SET_VREG r0, r2                     @ fp[A]<- r0
-    .endif
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
 
@@ -7397,7 +7367,7 @@
 .L_op_iget_byte_quick: /* 0xf0 */
 /* File: arm/op_iget_byte_quick.S */
 /* File: arm/op_iget_quick.S */
-    /* For: iget-quick, iget-object-quick */
+    /* For: iget-quick, iget-boolean-quick, iget-byte-quick, iget-char-quick, iget-short-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     FETCH r1, 1                         @ r1<- field byte offset
@@ -7407,11 +7377,7 @@
     beq     common_errNullObject        @ object was null
     ldrsb   r0, [r3, r1]                @ r0<- obj.field
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    .if 0
-    SET_VREG_OBJECT r0, r2              @ fp[A]<- r0
-    .else
     SET_VREG r0, r2                     @ fp[A]<- r0
-    .endif
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
 
@@ -7421,7 +7387,7 @@
 .L_op_iget_char_quick: /* 0xf1 */
 /* File: arm/op_iget_char_quick.S */
 /* File: arm/op_iget_quick.S */
-    /* For: iget-quick, iget-object-quick */
+    /* For: iget-quick, iget-boolean-quick, iget-byte-quick, iget-char-quick, iget-short-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     FETCH r1, 1                         @ r1<- field byte offset
@@ -7431,11 +7397,7 @@
     beq     common_errNullObject        @ object was null
     ldrh   r0, [r3, r1]                @ r0<- obj.field
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    .if 0
-    SET_VREG_OBJECT r0, r2              @ fp[A]<- r0
-    .else
     SET_VREG r0, r2                     @ fp[A]<- r0
-    .endif
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
 
@@ -7445,7 +7407,7 @@
 .L_op_iget_short_quick: /* 0xf2 */
 /* File: arm/op_iget_short_quick.S */
 /* File: arm/op_iget_quick.S */
-    /* For: iget-quick, iget-object-quick */
+    /* For: iget-quick, iget-boolean-quick, iget-byte-quick, iget-char-quick, iget-short-quick */
     /* op vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     FETCH r1, 1                         @ r1<- field byte offset
@@ -7455,11 +7417,7 @@
     beq     common_errNullObject        @ object was null
     ldrsh   r0, [r3, r1]                @ r0<- obj.field
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    .if 0
-    SET_VREG_OBJECT r0, r2              @ fp[A]<- r0
-    .else
     SET_VREG r0, r2                     @ fp[A]<- r0
-    .endif
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
 
@@ -12204,9 +12162,11 @@
  */
 MterpFallback:
     EXPORT_PC
+#if MTERP_LOGGING
     mov  r0, rSELF
     add  r1, rFP, #OFF_FP_SHADOWFRAME
     bl MterpLogFallback
+#endif
 MterpCommonFallback:
     mov     r0, #0                                  @ signal retry with reference interpreter.
     b       MterpDone
@@ -12220,9 +12180,6 @@
  *  uint32_t* rFP  (should still be live, pointer to base of vregs)
  */
 MterpExceptionReturn:
-    ldr     r2, [rFP, #OFF_FP_RESULT_REGISTER]
-    str     r0, [r2]
-    str     r1, [r2, #4]
     mov     r0, #1                                  @ signal return to caller.
     b MterpDone
 MterpReturn:
diff --git a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
new file mode 100644
index 0000000..54879fb
--- /dev/null
+++ b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+
+#include "base/casts.h"
+#include "base/macros.h"
+#include "java_vm_ext.h"
+#include "jni_env_ext.h"
+#include "thread-inl.h"
+
+namespace art {
+namespace {
+
+static volatile std::atomic<bool> vm_was_shutdown(false);
+
+extern "C" JNIEXPORT void JNICALL Java_Main_waitAndCallIntoJniEnv(JNIEnv* env, jclass) {
+  // Wait until the runtime is shutdown.
+  while (!vm_was_shutdown.load()) {
+    usleep(1000);
+  }
+  std::cout << "About to call exception check\n";
+  env->ExceptionCheck();
+  LOG(ERROR) << "Should not be reached!";
+}
+
+// NO_RETURN does not work with extern "C" for target builds.
+extern "C" JNIEXPORT void JNICALL Java_Main_destroyJavaVMAndExit(JNIEnv* env, jclass) {
+  // Fake up the managed stack so we can detach.
+  Thread* const self = Thread::Current();
+  self->SetTopOfStack(nullptr);
+  self->SetTopOfShadowStack(nullptr);
+  JavaVM* vm = down_cast<JNIEnvExt*>(env)->vm;
+  vm->DetachCurrentThread();
+  vm->DestroyJavaVM();
+  vm_was_shutdown.store(true);
+  // Give threads some time to get stuck in ExceptionCheck.
+  usleep(1000000);
+  if (env != nullptr) {
+    // Use env != nullptr to trick noreturn.
+    exit(0);
+  }
+}
+
+}  // namespace
+}  // namespace art
diff --git a/test/136-daemon-jni-shutdown/expected.txt b/test/136-daemon-jni-shutdown/expected.txt
new file mode 100644
index 0000000..f0b6353
--- /dev/null
+++ b/test/136-daemon-jni-shutdown/expected.txt
@@ -0,0 +1,5 @@
+JNI_OnLoad called
+About to call exception check
+About to call exception check
+About to call exception check
+About to call exception check
diff --git a/test/136-daemon-jni-shutdown/info.txt b/test/136-daemon-jni-shutdown/info.txt
new file mode 100644
index 0000000..06a12df
--- /dev/null
+++ b/test/136-daemon-jni-shutdown/info.txt
@@ -0,0 +1 @@
+Test that daemon threads that call into a JNI env after the runtime is shutdown do not crash.
\ No newline at end of file
diff --git a/test/136-daemon-jni-shutdown/src/Main.java b/test/136-daemon-jni-shutdown/src/Main.java
new file mode 100644
index 0000000..6eceb75
--- /dev/null
+++ b/test/136-daemon-jni-shutdown/src/Main.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Test that daemon threads that call into a JNI env after the runtime is shutdown do not crash.
+ */
+public class Main {
+
+    public final static int THREAD_COUNT = 4;
+
+    public static void main(String[] args) throws Exception {
+        System.loadLibrary(args[0]);
+
+        for (int i = 0; i < THREAD_COUNT; i++) {
+            Thread t = new Thread(new DaemonRunnable());
+            t.setDaemon(true);
+            t.start();
+        }
+        // Give threads time to start and become stuck in waitAndCallIntoJniEnv.
+        Thread.sleep(1000);
+        destroyJavaVMAndExit();
+    }
+
+    static native void waitAndCallIntoJniEnv();
+    static native void destroyJavaVMAndExit();
+
+    private static class DaemonRunnable implements Runnable {
+        public void run() {
+            for (;;) {
+                waitAndCallIntoJniEnv();
+            }
+        }
+    }
+}
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index f74a516..b922b45 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -30,6 +30,7 @@
   051-thread/thread_test.cc \
   117-nopatchoat/nopatchoat.cc \
   1337-gc-coverage/gc_coverage.cc \
+  136-daemon-jni-shutdown/daemon_jni_shutdown.cc \
   137-cfi/cfi.cc \
   139-register-natives/regnative.cc \
   141-class-unload/jni_unload.cc \