Merge "ART: Fix RegTypeCache::FromUnresolvedMerge()."
diff --git a/compiler/utils/swap_space.cc b/compiler/utils/swap_space.cc
index 244a5fe..1a8f567 100644
--- a/compiler/utils/swap_space.cc
+++ b/compiler/utils/swap_space.cc
@@ -152,7 +152,6 @@
   }
   size_ += next_part;
   SpaceChunk new_chunk = {ptr, next_part};
-  maps_.push_back(new_chunk);
   return new_chunk;
 #else
   UNUSED(min_size, kMininumMapSize);
diff --git a/compiler/utils/swap_space.h b/compiler/utils/swap_space.h
index b659f1d..bf06675 100644
--- a/compiler/utils/swap_space.h
+++ b/compiler/utils/swap_space.h
@@ -85,7 +85,6 @@
 
   int fd_;
   size_t size_;
-  std::list<SpaceChunk> maps_;
 
   // NOTE: Boost.Bimap would be useful for the two following members.
 
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index a60f31e..f97ad51 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -377,7 +377,7 @@
 
   Runtime* runtime = Runtime::Current();
   const void* existing_entry_point = GetEntryPointFromQuickCompiledCode();
-  DCHECK(existing_entry_point != nullptr);
+  CHECK(existing_entry_point != nullptr) << PrettyMethod(this) << "@" << this;
   ClassLinker* class_linker = runtime->GetClassLinker();
 
   if (class_linker->IsQuickGenericJniStub(existing_entry_point)) {
diff --git a/runtime/interpreter/mterp/mips/binop.S b/runtime/interpreter/mterp/mips/binop.S
index ce09da45..66627e2 100644
--- a/runtime/interpreter/mterp/mips/binop.S
+++ b/runtime/interpreter/mterp/mips/binop.S
@@ -7,8 +7,8 @@
      *
      * If "chkzero" is set to 1, we perform a divide-by-zero check on
      * vCC (a1).  Useful for integer division and modulus.  Note that we
-     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
-     * handles it correctly.
+     * *don't* check for (INT_MIN / -1) here, because the CPU handles it
+     * correctly.
      *
      * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
      *      xor-int, shl-int, shr-int, ushr-int
diff --git a/runtime/interpreter/mterp/mips64/bincmp.S b/runtime/interpreter/mterp/mips64/bincmp.S
index d39c900..aa5e74b 100644
--- a/runtime/interpreter/mterp/mips64/bincmp.S
+++ b/runtime/interpreter/mterp/mips64/bincmp.S
@@ -6,27 +6,27 @@
      * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
      */
     /* if-cmp vA, vB, +CCCC */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended CCCC
+    .extern MterpProfileBranch
     ext     a2, rINST, 8, 4             # a2 <- A
     ext     a3, rINST, 12, 4            # a3 <- B
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended CCCC)
     GET_VREG a0, a2                     # a0 <- vA
     GET_VREG a1, a3                     # a1 <- vB
-
     b${condition}c a0, a1, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + CCCC * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # CCCC * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/footer.S b/runtime/interpreter/mterp/mips64/footer.S
index 1a2e22b..14d5fe0 100644
--- a/runtime/interpreter/mterp/mips64/footer.S
+++ b/runtime/interpreter/mterp/mips64/footer.S
@@ -49,6 +49,7 @@
  *
  */
     .extern MterpHandleException
+    .extern MterpShouldSwitchInterpreters
 MterpException:
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -59,8 +60,11 @@
     REFRESH_IBASE
     daddu   rPC, a0, CODEITEM_INSNS_OFFSET
     dlsa    rPC, a1, rPC, 1                         # generate new dex_pc_ptr
-    sd      rPC, OFF_FP_DEX_PC_PTR(rFP)
+    /* Do we need to switch interpreters? */
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     /* resume execution at catch block */
+    EXPORT_PC
     FETCH_INST
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
@@ -81,10 +85,24 @@
     EXPORT_PC
     move    a0, rSELF
     jal     MterpSuspendCheck                       # (self)
+    bnezc   v0, MterpFallback                       # Something in the environment changed, switch interpreters
     GET_INST_OPCODE v0                              # extract opcode from rINST
     GOTO_OPCODE v0                                  # jump to next instruction
 
 /*
+ * On-stack replacement has happened, and now we've returned from the compiled method.
+ */
+MterpOnStackReplacement:
+#if MTERP_LOGGING
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST                               # rINST contains offset
+    jal     MterpLogOSR
+#endif
+    li      v0, 1                                   # Signal normal return
+    b       MterpDone
+
+/*
  * Bail out to reference interpreter.
  */
     .extern MterpLogFallback
