summaryrefslogtreecommitdiffstats
path: root/runtime
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 /runtime
parentbc72903b909f5147b8cb207f3e5d02a8ef85e4e7 (diff)
downloadart-9f1020305292a21fd14a402b189c765a125226ab.tar.gz
art-9f1020305292a21fd14a402b189c765a125226ab.tar.bz2
art-9f1020305292a21fd14a402b189c765a125226ab.zip
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
Diffstat (limited to 'runtime')
-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 73ed59025a..a0cecb0af5 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 09899c05bd..3d8b29fd24 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 261c241943..8f5da83f8f 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 6625801841..d0cb4ded04 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 e1fe563246..c7fb884fa4 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 0c69fe9cb6..d18f9f9bd5 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 19673ac178..cb4868c957 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 a43fad365e..bdf2a20192 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 19ee1ffe8c..66406bfa73 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 3db4be3645..4821e294f3 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 7b31a8270f..a20f7b941e 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 ecd1983140..f4721f2ff4 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 e3f9afc787..103492334c 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 a4229b33fc..1d600ed697 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 7f7b54257a..021c7c1da6 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 5de54b36ad..bff9b5221c 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 {