summaryrefslogtreecommitdiff
path: root/runtime/instrumentation.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/instrumentation.cc')
-rw-r--r--runtime/instrumentation.cc37
1 files changed, 33 insertions, 4 deletions
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 13c2b57821..104c46532b 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -457,6 +457,30 @@ void Instrumentation::UpdateEntrypointsForDebuggable() {
runtime->GetClassLinker()->VisitClasses(&visitor);
}
+bool Instrumentation::MethodSupportsExitEvents(ArtMethod* method,
+ const OatQuickMethodHeader* header) {
+ if (header == nullptr) {
+ // Header can be a nullptr for runtime / proxy methods that doesn't support method exit hooks
+ // or for native methods that use generic jni stubs. Generic jni stubs support method exit
+ // hooks.
+ return method->IsNative();
+ }
+
+ if (header->IsNterpMethodHeader()) {
+ // Nterp doesn't support method exit events
+ return false;
+ }
+
+ DCHECK(header->IsOptimized());
+ if (CodeInfo::IsDebuggable(header->GetOptimizedCodeInfoPtr())) {
+ // For optimized code, we only support method entry / exit hooks if they are compiled as
+ // debuggable.
+ return true;
+ }
+
+ return false;
+}
+
// Places the instrumentation exit pc as the return PC for every quick frame. This also allows
// deoptimization of quick frames to interpreter frames. When force_deopt is
// true the frames have to be deoptimized. If the frame has a deoptimization
@@ -508,9 +532,15 @@ void InstrumentationInstallStack(Thread* thread, void* arg, bool deopt_all_frame
LOG(INFO) << " Processing quick frame for updating exit hooks " << DescribeLocation();
}
- // Record the method so we can call method entry callbacks for all non-runtime methods on
- // the stack. Runtime methods don't need method entry callbacks.
- stack_methods_.push_back(m);
+ const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+ if (Runtime::Current()->GetInstrumentation()->MethodSupportsExitEvents(m, method_header)) {
+ // It is unexpected to see a method enter event but not a method exit event so record stack
+ // methods only for frames that support method exit events. Even if we deoptimize we make
+ // sure that we only call method exit event if the frame supported it in the first place.
+ // For ex: deoptimizing from JITed code with debug support calls a method exit hook but
+ // deoptimizing from nterp doesn't.
+ stack_methods_.push_back(m);
+ }
// If it is a JITed frame then just set the deopt bit if required otherwise continue.
// We need kForceDeoptForRedefinition to ensure we don't use any JITed code after a
@@ -519,7 +549,6 @@ void InstrumentationInstallStack(Thread* thread, void* arg, bool deopt_all_frame
// The CheckCallerForDeopt is an optimization which we only do for non-native JITed code for
// now. We can extend it to native methods but that needs reserving an additional stack slot.
// We don't do it currently since that wasn't important for debugger performance.
- const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
if (method_header != nullptr && method_header->HasShouldDeoptimizeFlag()) {
if (deopt_all_frames_) {
runtime_methods_need_deopt_check_ = true;