diff options
| -rw-r--r-- | runtime/debugger.cc | 3 | ||||
| -rw-r--r-- | runtime/entrypoints/entrypoint_utils.h | 2 | ||||
| -rw-r--r-- | runtime/instrumentation.cc | 26 | ||||
| -rw-r--r-- | runtime/instrumentation.h | 4 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_common.cc | 92 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_common.h | 3 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_goto_table_impl.cc | 2 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_switch_impl.cc | 2 | ||||
| -rw-r--r-- | runtime/jni_internal.cc | 3 | ||||
| -rw-r--r-- | runtime/mirror/art_method.cc | 2 | ||||
| -rw-r--r-- | runtime/mirror/class.cc | 4 | ||||
| -rw-r--r-- | runtime/oat.cc | 2 | ||||
| -rw-r--r-- | runtime/quick_exception_handler.cc | 21 | ||||
| -rw-r--r-- | runtime/quick_exception_handler.h | 3 | ||||
| -rw-r--r-- | runtime/thread.cc | 7 | ||||
| -rw-r--r-- | runtime/thread.h | 15 |
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 { |