Revert "Revert "JVMTI Exception and ExceptionCatch events""
Fixed error where we were incorrectly not updating a ShadowFrame
dex_pc causing deoptimization errors.
Bug: 62821960
Bug: 65049545
Test: ./test.py --host -j50
Test: ./art/tools/run-libcore-tests.sh \
--mode=host --variant-X32 --debug
This reverts commit 959742483885779f106e000df6dd422fc8657931.
Change-Id: I91ab2bc3e645ddf0359c189b19a59a3ecf0d8921
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index acef682..c41e15e 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -48,6 +48,7 @@
#include "nativehelper/ScopedLocalRef.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
+#include "stack.h"
#include "thread-inl.h"
#include "thread_list.h"
#include "ti_phase.h"
@@ -552,10 +553,123 @@
}
}
+ static void FindCatchMethodsFromThrow(art::Thread* self,
+ art::Handle<art::mirror::Throwable> exception,
+ /*out*/ art::ArtMethod** out_method,
+ /*out*/ uint32_t* dex_pc)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ // Finds the location where this exception will most likely be caught. We ignore intervening
+ // native frames (which could catch the exception) and return the closest java frame with a
+ // compatible catch statement.
+ class CatchLocationFinder FINAL : public art::StackVisitor {
+ public:
+ CatchLocationFinder(art::Thread* target,
+ art::Handle<art::mirror::Class> exception_class,
+ art::Context* context,
+ /*out*/ art::ArtMethod** out_catch_method,
+ /*out*/ uint32_t* out_catch_pc)
+ REQUIRES_SHARED(art::Locks::mutator_lock_)
+ : StackVisitor(target, context, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+ exception_class_(exception_class),
+ catch_method_ptr_(out_catch_method),
+ catch_dex_pc_ptr_(out_catch_pc) {}
+
+ bool VisitFrame() OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ art::ArtMethod* method = GetMethod();
+ DCHECK(method != nullptr);
+ if (method->IsRuntimeMethod()) {
+ return true;
+ }
+
+ if (!method->IsNative()) {
+ uint32_t cur_dex_pc = GetDexPc();
+ if (cur_dex_pc == art::DexFile::kDexNoIndex) {
+ // This frame looks opaque. Just keep on going.
+ return true;
+ }
+ bool has_no_move_exception = false;
+ uint32_t found_dex_pc = method->FindCatchBlock(
+ exception_class_, cur_dex_pc, &has_no_move_exception);
+ if (found_dex_pc != art::DexFile::kDexNoIndex) {
+ // We found the catch. Store the result and return.
+ *catch_method_ptr_ = method;
+ *catch_dex_pc_ptr_ = found_dex_pc;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ art::Handle<art::mirror::Class> exception_class_;
+ art::ArtMethod** catch_method_ptr_;
+ uint32_t* catch_dex_pc_ptr_;
+
+ DISALLOW_COPY_AND_ASSIGN(CatchLocationFinder);
+ };
+
+ art::StackHandleScope<1> hs(self);
+ *out_method = nullptr;
+ *dex_pc = 0;
+ std::unique_ptr<art::Context> context(art::Context::Create());
+
+ CatchLocationFinder clf(self,
+ hs.NewHandle(exception->GetClass()),
+ context.get(),
+ /*out*/ out_method,
+ /*out*/ dex_pc);
+ clf.WalkStack(/* include_transitions */ false);
+ }
+
// Call-back when an exception is thrown.
- void ExceptionThrown(art::Thread* self ATTRIBUTE_UNUSED,
- art::Handle<art::mirror::Throwable> exception_object ATTRIBUTE_UNUSED)
+ void ExceptionThrown(art::Thread* self, art::Handle<art::mirror::Throwable> exception_object)
REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE {
+ DCHECK(self->IsExceptionThrownByCurrentMethod(exception_object.Get()));
+ // The instrumentation events get rid of this for us.
+ DCHECK(!self->IsExceptionPending());
+ if (event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kException)) {
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ art::ArtMethod* catch_method;
+ uint32_t catch_pc;
+ FindCatchMethodsFromThrow(self, exception_object, &catch_method, &catch_pc);
+ uint32_t dex_pc = 0;
+ art::ArtMethod* method = self->GetCurrentMethod(&dex_pc,
+ /* check_suspended */ true,
+ /* abort_on_error */ art::kIsDebugBuild);
+ ScopedLocalRef<jobject> exception(jnienv,
+ AddLocalRef<jobject>(jnienv, exception_object.Get()));
+ RunEventCallback<ArtJvmtiEvent::kException>(
+ self,
+ jnienv,
+ art::jni::EncodeArtMethod(method),
+ static_cast<jlocation>(dex_pc),
+ exception.get(),
+ art::jni::EncodeArtMethod(catch_method),
+ static_cast<jlocation>(catch_pc));
+ }
+ return;
+ }
+
+ // Call-back when an exception is handled.
+ void ExceptionHandled(art::Thread* self, art::Handle<art::mirror::Throwable> exception_object)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE {
+ // Since the exception has already been handled there shouldn't be one pending.
+ DCHECK(!self->IsExceptionPending());
+ if (event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kExceptionCatch)) {
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ uint32_t dex_pc;
+ art::ArtMethod* method = self->GetCurrentMethod(&dex_pc,
+ /* check_suspended */ true,
+ /* abort_on_error */ art::kIsDebugBuild);
+ ScopedLocalRef<jobject> exception(jnienv,
+ AddLocalRef<jobject>(jnienv, exception_object.Get()));
+ RunEventCallback<ArtJvmtiEvent::kExceptionCatch>(
+ self,
+ jnienv,
+ art::jni::EncodeArtMethod(method),
+ static_cast<jlocation>(dex_pc),
+ exception.get());
+ }
return;
}
@@ -598,6 +712,10 @@
return art::instrumentation::Instrumentation::kDexPcMoved;
case ArtJvmtiEvent::kFramePop:
return art::instrumentation::Instrumentation::kWatchedFramePop;
+ case ArtJvmtiEvent::kException:
+ return art::instrumentation::Instrumentation::kExceptionThrown;
+ case ArtJvmtiEvent::kExceptionCatch:
+ return art::instrumentation::Instrumentation::kExceptionHandled;
default:
LOG(FATAL) << "Unknown event ";
return 0;
@@ -677,6 +795,8 @@
case ArtJvmtiEvent::kMethodExit:
case ArtJvmtiEvent::kFieldAccess:
case ArtJvmtiEvent::kFieldModification:
+ case ArtJvmtiEvent::kException:
+ case ArtJvmtiEvent::kExceptionCatch:
SetupTraceListener(method_trace_listener_.get(), event, enable);
return;