diff --git a/runtime/interpreter/mterp/mips64/header.S b/runtime/interpreter/mterp/mips64/header.S
index 4c3ca9e..dd0fbe0 100644
--- a/runtime/interpreter/mterp/mips64/header.S
+++ b/runtime/interpreter/mterp/mips64/header.S
@@ -82,14 +82,7 @@
 #define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
 #define OFF_FP_SHADOWFRAME (-SHADOWFRAME_VREGS_OFFSET)
 
-/*
- *
- * The reference interpreter performs explicit suspect checks, which is somewhat wasteful.
- * Dalvik's interpreter folded suspend checks into the jump table mechanism, and eventually
- * mterp should do so as well.
- */
-#define MTERP_SUSPEND 0
-
+#define MTERP_PROFILE_BRANCHES 1
 #define MTERP_LOGGING 0
 
 /*
diff --git a/runtime/interpreter/mterp/mips64/invoke.S b/runtime/interpreter/mterp/mips64/invoke.S
index 4ae4fb1..be647b6 100644
--- a/runtime/interpreter/mterp/mips64/invoke.S
+++ b/runtime/interpreter/mterp/mips64/invoke.S
@@ -5,6 +5,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern $helper
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -13,5 +14,7 @@
     jal     $helper
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
diff --git a/runtime/interpreter/mterp/mips64/op_goto.S b/runtime/interpreter/mterp/mips64/op_goto.S
index f2df3e4..7c7d0ec 100644
--- a/runtime/interpreter/mterp/mips64/op_goto.S
+++ b/runtime/interpreter/mterp/mips64/op_goto.S
@@ -5,19 +5,21 @@
      * double to get a byte offset.
      */
     /* goto +AA */
-    srl     a0, rINST, 8
-    seb     a0, a0                      # a0 <- sign-extended AA
-    dlsa    rPC, a0, rPC, 1             # rPC <- rPC + AA * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a0, 1f                      # AA * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-1:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a0, MterpCheckSuspendAndContinue
+    .extern MterpProfileBranch
+    srl     rINST, rINST, 8
+    seb     rINST, rINST                # rINST <- offset (sign-extended AA)
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_goto_16.S b/runtime/interpreter/mterp/mips64/op_goto_16.S
index cbf8cf2..566e3a7 100644
--- a/runtime/interpreter/mterp/mips64/op_goto_16.S
+++ b/runtime/interpreter/mterp/mips64/op_goto_16.S
@@ -5,18 +5,20 @@
      * double to get a byte offset.
      */
     /* goto/16 +AAAA */
-    lh      a0, 2(rPC)                  # a0 <- sign-extended AAAA
-    dlsa    rPC, a0, rPC, 1             # rPC <- rPC + AAAA * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a0, 1f                      # AA * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-1:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a0, MterpCheckSuspendAndContinue
+    .extern MterpProfileBranch
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended AAAA)
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_goto_32.S b/runtime/interpreter/mterp/mips64/op_goto_32.S
index 4a1feac..b260083 100644
--- a/runtime/interpreter/mterp/mips64/op_goto_32.S
+++ b/runtime/interpreter/mterp/mips64/op_goto_32.S
@@ -8,20 +8,22 @@
      * our "backward branch" test must be "<=0" instead of "<0".
      */
     /* goto/32 +AAAAAAAA */
-    lh      a0, 2(rPC)                  # a0 <- aaaa (low)
+    .extern MterpProfileBranch
+    lh      rINST, 2(rPC)               # rINST <- aaaa (low)
     lh      a1, 4(rPC)                  # a1 <- AAAA (high)
-    ins     a0, a1, 16, 16              # a0 = sign-extended AAAAaaaa
-    dlsa    rPC, a0, rPC, 1             # rPC <- rPC + AAAAAAAA * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgtz    a0, 1f                      # AA * 2 > 0 => no suspend check
-    REFRESH_IBASE
-1:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    blez    a0, MterpCheckSuspendAndContinue
+    ins     rINST, a1, 16, 16           # rINST <- offset (sign-extended AAAAaaaa)
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    blez    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_packed_switch.S b/runtime/interpreter/mterp/mips64/op_packed_switch.S
index cdbdf75..2c6eb2f 100644
--- a/runtime/interpreter/mterp/mips64/op_packed_switch.S
+++ b/runtime/interpreter/mterp/mips64/op_packed_switch.S
@@ -10,6 +10,7 @@
      */
     /* op vAA, +BBBBBBBB */
     .extern $func
