summaryrefslogtreecommitdiff
path: root/runtime/interpreter/interpreter.cc
diff options
context:
space:
mode:
author Alex Light <allight@google.com> 2018-10-10 15:58:14 +0000
committer Alex Light <allight@google.com> 2018-10-11 16:41:54 -0700
commit0aa7a5a6a7bc350b79351f52e26c97747e927acf (patch)
treea583889668d9703d16d37586d56421bd27c62661 /runtime/interpreter/interpreter.cc
parente12575640dca5118bf96245f373acda276c22178 (diff)
Revert^4 "JVMTI PopFrame support"
This reverts commit 202b617acf477e8e8e11915f467120a0bd518e74. This unreverts commit 202b617acf. This unreverts commit 88a2a9d7a1. There were several bugs with the implementation of pop-frame related to interactions between the jit, exception handling, class-loading, and deoptimization. - We were instrumenting the target thread stack in cases where it was unnecessary which caused the exception handler to incorrectly determine that a method was not deoptimizable. This caused the pop-frame to be ignored. - We were incorrectly sending ExceptionCatch events if an exception suppressed by pop-frame would have been caught in the current frame. - We were allowing pop-frame to be used on threads suspended in the ClassLoad or ClassPrepare events despite having surprising semantics in that situation (see b/117615146). Needed to modify test 1953 slightly for inclusion in CTS. I needed to make the CTS entrypoint not run the class-load tests (since the cts configuration means the classes are loaded by the verifier and not the interpreter). I updated the expected.txt and check script to reflect this. Reason for revert: Fixed issue causing Exception events to sometimes eat PopFrame and other issues. Test: ./test.py --host Test: ./art/tools/run-libjdwp-tests.sh --mode=host Bug: 73255278 Bug: 111357976 Bug: 117533193 Bug: 117615146 Change-Id: I655c4fe769938cf41d7589f931d6710cf2001506
Diffstat (limited to 'runtime/interpreter/interpreter.cc')
-rw-r--r--runtime/interpreter/interpreter.cc43
1 files changed, 34 insertions, 9 deletions
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index df66061d01..2ae95dcc41 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -261,6 +261,12 @@ static inline JValue Execute(
shadow_frame.GetThisObject(accessor.InsSize()),
method,
0);
+ if (UNLIKELY(shadow_frame.GetForcePopFrame())) {
+ // The caller will retry this invoke. Just return immediately without any value.
+ DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
+ DCHECK(PrevFrameWillRetry(self, shadow_frame));
+ return JValue();
+ }
if (UNLIKELY(self->IsExceptionPending())) {
instrumentation->MethodUnwindEvent(self,
shadow_frame.GetThisObject(accessor.InsSize()),
@@ -494,8 +500,8 @@ void EnterInterpreterFromDeoptimize(Thread* self,
JValue value;
// Set value to last known result in case the shadow frame chain is empty.
value.SetJ(ret_val->GetJ());
- // Are we executing the first shadow frame?
- bool first = true;
+ // How many frames we have executed.
+ size_t frame_cnt = 0;
while (shadow_frame != nullptr) {
// We do not want to recover lock state for lock counting when deoptimizing. Currently,
// the compiler should not have compiled a method that failed structured-locking checks.
@@ -510,24 +516,30 @@ void EnterInterpreterFromDeoptimize(Thread* self,
// the instrumentation. To prevent from reporting it a second time, we simply pass a
// null Instrumentation*.
const instrumentation::Instrumentation* const instrumentation =
- first ? nullptr : Runtime::Current()->GetInstrumentation();
+ frame_cnt == 0 ? nullptr : Runtime::Current()->GetInstrumentation();
new_dex_pc = MoveToExceptionHandler(
self, *shadow_frame, instrumentation) ? shadow_frame->GetDexPC() : dex::kDexNoIndex;
} else if (!from_code) {
// Deoptimization is not called from code directly.
const Instruction* instr = &accessor.InstructionAt(dex_pc);
- if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc) {
- DCHECK(first);
+ if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc ||
+ shadow_frame->GetForceRetryInstruction()) {
+ DCHECK(frame_cnt == 0 || (frame_cnt == 1 && shadow_frame->GetForceRetryInstruction()))
+ << "frame_cnt: " << frame_cnt
+ << " force-retry: " << shadow_frame->GetForceRetryInstruction();
// Need to re-execute the dex instruction.
// (1) An invocation might be split into class initialization and invoke.
// In this case, the invoke should not be skipped.
// (2) A suspend check should also execute the dex instruction at the
// corresponding dex pc.
+ // If the ForceRetryInstruction bit is set this must be the second frame (the first being
+ // the one that is being popped).
DCHECK_EQ(new_dex_pc, dex_pc);
+ shadow_frame->SetForceRetryInstruction(false);
} else if (instr->Opcode() == Instruction::MONITOR_ENTER ||
instr->Opcode() == Instruction::MONITOR_EXIT) {
DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault);
- DCHECK(first);
+ DCHECK_EQ(frame_cnt, 0u);
// Non-idempotent dex instruction should not be re-executed.
// On the other hand, if a MONITOR_ENTER is at the dex_pc of a suspend
// check, that MONITOR_ENTER should be executed. That case is handled
@@ -553,7 +565,7 @@ void EnterInterpreterFromDeoptimize(Thread* self,
DCHECK_EQ(new_dex_pc, dex_pc);
} else {
DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault);
- DCHECK(first);
+ DCHECK_EQ(frame_cnt, 0u);
// By default, we re-execute the dex instruction since if they are not
// an invoke, so that we don't have to decode the dex instruction to move
// result into the right vreg. All slow paths have been audited to be
@@ -566,7 +578,7 @@ void EnterInterpreterFromDeoptimize(Thread* self,
} else {
// Nothing to do, the dex_pc is the one at which the code requested
// the deoptimization.
- DCHECK(first);
+ DCHECK_EQ(frame_cnt, 0u);
DCHECK_EQ(new_dex_pc, dex_pc);
}
if (new_dex_pc != dex::kDexNoIndex) {
@@ -585,7 +597,7 @@ void EnterInterpreterFromDeoptimize(Thread* self,
// and should advance dex pc past the invoke instruction.
from_code = false;
deopt_method_type = DeoptimizationMethodType::kDefault;
- first = false;
+ frame_cnt++;
}
ret_val->SetJ(value.GetJ());
}
@@ -657,5 +669,18 @@ void InitInterpreterTls(Thread* self) {
InitMterpTls(self);
}
+bool PrevFrameWillRetry(Thread* self, const ShadowFrame& frame) {
+ ShadowFrame* prev_frame = frame.GetLink();
+ if (prev_frame == nullptr) {
+ NthCallerVisitor vis(self, 1, false);
+ vis.WalkStack();
+ prev_frame = vis.GetCurrentShadowFrame();
+ if (prev_frame == nullptr) {
+ prev_frame = self->FindDebuggerShadowFrame(vis.GetFrameId());
+ }
+ }
+ return prev_frame != nullptr && prev_frame->GetForceRetryInstruction();
+}
+
} // namespace interpreter
} // namespace art