diff options
author | 2024-05-15 17:53:30 +0000 | |
---|---|---|
committer | 2024-05-22 10:39:58 +0000 | |
commit | b42b645e26e206a2b1457cf9ea453b5021a873f5 (patch) | |
tree | e4acdbd3610a5a63e6f3593664d193e12ae2dbe4 /runtime/quick_exception_handler.cc | |
parent | c82d3a69bdf3a95720e8e8b8d2b72cc4db19645c (diff) |
Report method unwind events for native methods
When we are returning from JNI with a pending exception we deoptimize to
correctly handle the exception. We missed reporting an unwind event for
the native method that was returning. Also adds a regression test for
this case.
Bug: 339662394
Test:art/test.py -t 989
Change-Id: I8336dc831e3801b8c0976a5588d1682363d10e64
Diffstat (limited to 'runtime/quick_exception_handler.cc')
-rw-r--r-- | runtime/quick_exception_handler.cc | 33 |
1 files changed, 25 insertions, 8 deletions
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 2ebcbb0fd0..37734f7d74 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -439,19 +439,41 @@ class DeoptimizeStackVisitor final : public StackVisitor { ArtMethod* method = GetMethod(); VLOG(deopt) << "Deoptimizing stack: depth: " << GetFrameDepth() << " at method " << ArtMethod::PrettyMethod(method); + if (method == nullptr || single_frame_done_) { FinishStackWalk(); return false; // End stack walk. - } else if (method->IsRuntimeMethod()) { + } + + // Update if method exit event needs to be reported. We should report exit event only if we + // have reported an entry event. So tell interpreter if/ an entry event was reported. + bool supports_exit_events = Runtime::Current()->GetInstrumentation()->MethodSupportsExitEvents( + method, GetCurrentOatQuickMethodHeader()); + + if (method->IsRuntimeMethod()) { // Ignore callee save method. DCHECK(method->IsCalleeSaveMethod()); return true; } else if (method->IsNative()) { // If we return from JNI with a pending exception and want to deoptimize, we need to skip // the native method. The top method is a runtime method, the native method comes next. - // We also deoptimize due to method instrumentation reasons from method entry / exit - // callbacks. In these cases native method is at the top of stack. + // We also deoptimize due to method instrumentation reasons from method exit callbacks. + // In these cases native method is at the top of stack. CHECK((GetFrameDepth() == 1U) || (GetFrameDepth() == 0U)); + // We see a native frame when: + // 1. returning from JNI with a pending exception + // 2. deopting from method exit callbacks (with or without a pending exception). + // skip_method_exit_callbacks_ is set in this case + // 3. handling async exception on suspend points for fast native methods. + // We only need to call method unwind event in the first case. + if (supports_exit_events && + !skip_method_exit_callbacks_ && + GetThread()->IsExceptionPending()) { + // An exception has occurred in a native method and we are deoptimizing past the native + // method. So report method unwind event here. + Runtime::Current()->GetInstrumentation()->MethodUnwindEvent( + GetThread(), method, dex::kDexNoIndex); + } callee_method_ = method; return true; } else if (!single_frame_deopt_ && @@ -482,11 +504,6 @@ class DeoptimizeStackVisitor final : public StackVisitor { } else { HandleOptimizingDeoptimization(method, new_frame, updated_vregs); } - // Update if method exit event needs to be reported. We should report exit event only if we - // have reported an entry event. So tell interpreter if/ an entry event was reported. - bool supports_exit_events = - Runtime::Current()->GetInstrumentation()->MethodSupportsExitEvents( - method, GetCurrentOatQuickMethodHeader()); new_frame->SetSkipMethodExitEvents(!supports_exit_events); // If we are deoptimizing after method exit callback we shouldn't call the method exit // callbacks again for the top frame. We may have to deopt after the callback if the callback |