diff options
| author | 2018-10-10 15:58:14 +0000 | |
|---|---|---|
| committer | 2018-10-11 16:41:54 -0700 | |
| commit | 0aa7a5a6a7bc350b79351f52e26c97747e927acf (patch) | |
| tree | a583889668d9703d16d37586d56421bd27c62661 /runtime/interpreter/interpreter.cc | |
| parent | e12575640dca5118bf96245f373acda276c22178 (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.cc | 43 |
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 |