+    .extern MterpProfileBranch
     lh      a0, 2(rPC)                  # a0 <- bbbb (lo)
     lh      a1, 4(rPC)                  # a1 <- BBBB (hi)
     srl     a3, rINST, 8                # a3 <- AA
@@ -17,15 +18,19 @@
     GET_VREG a1, a3                     # a1 <- vAA
     dlsa    a0, a0, rPC, 1              # a0 <- PC + BBBBbbbb*2
     jal     $func                       # v0 <- code-unit branch offset
-    dlsa    rPC, v0, rPC, 1             # rPC <- rPC + offset * 2
-    FETCH_INST                          # load rINST
-#if MTERP_SUSPEND
-    bgtz    v0, 1f                      # offset * 2 > 0 => no suspend check
-    REFRESH_IBASE
-1:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    blez    v0, MterpCheckSuspendAndContinue
+    move    rINST, v0
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    blez    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/zcmp.S b/runtime/interpreter/mterp/mips64/zcmp.S
index d7ad894..0e0477f 100644
--- a/runtime/interpreter/mterp/mips64/zcmp.S
+++ b/runtime/interpreter/mterp/mips64/zcmp.S
@@ -6,25 +6,25 @@
      * For: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
      */
     /* if-cmp vAA, +BBBB */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended BBBB
+    .extern MterpProfileBranch
     srl     a2, rINST, 8                # a2 <- AA
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended BBBB)
     GET_VREG a0, a2                     # a0 <- vAA
-
     b${condition}zc a0, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + BBBB * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # BBBB * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index ca727f4..10b19c5 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -147,16 +147,7 @@
     SHARED_REQUIRES(Locks::mutator_lock_) {
   const instrumentation::Instrumentation* const instrumentation =
       Runtime::Current()->GetInstrumentation();
-  bool unhandled_instrumentation;
-  // TODO: enable for other targets after more extensive testing.
-  if ((kRuntimeISA == kArm64) || (kRuntimeISA == kArm) ||
-      (kRuntimeISA == kX86_64) || (kRuntimeISA == kX86) ||
-      (kRuntimeISA == kMips)) {
-    unhandled_instrumentation = instrumentation->NonJitProfilingActive();
-  } else {
-    unhandled_instrumentation = instrumentation->IsActive();
-  }
-  return unhandled_instrumentation || Dbg::IsDebuggerActive();
+  return instrumentation->NonJitProfilingActive() || Dbg::IsDebuggerActive();
 }
 
 
diff --git a/runtime/interpreter/mterp/out/mterp_mips64.S b/runtime/interpreter/mterp/out/mterp_mips64.S
index 7cef823..a17252b 100644
--- a/runtime/interpreter/mterp/out/mterp_mips64.S
+++ b/runtime/interpreter/mterp/out/mterp_mips64.S
@@ -89,14 +89,7 @@
 #define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
 #define OFF_FP_SHADOWFRAME (-SHADOWFRAME_VREGS_OFFSET)
 
-/*
- *
- * The reference interpreter performs explicit suspect checks, which is somewhat wasteful.
- * Dalvik's interpreter folded suspend checks into the jump table mechanism, and eventually
- * mterp should do so as well.
- */
-#define MTERP_SUSPEND 0
-
+#define MTERP_PROFILE_BRANCHES 1
 #define MTERP_LOGGING 0
 
 /*
@@ -1107,20 +1100,22 @@
      * double to get a byte offset.
      */
     /* goto +AA */
-    srl     a0, rINST, 8
-    seb     a0, a0                      # a0 <- sign-extended AA
-    dlsa    rPC, a0, rPC, 1             # rPC <- rPC + AA * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a0, 1f                      # AA * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-1:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a0, MterpCheckSuspendAndContinue
+    .extern MterpProfileBranch
+    srl     rINST, rINST, 8
+    seb     rINST, rINST                # rINST <- offset (sign-extended AA)
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1135,19 +1130,21 @@
      * double to get a byte offset.
      */
     /* goto/16 +AAAA */
