Remove ShadowFrame::dex_pc_ (but keep dex_pc_ptr_)

They store the same information which is redundant and error prone.

Test: ./art/test.py --interpreter
Change-Id: I379c20973b90645e3c1016c253d9a6db9a2417dc
diff --git a/oatdump/oatdump_app_test.cc b/oatdump/oatdump_app_test.cc
index 4490647..bbd0e3d 100644
--- a/oatdump/oatdump_app_test.cc
+++ b/oatdump/oatdump_app_test.cc
@@ -19,27 +19,27 @@
 namespace art {
 
 TEST_F(OatDumpTest, TestAppWithBootImage) {
-  ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M"}));
-  ASSERT_TRUE(Exec(kDynamic, kModeOatWithBootImage, {}, kListAndCode));
+  ASSERT_TRUE(GenerateAppOdexFile(kDynamicLinking, {"--runtime-arg", "-Xmx64M"}));
+  ASSERT_TRUE(Exec(kDynamicLinking, kModeOatWithBootImage, {}, kListAndCode));
 }
 TEST_F(OatDumpTest, TestAppWithBootImageStatic) {
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
-  ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M"}));
-  ASSERT_TRUE(Exec(kStatic, kModeOatWithBootImage, {}, kListAndCode));
+  ASSERT_TRUE(GenerateAppOdexFile(kStaticLinking, {"--runtime-arg", "-Xmx64M"}));
+  ASSERT_TRUE(Exec(kStaticLinking, kModeOatWithBootImage, {}, kListAndCode));
 }
 
 TEST_F(OatDumpTest, TestAppImageWithBootImage) {
   TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS();  // GC bug, b/126305867
   const std::string app_image_arg = "--app-image-file=" + GetAppImageName();
-  ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M", app_image_arg}));
-  ASSERT_TRUE(Exec(kDynamic, kModeAppImage, {}, kListAndCode));
+  ASSERT_TRUE(GenerateAppOdexFile(kDynamicLinking, {"--runtime-arg", "-Xmx64M", app_image_arg}));
+  ASSERT_TRUE(Exec(kDynamicLinking, kModeAppImage, {}, kListAndCode));
 }
 TEST_F(OatDumpTest, TestAppImageWithBootImageStatic) {
   TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS();  // GC bug, b/126305867
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   const std::string app_image_arg = "--app-image-file=" + GetAppImageName();
-  ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M", app_image_arg}));
-  ASSERT_TRUE(Exec(kStatic, kModeAppImage, {}, kListAndCode));
+  ASSERT_TRUE(GenerateAppOdexFile(kStaticLinking, {"--runtime-arg", "-Xmx64M", app_image_arg}));
+  ASSERT_TRUE(Exec(kStaticLinking, kModeAppImage, {}, kListAndCode));
 }
 
 }  // namespace art
diff --git a/oatdump/oatdump_image_test.cc b/oatdump/oatdump_image_test.cc
index 0a076f0..6f6b83b 100644
--- a/oatdump/oatdump_image_test.cc
+++ b/oatdump/oatdump_image_test.cc
@@ -28,25 +28,25 @@
 TEST_F(OatDumpTest, TestImage) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kDynamic, kModeArt, {}, kListAndCode));
+  ASSERT_TRUE(Exec(kDynamicLinking, kModeArt, {}, kListAndCode));
 }
 TEST_F(OatDumpTest, TestImageStatic) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kStatic, kModeArt, {}, kListAndCode));
+  ASSERT_TRUE(Exec(kStaticLinking, kModeArt, {}, kListAndCode));
 }
 
 TEST_F(OatDumpTest, TestOatImage) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kDynamic, kModeCoreOat, {}, kListAndCode));
+  ASSERT_TRUE(Exec(kDynamicLinking, kModeCoreOat, {}, kListAndCode));
 }
 TEST_F(OatDumpTest, TestOatImageStatic) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kStatic, kModeCoreOat, {}, kListAndCode));
