Merge "Add support for vex coding scheme in x86 assembler"
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 3f4fb15..a9acf90 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1205,6 +1205,7 @@
   //      mr        : Runtime reserved.
   //      ip1       : VIXL core temp.
   //      ip0       : VIXL core temp.
+  //      x18       : Platform register.
   //
   // Blocked fp registers:
   //      d31       : VIXL fp temp.
@@ -1213,6 +1214,7 @@
   while (!reserved_core_registers.IsEmpty()) {
     blocked_core_registers_[reserved_core_registers.PopLowestIndex().GetCode()] = true;
   }
+  blocked_core_registers_[X18] = true;
 
   CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
   while (!reserved_fp_registers.IsEmpty()) {
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 6f43527..7bdaebe 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -287,9 +287,8 @@
 
     /*
      * Creates ImageSection objects that describe most of the sections of a
-     * boot or AppImage.  The following sections are not included:
+     * boot or AppImage. The following sections are not included:
      *   - ImageHeader::kSectionImageBitmap
-     *   - ImageHeader::kSectionStringReferenceOffsets
      *
      * In addition, the ImageHeader is not covered here.
      *
diff --git a/runtime/Android.bp b/runtime/Android.bp
index bedeaf7..5d99187 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -96,7 +96,10 @@
         "interpreter/interpreter_cache.cc",
         "interpreter/interpreter_common.cc",
         "interpreter/interpreter_intrinsics.cc",
-        "interpreter/interpreter_switch_impl.cc",
+        "interpreter/interpreter_switch_impl0.cc",
+        "interpreter/interpreter_switch_impl1.cc",
+        "interpreter/interpreter_switch_impl2.cc",
+        "interpreter/interpreter_switch_impl3.cc",
         "interpreter/lock_count_data.cc",
         "interpreter/shadow_frame.cc",
         "interpreter/unstarted_runtime.cc",
diff --git a/runtime/arch/arm64/callee_save_frame_arm64.h b/runtime/arch/arm64/callee_save_frame_arm64.h
index bc36bfa..a5aea2a 100644
--- a/runtime/arch/arm64/callee_save_frame_arm64.h
+++ b/runtime/arch/arm64/callee_save_frame_arm64.h
@@ -54,7 +54,7 @@
     (1 << art::arm64::X9) | (1 << art::arm64::X10) | (1 << art::arm64::X11) |
     (1 << art::arm64::X12) | (1 << art::arm64::X13) | (1 << art::arm64::X14) |
     (1 << art::arm64::X15) | (1 << art::arm64::X16) | (1 << art::arm64::X17) |
-    (1 << art::arm64::X18) | (1 << art::arm64::X19);
+    (1 << art::arm64::X19);
 
 static constexpr uint32_t kArm64CalleeSaveFpAlwaysSpills = 0;
 static constexpr uint32_t kArm64CalleeSaveFpRefSpills = 0;
diff --git a/runtime/arch/arm64/entrypoints_init_arm64.cc b/runtime/arch/arm64/entrypoints_init_arm64.cc
index e681d63..22f0c28 100644
--- a/runtime/arch/arm64/entrypoints_init_arm64.cc
+++ b/runtime/arch/arm64/entrypoints_init_arm64.cc
@@ -103,7 +103,6 @@
   qpoints->pReadBarrierMarkReg14 = is_active ? art_quick_read_barrier_mark_reg14 : nullptr;
   qpoints->pReadBarrierMarkReg15 = is_active ? art_quick_read_barrier_mark_reg15 : nullptr;
   qpoints->pReadBarrierMarkReg17 = is_active ? art_quick_read_barrier_mark_reg17 : nullptr;
-  qpoints->pReadBarrierMarkReg18 = is_active ? art_quick_read_barrier_mark_reg18 : nullptr;
   qpoints->pReadBarrierMarkReg19 = is_active ? art_quick_read_barrier_mark_reg19 : nullptr;
   qpoints->pReadBarrierMarkReg20 = is_active ? art_quick_read_barrier_mark_reg20 : nullptr;
   qpoints->pReadBarrierMarkReg21 = is_active ? art_quick_read_barrier_mark_reg21 : nullptr;
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 96ceecf..9f3377e 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -289,36 +289,33 @@
 #endif
 
     // Save FP registers.
-    // For better performance, store d0 and d31 separately, so that all STPs are 16-byte aligned.
-    str d0,       [sp, #8]
-    stp d1, d2,   [sp, #16]
-    stp d3, d4,   [sp, #32]
-    stp d5, d6,   [sp, #48]
-    stp d7, d8,   [sp, #64]
-    stp d9, d10,  [sp, #80]
-    stp d11, d12, [sp, #96]
-    stp d13, d14, [sp, #112]
-    stp d15, d16, [sp, #128]
-    stp d17, d18, [sp, #144]
-    stp d19, d20, [sp, #160]
-    stp d21, d22, [sp, #176]
-    stp d23, d24, [sp, #192]
-    stp d25, d26, [sp, #208]
-    stp d27, d28, [sp, #224]
-    stp d29, d30, [sp, #240]
-    str d31,      [sp, #256]
+    stp d0, d1,   [sp, #16]
+    stp d2, d3,   [sp, #32]
+    stp d4, d5,   [sp, #48]
+    stp d6, d7,   [sp, #64]
+    stp d8, d9,   [sp, #80]
+    stp d10, d11, [sp, #96]
+    stp d12, d13, [sp, #112]
+    stp d14, d15, [sp, #128]
+    stp d16, d17, [sp, #144]
+    stp d18, d19, [sp, #160]
+    stp d20, d21, [sp, #176]
+    stp d22, d23, [sp, #192]
+    stp d24, d25, [sp, #208]
+    stp d26, d27, [sp, #224]
+    stp d28, d29, [sp, #240]
+    stp d30, d31, [sp, #256]
 
     // Save core registers.
-    SAVE_REG            x0, 264
-    SAVE_TWO_REGS  x1,  x2, 272
-    SAVE_TWO_REGS  x3,  x4, 288
-    SAVE_TWO_REGS  x5,  x6, 304
-    SAVE_TWO_REGS  x7,  x8, 320
-    SAVE_TWO_REGS  x9, x10, 336
-    SAVE_TWO_REGS x11, x12, 352
-    SAVE_TWO_REGS x13, x14, 368
-    SAVE_TWO_REGS x15, x16, 384
-    SAVE_TWO_REGS x17, x18, 400
+    SAVE_TWO_REGS  x0,  x1, 272
+    SAVE_TWO_REGS  x2,  x3, 288
+    SAVE_TWO_REGS  x4,  x5, 304
+    SAVE_TWO_REGS  x6,  x7, 320
+    SAVE_TWO_REGS  x8,  x9, 336
+    SAVE_TWO_REGS x10, x11, 352
+    SAVE_TWO_REGS x12, x13, 368
+    SAVE_TWO_REGS x14, x15, 384
+    SAVE_TWO_REGS x16, x17, 400 // Do not save the platform register.
     SAVE_TWO_REGS x19, x20, 416
     SAVE_TWO_REGS x21, x22, 432
     SAVE_TWO_REGS x23, x24, 448
@@ -351,35 +348,33 @@
 
 .macro RESTORE_SAVE_EVERYTHING_FRAME_KEEP_X0
     // Restore FP registers.
-    // For better performance, load d0 and d31 separately, so that all LDPs are 16-byte aligned.
-    ldr d0,       [sp, #8]
-    ldp d1, d2,   [sp, #16]
-    ldp d3, d4,   [sp, #32]
-    ldp d5, d6,   [sp, #48]
-    ldp d7, d8,   [sp, #64]
-    ldp d9, d10,  [sp, #80]
-    ldp d11, d12, [sp, #96]
-    ldp d13, d14, [sp, #112]
-    ldp d15, d16, [sp, #128]
-    ldp d17, d18, [sp, #144]
-    ldp d19, d20, [sp, #160]
-    ldp d21, d22, [sp, #176]
-    ldp d23, d24, [sp, #192]
-    ldp d25, d26, [sp, #208]
-    ldp d27, d28, [sp, #224]
-    ldp d29, d30, [sp, #240]
-    ldr d31,      [sp, #256]
+    ldp d0, d1,   [sp, #16]
+    ldp d2, d3,   [sp, #32]
+    ldp d4, d5,   [sp, #48]
+    ldp d6, d7,   [sp, #64]
+    ldp d8, d9,   [sp, #80]
+    ldp d10, d11, [sp, #96]
+    ldp d12, d13, [sp, #112]
+    ldp d14, d15, [sp, #128]
+    ldp d16, d17, [sp, #144]
+    ldp d18, d19, [sp, #160]
+    ldp d20, d21, [sp, #176]
+    ldp d22, d23, [sp, #192]
+    ldp d24, d25, [sp, #208]
+    ldp d26, d27, [sp, #224]
+    ldp d28, d29, [sp, #240]
+    ldp d30, d31, [sp, #256]
 
     // Restore core registers, except x0.
-    RESTORE_TWO_REGS  x1,  x2, 272
-    RESTORE_TWO_REGS  x3,  x4, 288
-    RESTORE_TWO_REGS  x5,  x6, 304
-    RESTORE_TWO_REGS  x7,  x8, 320
-    RESTORE_TWO_REGS  x9, x10, 336
-    RESTORE_TWO_REGS x11, x12, 352
-    RESTORE_TWO_REGS x13, x14, 368
-    RESTORE_TWO_REGS x15, x16, 384
-    RESTORE_TWO_REGS x17, x18, 400
+    RESTORE_REG            x1, 280
+    RESTORE_TWO_REGS  x2,  x3, 288
+    RESTORE_TWO_REGS  x4,  x5, 304
+    RESTORE_TWO_REGS  x6,  x7, 320
+    RESTORE_TWO_REGS  x8,  x9, 336
+    RESTORE_TWO_REGS x10, x11, 352
+    RESTORE_TWO_REGS x12, x13, 368
+    RESTORE_TWO_REGS x14, x15, 384
+    RESTORE_TWO_REGS x16, x17, 400 // Do not restore the platform register.
     RESTORE_TWO_REGS x19, x20, 416
     RESTORE_TWO_REGS x21, x22, 432
     RESTORE_TWO_REGS x23, x24, 448
@@ -391,7 +386,7 @@
 .endm
 
 .macro RESTORE_SAVE_EVERYTHING_FRAME
-    RESTORE_REG  x0, 264
+    RESTORE_REG  x0, 272
     RESTORE_SAVE_EVERYTHING_FRAME_KEEP_X0
 .endm
 
@@ -1116,7 +1111,8 @@
     ldp x12, x13, [x0, #96]
     ldp x14, x15, [x0, #112]
     // Do not load IP0 (x16) and IP1 (x17), these shall be clobbered below.
-    ldp x18, x19, [x0, #144]      // X18 and xSELF.
+    // Don't load the platform register (x18) either.
+    ldr      x19, [x0, #152]      // xSELF.
     ldp x20, x21, [x0, #160]      // For Baker RB, wMR (w20) is reloaded below.
     ldp x22, x23, [x0, #176]
     ldp x24, x25, [x0, #192]
@@ -2293,8 +2289,8 @@
     mov   xLR, #0             // Clobber LR for later checks.
     SETUP_SAVE_EVERYTHING_FRAME
 
-    add   x3, sp, #8          // Pass floating-point result pointer, in kSaveEverything frame.
-    add   x2, sp, #264        // Pass integer result pointer, in kSaveEverything frame.
+    add   x3, sp, #16         // Pass floating-point result pointer, in kSaveEverything frame.
+    add   x2, sp, #272        // Pass integer result pointer, in kSaveEverything frame.
     mov   x1, sp              // Pass SP.
     mov   x0, xSELF           // Pass Thread.
     bl   artInstrumentationMethodExitFromCode    // (Thread*, SP, gpr_res*, fpr_res*)
@@ -2496,7 +2492,8 @@
 .Lslow_rb_\name:
     /*
      * Allocate 44 stack slots * 8 = 352 bytes:
-     * - 20 slots for core registers X0-15, X17-X19, LR
+     * - 19 slots for core registers X0-15, X17, X19, LR
+     * - 1 slot padding
      * - 24 slots for floating-point registers D0-D7 and D16-D31
      */
     // We must not clobber IP1 since code emitted for HLoadClass and HLoadString
@@ -2510,8 +2507,8 @@
     SAVE_TWO_REGS x10, x11, 80
     SAVE_TWO_REGS x12, x13, 96
     SAVE_TWO_REGS x14, x15, 112
-    SAVE_TWO_REGS x17, x18, 128  // Skip x16, i.e. IP0.
-    SAVE_TWO_REGS x19, xLR, 144  // Save also return address.
+    SAVE_TWO_REGS x17, x19, 128  // Skip x16, i.e. IP0, and x18, the platform register.
+    SAVE_REG      xLR,      144  // Save also return address.
     // Save all potentially live caller-save floating-point registers.
     stp   d0, d1,   [sp, #160]
     stp   d2, d3,   [sp, #176]
@@ -2544,8 +2541,8 @@
     POP_REGS_NE x10, x11, 80,  \xreg
     POP_REGS_NE x12, x13, 96,  \xreg
     POP_REGS_NE x14, x15, 112, \xreg
-    POP_REGS_NE x17, x18, 128, \xreg
-    POP_REGS_NE x19, xLR, 144, \xreg  // Restore also return address.
+    POP_REGS_NE x17, x19, 128, \xreg
+    POP_REG_NE  xLR,      144, \xreg  // Restore also return address.
     // Restore floating-point registers.
     ldp   d0, d1,   [sp, #160]
     ldp   d2, d3,   [sp, #176]
@@ -2588,7 +2585,7 @@
 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg15, w15, x15
 // READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg16, w16, x16 ip0 is blocked
 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg17, w17, x17
-READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg18, w18, x18
+// READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg18, w18, x18 x18 is blocked
 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg19, w19, x19
 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg20, w20, x20
 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg21, w21, x21
@@ -2629,7 +2626,7 @@
     SELECT_X_OR_W_FOR_MACRO \macro_for_register, x15, w15, \xreg
     \macro_for_reserved_register  // IP0 is reserved
     \macro_for_reserved_register  // IP1 is reserved
-    SELECT_X_OR_W_FOR_MACRO \macro_for_register, x18, w18, \xreg
+    \macro_for_reserved_register  // x18 is reserved
     SELECT_X_OR_W_FOR_MACRO \macro_for_register, x19, w19, \xreg
     SELECT_X_OR_W_FOR_MACRO \macro_for_register, x20, w20, \xreg
     SELECT_X_OR_W_FOR_MACRO \macro_for_register, x21, w21, \xreg
@@ -2673,13 +2670,12 @@
 
 .macro READ_BARRIER_MARK_INTROSPECTION_SLOW_PATH ldr_offset
     /*
-     * Allocate 44 stack slots * 8 = 352 bytes:
-     * - 19 slots for core registers X0-15, X18-X19, LR
-     * - 1 slot padding
+     * Allocate 42 stack slots * 8 = 336 bytes:
+     * - 18 slots for core registers X0-15, X19, LR
      * - 24 slots for floating-point registers D0-D7 and D16-D31
      */
     // Save all potentially live caller-save core registers.
-    SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 352
+    SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 336
     SAVE_TWO_REGS  x2,  x3, 16
     SAVE_TWO_REGS  x4,  x5, 32
     SAVE_TWO_REGS  x6,  x7, 48
@@ -2687,21 +2683,21 @@
     SAVE_TWO_REGS x10, x11, 80
     SAVE_TWO_REGS x12, x13, 96
     SAVE_TWO_REGS x14, x15, 112
-    SAVE_TWO_REGS x18, x19, 128       // Skip x16, x17, i.e. IP0, IP1.
-    SAVE_REG      xLR,      144       // Save return address, skip padding at 152.
+    // Skip x16, x17, i.e. IP0, IP1, and x18, the platform register.
+    SAVE_TWO_REGS x19, xLR, 128       // Save return address.
     // Save all potentially live caller-save floating-point registers.
-    stp   d0, d1,   [sp, #160]
-    stp   d2, d3,   [sp, #176]
-    stp   d4, d5,   [sp, #192]
-    stp   d6, d7,   [sp, #208]
-    stp   d16, d17, [sp, #224]
-    stp   d18, d19, [sp, #240]
-    stp   d20, d21, [sp, #256]
-    stp   d22, d23, [sp, #272]
-    stp   d24, d25, [sp, #288]
-    stp   d26, d27, [sp, #304]
-    stp   d28, d29, [sp, #320]
-    stp   d30, d31, [sp, #336]
+    stp   d0, d1,   [sp, #144]
+    stp   d2, d3,   [sp, #160]
+    stp   d4, d5,   [sp, #176]
+    stp   d6, d7,   [sp, #192]
+    stp   d16, d17, [sp, #208]
+    stp   d18, d19, [sp, #224]
+    stp   d20, d21, [sp, #240]
+    stp   d22, d23, [sp, #256]
+    stp   d24, d25, [sp, #272]
+    stp   d26, d27, [sp, #288]
+    stp   d28, d29, [sp, #304]
+    stp   d30, d31, [sp, #320]
 
     mov   x0, xIP0
     bl    artReadBarrierMark          // artReadBarrierMark(obj)
@@ -2716,26 +2712,26 @@
     RESTORE_TWO_REGS x10, x11, 80
     RESTORE_TWO_REGS x12, x13, 96
     RESTORE_TWO_REGS x14, x15, 112
-    RESTORE_TWO_REGS x18, x19, 128    // Skip x16, x17, i.e. IP0, IP1.
-    RESTORE_REG      xLR,      144    // Restore return address.
+    // Skip x16, x17, i.e. IP0, IP1, and x18, the platform register.
+    RESTORE_TWO_REGS x19, xLR, 128    // Restore return address.
     // Restore caller-save floating-point registers.
-    ldp   d0, d1,   [sp, #160]
-    ldp   d2, d3,   [sp, #176]
-    ldp   d4, d5,   [sp, #192]
-    ldp   d6, d7,   [sp, #208]
-    ldp   d16, d17, [sp, #224]
-    ldp   d18, d19, [sp, #240]
-    ldp   d20, d21, [sp, #256]
-    ldp   d22, d23, [sp, #272]
-    ldp   d24, d25, [sp, #288]
-    ldp   d26, d27, [sp, #304]
-    ldp   d28, d29, [sp, #320]
-    ldp   d30, d31, [sp, #336]
+    ldp   d0, d1,   [sp, #144]
+    ldp   d2, d3,   [sp, #160]
+    ldp   d4, d5,   [sp, #176]
+    ldp   d6, d7,   [sp, #192]
+    ldp   d16, d17, [sp, #208]
+    ldp   d18, d19, [sp, #224]
+    ldp   d20, d21, [sp, #240]
+    ldp   d22, d23, [sp, #256]
+    ldp   d24, d25, [sp, #272]
+    ldp   d26, d27, [sp, #288]
+    ldp   d28, d29, [sp, #304]
+    ldp   d30, d31, [sp, #320]
 
     ldr   x0, [lr, #\ldr_offset]      // Load the instruction.
     adr   xIP1, .Lmark_introspection_return_switch
     bfi   xIP1, x0, #3, #5            // Calculate switch case address.
-    RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 352
+    RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 336
     br    xIP1
 .endm
 
diff --git a/runtime/image.h b/runtime/image.h
index 0496650..bd903da 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -289,14 +289,14 @@
     return GetImageSection(kSectionClassTable);
   }
 
-  const ImageSection& GetImageBitmapSection() const {
-    return GetImageSection(kSectionImageBitmap);
-  }
-
   const ImageSection& GetImageStringReferenceOffsetsSection() const {
     return GetImageSection(kSectionStringReferenceOffsets);
   }
 
+  const ImageSection& GetImageBitmapSection() const {
+    return GetImageSection(kSectionImageBitmap);
+  }
+
   template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   ObjPtr<mirror::Object> GetImageRoot(ImageRoot image_root) const
       REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index d533054..cbcaaef 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -1360,38 +1360,56 @@
       : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
         shorty('V') {}
 
+  static uint16_t GetMethodIndexOfInvoke(ArtMethod* caller,
+                                         const Instruction& inst,
+                                         uint32_t dex_pc)
+        REQUIRES_SHARED(Locks::mutator_lock_) {
+    switch (inst.Opcode()) {
+      case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
+      case Instruction::INVOKE_VIRTUAL_QUICK: {
+        uint16_t method_idx = caller->GetIndexFromQuickening(dex_pc);
+        CHECK_NE(method_idx, DexFile::kDexNoIndex16);
+        return method_idx;
+      }
+      default: {
+        return inst.VRegB();
+      }
+    }
+  }
+
   bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
-    if (m != nullptr && !m->IsRuntimeMethod()) {
-      // The first Java method.
-      if (m->IsNative()) {
-        // Use JNI method's shorty for the jni stub.
-        shorty = m->GetShorty()[0];
-        return false;
-      }
-      if (m->IsProxyMethod()) {
-        // Proxy method just invokes its proxied method via
-        // art_quick_proxy_invoke_handler.
-        shorty = m->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()[0];
-        return false;
-      }
+    if (m == nullptr || m->IsRuntimeMethod()) {
+      return true;
+    }
+    // The first Java method.
+    if (m->IsNative()) {
+      // Use JNI method's shorty for the jni stub.
+      shorty = m->GetShorty()[0];
+    } else if (m->IsProxyMethod()) {
+      // Proxy method just invokes its proxied method via
+      // art_quick_proxy_invoke_handler.
+      shorty = m->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()[0];
+    } else {
       const Instruction& instr = m->DexInstructions().InstructionAt(GetDexPc());
       if (instr.IsInvoke()) {
+        uint16_t method_index = GetMethodIndexOfInvoke(m, instr, GetDexPc());
         const DexFile* dex_file = m->GetDexFile();
-        if (interpreter::IsStringInit(dex_file, instr.VRegB())) {
+        if (interpreter::IsStringInit(dex_file, method_index)) {
           // Invoking string init constructor is turned into invoking
           // StringFactory.newStringFromChars() which returns a string.
           shorty = 'L';
-          return false;
+        } else {
+          shorty = dex_file->GetMethodShorty(method_index)[0];
         }
-        // A regular invoke, use callee's shorty.
-        uint32_t method_idx = instr.VRegB();
-        shorty = dex_file->GetMethodShorty(method_idx)[0];
+      } else {
+        // It could be that a non-invoke opcode invokes a stub, which in turn
+        // invokes Java code. In such cases, we should never expect a return
+        // value from the stub.
       }
-      // Stop stack walking since we've seen a Java frame.
-      return false;
     }
-    return true;
+    // Stop stack walking since we've seen a Java frame.
+    return false;
   }
 
   char shorty;
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl-inl.h
similarity index 99%
rename from runtime/interpreter/interpreter_switch_impl.cc
rename to runtime/interpreter/interpreter_switch_impl-inl.h
index 4757b57..4774d69 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#ifndef ART_RUNTIME_INTERPRETER_INTERPRETER_SWITCH_IMPL_INL_H_
+#define ART_RUNTIME_INTERPRETER_INTERPRETER_SWITCH_IMPL_INL_H_
+
 #include "interpreter_switch_impl.h"
 
 #include "base/enums.h"
@@ -2571,15 +2574,7 @@
   return;
 }  // NOLINT(readability/fn_size)
 
-// Explicit definitions of ExecuteSwitchImplCpp.
-template HOT_ATTR
-void ExecuteSwitchImplCpp<true, false>(SwitchImplContext* ctx);
-template HOT_ATTR
-void ExecuteSwitchImplCpp<false, false>(SwitchImplContext* ctx);
-template
-void ExecuteSwitchImplCpp<true, true>(SwitchImplContext* ctx);
-template
-void ExecuteSwitchImplCpp<false, true>(SwitchImplContext* ctx);
-
 }  // namespace interpreter
 }  // namespace art
+
+#endif  // ART_RUNTIME_INTERPRETER_INTERPRETER_SWITCH_IMPL_INL_H_
diff --git a/runtime/interpreter/interpreter_switch_impl0.cc b/runtime/interpreter/interpreter_switch_impl0.cc
new file mode 100644
index 0000000..00159ec
--- /dev/null
+++ b/runtime/interpreter/interpreter_switch_impl0.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// The interpreter function takes considerable time to compile and link.
+// We compile the explicit definitions separately to speed up the build.
+
+#include "interpreter_switch_impl-inl.h"
+
+namespace art {
+namespace interpreter {
+
+// Explicit definition of ExecuteSwitchImplCpp.
+template HOT_ATTR
+void ExecuteSwitchImplCpp<false, false>(SwitchImplContext* ctx);
+
+}  // namespace interpreter
+}  // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl1.cc b/runtime/interpreter/interpreter_switch_impl1.cc
new file mode 100644
index 0000000..3a86765
--- /dev/null
+++ b/runtime/interpreter/interpreter_switch_impl1.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// The interpreter function takes considerable time to compile and link.
+// We compile the explicit definitions separately to speed up the build.
+
+#include "interpreter_switch_impl-inl.h"
+
+namespace art {
+namespace interpreter {
+
+// Explicit definition of ExecuteSwitchImplCpp.
+template
+void ExecuteSwitchImplCpp<false, true>(SwitchImplContext* ctx);
+
+}  // namespace interpreter
+}  // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl2.cc b/runtime/interpreter/interpreter_switch_impl2.cc
new file mode 100644
index 0000000..c2739c1
--- /dev/null
+++ b/runtime/interpreter/interpreter_switch_impl2.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// The interpreter function takes considerable time to compile and link.
+// We compile the explicit definitions separately to speed up the build.
+
+#include "interpreter_switch_impl-inl.h"
+
+namespace art {
+namespace interpreter {
+
+// Explicit definition of ExecuteSwitchImplCpp.
+template HOT_ATTR
+void ExecuteSwitchImplCpp<true, false>(SwitchImplContext* ctx);
+
+}  // namespace interpreter
+}  // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl3.cc b/runtime/interpreter/interpreter_switch_impl3.cc
new file mode 100644
index 0000000..808e4bc
--- /dev/null
+++ b/runtime/interpreter/interpreter_switch_impl3.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// The interpreter function takes considerable time to compile and link.
+// We compile the explicit definitions separately to speed up the build.
+
+#include "interpreter_switch_impl-inl.h"
+
+namespace art {
+namespace interpreter {
+
+// Explicit definition of ExecuteSwitchImplCpp.
+template
+void ExecuteSwitchImplCpp<true, true>(SwitchImplContext* ctx);
+
+}  // namespace interpreter
+}  // namespace art
diff --git a/test/602-deoptimizeable/info.txt b/test/602-deoptimizeable/info.txt
index 4b6147f..d0952f9 100644
--- a/test/602-deoptimizeable/info.txt
+++ b/test/602-deoptimizeable/info.txt
@@ -1,8 +1 @@
 Test various cases for full/partial-fragment deoptimization.
-
-TODO: we should remove this test as its expectations at point of
-writing was that debuggable apps could run un-deoptimizeable frames
-from the boot image. Today, we deoptimize the boot image as soon as
-we see the app being debuggable. Test 685-deoptimizeable is the proper
-version of this test, but we currently keep the 602 version around to
-try diagnosing a gcstress issue.
diff --git a/test/602-deoptimizeable/src/Main.java b/test/602-deoptimizeable/src/Main.java
index 7a3285d..46584b0 100644
--- a/test/602-deoptimizeable/src/Main.java
+++ b/test/602-deoptimizeable/src/Main.java
@@ -33,10 +33,7 @@
 
     public int hashCode() {
         sHashCodeInvoked = true;
-        Main.assertIsManaged();
         Main.deoptimizeAll();
-        Main.assertIsInterpreted();
-        Main.assertCallerIsManaged();  // Caller is from framework code HashMap.
         return i % 64;
     }
 }
@@ -46,13 +43,6 @@
 
     public static native void deoptimizeAll();
     public static native void undeoptimizeAll();
-    public static native void assertIsInterpreted();
-    public static native void assertIsManaged();
-    public static native void assertCallerIsInterpreted();
-    public static native void assertCallerIsManaged();
-    public static native void disableStackFrameAsserts();
-    public static native boolean hasOatFile();
-    public static native boolean isInterpreted();
 
     public static void execute(Runnable runnable) throws Exception {
       Thread t = new Thread(runnable);
@@ -62,19 +52,13 @@
 
     public static void main(String[] args) throws Exception {
         System.loadLibrary(args[0]);
-        // TODO: Stack frame assertions are irrelevant in this test as we now
-        // always run JIT with debuggable. 685-deoptimizeable is the proper version
-        // of this test, but we keep this version around to diagnose a gcstress issue.
-        disableStackFrameAsserts();
         final HashMap<DummyObject, Long> map = new HashMap<DummyObject, Long>();
 
         // Single-frame deoptimization that covers partial fragment.
         execute(new Runnable() {
             public void run() {
                 int[] arr = new int[3];
-                assertIsManaged();
                 int res = $noinline$run1(arr);
-                assertIsManaged();  // Only single frame is deoptimized.
                 if (res != 79) {
                     System.out.println("Failure 1!");
                     System.exit(0);
@@ -87,13 +71,11 @@
             public void run() {
                 try {
                     int[] arr = new int[3];
-                    assertIsManaged();
                     // Use reflection to call $noinline$run2 so that it does
                     // full-fragment deoptimization since that is an upcall.
                     Class<?> cls = Class.forName("Main");
                     Method method = cls.getDeclaredMethod("$noinline$run2", int[].class);
                     double res = (double)method.invoke(Main.class, arr);
-                    assertIsManaged();  // Only single frame is deoptimized.
                     if (res != 79.3d) {
                         System.out.println("Failure 2!");
                         System.exit(0);
@@ -107,9 +89,7 @@
         // Full-fragment deoptimization.
         execute(new Runnable() {
             public void run() {
-                assertIsManaged();
                 float res = $noinline$run3B();
-                assertIsInterpreted();  // Every deoptimizeable method is deoptimized.
                 if (res != 0.034f) {
                     System.out.println("Failure 3!");
                     System.exit(0);
@@ -123,9 +103,7 @@
         execute(new Runnable() {
             public void run() {
                 try {
-                    assertIsManaged();
                     map.put(new DummyObject(10), Long.valueOf(100));
-                    assertIsInterpreted();  // Every deoptimizeable method is deoptimized.
                     if (map.get(new DummyObject(10)) == null) {
                         System.out.println("Expected map to contain DummyObject(10)");
                     }
@@ -147,7 +125,6 @@
     }
 
     public static int $noinline$run1(int[] arr) {
-        assertIsManaged();
         // Prevent inlining.
         if (sFlag) {
             throw new Error();
@@ -161,18 +138,15 @@
             // This causes AIOOBE and triggers deoptimization from compiled code.
             arr[3] = 1;
         } catch (ArrayIndexOutOfBoundsException e) {
-            assertIsInterpreted(); // Single-frame deoptimization triggered.
             caught = true;
         }
         if (!caught) {
             System.out.println("Expected exception");
         }
-        assertIsInterpreted();
         return 79;
     }
 
     public static double $noinline$run2(int[] arr) {
-        assertIsManaged();
         // Prevent inlining.
         if (sFlag) {
             throw new Error();
@@ -186,37 +160,30 @@
             // This causes AIOOBE and triggers deoptimization from compiled code.
             arr[3] = 1;
         } catch (ArrayIndexOutOfBoundsException e) {
-            assertIsInterpreted();  // Single-frame deoptimization triggered.
             caught = true;
         }
         if (!caught) {
             System.out.println("Expected exception");
         }
-        assertIsInterpreted();
         return 79.3d;
     }
 
     public static float $noinline$run3A() {
-        assertIsManaged();
         // Prevent inlining.
         if (sFlag) {
             throw new Error();
         }
         // Deoptimize callers.
         deoptimizeAll();
-        assertIsInterpreted();
-        assertCallerIsInterpreted();  // $noinline$run3B is deoptimizeable.
         return 0.034f;
     }
 
     public static float $noinline$run3B() {
-        assertIsManaged();
         // Prevent inlining.
         if (sFlag) {
             throw new Error();
         }
         float res = $noinline$run3A();
-        assertIsInterpreted();
         return res;
     }
 }
diff --git a/test/687-deopt/expected.txt b/test/687-deopt/expected.txt
new file mode 100644
index 0000000..6a5618e
--- /dev/null
+++ b/test/687-deopt/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/687-deopt/info.txt b/test/687-deopt/info.txt
new file mode 100644
index 0000000..ef56f51
--- /dev/null
+++ b/test/687-deopt/info.txt
@@ -0,0 +1,2 @@
+Regression test for instrumentation deopt, which previously did not expect a
+quickened instruction when returning from instrumentation stub.
diff --git a/test/687-deopt/src/Main.java b/test/687-deopt/src/Main.java
new file mode 100644
index 0000000..afe90d6
--- /dev/null
+++ b/test/687-deopt/src/Main.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+import java.util.HashMap;
+
+public class Main {
+  public static void main(String[] args) {
+    System.loadLibrary(args[0]);
+
+    // Jit compile HashMap.hash method, so that instrumentation stubs
+    // will deoptimize it.
+    ensureJitCompiled(HashMap.class, "hash");
+
+    Main key = new Main();
+    Integer value = new Integer(10);
+    HashMap<Main, Integer> map = new HashMap<>();
+    map.put(key, value);
+    Integer res = map.get(key);
+    if (!value.equals(res)) {
+      throw new Error("Expected 10, got " + res);
+    }
+  }
+
+  public int hashCode() {
+    // The call stack at this point is:
+    // Main.main
+    //  HashMap.put
+    //    HashMap.hash
+    //      Main.hashCode
+    //
+    // The opcode at HashMap.hash is invoke-virtual-quick which the
+    // instrumentation code did not expect and used to fetch the wrong
+    // method index for it.
+    deoptimizeAll();
+    return 42;
+  }
+
+  public static native void deoptimizeAll();
+  public static native void ensureJitCompiled(Class<?> cls, String methodName);
+}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index d831993..7b40160 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -948,6 +948,7 @@
           "685-deoptimizeable",
           "685-shifts",
           "686-get-this",
+          "687-deopt",
           "706-checker-scheduler",
           "707-checker-invalid-profile",
           "714-invoke-custom-lambda-metafactory",