-    lh      a0, 2(rPC)                  # a0 <- sign-extended AAAA
-    dlsa    rPC, a0, rPC, 1             # rPC <- rPC + AAAA * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a0, 1f                      # AA * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-1:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a0, MterpCheckSuspendAndContinue
+    .extern MterpProfileBranch
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended AAAA)
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1165,21 +1162,23 @@
      * our "backward branch" test must be "<=0" instead of "<0".
      */
     /* goto/32 +AAAAAAAA */
-    lh      a0, 2(rPC)                  # a0 <- aaaa (low)
+    .extern MterpProfileBranch
+    lh      rINST, 2(rPC)               # rINST <- aaaa (low)
     lh      a1, 4(rPC)                  # a1 <- AAAA (high)
-    ins     a0, a1, 16, 16              # a0 = sign-extended AAAAaaaa
-    dlsa    rPC, a0, rPC, 1             # rPC <- rPC + AAAAAAAA * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgtz    a0, 1f                      # AA * 2 > 0 => no suspend check
-    REFRESH_IBASE
-1:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    blez    a0, MterpCheckSuspendAndContinue
+    ins     rINST, a1, 16, 16           # rINST <- offset (sign-extended AAAAaaaa)
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    blez    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1198,6 +1197,7 @@
      */
     /* op vAA, +BBBBBBBB */
     .extern MterpDoPackedSwitch
+    .extern MterpProfileBranch
     lh      a0, 2(rPC)                  # a0 <- bbbb (lo)
     lh      a1, 4(rPC)                  # a1 <- BBBB (hi)
     srl     a3, rINST, 8                # a3 <- AA
@@ -1205,16 +1205,20 @@
     GET_VREG a1, a3                     # a1 <- vAA
     dlsa    a0, a0, rPC, 1              # a0 <- PC + BBBBbbbb*2
     jal     MterpDoPackedSwitch                       # v0 <- code-unit branch offset
-    dlsa    rPC, v0, rPC, 1             # rPC <- rPC + offset * 2
-    FETCH_INST                          # load rINST
-#if MTERP_SUSPEND
-    bgtz    v0, 1f                      # offset * 2 > 0 => no suspend check
-    REFRESH_IBASE
-1:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    blez    v0, MterpCheckSuspendAndContinue
+    move    rINST, v0
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    blez    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1234,6 +1238,7 @@
      */
     /* op vAA, +BBBBBBBB */
     .extern MterpDoSparseSwitch
+    .extern MterpProfileBranch
     lh      a0, 2(rPC)                  # a0 <- bbbb (lo)
     lh      a1, 4(rPC)                  # a1 <- BBBB (hi)
     srl     a3, rINST, 8                # a3 <- AA
@@ -1241,16 +1246,20 @@
     GET_VREG a1, a3                     # a1 <- vAA
     dlsa    a0, a0, rPC, 1              # a0 <- PC + BBBBbbbb*2
     jal     MterpDoSparseSwitch                       # v0 <- code-unit branch offset
-    dlsa    rPC, v0, rPC, 1             # rPC <- rPC + offset * 2
-    FETCH_INST                          # load rINST
-#if MTERP_SUSPEND
-    bgtz    v0, 1f                      # offset * 2 > 0 => no suspend check
-    REFRESH_IBASE
-1:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    blez    v0, MterpCheckSuspendAndContinue
+    move    rINST, v0
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    blez    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1438,28 +1447,28 @@
      * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
      */
     /* if-cmp vA, vB, +CCCC */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended CCCC
+    .extern MterpProfileBranch
     ext     a2, rINST, 8, 4             # a2 <- A
     ext     a3, rINST, 12, 4            # a3 <- B
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended CCCC)
     GET_VREG a0, a2                     # a0 <- vA
     GET_VREG a1, a3                     # a1 <- vB
-
     beqc a0, a1, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + CCCC * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # CCCC * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1477,28 +1486,28 @@
      * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
      */
     /* if-cmp vA, vB, +CCCC */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended CCCC
+    .extern MterpProfileBranch
     ext     a2, rINST, 8, 4             # a2 <- A
     ext     a3, rINST, 12, 4            # a3 <- B
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended CCCC)
     GET_VREG a0, a2                     # a0 <- vA
     GET_VREG a1, a3                     # a1 <- vB
-
     bnec a0, a1, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + CCCC * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # CCCC * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1516,28 +1525,28 @@
      * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
      */
     /* if-cmp vA, vB, +CCCC */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended CCCC
