Revert "Remove ShadowFrame::dex_pc_ (but keep dex_pc_ptr_)"
This reverts commit 50bc8fb89c79874e731f245abda3b9e48a541cfe.
Reason for revert: Performance regression
Change-Id: Ib39ceb9e1f2753c518dd24fd193a824211fd5795
diff --git a/oatdump/oatdump_app_test.cc b/oatdump/oatdump_app_test.cc
index bbd0e3d..4490647 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(kDynamicLinking, {"--runtime-arg", "-Xmx64M"}));
- ASSERT_TRUE(Exec(kDynamicLinking, kModeOatWithBootImage, {}, kListAndCode));
+ ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M"}));
+ ASSERT_TRUE(Exec(kDynamic, kModeOatWithBootImage, {}, kListAndCode));
}
TEST_F(OatDumpTest, TestAppWithBootImageStatic) {
TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
- ASSERT_TRUE(GenerateAppOdexFile(kStaticLinking, {"--runtime-arg", "-Xmx64M"}));
- ASSERT_TRUE(Exec(kStaticLinking, kModeOatWithBootImage, {}, kListAndCode));
+ ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M"}));
+ ASSERT_TRUE(Exec(kStatic, 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(kDynamicLinking, {"--runtime-arg", "-Xmx64M", app_image_arg}));
- ASSERT_TRUE(Exec(kDynamicLinking, kModeAppImage, {}, kListAndCode));
+ ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M", app_image_arg}));
+ ASSERT_TRUE(Exec(kDynamic, 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(kStaticLinking, {"--runtime-arg", "-Xmx64M", app_image_arg}));
- ASSERT_TRUE(Exec(kStaticLinking, kModeAppImage, {}, kListAndCode));
+ ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M", app_image_arg}));
+ ASSERT_TRUE(Exec(kStatic, kModeAppImage, {}, kListAndCode));
}
} // namespace art
diff --git a/oatdump/oatdump_image_test.cc b/oatdump/oatdump_image_test.cc
index 6f6b83b..0a076f0 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(kDynamicLinking, kModeArt, {}, kListAndCode));
+ ASSERT_TRUE(Exec(kDynamic, 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(kStaticLinking, kModeArt, {}, kListAndCode));
+ ASSERT_TRUE(Exec(kStatic, kModeArt, {}, kListAndCode));
}
TEST_F(OatDumpTest, TestOatImage) {
TEST_DISABLED_FOR_ARM_AND_MIPS();
std::string error_msg;
- ASSERT_TRUE(Exec(kDynamicLinking, kModeCoreOat, {}, kListAndCode));
+ ASSERT_TRUE(Exec(kDynamic, 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(kStaticLinking, kModeCoreOat, {}, kListAndCode));
+ ASSERT_TRUE(Exec(kStatic, kModeCoreOat, {}, kListAndCode));
}
} // namespace art
diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc
index 87f9ac6..506fde7 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(kDynamicLinking, kModeArt, {"--no-dump:vmap"}, kListAndCode));
+ ASSERT_TRUE(Exec(kDynamic, 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(kStaticLinking, kModeArt, {"--no-dump:vmap"}, kListAndCode));
+ ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-dump:vmap"}, kListAndCode));
}
TEST_F(OatDumpTest, TestNoDisassemble) {
TEST_DISABLED_FOR_ARM_AND_MIPS();
std::string error_msg;
- ASSERT_TRUE(Exec(kDynamicLinking, kModeArt, {"--no-disassemble"}, kListAndCode));
+ ASSERT_TRUE(Exec(kDynamic, 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(kStaticLinking, kModeArt, {"--no-disassemble"}, kListAndCode));
+ ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-disassemble"}, kListAndCode));
}
TEST_F(OatDumpTest, TestListClasses) {
TEST_DISABLED_FOR_ARM_AND_MIPS();
std::string error_msg;
- ASSERT_TRUE(Exec(kDynamicLinking, kModeArt, {"--list-classes"}, kListOnly));
+ ASSERT_TRUE(Exec(kDynamic, 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(kStaticLinking, kModeArt, {"--list-classes"}, kListOnly));
+ ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-classes"}, kListOnly));
}
TEST_F(OatDumpTest, TestListMethods) {
TEST_DISABLED_FOR_ARM_AND_MIPS();
std::string error_msg;
- ASSERT_TRUE(Exec(kDynamicLinking, kModeArt, {"--list-methods"}, kListOnly));
+ ASSERT_TRUE(Exec(kDynamic, 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(kStaticLinking, kModeArt, {"--list-methods"}, kListOnly));
+ ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-methods"}, kListOnly));
}
TEST_F(OatDumpTest, TestSymbolize) {
TEST_DISABLED_FOR_ARM_AND_MIPS();
std::string error_msg;
- ASSERT_TRUE(Exec(kDynamicLinking, kModeSymbolize, {}, kListOnly));
+ ASSERT_TRUE(Exec(kDynamic, 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(kStaticLinking, kModeSymbolize, {}, kListOnly));
+ ASSERT_TRUE(Exec(kStatic, 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(kDynamicLinking, {"--runtime-arg", "-Xmx64M"}));
- ASSERT_TRUE(Exec(kDynamicLinking, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
+ ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M"}));
+ ASSERT_TRUE(Exec(kDynamic, 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(kStaticLinking, {"--runtime-arg", "-Xmx64M"}));
- ASSERT_TRUE(Exec(kStaticLinking, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
+ ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M"}));
+ ASSERT_TRUE(Exec(kStatic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
}
} // namespace art
diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h
index 997321f..359b060 100644
--- a/oatdump/oatdump_test.h
+++ b/oatdump/oatdump_test.h
@@ -66,8 +66,8 @@
// Linking flavor.
enum Flavor {
- kDynamicLinking, // oatdump(d), dex2oat(d)
- kStaticLinking, // oatdump(d)s, dex2oat(d)s
+ kDynamic, // oatdump(d), dex2oat(d)
+ kStatic, // 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 == kStaticLinking);
+ return GetExecutableFilePath(name, kIsDebugBuild, flavor == kStatic);
}
enum Mode {
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index d22771d..fc3005d 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -1917,7 +1917,6 @@
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 95bc864..12b3dab 100644
--- a/runtime/interpreter/mterp/arm/main.S
+++ b/runtime/interpreter/mterp/arm/main.S
@@ -109,10 +109,12 @@
*/
#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)
/*
@@ -120,11 +122,25 @@
* 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.
*/
@@ -382,13 +398,18 @@
/* 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 @ 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.
+ 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
CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
+ EXPORT_PC
/* Starting ibase */
ldr rIBASE, [rSELF, #THREAD_CURRENT_IBASE_OFFSET]
@@ -530,8 +551,10 @@
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]
- ldr rPC, [rFP, #OFF_FP_DEX_PC_PTR] @ reload dex pc pointer.
+ add rPC, r0, r1, lsl #1 @ generate new dex_pc_ptr
/* 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 e16b51c..fd745f1 100644
--- a/runtime/interpreter/mterp/arm64/main.S
+++ b/runtime/interpreter/mterp/arm64/main.S
@@ -115,10 +115,12 @@
*/
#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)
/*
@@ -126,6 +128,12 @@
* 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]
@@ -403,13 +411,18 @@
/* 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 // 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.
+ 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
CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
+ EXPORT_PC
/* Starting ibase */
ldr xIBASE, [xSELF, #THREAD_CURRENT_IBASE_OFFSET]
@@ -548,8 +561,10 @@
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]
- ldr xPC, [xFP, #OFF_FP_DEX_PC_PTR] // reload dex pc pointer.
+ add xPC, x0, x1, lsl #1 // generate new dex_pc_ptr
/* 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 57ebfac..80ebf21 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -554,10 +554,14 @@
}
DCHECK(!Runtime::Current()->IsActiveTransaction());
const Instruction* inst = Instruction::At(dex_pc_ptr);
- 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());
+ uint16_t inst_data = inst->Fetch16(0);
+ if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
+ self->AssertPendingException();
+ } else {
+ self->AssertNoPendingException();
+ }
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 d8fe358..af52758 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.
-constexpr bool kTestExportPC = true;
+// Set true to enable poison testing of ExportPC. Uses Alt interpreter.
+constexpr bool kTestExportPC = false;
constexpr size_t kMterpHandlerSize = 128;
diff --git a/runtime/interpreter/mterp/x86/main.S b/runtime/interpreter/mterp/x86/main.S
index 03cbf49..8df75d2 100644
--- a/runtime/interpreter/mterp/x86/main.S
+++ b/runtime/interpreter/mterp/x86/main.S
@@ -131,10 +131,12 @@
*/
#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)
@@ -180,6 +182,12 @@
* 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)
@@ -385,12 +393,18 @@
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_PTR_OFFSET(%edx), rPC
+ movl SHADOWFRAME_DEX_PC_OFFSET(%edx), %eax
+ lea (%ecx, %eax, 2), 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
@@ -556,7 +570,10 @@
call SYMBOL(MterpHandleException)
testb %al, %al
jz MterpExceptionReturn
- movl OFF_FP_DEX_PC_PTR(rFP), rPC
+ 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)
/* 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 11e4d61..5f1fd2d 100644
--- a/runtime/interpreter/mterp/x86_64/main.S
+++ b/runtime/interpreter/mterp/x86_64/main.S
@@ -127,10 +127,12 @@
*/
#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)
@@ -181,6 +183,12 @@
* 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)
@@ -372,12 +380,17 @@
/* 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
- movq SHADOWFRAME_DEX_PC_PTR_OFFSET(IN_ARG2), rPC
+ movl SHADOWFRAME_DEX_PC_OFFSET(IN_ARG2), %eax
+ leaq (IN_ARG1, %rax, 2), rPC
CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
+ EXPORT_PC
/* Starting ibase */
movq IN_ARG0, rSELF
@@ -523,7 +536,10 @@
call SYMBOL(MterpHandleException)
testb %al, %al
jz MterpExceptionReturn
- movq OFF_FP_DEX_PC_PTR(rFP), rPC
+ 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)
/* 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 b0fa4a3..8cb2b33 100644
--- a/runtime/interpreter/shadow_frame.h
+++ b/runtime/interpreter/shadow_frame.h
@@ -21,10 +21,8 @@
#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"
@@ -104,7 +102,7 @@
}
uint32_t GetDexPC() const {
- return (dex_pc_ptr_ == nullptr) ? dex::kDexNoIndex : (dex_pc_ptr_ - dex_instructions_);
+ return (dex_pc_ptr_ == nullptr) ? dex_pc_ : dex_pc_ptr_ - dex_instructions_;
}
int16_t GetCachedHotnessCountdown() const {
@@ -124,7 +122,8 @@
}
void SetDexPC(uint32_t dex_pc) {
- dex_pc_ptr_ = (dex_pc == dex::kDexNoIndex) ? nullptr : (dex_instructions_ + dex_pc);
+ dex_pc_ = dex_pc;
+ dex_pc_ptr_ = nullptr;
}
ShadowFrame* GetLink() const {
@@ -281,6 +280,10 @@
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_);
}
@@ -297,6 +300,10 @@
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_);
}
@@ -382,9 +389,10 @@
: link_(link),
method_(method),
result_register_(nullptr),
- dex_instructions_(method == nullptr ? nullptr : method->DexInstructionData().Insns()),
- dex_pc_ptr_(dex_instructions_ + dex_pc),
+ dex_pc_ptr_(nullptr),
+ dex_instructions_(nullptr),
number_of_vregs_(num_vregs),
+ dex_pc_(dex_pc),
cached_hotness_countdown_(0),
hotness_countdown_(0),
frame_flags_(0) {
@@ -417,10 +425,12 @@
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 5bf3bef..10a309c 100644
--- a/tools/cpp-define-generator/shadow_frame.def
+++ b/tools/cpp-define-generator/shadow_frame.def
@@ -20,6 +20,10 @@
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,