summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author David Srbecky <dsrbecky@google.com> 2019-07-04 10:00:12 +0000
committer Treehugger Robot <treehugger-gerrit@google.com> 2019-07-05 00:20:19 +0000
commite81f10a3f672a8bcc421cab812e6435749181566 (patch)
tree076df5318e4bfdb6148fd6bb0faf5ea8de1d3336
parent9690542a9ed7740110459d3167708e6edc1a2686 (diff)
Revert "Remove ShadowFrame::dex_pc_ (but keep dex_pc_ptr_)"
This reverts commit 50bc8fb89c79874e731f245abda3b9e48a541cfe. Reason for revert: Performance regression Change-Id: Ib39ceb9e1f2753c518dd24fd193a824211fd5795
-rw-r--r--oatdump/oatdump_app_test.cc16
-rw-r--r--oatdump/oatdump_image_test.cc8
-rw-r--r--oatdump/oatdump_test.cc28
-rw-r--r--oatdump/oatdump_test.h6
-rw-r--r--runtime/interpreter/interpreter_switch_impl-inl.h1
-rw-r--r--runtime/interpreter/mterp/arm/main.S31
-rw-r--r--runtime/interpreter/mterp/arm64/main.S23
-rw-r--r--runtime/interpreter/mterp/mterp.cc10
-rw-r--r--runtime/interpreter/mterp/mterp.h4
-rw-r--r--runtime/interpreter/mterp/x86/main.S21
-rw-r--r--runtime/interpreter/mterp/x86_64/main.S20
-rw-r--r--runtime/interpreter/shadow_frame.h24
-rw-r--r--tools/cpp-define-generator/shadow_frame.def4
13 files changed, 142 insertions, 54 deletions
diff --git a/oatdump/oatdump_app_test.cc b/oatdump/oatdump_app_test.cc
index bbd0e3d34c..4490647d2c 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 6f6b83bc53..0a076f065e 100644
--- a/oatdump/oatdump_image_test.cc
+++ b/oatdump/oatdump_image_test.cc
@@ -28,25 +28,25 @@ namespace art {
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 87f9ac69ca..506fde776b 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -30,61 +30,61 @@ namespace art {
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_F(OatDumpTest, TestExportDex) {
// 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_F(OatDumpTest, TestExportDexStatic) {
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 997321f1b3..359b060f1f 100644
--- a/oatdump/oatdump_test.h
+++ b/oatdump/oatdump_test.h
@@ -66,8 +66,8 @@ class OatDumpTest : public CommonRuntimeTest {
// 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 @@ class OatDumpTest : public CommonRuntimeTest {
}
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 d22771dea8..fc3005d72c 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -1917,7 +1917,6 @@ ATTRIBUTE_NO_SANITIZE_ADDRESS void ExecuteSwitchImplCpp(SwitchImplContext* ctx)
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 95bc864ad9..12b3dab003 100644
--- a/runtime/interpreter/mterp/arm/main.S
+++ b/runtime/interpreter/mterp/arm/main.S
@@ -109,10 +109,12 @@ unspecified registers or condition codes.
*/
#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 @@ unspecified registers or condition codes.
* 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 @@ ENTRY ExecuteMterpImpl
/* 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 @@ MterpException:
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 e16b51cb08..fd745f1bd1 100644
--- a/runtime/interpreter/mterp/arm64/main.S
+++ b/runtime/interpreter/mterp/arm64/main.S
@@ -115,10 +115,12 @@ codes.
*/
#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 @@ codes.
* 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 @@ ENTRY ExecuteMterpImpl
/* 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 @@ MterpException:
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 57ebface31..80ebf21b40 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -554,10 +554,14 @@ extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame, uint16
}
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 d8fe358885..af52758bbc 100644
--- a/runtime/interpreter/mterp/mterp.h
+++ b/runtime/interpreter/mterp/mterp.h
@@ -40,8 +40,8 @@ bool CanUseMterp();
// 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 03cbf49a06..8df75d2f66 100644
--- a/runtime/interpreter/mterp/x86/main.S
+++ b/runtime/interpreter/mterp/x86/main.S
@@ -131,10 +131,12 @@ unspecified registers or condition codes.
*/
#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 @@ unspecified registers or condition codes.
* 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 @@ ENTRY ExecuteMterpImpl
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 @@ MterpException:
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 11e4d616d6..5f1fd2dfbe 100644
--- a/runtime/interpreter/mterp/x86_64/main.S
+++ b/runtime/interpreter/mterp/x86_64/main.S
@@ -127,10 +127,12 @@ unspecified registers or condition codes.
*/
#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 @@ unspecified registers or condition codes.
* 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 @@ ENTRY ExecuteMterpImpl
/* 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 @@ MterpException:
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 b0fa4a3be1..8cb2b33a07 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 @@ class ShadowFrame {
}
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 @@ class ShadowFrame {
}
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 @@ class ShadowFrame {
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 @@ class ShadowFrame {
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 @@ class ShadowFrame {
: 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 @@ class ShadowFrame {
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 5bf3befea0..10a309cbdb 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,