+    .extern MterpProfileBranch
     ext     a2, rINST, 8, 4             # a2 <- A
     ext     a3, rINST, 12, 4            # a3 <- B
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended CCCC)
     GET_VREG a0, a2                     # a0 <- vA
     GET_VREG a1, a3                     # a1 <- vB
-
     bltc a0, a1, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + CCCC * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # CCCC * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1555,28 +1564,28 @@
      * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
      */
     /* if-cmp vA, vB, +CCCC */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended CCCC
+    .extern MterpProfileBranch
     ext     a2, rINST, 8, 4             # a2 <- A
     ext     a3, rINST, 12, 4            # a3 <- B
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended CCCC)
     GET_VREG a0, a2                     # a0 <- vA
     GET_VREG a1, a3                     # a1 <- vB
-
     bgec a0, a1, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + CCCC * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # CCCC * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1594,28 +1603,28 @@
      * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
      */
     /* if-cmp vA, vB, +CCCC */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended CCCC
+    .extern MterpProfileBranch
     ext     a2, rINST, 8, 4             # a2 <- A
     ext     a3, rINST, 12, 4            # a3 <- B
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended CCCC)
     GET_VREG a0, a2                     # a0 <- vA
     GET_VREG a1, a3                     # a1 <- vB
-
     bgtc a0, a1, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + CCCC * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # CCCC * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1633,28 +1642,28 @@
      * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
      */
     /* if-cmp vA, vB, +CCCC */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended CCCC
+    .extern MterpProfileBranch
     ext     a2, rINST, 8, 4             # a2 <- A
     ext     a3, rINST, 12, 4            # a3 <- B
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended CCCC)
     GET_VREG a0, a2                     # a0 <- vA
     GET_VREG a1, a3                     # a1 <- vB
-
     blec a0, a1, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + CCCC * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # CCCC * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1672,26 +1681,26 @@
      * For: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
      */
     /* if-cmp vAA, +BBBB */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended BBBB
+    .extern MterpProfileBranch
     srl     a2, rINST, 8                # a2 <- AA
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended BBBB)
     GET_VREG a0, a2                     # a0 <- vAA
-
     beqzc a0, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + BBBB * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # BBBB * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1709,26 +1718,26 @@
      * For: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
      */
     /* if-cmp vAA, +BBBB */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended BBBB
+    .extern MterpProfileBranch
     srl     a2, rINST, 8                # a2 <- AA
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended BBBB)
     GET_VREG a0, a2                     # a0 <- vAA
-
     bnezc a0, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + BBBB * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # BBBB * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1746,26 +1755,26 @@
      * For: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
      */
     /* if-cmp vAA, +BBBB */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended BBBB
+    .extern MterpProfileBranch
     srl     a2, rINST, 8                # a2 <- AA
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended BBBB)
     GET_VREG a0, a2                     # a0 <- vAA
-
     bltzc a0, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + BBBB * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # BBBB * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1783,26 +1792,26 @@
      * For: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
      */
     /* if-cmp vAA, +BBBB */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended BBBB
+    .extern MterpProfileBranch
     srl     a2, rINST, 8                # a2 <- AA
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended BBBB)
     GET_VREG a0, a2                     # a0 <- vAA
-
     bgezc a0, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + BBBB * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # BBBB * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1820,26 +1829,26 @@
      * For: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
      */
     /* if-cmp vAA, +BBBB */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended BBBB
+    .extern MterpProfileBranch
     srl     a2, rINST, 8                # a2 <- AA
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended BBBB)
     GET_VREG a0, a2                     # a0 <- vAA
-
     bgtzc a0, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + BBBB * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # BBBB * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -1857,26 +1866,26 @@
      * For: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
      */
     /* if-cmp vAA, +BBBB */
-    lh      a4, 2(rPC)                  # a4 <- sign-extended BBBB
+    .extern MterpProfileBranch
     srl     a2, rINST, 8                # a2 <- AA
+    lh      rINST, 2(rPC)               # rINST <- offset (sign-extended BBBB)
     GET_VREG a0, a2                     # a0 <- vAA
-
     blezc a0, 1f
-    li      a4, 2                       # offset if branch not taken
+    li      rINST, 2                    # offset if branch not taken
 1:
