summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Hertz <shertz@google.com>2014-05-23 08:59:42 +0200
committerSebastien Hertz <shertz@google.com>2014-06-11 14:29:00 +0200
commit9f1020305292a21fd14a402b189c765a125226ab (patch)
tree6b730cbe56ded370d1b4293629826ad2c7b06f7f
parentbc72903b909f5147b8cb207f3e5d02a8ef85e4e7 (diff)
downloadart-9f1020305292a21fd14a402b189c765a125226ab.zip
art-9f1020305292a21fd14a402b189c765a125226ab.tar.gz
art-9f1020305292a21fd14a402b189c765a125226ab.tar.bz2
Fix exception reporting from interpreter
To comply with JDWP exception report rules, we must report an exception at the location of the throw (or the first instruction encountered after a native call). To do this, we use the CatchLocationFinder visitor to look for a catch handler until we reach a native frame or the top frame. Because interpreter handles pending exception on a method-by-method basis, we need a flag to remember we already reported the exception and avoid reporting it multiple times when unwinding methods. The drawback is we need to maintain the state of this flag. We clear it when the exception is cleared. In the case we temporarily clear the exception (when finding a catch handler for instance), we restore the flag to its previous value at the same time we restore the pending exception. Bump oat version to force recompilation because we modify Thread offsets. Bug: 14402770 Change-Id: Ic059c58f80b2023b118038301f8f0a24f1e18241
-rw-r--r--runtime/debugger.cc3
-rw-r--r--runtime/entrypoints/entrypoint_utils.h2
-rw-r--r--runtime/instrumentation.cc26
-rw-r--r--runtime/instrumentation.h4
-rw-r--r--runtime/interpreter/interpreter_common.cc92
-rw-r--r--runtime/interpreter/interpreter_common.h3
-rw-r--r--runtime/interpreter/interpreter_goto_table_impl.cc2
-rw-r--r--runtime/interpreter/interpreter_switch_impl.cc2
-rw-r--r--runtime/jni_internal.cc3
-rw-r--r--runtime/mirror/art_method.cc2
-rw-r--r--runtime/mirror/class.cc4
-rw-r--r--runtime/oat.cc2
-rw-r--r--runtime/quick_exception_handler.cc21
-rw-r--r--runtime/quick_exception_handler.h3
-rw-r--r--runtime/thread.cc7
-rw-r--r--runtime/thread.h15
16 files changed, 153 insertions, 38 deletions
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 73ed590..a0cecb0 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -3430,6 +3430,7 @@ void Dbg::ExecuteMethod(DebugInvokeReq* pReq) {
auto old_throw_method = hs.NewHandle<mirror::ArtMethod>(nullptr);
auto old_exception = hs.NewHandle<mirror::Throwable>(nullptr);
uint32_t old_throw_dex_pc;
+ bool old_exception_report_flag;
{
ThrowLocation old_throw_location;
mirror::Throwable* old_exception_obj = soa.Self()->GetException(&old_throw_location);
@@ -3437,6 +3438,7 @@ void Dbg::ExecuteMethod(DebugInvokeReq* pReq) {
old_throw_method.Assign(old_throw_location.GetMethod());
old_exception.Assign(old_exception_obj);
old_throw_dex_pc = old_throw_location.GetDexPc();
+ old_exception_report_flag = soa.Self()->IsExceptionReportedToInstrumentation();
soa.Self()->ClearException();
}
@@ -3491,6 +3493,7 @@ void Dbg::ExecuteMethod(DebugInvokeReq* pReq) {
ThrowLocation gc_safe_throw_location(old_throw_this_object.Get(), old_throw_method.Get(),
old_throw_dex_pc);
soa.Self()->SetException(gc_safe_throw_location, old_exception.Get());
+ soa.Self()->SetExceptionReportedToInstrumentation(old_exception_report_flag);
}
}
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 09899c0..3d8b29f 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -652,6 +652,7 @@ static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
// Save any pending exception over monitor exit call.
mirror::Throwable* saved_exception = NULL;
ThrowLocation saved_throw_location;
+ bool is_exception_reported = self->IsExceptionReportedToInstrumentation();
if (UNLIKELY(self->IsExceptionPending())) {
saved_exception = self->GetException(&saved_throw_location);
self->ClearException();
@@ -667,6 +668,7 @@ static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
// Restore pending exception.
if (saved_exception != NULL) {
self->SetException(saved_throw_location, saved_exception);
+ self->SetExceptionReportedToInstrumentation(is_exception_reported);
}
}
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 261c241..8f5da83 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -780,24 +780,20 @@ void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_o
void Instrumentation::FieldReadEventImpl(Thread* thread, mirror::Object* this_object,
mirror::ArtMethod* method, uint32_t dex_pc,
mirror::ArtField* field) const {
- if (have_field_read_listeners_) {
- // TODO: same comment than DexPcMovedEventImpl.
- std::list<InstrumentationListener*> copy(field_read_listeners_);
- for (InstrumentationListener* listener : copy) {
- listener->FieldRead(thread, this_object, method, dex_pc, field);
- }
+ // TODO: same comment than DexPcMovedEventImpl.
+ std::list<InstrumentationListener*> copy(field_read_listeners_);
+ for (InstrumentationListener* listener : copy) {
+ listener->FieldRead(thread, this_object, method, dex_pc, field);
}
}
void Instrumentation::FieldWriteEventImpl(Thread* thread, mirror::Object* this_object,
mirror::ArtMethod* method, uint32_t dex_pc,
mirror::ArtField* field, const JValue& field_value) const {
- if (have_field_write_listeners_) {
- // TODO: same comment than DexPcMovedEventImpl.
- std::list<InstrumentationListener*> copy(field_write_listeners_);
- for (InstrumentationListener* listener : copy) {
- listener->FieldWritten(thread, this_object, method, dex_pc, field, field_value);
- }
+ // TODO: same comment than DexPcMovedEventImpl.
+ std::list<InstrumentationListener*> copy(field_write_listeners_);
+ for (InstrumentationListener* listener : copy) {
+ listener->FieldWritten(thread, this_object, method, dex_pc, field, field_value);
}
}
@@ -805,8 +801,9 @@ void Instrumentation::ExceptionCaughtEvent(Thread* thread, const ThrowLocation&
mirror::ArtMethod* catch_method,
uint32_t catch_dex_pc,
mirror::Throwable* exception_object) const {
- if (have_exception_caught_listeners_) {
- DCHECK_EQ(thread->GetException(NULL), exception_object);
+ if (HasExceptionCaughtListeners()) {
+ DCHECK_EQ(thread->GetException(nullptr), exception_object);
+ bool is_exception_reported = thread->IsExceptionReportedToInstrumentation();
thread->ClearException();
// TODO: The copy below is due to the debug listener having an action where it can remove
// itself as a listener and break the iterator. The copy only works around the problem.
@@ -815,6 +812,7 @@ void Instrumentation::ExceptionCaughtEvent(Thread* thread, const ThrowLocation&
listener->ExceptionCaught(thread, throw_location, catch_method, catch_dex_pc, exception_object);
}
thread->SetException(throw_location, exception_object);
+ thread->SetExceptionReportedToInstrumentation(is_exception_reported);
}
}
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index 6625801..d0cb4de 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -237,6 +237,10 @@ class Instrumentation {
return have_field_write_listeners_;
}
+ bool HasExceptionCaughtListeners() const {
+ return have_exception_caught_listeners_;
+ }
+
bool IsActive() const {
return have_dex_pc_listeners_ || have_method_entry_listeners_ || have_method_exit_listeners_ ||
have_field_read_listeners_ || have_field_write_listeners_ ||
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index e1fe563..c7fb884 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -372,31 +372,107 @@ EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimNot); // iget-object
#undef EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL
#undef EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL
+/**
+ * Finds the location where this exception will be caught. We search until we reach either the top
+ * frame or a native frame, in which cases this exception is considered uncaught.
+ */
+class CatchLocationFinder : public StackVisitor {
+ public:
+ explicit CatchLocationFinder(Thread* self, Handle<mirror::Throwable>* exception)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : StackVisitor(self, nullptr), self_(self), handle_scope_(self), exception_(exception),
+ catch_method_(handle_scope_.NewHandle<mirror::ArtMethod>(nullptr)),
+ catch_dex_pc_(DexFile::kDexNoIndex), clear_exception_(false) {
+ }
+
+ bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::ArtMethod* method = GetMethod();
+ if (method == nullptr) {
+ return true;
+ }
+ if (method->IsRuntimeMethod()) {
+ // Ignore callee save method.
+ DCHECK(method->IsCalleeSaveMethod());
+ return true;
+ }
+ if (method->IsNative()) {
+ return false; // End stack walk.
+ }
+ DCHECK(!method->IsNative());
+ uint32_t dex_pc = GetDexPc();
+ if (dex_pc != DexFile::kDexNoIndex) {
+ uint32_t found_dex_pc;
+ {
+ StackHandleScope<3> hs(self_);
+ Handle<mirror::Class> exception_class(hs.NewHandle((*exception_)->GetClass()));
+ Handle<mirror::ArtMethod> h_method(hs.NewHandle(method));
+ found_dex_pc = mirror::ArtMethod::FindCatchBlock(h_method, exception_class, dex_pc,
+ &clear_exception_);
+ }
+ if (found_dex_pc != DexFile::kDexNoIndex) {
+ catch_method_.Assign(method);
+ catch_dex_pc_ = found_dex_pc;
+ return false; // End stack walk.
+ }
+ }
+ return true; // Continue stack walk.
+ }
+
+ ArtMethod* GetCatchMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return catch_method_.Get();
+ }
+
+ uint32_t GetCatchDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return catch_dex_pc_;
+ }
+
+ bool NeedClearException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return clear_exception_;
+ }
+
+ private:
+ Thread* const self_;
+ StackHandleScope<1> handle_scope_;
+ Handle<mirror::Throwable>* exception_;
+ Handle<mirror::ArtMethod> catch_method_;
+ uint32_t catch_dex_pc_;
+ bool clear_exception_;
+
+
+ DISALLOW_COPY_AND_ASSIGN(CatchLocationFinder);
+};
+
uint32_t FindNextInstructionFollowingException(Thread* self,
ShadowFrame& shadow_frame,
uint32_t dex_pc,
- mirror::Object* this_object,
const instrumentation::Instrumentation* instrumentation) {
self->VerifyStack();
ThrowLocation throw_location;
- mirror::Throwable* exception = self->GetException(&throw_location);
+ StackHandleScope<3> hs(self);
+ Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException(&throw_location)));
+ if (!self->IsExceptionReportedToInstrumentation() && instrumentation->HasExceptionCaughtListeners()) {
+ CatchLocationFinder clf(self, &exception);
+ clf.WalkStack(false);
+ instrumentation->ExceptionCaughtEvent(self, throw_location, clf.GetCatchMethod(),
+ clf.GetCatchDexPc(), exception.Get());
+ self->SetExceptionReportedToInstrumentation(true);
+ }
bool clear_exception = false;
uint32_t found_dex_pc;
{
- StackHandleScope<3> hs(self);
Handle<mirror::Class> exception_class(hs.NewHandle(exception->GetClass()));
Handle<mirror::ArtMethod> h_method(hs.NewHandle(shadow_frame.GetMethod()));
- HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(&this_object));
found_dex_pc = mirror::ArtMethod::FindCatchBlock(h_method, exception_class, dex_pc,
&clear_exception);
}
if (found_dex_pc == DexFile::kDexNoIndex) {
- instrumentation->MethodUnwindEvent(self, this_object,
+ instrumentation->MethodUnwindEvent(self, shadow_frame.GetThisObject(),
shadow_frame.GetMethod(), dex_pc);
} else {
- instrumentation->ExceptionCaughtEvent(self, throw_location,
- shadow_frame.GetMethod(),
- found_dex_pc, exception);
+ if (self->IsExceptionReportedToInstrumentation()) {
+ instrumentation->MethodUnwindEvent(self, shadow_frame.GetThisObject(),
+ shadow_frame.GetMethod(), dex_pc);
+ }
if (clear_exception) {
self->ClearException();
}
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 0c69fe9..d18f9f9 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -334,8 +334,7 @@ static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame&
}
uint32_t FindNextInstructionFollowingException(Thread* self, ShadowFrame& shadow_frame,
- uint32_t dex_pc, mirror::Object* this_object,
- const instrumentation::Instrumentation* instrumentation)
+ uint32_t dex_pc, const instrumentation::Instrumentation* instrumentation)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 19673ac..cb4868c 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -2391,10 +2391,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
CheckSuspend(self);
UPDATE_HANDLER_TABLE();
}
- Object* this_object = shadow_frame.GetThisObject(code_item->ins_size_);
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
uint32_t found_dex_pc = FindNextInstructionFollowingException(self, shadow_frame, dex_pc,
- this_object,
instrumentation);
if (found_dex_pc == DexFile::kDexNoIndex) {
return JValue(); /* Handled in caller. */
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index a43fad3..bdf2a20 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -25,10 +25,8 @@ namespace interpreter {
if (UNLIKELY(self->TestAllFlags())) { \
CheckSuspend(self); \
} \
- Object* this_object = shadow_frame.GetThisObject(code_item->ins_size_); \
uint32_t found_dex_pc = FindNextInstructionFollowingException(self, shadow_frame, \
inst->GetDexPc(insns), \
- this_object, \
instrumentation); \
if (found_dex_pc == DexFile::kDexNoIndex) { \
return JValue(); /* Handled in caller. */ \
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 19ee1ff..66406bf 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -682,6 +682,7 @@ class JNI {
auto old_throw_method(hs.NewHandle<mirror::ArtMethod>(nullptr));
auto old_exception(hs.NewHandle<mirror::Throwable>(nullptr));
uint32_t old_throw_dex_pc;
+ bool old_is_exception_reported;
{
ThrowLocation old_throw_location;
mirror::Throwable* old_exception_obj = soa.Self()->GetException(&old_throw_location);
@@ -689,6 +690,7 @@ class JNI {
old_throw_method.Assign(old_throw_location.GetMethod());
old_exception.Assign(old_exception_obj);
old_throw_dex_pc = old_throw_location.GetDexPc();
+ old_is_exception_reported = soa.Self()->IsExceptionReportedToInstrumentation();
soa.Self()->ClearException();
}
ScopedLocalRef<jthrowable> exception(env,
@@ -710,6 +712,7 @@ class JNI {
old_throw_dex_pc);
soa.Self()->SetException(gc_safe_throw_location, old_exception.Get());
+ soa.Self()->SetExceptionReportedToInstrumentation(old_is_exception_reported);
}
static jthrowable ExceptionOccurred(JNIEnv* env) {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 3db4be3..4821e29 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -240,6 +240,7 @@ uint32_t ArtMethod::FindCatchBlock(Handle<ArtMethod> h_this, Handle<Class> excep
ThrowLocation throw_location;
StackHandleScope<1> hs(self);
Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException(&throw_location)));
+ bool is_exception_reported = self->IsExceptionReportedToInstrumentation();
self->ClearException();
// Default to handler not found.
uint32_t found_dex_pc = DexFile::kDexNoIndex;
@@ -276,6 +277,7 @@ uint32_t ArtMethod::FindCatchBlock(Handle<ArtMethod> h_this, Handle<Class> excep
// Put the exception back.
if (exception.Get() != nullptr) {
self->SetException(throw_location, exception.Get());
+ self->SetExceptionReportedToInstrumentation(is_exception_reported);
}
return found_dex_pc;
}
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 7b31a82..a20f7b9 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -84,7 +84,7 @@ void Class::SetStatus(Status new_status, Thread* self) {
Handle<mirror::Object> old_throw_this_object(hs.NewHandle(old_throw_location.GetThis()));
Handle<mirror::ArtMethod> old_throw_method(hs.NewHandle(old_throw_location.GetMethod()));
uint32_t old_throw_dex_pc = old_throw_location.GetDexPc();
-
+ bool is_exception_reported = self->IsExceptionReportedToInstrumentation();
// clear exception to call FindSystemClass
self->ClearException();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -102,8 +102,8 @@ void Class::SetStatus(Status new_status, Thread* self) {
// Restore exception.
ThrowLocation gc_safe_throw_location(old_throw_this_object.Get(), old_throw_method.Get(),
old_throw_dex_pc);
-
self->SetException(gc_safe_throw_location, old_exception.Get());
+ self->SetExceptionReportedToInstrumentation(is_exception_reported);
}
COMPILE_ASSERT(sizeof(Status) == sizeof(uint32_t), size_of_status_not_uint32);
if (Runtime::Current()->IsActiveTransaction()) {
diff --git a/runtime/oat.cc b/runtime/oat.cc
index ecd1983..f4721f2 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
namespace art {
const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '3', '4', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '3', '5', '\0' };
OatHeader::OatHeader() {
memset(this, 0, sizeof(*this));
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index e3f9afc..1034923 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -110,7 +110,8 @@ class CatchBlockStackVisitor FINAL : public StackVisitor {
};
void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,
- mirror::Throwable* exception) {
+ mirror::Throwable* exception,
+ bool is_exception_reported) {
DCHECK(!is_deoptimization_);
if (kDebugExceptionDelivery) {
mirror::String* msg = exception->GetDetailMessage();
@@ -141,12 +142,24 @@ void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,
} else {
// Put exception back in root set with clear throw location.
self_->SetException(ThrowLocation(), exception_ref.Get());
+ self_->SetExceptionReportedToInstrumentation(is_exception_reported);
}
// The debugger may suspend this thread and walk its stack. Let's do this before popping
// instrumentation frames.
- instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
- instrumentation->ExceptionCaughtEvent(self_, throw_location, handler_method_, handler_dex_pc_,
- exception_ref.Get());
+ if (!is_exception_reported) {
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+ instrumentation->ExceptionCaughtEvent(self_, throw_location, handler_method_, handler_dex_pc_,
+ exception_ref.Get());
+ // We're not catching this exception but let's remind we already reported the exception above
+ // to avoid reporting it twice.
+ self_->SetExceptionReportedToInstrumentation(true);
+ }
+ bool caught_exception = (handler_method_ != nullptr && handler_dex_pc_ != DexFile::kDexNoIndex);
+ if (caught_exception) {
+ // We're catching this exception so we finish reporting it. We do it here to avoid doing it
+ // in the compiled code.
+ self_->SetExceptionReportedToInstrumentation(false);
+ }
}
// Prepares deoptimization.
diff --git a/runtime/quick_exception_handler.h b/runtime/quick_exception_handler.h
index a4229b3..1d600ed 100644
--- a/runtime/quick_exception_handler.h
+++ b/runtime/quick_exception_handler.h
@@ -42,7 +42,8 @@ class QuickExceptionHandler {
LOG(FATAL) << "UNREACHABLE"; // Expected to take long jump.
}
- void FindCatch(const ThrowLocation& throw_location, mirror::Throwable* exception)
+ void FindCatch(const ThrowLocation& throw_location, mirror::Throwable* exception,
+ bool is_exception_reported)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void DeoptimizeStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void UpdateInstrumentationStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 7f7b542..021c7c1 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1611,6 +1611,7 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
Handle<mirror::ArtMethod> saved_throw_method(hs.NewHandle(throw_location.GetMethod()));
// Ignore the cause throw location. TODO: should we report this as a re-throw?
ScopedLocalRef<jobject> cause(GetJniEnv(), soa.AddLocalReference<jobject>(GetException(nullptr)));
+ bool is_exception_reported = IsExceptionReportedToInstrumentation();
ClearException();
Runtime* runtime = Runtime::Current();
@@ -1641,6 +1642,7 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
ThrowLocation gc_safe_throw_location(saved_throw_this.Get(), saved_throw_method.Get(),
throw_location.GetDexPc());
SetException(gc_safe_throw_location, Runtime::Current()->GetPreAllocatedOutOfMemoryError());
+ SetExceptionReportedToInstrumentation(is_exception_reported);
return;
}
@@ -1693,6 +1695,7 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
ThrowLocation gc_safe_throw_location(saved_throw_this.Get(), saved_throw_method.Get(),
throw_location.GetDexPc());
SetException(gc_safe_throw_location, exception.Get());
+ SetExceptionReportedToInstrumentation(is_exception_reported);
} else {
jvalue jv_args[2];
size_t i = 0;
@@ -1710,6 +1713,7 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
ThrowLocation gc_safe_throw_location(saved_throw_this.Get(), saved_throw_method.Get(),
throw_location.GetDexPc());
SetException(gc_safe_throw_location, exception.Get());
+ SetExceptionReportedToInstrumentation(is_exception_reported);
}
}
}
@@ -1892,13 +1896,14 @@ void Thread::QuickDeliverException() {
CHECK(exception != nullptr);
// Don't leave exception visible while we try to find the handler, which may cause class
// resolution.
+ bool is_exception_reported = IsExceptionReportedToInstrumentation();
ClearException();
bool is_deoptimization = (exception == GetDeoptimizationException());
QuickExceptionHandler exception_handler(this, is_deoptimization);
if (is_deoptimization) {
exception_handler.DeoptimizeStack();
} else {
- exception_handler.FindCatch(throw_location, exception);
+ exception_handler.FindCatch(throw_location, exception, is_exception_reported);
}
exception_handler.UpdateInstrumentationStack();
exception_handler.DoLongJump();
diff --git a/runtime/thread.h b/runtime/thread.h
index 5de54b3..bff9b52 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -329,6 +329,7 @@ class Thread {
void ClearException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
tlsPtr_.exception = nullptr;
tlsPtr_.throw_location.Clear();
+ SetExceptionReportedToInstrumentation(false);
}
// Find catch block and perform long jump to appropriate exception handle
@@ -809,6 +810,14 @@ class Thread {
tlsPtr_.rosalloc_runs[index] = run;
}
+ bool IsExceptionReportedToInstrumentation() const {
+ return tls32_.is_exception_reported_to_instrumentation_;
+ }
+
+ void SetExceptionReportedToInstrumentation(bool reported) {
+ tls32_.is_exception_reported_to_instrumentation_ = reported;
+ }
+
private:
explicit Thread(bool daemon);
~Thread() LOCKS_EXCLUDED(Locks::mutator_lock_,
@@ -911,7 +920,7 @@ class Thread {
explicit tls_32bit_sized_values(bool is_daemon) :
suspend_count(0), debug_suspend_count(0), thin_lock_thread_id(0), tid(0),
daemon(is_daemon), throwing_OutOfMemoryError(false), no_thread_suspension(0),
- thread_exit_check_count(0) {
+ thread_exit_check_count(0), is_exception_reported_to_instrumentation_(false) {
}
union StateAndFlags state_and_flags;
@@ -947,6 +956,10 @@ class Thread {
// How many times has our pthread key's destructor been called?
uint32_t thread_exit_check_count;
+
+ // When true this field indicates that the exception associated with this thread has already
+ // been reported to instrumentation.
+ bool32_t is_exception_reported_to_instrumentation_;
} tls32_;
struct PACKED(8) tls_64bit_sized_values {