summaryrefslogtreecommitdiff
path: root/runtime/quick_exception_handler.cc
diff options
context:
space:
mode:
author Mythri Alle <mythria@google.com> 2024-05-15 17:53:30 +0000
committer Mythri Alle <mythria@google.com> 2024-05-22 10:39:58 +0000
commitb42b645e26e206a2b1457cf9ea453b5021a873f5 (patch)
treee4acdbd3610a5a63e6f3593664d193e12ae2dbe4 /runtime/quick_exception_handler.cc
parentc82d3a69bdf3a95720e8e8b8d2b72cc4db19645c (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.cc33
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