+  ASSERT_TRUE(Exec(kStaticLinking, kModeCoreOat, {}, kListAndCode));
 }
 
 }  // namespace art
diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc
index 506fde7..87f9ac6 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -30,61 +30,61 @@
 TEST_F(OatDumpTest, TestNoDumpVmap) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-dump:vmap"}, kListAndCode));
+  ASSERT_TRUE(Exec(kDynamicLinking, kModeArt, {"--no-dump:vmap"}, kListAndCode));
 }
 TEST_F(OatDumpTest, TestNoDumpVmapStatic) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-dump:vmap"}, kListAndCode));
+  ASSERT_TRUE(Exec(kStaticLinking, kModeArt, {"--no-dump:vmap"}, kListAndCode));
 }
 
 TEST_F(OatDumpTest, TestNoDisassemble) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-disassemble"}, kListAndCode));
+  ASSERT_TRUE(Exec(kDynamicLinking, kModeArt, {"--no-disassemble"}, kListAndCode));
 }
 TEST_F(OatDumpTest, TestNoDisassembleStatic) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-disassemble"}, kListAndCode));
+  ASSERT_TRUE(Exec(kStaticLinking, kModeArt, {"--no-disassemble"}, kListAndCode));
 }
 
 TEST_F(OatDumpTest, TestListClasses) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-classes"}, kListOnly));
+  ASSERT_TRUE(Exec(kDynamicLinking, kModeArt, {"--list-classes"}, kListOnly));
 }
 TEST_F(OatDumpTest, TestListClassesStatic) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-classes"}, kListOnly));
+  ASSERT_TRUE(Exec(kStaticLinking, kModeArt, {"--list-classes"}, kListOnly));
 }
 
 TEST_F(OatDumpTest, TestListMethods) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-methods"}, kListOnly));
+  ASSERT_TRUE(Exec(kDynamicLinking, kModeArt, {"--list-methods"}, kListOnly));
 }
 TEST_F(OatDumpTest, TestListMethodsStatic) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-methods"}, kListOnly));
+  ASSERT_TRUE(Exec(kStaticLinking, kModeArt, {"--list-methods"}, kListOnly));
 }
 
 TEST_F(OatDumpTest, TestSymbolize) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kDynamic, kModeSymbolize, {}, kListOnly));
+  ASSERT_TRUE(Exec(kDynamicLinking, kModeSymbolize, {}, kListOnly));
 }
 TEST_F(OatDumpTest, TestSymbolizeStatic) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kStatic, kModeSymbolize, {}, kListOnly));
