ART: Fix infinite recursion for deopt at dex pc 0.
Previously, the interpreter checked for dex pc 0 to see if
the method was just entered. If we deopt at dex pc 0, the
instrumentation would emit an erroneous MethodEnteredEvent
and the JIT would have received a MethodEntered() call. For
JIT-on-first-use, the method would be compiled the same way
as before, leading to the same deopt until stack overflow.
We fix this by using a new `from_deoptimize` flag passed
by the caller.
Test: 680-checker-deopt-dex-pc-0
Test: testrunner.py --host \
--jit --runtime-option=-Xjitthreshold:0
Bug: 62611253
Change-Id: I50b88f15484aeae16e1375a1d80f6563fb9066e7
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 735c0e8..f23304c 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -243,11 +243,13 @@
const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame,
JValue result_register,
- bool stay_in_interpreter = false) REQUIRES_SHARED(Locks::mutator_lock_) {
+ bool stay_in_interpreter = false,
+ bool from_deoptimize = false) REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(!shadow_frame.GetMethod()->IsAbstract());
DCHECK(!shadow_frame.GetMethod()->IsNative());
- if (LIKELY(shadow_frame.GetDexPC() == 0)) { // Entering the method, but not via deoptimization.
+ if (LIKELY(!from_deoptimize)) { // Entering the method, but not via deoptimization.
if (kIsDebugBuild) {
+ CHECK_EQ(shadow_frame.GetDexPC(), 0u);
self->AssertNoPendingException();
}
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
@@ -568,7 +570,12 @@
}
if (new_dex_pc != dex::kDexNoIndex) {
shadow_frame->SetDexPC(new_dex_pc);
- value = Execute(self, accessor, *shadow_frame, value);
+ value = Execute(self,
+ accessor,
+ *shadow_frame,
+ value,
+ /* stay_in_interpreter */ true,
+ /* from_deoptimize */ true);
}
ShadowFrame* old_frame = shadow_frame;
shadow_frame = shadow_frame->GetLink();