-
-    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + BBBB * 2
-    FETCH_INST                          # load rINST
-
-#if MTERP_SUSPEND
-    bgez    a4, 2f                      # BBBB * 2 >= 0 => no suspend check
-    REFRESH_IBASE
-2:
-#else
-    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
-    bltz    a4, MterpCheckSuspendAndContinue
+#if MTERP_PROFILE_BRANCHES
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST
+    jal     MterpProfileBranch          # (self, shadow_frame, offset)
+    bnezc   v0, MterpOnStackReplacement # Note: offset must be in rINST
 #endif
-
+    dlsa    rPC, rINST, rPC, 1          # rPC <- rPC + offset * 2
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    move    a0, rINST                   # a0 <- offset
+    FETCH_INST                          # load rINST
+    bltz    a0, MterpCheckSuspendAndContinue  # suspend check if backwards branch
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
@@ -3166,6 +3175,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeVirtual
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -3174,6 +3184,8 @@
     jal     MterpInvokeVirtual
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -3196,6 +3208,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeSuper
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -3204,6 +3217,8 @@
     jal     MterpInvokeSuper
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -3226,6 +3241,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeDirect
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -3234,6 +3250,8 @@
     jal     MterpInvokeDirect
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -3249,6 +3267,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeStatic
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -3257,6 +3276,8 @@
     jal     MterpInvokeStatic
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -3272,6 +3293,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeInterface
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -3280,6 +3302,8 @@
     jal     MterpInvokeInterface
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -3316,6 +3340,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeVirtualRange
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -3324,6 +3349,8 @@
     jal     MterpInvokeVirtualRange
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -3339,6 +3366,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeSuperRange
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -3347,6 +3375,8 @@
     jal     MterpInvokeSuperRange
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -3362,6 +3392,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeDirectRange
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -3370,6 +3401,8 @@
     jal     MterpInvokeDirectRange
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -3385,6 +3418,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeStaticRange
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -3393,6 +3427,8 @@
     jal     MterpInvokeStaticRange
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -3408,6 +3444,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeInterfaceRange
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -3416,6 +3453,8 @@
     jal     MterpInvokeInterfaceRange
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -6962,6 +7001,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeVirtualQuick
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -6970,6 +7010,8 @@
     jal     MterpInvokeVirtualQuick
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -6985,6 +7027,7 @@
     /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
     /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
     .extern MterpInvokeVirtualQuickRange
+    .extern MterpShouldSwitchInterpreters
     EXPORT_PC
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -6993,6 +7036,8 @@
     jal     MterpInvokeVirtualQuickRange
     beqzc   v0, MterpException
     FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
 
@@ -12256,6 +12301,7 @@
  *
  */
     .extern MterpHandleException
+    .extern MterpShouldSwitchInterpreters
 MterpException:
     move    a0, rSELF
     daddu   a1, rFP, OFF_FP_SHADOWFRAME
@@ -12266,8 +12312,11 @@
     REFRESH_IBASE
     daddu   rPC, a0, CODEITEM_INSNS_OFFSET
     dlsa    rPC, a1, rPC, 1                         # generate new dex_pc_ptr
-    sd      rPC, OFF_FP_DEX_PC_PTR(rFP)
+    /* Do we need to switch interpreters? */
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
     /* resume execution at catch block */
+    EXPORT_PC
     FETCH_INST
     GET_INST_OPCODE v0
     GOTO_OPCODE v0
@@ -12288,10 +12337,24 @@
     EXPORT_PC
     move    a0, rSELF
     jal     MterpSuspendCheck                       # (self)
+    bnezc   v0, MterpFallback                       # Something in the environment changed, switch interpreters
     GET_INST_OPCODE v0                              # extract opcode from rINST
     GOTO_OPCODE v0                                  # jump to next instruction
 
 /*
+ * On-stack replacement has happened, and now we've returned from the compiled method.
+ */
+MterpOnStackReplacement:
+#if MTERP_LOGGING
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rINST                               # rINST contains offset
+    jal     MterpLogOSR
+#endif
+    li      v0, 1                                   # Signal normal return
+    b       MterpDone
+
+/*
  * Bail out to reference interpreter.
  */
     .extern MterpLogFallback
diff --git a/test/462-checker-inlining-across-dex-files/multidex.jpp b/test/462-checker-inlining-across-dex-files/multidex.jpp
new file mode 100644
index 0000000..ae55456
--- /dev/null
+++ b/test/462-checker-inlining-across-dex-files/multidex.jpp
@@ -0,0 +1,8 @@
+Main:
+  @@com.android.jack.annotations.ForceInMainDex
+  class Main
+
+AAA:
+  @@com.android.jack.annotations.ForceInMainDex
+  class AAA
+
diff --git a/test/556-invoke-super/multidex.jpp b/test/556-invoke-super/multidex.jpp
new file mode 100644
index 0000000..fe01801
--- /dev/null
+++ b/test/556-invoke-super/multidex.jpp
@@ -0,0 +1,4 @@
+Main:
+  @@com.android.jack.annotations.ForceInMainDex
+  class Main*
+
diff --git a/test/569-checker-pattern-replacement/multidex.jpp b/test/569-checker-pattern-replacement/multidex.jpp
new file mode 100644
index 0000000..cfc8ad1
--- /dev/null
+++ b/test/569-checker-pattern-replacement/multidex.jpp
@@ -0,0 +1,8 @@
+Main:
+  @@com.android.jack.annotations.ForceInMainDex
+  class Main
+
+BaseInMainDex:
+  @@com.android.jack.annotations.ForceInMainDex
+  class BaseInMainDex
+
diff --git a/test/etc/default-build b/test/etc/default-build
index 6e855ec..5f78496 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -116,28 +116,33 @@
   SKIP_DX_MERGER="true"
 fi
 
-if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then
-  # Jack does not support this configuration unless we specify how to partition the DEX file
-  # with a .jpp file.
-  USE_JACK="false"
-fi
-
 if [ ${USE_JACK} = "true" ]; then
   # Jack toolchain
   if [ "${HAS_SRC}" = "true" ]; then
-    ${JACK} ${JACK_ARGS} --output-jack src.jack src
-    imported_jack_files="--import src.jack"
+    if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then
+      # Compile src and src-multidex in the same .jack file. We will apply multidex partitioning
+      # when creating the output .dex file.
+      ${JACK} ${JACK_ARGS} --output-jack src.jack src src src-multidex
+      jack_extra_args="${jack_extra_args} -D jack.dex.output.policy=minimal-multidex"
+      jack_extra_args="${jack_extra_args} -D jack.preprocessor=true"
+      jack_extra_args="${jack_extra_args} -D jack.preprocessor.file=multidex.jpp"
+    else
+      ${JACK} ${JACK_ARGS} --output-jack src.jack src
+    fi
+    jack_extra_args="${jack_extra_args} --import src.jack"
   fi
 
   if [ "${HAS_SRC2}" = "true" ]; then
     ${JACK} ${JACK_ARGS} --output-jack src2.jack src2
-    imported_jack_files="--import src2.jack ${imported_jack_files}"
+    # In case of duplicate classes, we want to take into account the classes from src2. Therefore
+    # we apply the 'keep-first' policy and import src2.jack file *before* the src.jack file.
+    jack_extra_args="${jack_extra_args} -D jack.import.type.policy=keep-first"
+    jack_extra_args="--import src2.jack ${jack_extra_args}"
   fi
 
-  # Compile jack files into a DEX file. We set jack.import.type.policy=keep-first to consider
-  # class definitions from src2 first.
+  # Compile jack files into a DEX file.
   if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ]; then
-    ${JACK} ${JACK_ARGS} ${imported_jack_files} -D jack.import.type.policy=keep-first --output-dex .
+    ${JACK} ${JACK_ARGS} ${jack_extra_args} --output-dex .
   fi
 else
   # Legacy toolchain with javac+dx
diff --git a/tools/setup-buildbot-device.sh b/tools/setup-buildbot-device.sh
index 9e085b5..1e9c763 100755
--- a/tools/setup-buildbot-device.sh
+++ b/tools/setup-buildbot-device.sh
@@ -46,5 +46,13 @@
 adb logcat -p
 
 echo -e "${green}Kill stalled dalvikvm processes${nc}"
-processes=$(adb shell "ps" | grep dalvikvm | awk '{print $2}')
-for i in $processes; do adb shell kill -9 $i; done
+# 'ps' on M can sometimes hang.
+timeout 2s adb shell "ps"
+if [ $? = 124 ]; then
+  echo -e "${green}Rebooting device to fix 'ps'${nc}"
+  adb reboot
+  adb wait-for-device root
+else
+  processes=$(adb shell "ps" | grep dalvikvm | awk '{print $2}')
+  for i in $processes; do adb shell kill -9 $i; done
+fi