+  ASSERT_TRUE(Exec(kStaticLinking, kModeSymbolize, {}, kListOnly));
 }
 
 TEST_F(OatDumpTest, TestExportDex) {
@@ -92,8 +92,8 @@
   // Test is failing on target, b/77469384.
   TEST_DISABLED_FOR_TARGET();
   std::string error_msg;
-  ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M"}));
-  ASSERT_TRUE(Exec(kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
+  ASSERT_TRUE(GenerateAppOdexFile(kDynamicLinking, {"--runtime-arg", "-Xmx64M"}));
+  ASSERT_TRUE(Exec(kDynamicLinking, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
   const std::string dex_location =
       tmp_dir_+ "/" + android::base::Basename(GetTestDexFileName(GetAppBaseName().c_str())) +
       "_export.dex";
@@ -109,8 +109,8 @@
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
-  ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M"}));
-  ASSERT_TRUE(Exec(kStatic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
+  ASSERT_TRUE(GenerateAppOdexFile(kStaticLinking, {"--runtime-arg", "-Xmx64M"}));
+  ASSERT_TRUE(Exec(kStaticLinking, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
 }
 
 }  // namespace art
diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h
index 359b060..997321f 100644
--- a/oatdump/oatdump_test.h
+++ b/oatdump/oatdump_test.h
@@ -66,8 +66,8 @@
 
   // Linking flavor.
   enum Flavor {
-    kDynamic,  // oatdump(d), dex2oat(d)
-    kStatic,   // oatdump(d)s, dex2oat(d)s
+    kDynamicLinking,  // oatdump(d), dex2oat(d)
+    kStaticLinking,   // oatdump(d)s, dex2oat(d)s
   };
 
   // Returns path to the oatdump/dex2oat/dexdump binary.
@@ -83,7 +83,7 @@
   }
 
   std::string GetExecutableFilePath(Flavor flavor, const char* name) {
-    return GetExecutableFilePath(name, kIsDebugBuild, flavor == kStatic);
+    return GetExecutableFilePath(name, kIsDebugBuild, flavor == kStaticLinking);
   }
 
   enum Mode {
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index fc3005d..d22771d 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -1917,6 +1917,7 @@
   self->VerifyStack();
 
   uint32_t dex_pc = shadow_frame.GetDexPC();
+  DCHECK_LT(dex_pc, shadow_frame.GetMethod()->DexInstructionData().InsnsSizeInCodeUnits());
   const auto* const instrumentation = Runtime::Current()->GetInstrumentation();
   const uint16_t* const insns = accessor.Insns();
   const Instruction* next = Instruction::At(insns + dex_pc);
diff --git a/runtime/interpreter/mterp/arm/main.S b/runtime/interpreter/mterp/arm/main.S
index 12b3dab..95bc864 100644
--- a/runtime/interpreter/mterp/arm/main.S
+++ b/runtime/interpreter/mterp/arm/main.S
@@ -109,12 +109,10 @@
  */
 #define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET)
 #define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET)
-#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET)
 #define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET)
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_SHADOWFRAME OFF_FP(0)
 
 /*
@@ -122,25 +120,11 @@
  * be done *before* something throws.
  *
  * It's okay to do this more than once.
- *
- * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped
- * dex byte codes.  However, the rest of the runtime expects dex pc to be an instruction
- * offset into the code_items_[] array.  For effiency, we will "export" the
- * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC
- * to convert to a dex pc when needed.
  */
 .macro EXPORT_PC
     str  rPC, [rFP, #OFF_FP_DEX_PC_PTR]
 .endm
 
-.macro EXPORT_DEX_PC tmp
-    ldr  \tmp, [rFP, #OFF_FP_DEX_INSTRUCTIONS]
-    str  rPC, [rFP, #OFF_FP_DEX_PC_PTR]
-    sub  \tmp, rPC, \tmp
-    asr  \tmp, #1
-    str  \tmp, [rFP, #OFF_FP_DEX_PC]
-.endm
-
 /*
  * Fetch the next instruction from rPC into rINST.  Does not advance rPC.
  */
@@ -398,18 +382,13 @@
     /* Remember the return register */
     str     r3, [r2, #SHADOWFRAME_RESULT_REGISTER_OFFSET]
 
-    /* Remember the dex instruction pointer */
-    str     r1, [r2, #SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET]
-
     /* set up "named" registers */
     mov     rSELF, r0
     ldr     r0, [r2, #SHADOWFRAME_NUMBER_OF_VREGS_OFFSET]
-    add     rFP, r2, #SHADOWFRAME_VREGS_OFFSET     @ point to vregs.
-    VREG_INDEX_TO_ADDR rREFS, r0                   @ point to reference array in shadow frame
-    ldr     r0, [r2, #SHADOWFRAME_DEX_PC_OFFSET]   @ Get starting dex_pc.
-    add     rPC, r1, r0, lsl #1                    @ Create direct pointer to 1st dex opcode
+    add     rFP, r2, #SHADOWFRAME_VREGS_OFFSET         @ pointer to vregs.
+    VREG_INDEX_TO_ADDR rREFS, r0                       @ pointer to reference array in shadow frame
+    ldr     rPC, [r2, #SHADOWFRAME_DEX_PC_PTR_OFFSET]  @ pointer to current dex instruction.
     CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
-    EXPORT_PC
 
     /* Starting ibase */
     ldr     rIBASE, [rSELF, #THREAD_CURRENT_IBASE_OFFSET]
@@ -551,10 +530,8 @@
     bl      MterpHandleException                    @ (self, shadow_frame)
     cmp     r0, #0
     beq     MterpExceptionReturn                    @ no local catch, back to caller.
-    ldr     r0, [rFP, #OFF_FP_DEX_INSTRUCTIONS]
-    ldr     r1, [rFP, #OFF_FP_DEX_PC]
     ldr     rIBASE, [rSELF, #THREAD_CURRENT_IBASE_OFFSET]
-    add     rPC, r0, r1, lsl #1                     @ generate new dex_pc_ptr
+    ldr     rPC, [rFP, #OFF_FP_DEX_PC_PTR]          @ reload dex pc pointer.
     /* Do we need to switch interpreters? */
     ldr     r0, [rSELF, #THREAD_USE_MTERP_OFFSET]
     cmp     r0, #0
diff --git a/runtime/interpreter/mterp/arm64/main.S b/runtime/interpreter/mterp/arm64/main.S
index fd745f1..e16b51c 100644
--- a/runtime/interpreter/mterp/arm64/main.S
+++ b/runtime/interpreter/mterp/arm64/main.S
@@ -115,12 +115,10 @@
  */
 #define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET)
 #define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET)
-#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET)
 #define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET)
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_SHADOWFRAME OFF_FP(0)
 
 /*
@@ -128,12 +126,6 @@
  * be done *before* something throws.
  *
  * It's okay to do this more than once.
- *
- * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped
- * dex byte codes.  However, the rest of the runtime expects dex pc to be an instruction
- * offset into the code_items_[] array.  For effiency, we will "export" the
- * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC
- * to convert to a dex pc when needed.
  */
 .macro EXPORT_PC
     str  xPC, [xFP, #OFF_FP_DEX_PC_PTR]
@@ -411,18 +403,13 @@
     /* Remember the return register */
     str     x3, [x2, #SHADOWFRAME_RESULT_REGISTER_OFFSET]
 
-    /* Remember the dex instruction pointer */
-    str     x1, [x2, #SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET]
-
     /* set up "named" registers */
     mov     xSELF, x0
     ldr     w0, [x2, #SHADOWFRAME_NUMBER_OF_VREGS_OFFSET]
-    add     xFP, x2, #SHADOWFRAME_VREGS_OFFSET     // point to vregs.
-    add     xREFS, xFP, w0, uxtw #2                // point to reference array in shadow frame
-    ldr     w0, [x2, #SHADOWFRAME_DEX_PC_OFFSET]   // Get starting dex_pc.
-    add     xPC, x1, w0, uxtw #1                   // Create direct pointer to 1st dex opcode
+    add     xFP, x2, #SHADOWFRAME_VREGS_OFFSET         // pointer to vregs.
+    add     xREFS, xFP, w0, uxtw #2                    // pointer to reference array in shadow frame
+    ldr     xPC, [x2, #SHADOWFRAME_DEX_PC_PTR_OFFSET]  // pointer to current dex instruction.
     CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
-    EXPORT_PC
 
     /* Starting ibase */
     ldr     xIBASE, [xSELF, #THREAD_CURRENT_IBASE_OFFSET]
@@ -561,10 +548,8 @@
     add     x1, xFP, #OFF_FP_SHADOWFRAME
     bl      MterpHandleException                    // (self, shadow_frame)
     cbz     w0, MterpExceptionReturn                // no local catch, back to caller.
-    ldr     x0, [xFP, #OFF_FP_DEX_INSTRUCTIONS]
-    ldr     w1, [xFP, #OFF_FP_DEX_PC]
     ldr     xIBASE, [xSELF, #THREAD_CURRENT_IBASE_OFFSET]
-    add     xPC, x0, x1, lsl #1                     // generate new dex_pc_ptr
+    ldr     xPC, [xFP, #OFF_FP_DEX_PC_PTR]          // reload dex pc pointer.
     /* Do we need to switch interpreters? */
     ldr     w0, [xSELF, #THREAD_USE_MTERP_OFFSET]
     cbz     w0, MterpFallback
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 80ebf21..57ebfac 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -554,14 +554,10 @@
   }
   DCHECK(!Runtime::Current()->IsActiveTransaction());
   const Instruction* inst = Instruction::At(dex_pc_ptr);
-  uint16_t inst_data = inst->Fetch16(0);
-  if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
-    self->AssertPendingException();
-  } else {
-    self->AssertNoPendingException();
-  }
+  DCHECK_EQ(self->IsExceptionPending(), inst->Opcode() == Instruction::MOVE_EXCEPTION);
+  uint32_t dex_pc = dex_pc_ptr - shadow_frame->GetDexInstructions();
+  DCHECK_LT(dex_pc, shadow_frame->GetMethod()->DexInstructionData().InsnsSizeInCodeUnits());
   if (kTraceExecutionEnabled) {
-    uint32_t dex_pc = dex_pc_ptr - shadow_frame->GetDexInstructions();
     TraceExecution(*shadow_frame, inst, dex_pc);
   }
   if (kTestExportPC) {
diff --git a/runtime/interpreter/mterp/mterp.h b/runtime/interpreter/mterp/mterp.h
index af52758..d8fe358 100644
--- a/runtime/interpreter/mterp/mterp.h
+++ b/runtime/interpreter/mterp/mterp.h
@@ -40,8 +40,8 @@
 // handler for a recent opcode failed to export the Dalvik PC prior to a possible exit from
 // the mterp environment.
 constexpr uintptr_t kExportPCPoison = 0xdead00ff;
-// Set true to enable poison testing of ExportPC.  Uses Alt interpreter.
-constexpr bool kTestExportPC = false;
+// Set true to enable poison testing of ExportPC.
+constexpr bool kTestExportPC = true;
 
 constexpr size_t kMterpHandlerSize = 128;
 
diff --git a/runtime/interpreter/mterp/x86/main.S b/runtime/interpreter/mterp/x86/main.S
index 8df75d2..03cbf49 100644
--- a/runtime/interpreter/mterp/x86/main.S
+++ b/runtime/interpreter/mterp/x86/main.S
@@ -131,12 +131,10 @@
  */
 #define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET)
 #define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET)
-#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET)
 #define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET)
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_COUNTDOWN_OFFSET OFF_FP(SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET)
 #define OFF_FP_SHADOWFRAME OFF_FP(0)
 
@@ -182,12 +180,6 @@
  * be done *before* something throws.
  *
  * It's okay to do this more than once.
- *
- * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped
- * dex byte codes.  However, the rest of the runtime expects dex pc to be an instruction
- * offset into the code_items_[] array.  For effiency, we will "export" the
- * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC
- * to convert to a dex pc when needed.
  */
 .macro EXPORT_PC
     movl    rPC, OFF_FP_DEX_PC_PTR(rFP)
@@ -393,18 +385,12 @@
     movl    IN_ARG3(%esp), %eax
     movl    %eax, SHADOWFRAME_RESULT_REGISTER_OFFSET(%edx)
 
-    /* Remember the code_item */
-    movl    IN_ARG1(%esp), %ecx
-    movl    %ecx, SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET(%edx)
-
     /* set up "named" registers */
     movl    SHADOWFRAME_NUMBER_OF_VREGS_OFFSET(%edx), %eax
     leal    SHADOWFRAME_VREGS_OFFSET(%edx), rFP
     leal    (rFP, %eax, 4), rREFS
-    movl    SHADOWFRAME_DEX_PC_OFFSET(%edx), %eax
-    lea     (%ecx, %eax, 2), rPC
+    movl    SHADOWFRAME_DEX_PC_PTR_OFFSET(%edx), rPC
     CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
-    EXPORT_PC
 
     /* Set up for backwards branches & osr profiling */
     movl    OFF_FP_METHOD(rFP), %eax
@@ -570,10 +556,7 @@
     call    SYMBOL(MterpHandleException)
     testb   %al, %al
     jz      MterpExceptionReturn
-    movl    OFF_FP_DEX_INSTRUCTIONS(rFP), %eax
-    movl    OFF_FP_DEX_PC(rFP), %ecx
-    lea     (%eax, %ecx, 2), rPC
-    movl    rPC, OFF_FP_DEX_PC_PTR(rFP)
+    movl    OFF_FP_DEX_PC_PTR(rFP), rPC
     /* Do we need to switch interpreters? */
     movl    rSELF, %eax
     cmpb    LITERAL(0), THREAD_USE_MTERP_OFFSET(%eax)
diff --git a/runtime/interpreter/mterp/x86_64/main.S b/runtime/interpreter/mterp/x86_64/main.S
index 5f1fd2d..11e4d61 100644
--- a/runtime/interpreter/mterp/x86_64/main.S
+++ b/runtime/interpreter/mterp/x86_64/main.S
@@ -127,12 +127,10 @@
  */
 #define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET)
 #define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET)
-#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET)
 #define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET)
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_COUNTDOWN_OFFSET OFF_FP(SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET)
 #define OFF_FP_SHADOWFRAME (-SHADOWFRAME_VREGS_OFFSET)
 
@@ -183,12 +181,6 @@
  * be done *before* something throws.
  *
  * It's okay to do this more than once.
- *
- * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped
- * dex byte codes.  However, the rest of the runtime expects dex pc to be an instruction
- * offset into the code_items_[] array.  For effiency, we will "export" the
- * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC
- * to convert to a dex pc when needed.
  */
 .macro EXPORT_PC
     movq    rPC, OFF_FP_DEX_PC_PTR(rFP)
@@ -380,17 +372,12 @@
     /* Remember the return register */
     movq    IN_ARG3, SHADOWFRAME_RESULT_REGISTER_OFFSET(IN_ARG2)
 
-    /* Remember the code_item */
-    movq    IN_ARG1, SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET(IN_ARG2)
-
     /* set up "named" registers */
     movl    SHADOWFRAME_NUMBER_OF_VREGS_OFFSET(IN_ARG2), %eax
     leaq    SHADOWFRAME_VREGS_OFFSET(IN_ARG2), rFP
     leaq    (rFP, %rax, 4), rREFS
-    movl    SHADOWFRAME_DEX_PC_OFFSET(IN_ARG2), %eax
-    leaq    (IN_ARG1, %rax, 2), rPC
+    movq    SHADOWFRAME_DEX_PC_PTR_OFFSET(IN_ARG2), rPC
     CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
-    EXPORT_PC
 
     /* Starting ibase */
     movq    IN_ARG0, rSELF
@@ -536,10 +523,7 @@
     call    SYMBOL(MterpHandleException)
     testb   %al, %al
     jz      MterpExceptionReturn
-    movq    OFF_FP_DEX_INSTRUCTIONS(rFP), %rax
-    mov     OFF_FP_DEX_PC(rFP), %ecx
-    leaq    (%rax, %rcx, 2), rPC
-    movq    rPC, OFF_FP_DEX_PC_PTR(rFP)
+    movq    OFF_FP_DEX_PC_PTR(rFP), rPC
     /* Do we need to switch interpreters? */
     movq    rSELF, %rax
     cmpb    LITERAL(0), THREAD_USE_MTERP_OFFSET(%rax)
diff --git a/runtime/interpreter/shadow_frame.h b/runtime/interpreter/shadow_frame.h
index 8cb2b33..b0fa4a3 100644
--- a/runtime/interpreter/shadow_frame.h
+++ b/runtime/interpreter/shadow_frame.h
@@ -21,8 +21,10 @@
 #include <cstring>
 #include <string>
 
+#include "art_method.h"
 #include "base/locks.h"
 #include "base/macros.h"
+#include "dex/code_item_accessors-inl.h"
 #include "lock_count_data.h"
 #include "read_barrier.h"
 #include "stack_reference.h"
@@ -102,7 +104,7 @@
   }
 
   uint32_t GetDexPC() const {
-    return (dex_pc_ptr_ == nullptr) ? dex_pc_ : dex_pc_ptr_ - dex_instructions_;
+    return (dex_pc_ptr_ == nullptr) ? dex::kDexNoIndex : (dex_pc_ptr_ - dex_instructions_);
   }
 
   int16_t GetCachedHotnessCountdown() const {
@@ -122,8 +124,7 @@
   }
 
   void SetDexPC(uint32_t dex_pc) {
-    dex_pc_ = dex_pc;
-    dex_pc_ptr_ = nullptr;
+    dex_pc_ptr_ = (dex_pc == dex::kDexNoIndex) ? nullptr : (dex_instructions_ + dex_pc);
   }
 
   ShadowFrame* GetLink() const {
@@ -280,10 +281,6 @@
     return OFFSETOF_MEMBER(ShadowFrame, method_);
   }
 
-  static constexpr size_t DexPCOffset() {
-    return OFFSETOF_MEMBER(ShadowFrame, dex_pc_);
-  }
-
   static constexpr size_t NumberOfVRegsOffset() {
     return OFFSETOF_MEMBER(ShadowFrame, number_of_vregs_);
   }
@@ -300,10 +297,6 @@
     return OFFSETOF_MEMBER(ShadowFrame, dex_pc_ptr_);
   }
 
-  static constexpr size_t DexInstructionsOffset() {
-    return OFFSETOF_MEMBER(ShadowFrame, dex_instructions_);
-  }
-
   static constexpr size_t CachedHotnessCountdownOffset() {
     return OFFSETOF_MEMBER(ShadowFrame, cached_hotness_countdown_);
   }
@@ -389,10 +382,9 @@
       : link_(link),
         method_(method),
         result_register_(nullptr),
-        dex_pc_ptr_(nullptr),
-        dex_instructions_(nullptr),
+        dex_instructions_(method == nullptr ? nullptr : method->DexInstructionData().Insns()),
+        dex_pc_ptr_(dex_instructions_ + dex_pc),
         number_of_vregs_(num_vregs),
-        dex_pc_(dex_pc),
         cached_hotness_countdown_(0),
         hotness_countdown_(0),
         frame_flags_(0) {
@@ -425,12 +417,10 @@
   ShadowFrame* link_;
   ArtMethod* method_;
   JValue* result_register_;
+  const uint16_t* dex_instructions_;  // Dex instruction base of the code item.
   const uint16_t* dex_pc_ptr_;
-  // Dex instruction base of the code item.
-  const uint16_t* dex_instructions_;
   LockCountData lock_count_data_;  // This may contain GC roots when lock counting is active.
   const uint32_t number_of_vregs_;
-  uint32_t dex_pc_;
   int16_t cached_hotness_countdown_;
   int16_t hotness_countdown_;
 
diff --git a/tools/cpp-define-generator/shadow_frame.def b/tools/cpp-define-generator/shadow_frame.def
index 10a309c..5bf3bef 100644
--- a/tools/cpp-define-generator/shadow_frame.def
+++ b/tools/cpp-define-generator/shadow_frame.def
@@ -20,10 +20,6 @@
 
 ASM_DEFINE(SHADOWFRAME_CACHED_HOTNESS_COUNTDOWN_OFFSET,
            art::ShadowFrame::CachedHotnessCountdownOffset())
-ASM_DEFINE(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET,
-           art::ShadowFrame::DexInstructionsOffset())
-ASM_DEFINE(SHADOWFRAME_DEX_PC_OFFSET,
-           art::ShadowFrame::DexPCOffset())
 ASM_DEFINE(SHADOWFRAME_DEX_PC_PTR_OFFSET,
            art::ShadowFrame::DexPCPtrOffset())
 ASM_DEFINE(SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET,