diff options
author | 2017-09-05 09:32:49 -0700 | |
---|---|---|
committer | 2017-09-05 10:54:05 -0700 | |
commit | 9fb1ab1f6bb58bdaccef78bc81b3202d0121e2ed (patch) | |
tree | f4ec9bb10a2191f4aa80b1ee40332071bed38bab | |
parent | c101222c854a0c476f5b6ae64e20adbd38126a3c (diff) |
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
44 files changed, 3665 insertions, 42 deletions
diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h index d74e25b807..93eee28c0a 100644 --- a/openjdkjvmti/art_jvmti.h +++ b/openjdkjvmti/art_jvmti.h @@ -236,7 +236,7 @@ const jvmtiCapabilities kPotentialCapabilities = { .can_access_local_variables = 1, .can_maintain_original_method_order = 1, .can_generate_single_step_events = 1, - .can_generate_exception_events = 0, + .can_generate_exception_events = 1, .can_generate_frame_pop_events = 1, .can_generate_breakpoint_events = 1, .can_suspend = 1, diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc index acef682a13..c41e15eaa8 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 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat } } + 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 @@ static uint32_t GetInstrumentationEventsFor(ArtJvmtiEvent event) { 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 @@ void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) { case ArtJvmtiEvent::kMethodExit: case ArtJvmtiEvent::kFieldAccess: case ArtJvmtiEvent::kFieldModification: + case ArtJvmtiEvent::kException: + case ArtJvmtiEvent::kExceptionCatch: SetupTraceListener(method_trace_listener_.get(), event, enable); return; diff --git a/runtime/debugger.cc b/runtime/debugger.cc index fe0bad2111..af56810fcb 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -262,6 +262,13 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati << " " << dex_pc; } + // TODO Might be worth it to post ExceptionCatch event. + void ExceptionHandled(Thread* thread ATTRIBUTE_UNUSED, + Handle<mirror::Throwable> throwable ATTRIBUTE_UNUSED) OVERRIDE { + LOG(ERROR) << "Unexpected exception handled event in debugger"; + } + + private: static bool IsReturn(ArtMethod* method, uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) { diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 05384b417c..6e457a47bf 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -108,6 +108,7 @@ Instrumentation::Instrumentation() have_watched_frame_pop_listeners_(false), have_branch_listeners_(false), have_invoke_virtual_or_interface_listeners_(false), + have_exception_handled_listeners_(false), deoptimized_methods_lock_("deoptimized methods lock", kDeoptimizedMethodsLock), deoptimization_enabled_(false), interpreter_handler_table_(kMainHandlerTable), @@ -510,6 +511,11 @@ void Instrumentation::AddListener(InstrumentationListener* listener, uint32_t ev watched_frame_pop_listeners_, listener, &have_watched_frame_pop_listeners_); + PotentiallyAddListenerTo(kExceptionHandled, + events, + exception_handled_listeners_, + listener, + &have_exception_handled_listeners_); UpdateInterpreterHandlerTable(); } @@ -592,6 +598,11 @@ void Instrumentation::RemoveListener(InstrumentationListener* listener, uint32_t watched_frame_pop_listeners_, listener, &have_watched_frame_pop_listeners_); + PotentiallyRemoveListenerFrom(kExceptionHandled, + events, + exception_handled_listeners_, + listener, + &have_exception_handled_listeners_); UpdateInterpreterHandlerTable(); } @@ -1114,10 +1125,28 @@ void Instrumentation::ExceptionThrownEvent(Thread* thread, listener->ExceptionThrown(thread, h_exception); } } + // See b/65049545 for discussion about this behavior. + thread->AssertNoPendingException(); thread->SetException(h_exception.Get()); } } +void Instrumentation::ExceptionHandledEvent(Thread* thread, + mirror::Throwable* exception_object) const { + Thread* self = Thread::Current(); + StackHandleScope<1> hs(self); + Handle<mirror::Throwable> h_exception(hs.NewHandle(exception_object)); + if (HasExceptionHandledListeners()) { + // We should have cleared the exception so that callers can detect a new one. + DCHECK(thread->GetException() == nullptr); + for (InstrumentationListener* listener : exception_handled_listeners_) { + if (listener != nullptr) { + listener->ExceptionHandled(thread, h_exception); + } + } + } +} + // Computes a frame ID by ignoring inlined frames. size_t Instrumentation::ComputeFrameId(Thread* self, size_t frame_depth, diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h index 114db7682d..fec027e39f 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -130,6 +130,10 @@ struct InstrumentationListener { Handle<mirror::Throwable> exception_object) REQUIRES_SHARED(Locks::mutator_lock_) = 0; + // Call-back when an exception is caught/handled by java code. + virtual void ExceptionHandled(Thread* thread, Handle<mirror::Throwable> exception_object) + REQUIRES_SHARED(Locks::mutator_lock_) = 0; + // Call-back for when we execute a branch. virtual void Branch(Thread* thread, ArtMethod* method, @@ -172,6 +176,7 @@ class Instrumentation { kBranch = 0x80, kInvokeVirtualOrInterface = 0x100, kWatchedFramePop = 0x200, + kExceptionHandled = 0x400, }; enum class InstrumentationLevel { @@ -349,12 +354,16 @@ class Instrumentation { return have_watched_frame_pop_listeners_; } + bool HasExceptionHandledListeners() const REQUIRES_SHARED(Locks::mutator_lock_) { + return have_exception_handled_listeners_; + } + bool IsActive() const REQUIRES_SHARED(Locks::mutator_lock_) { return have_dex_pc_listeners_ || have_method_entry_listeners_ || have_method_exit_listeners_ || have_field_read_listeners_ || have_field_write_listeners_ || have_exception_thrown_listeners_ || have_method_unwind_listeners_ || have_branch_listeners_ || have_invoke_virtual_or_interface_listeners_ || - have_watched_frame_pop_listeners_; + have_watched_frame_pop_listeners_ || have_exception_handled_listeners_; } // Any instrumentation *other* than what is needed for Jit profiling active? @@ -362,7 +371,8 @@ class Instrumentation { return have_dex_pc_listeners_ || have_method_exit_listeners_ || have_field_read_listeners_ || have_field_write_listeners_ || have_exception_thrown_listeners_ || have_method_unwind_listeners_ || - have_branch_listeners_ || have_watched_frame_pop_listeners_; + have_branch_listeners_ || have_watched_frame_pop_listeners_ || + have_exception_handled_listeners_; } // Inform listeners that a method has been entered. A dex PC is provided as we may install @@ -452,6 +462,11 @@ class Instrumentation { void ExceptionThrownEvent(Thread* thread, mirror::Throwable* exception_object) const REQUIRES_SHARED(Locks::mutator_lock_); + // Inform listeners that an exception has been handled. This is not sent for native code or for + // exceptions which reach the end of the thread's stack. + void ExceptionHandledEvent(Thread* thread, mirror::Throwable* exception_object) const + REQUIRES_SHARED(Locks::mutator_lock_); + // Called when an instrumented method is entered. The intended link register (lr) is saved so // that returning causes a branch to the method exit stub. Generates method enter events. void PushInstrumentationStackFrame(Thread* self, mirror::Object* this_object, @@ -637,6 +652,10 @@ class Instrumentation { // Do we have any invoke listeners? Short-cut to avoid taking the instrumentation_lock_. bool have_invoke_virtual_or_interface_listeners_ GUARDED_BY(Locks::mutator_lock_); + // Do we have any exception handled listeners? Short-cut to avoid taking the + // instrumentation_lock_. + bool have_exception_handled_listeners_ GUARDED_BY(Locks::mutator_lock_); + // Contains the instrumentation level required by each client of the instrumentation identified // by a string key. typedef SafeMap<const char*, InstrumentationLevel> InstrumentationLevelTable; @@ -663,6 +682,7 @@ class Instrumentation { std::list<InstrumentationListener*> field_write_listeners_ GUARDED_BY(Locks::mutator_lock_); std::list<InstrumentationListener*> exception_thrown_listeners_ GUARDED_BY(Locks::mutator_lock_); std::list<InstrumentationListener*> watched_frame_pop_listeners_ GUARDED_BY(Locks::mutator_lock_); + std::list<InstrumentationListener*> exception_handled_listeners_ GUARDED_BY(Locks::mutator_lock_); // The set of methods being deoptimized (by the debugger) which must be executed with interpreter // only. diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc index 7390f4fc97..9b77d1219a 100644 --- a/runtime/instrumentation_test.cc +++ b/runtime/instrumentation_test.cc @@ -48,6 +48,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio received_field_written_event(false), received_field_written_object_event(false), received_exception_thrown_event(false), + received_exception_handled_event(false), received_branch_event(false), received_invoke_virtual_or_interface_event(false), received_watched_frame_pop(false) {} @@ -131,6 +132,12 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio received_exception_thrown_event = true; } + void ExceptionHandled(Thread* self ATTRIBUTE_UNUSED, + Handle<mirror::Throwable> throwable ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { + received_exception_handled_event = true; + } + void Branch(Thread* thread ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, @@ -163,6 +170,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio received_field_written_event = false; received_field_written_object_event = false; received_exception_thrown_event = false; + received_exception_handled_event = false; received_branch_event = false; received_invoke_virtual_or_interface_event = false; received_watched_frame_pop = false; @@ -177,6 +185,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio bool received_field_written_event; bool received_field_written_object_event; bool received_exception_thrown_event; + bool received_exception_handled_event; bool received_branch_event; bool received_invoke_virtual_or_interface_event; bool received_watched_frame_pop; @@ -369,6 +378,8 @@ class InstrumentationTest : public CommonRuntimeTest { return instr->HasFieldWriteListeners(); case instrumentation::Instrumentation::kExceptionThrown: return instr->HasExceptionThrownListeners(); + case instrumentation::Instrumentation::kExceptionHandled: + return instr->HasExceptionHandledListeners(); case instrumentation::Instrumentation::kBranch: return instr->HasBranchListeners(); case instrumentation::Instrumentation::kInvokeVirtualOrInterface: @@ -429,6 +440,13 @@ class InstrumentationTest : public CommonRuntimeTest { case instrumentation::Instrumentation::kWatchedFramePop: instr->WatchedFramePopped(self, frame); break; + case instrumentation::Instrumentation::kExceptionHandled: { + ThrowArithmeticExceptionDivideByZero(); + mirror::Throwable* event_exception = self->GetException(); + self->ClearException(); + instr->ExceptionHandledEvent(self, event_exception); + break; + } default: LOG(FATAL) << "Unknown instrumentation event " << event_type; UNREACHABLE(); @@ -455,6 +473,8 @@ class InstrumentationTest : public CommonRuntimeTest { (with_object && listener.received_field_written_object_event); case instrumentation::Instrumentation::kExceptionThrown: return listener.received_exception_thrown_event; + case instrumentation::Instrumentation::kExceptionHandled: + return listener.received_exception_handled_event; case instrumentation::Instrumentation::kBranch: return listener.received_branch_event; case instrumentation::Instrumentation::kInvokeVirtualOrInterface: @@ -484,6 +504,7 @@ TEST_F(InstrumentationTest, NoInstrumentation) { // Check there is no registered listener. EXPECT_FALSE(instr->HasDexPcListeners()); EXPECT_FALSE(instr->HasExceptionThrownListeners()); + EXPECT_FALSE(instr->HasExceptionHandledListeners()); EXPECT_FALSE(instr->HasFieldReadListeners()); EXPECT_FALSE(instr->HasFieldWriteListeners()); EXPECT_FALSE(instr->HasMethodEntryListeners()); @@ -587,6 +608,10 @@ TEST_F(InstrumentationTest, FieldWritePrimEvent) { /*with_object*/ false); } +TEST_F(InstrumentationTest, ExceptionHandledEvent) { + TestEvent(instrumentation::Instrumentation::kExceptionHandled); +} + TEST_F(InstrumentationTest, ExceptionThrownEvent) { TestEvent(instrumentation::Instrumentation::kExceptionThrown); } diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 9cb74f7c36..33498335ca 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -522,10 +522,8 @@ void EnterInterpreterFromDeoptimize(Thread* self, // null Instrumentation*. const instrumentation::Instrumentation* const instrumentation = first ? nullptr : Runtime::Current()->GetInstrumentation(); - uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame, dex_pc, - instrumentation); - new_dex_pc = found_dex_pc; // the dex pc of a matching catch handler - // or DexFile::kDexNoIndex if there is none. + new_dex_pc = MoveToExceptionHandler( + self, *shadow_frame, instrumentation) ? shadow_frame->GetDexPC() : DexFile::kDexNoIndex; } else if (!from_code) { // For the debugger and full deoptimization stack, we must go past the invoke // instruction, as it already executed. diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index ae461fd987..0028b21f94 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -416,35 +416,57 @@ EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimNot) // iput-objec #undef EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL #undef EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL +// We execute any instrumentation events that are triggered by this exception and change the +// shadow_frame's dex_pc to that of the exception handler if there is one in the current method. +// Return true if we should continue executing in the current method and false if we need to go up +// the stack to find an exception handler. // We accept a null Instrumentation* meaning we must not report anything to the instrumentation. -uint32_t FindNextInstructionFollowingException( - Thread* self, ShadowFrame& shadow_frame, uint32_t dex_pc, - const instrumentation::Instrumentation* instrumentation) { +// TODO We should have a better way to skip instrumentation reporting or possibly rethink that +// behavior. +bool MoveToExceptionHandler(Thread* self, + ShadowFrame& shadow_frame, + const instrumentation::Instrumentation* instrumentation) { self->VerifyStack(); StackHandleScope<2> hs(self); Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException())); - if (instrumentation != nullptr && instrumentation->HasExceptionThrownListeners() - && self->IsExceptionThrownByCurrentMethod(exception.Get())) { + if (instrumentation != nullptr && + instrumentation->HasExceptionThrownListeners() && + self->IsExceptionThrownByCurrentMethod(exception.Get())) { + // See b/65049545 for why we don't need to check to see if the exception has changed. instrumentation->ExceptionThrownEvent(self, exception.Get()); } bool clear_exception = false; uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock( - hs.NewHandle(exception->GetClass()), dex_pc, &clear_exception); - if (found_dex_pc == DexFile::kDexNoIndex && instrumentation != nullptr) { - if (shadow_frame.NeedsNotifyPop()) { - instrumentation->WatchedFramePopped(self, shadow_frame); + hs.NewHandle(exception->GetClass()), shadow_frame.GetDexPC(), &clear_exception); + if (found_dex_pc == DexFile::kDexNoIndex) { + if (instrumentation != nullptr) { + if (shadow_frame.NeedsNotifyPop()) { + instrumentation->WatchedFramePopped(self, shadow_frame); + } + // Exception is not caught by the current method. We will unwind to the + // caller. Notify any instrumentation listener. + instrumentation->MethodUnwindEvent(self, + shadow_frame.GetThisObject(), + shadow_frame.GetMethod(), + shadow_frame.GetDexPC()); } - // Exception is not caught by the current method. We will unwind to the - // caller. Notify any instrumentation listener. - instrumentation->MethodUnwindEvent(self, shadow_frame.GetThisObject(), - shadow_frame.GetMethod(), dex_pc); + return false; } else { - // Exception is caught in the current method. We will jump to the found_dex_pc. - if (clear_exception) { + shadow_frame.SetDexPC(found_dex_pc); + if (instrumentation != nullptr && instrumentation->HasExceptionHandledListeners()) { + self->ClearException(); + instrumentation->ExceptionHandledEvent(self, exception.Get()); + if (UNLIKELY(self->IsExceptionPending())) { + // Exception handled event threw an exception. Try to find the handler for this one. + return MoveToExceptionHandler(self, shadow_frame, instrumentation); + } else if (!clear_exception) { + self->SetException(exception.Get()); + } + } else if (clear_exception) { self->ClearException(); } + return true; } - return found_dex_pc; } void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame) { diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 5b942f2e73..82e12f5c6a 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -462,9 +462,17 @@ static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& return 3; } -uint32_t FindNextInstructionFollowingException(Thread* self, ShadowFrame& shadow_frame, - uint32_t dex_pc, const instrumentation::Instrumentation* instrumentation) - REQUIRES_SHARED(Locks::mutator_lock_); +// We execute any instrumentation events triggered by throwing and/or handing the pending exception +// and change the shadow_frames dex_pc to the appropriate exception handler if the current method +// has one. If the exception has been handled and the shadow_frame is now pointing to a catch clause +// we return true. If the current method is unable to handle the exception we return false. +// This function accepts a null Instrumentation* as a way to cause instrumentation events not to be +// reported. +// TODO We might wish to reconsider how we cause some events to be ignored. +bool MoveToExceptionHandler(Thread* self, + ShadowFrame& shadow_frame, + const instrumentation::Instrumentation* instrumentation) + REQUIRES_SHARED(Locks::mutator_lock_); NO_RETURN void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame) __attribute__((cold)) diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index f352960204..69e091b42d 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -30,10 +30,7 @@ namespace interpreter { do { \ DCHECK(self->IsExceptionPending()); \ self->AllowThreadSuspension(); \ - uint32_t found_dex_pc = FindNextInstructionFollowingException(self, shadow_frame, \ - inst->GetDexPc(insns), \ - instr); \ - if (found_dex_pc == DexFile::kDexNoIndex) { \ + if (!MoveToExceptionHandler(self, shadow_frame, instr)) { \ /* Structured locking is to be enforced for abnormal termination, too. */ \ DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame); \ if (interpret_one_instruction) { \ @@ -42,7 +39,8 @@ namespace interpreter { } \ return JValue(); /* Handled in caller. */ \ } else { \ - int32_t displacement = static_cast<int32_t>(found_dex_pc) - static_cast<int32_t>(dex_pc); \ + int32_t displacement = \ + static_cast<int32_t>(shadow_frame.GetDexPC()) - static_cast<int32_t>(dex_pc); \ inst = inst->RelativeAt(displacement); \ } \ } while (false) diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc index 88254a8cdc..b8a7a2ad3f 100644 --- a/runtime/interpreter/mterp/mterp.cc +++ b/runtime/interpreter/mterp/mterp.cc @@ -490,15 +490,7 @@ extern "C" size_t MterpHandleException(Thread* self, ShadowFrame* shadow_frame) DCHECK(self->IsExceptionPending()); const instrumentation::Instrumentation* const instrumentation = Runtime::Current()->GetInstrumentation(); - uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame, - shadow_frame->GetDexPC(), - instrumentation); - if (found_dex_pc == DexFile::kDexNoIndex) { - return false; - } - // OK - we can deal with it. Update and continue. - shadow_frame->SetDexPC(found_dex_pc); - return true; + return MoveToExceptionHandler(self, *shadow_frame, instrumentation); } extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr) diff --git a/runtime/trace.cc b/runtime/trace.cc index d7673f3563..b30de795a4 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -811,6 +811,12 @@ void Trace::ExceptionThrown(Thread* thread ATTRIBUTE_UNUSED, LOG(ERROR) << "Unexpected exception thrown event in tracing"; } +void Trace::ExceptionHandled(Thread* thread ATTRIBUTE_UNUSED, + Handle<mirror::Throwable> exception_object ATTRIBUTE_UNUSED) + REQUIRES_SHARED(Locks::mutator_lock_) { + LOG(ERROR) << "Unexpected exception thrown event in tracing"; +} + void Trace::Branch(Thread* /*thread*/, ArtMethod* method, uint32_t /*dex_pc*/, int32_t /*dex_pc_offset*/) REQUIRES_SHARED(Locks::mutator_lock_) { diff --git a/runtime/trace.h b/runtime/trace.h index 8b0931df80..49d5b22373 100644 --- a/runtime/trace.h +++ b/runtime/trace.h @@ -181,6 +181,8 @@ class Trace FINAL : public instrumentation::InstrumentationListener { void ExceptionThrown(Thread* thread, Handle<mirror::Throwable> exception_object) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_) OVERRIDE; + void ExceptionHandled(Thread* thread, Handle<mirror::Throwable> exception_object) + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_) OVERRIDE; void Branch(Thread* thread, ArtMethod* method, uint32_t dex_pc, diff --git a/test/1927-exception-event/exception_event.cc b/test/1927-exception-event/exception_event.cc new file mode 100644 index 0000000000..3197bcd1ae --- /dev/null +++ b/test/1927-exception-event/exception_event.cc @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <pthread.h> + +#include <cstdio> +#include <iostream> +#include <vector> + +#include "android-base/logging.h" +#include "jni.h" +#include "jvmti.h" + +#include "scoped_local_ref.h" +#include "scoped_primitive_array.h" + +// Test infrastructure +#include "jvmti_helper.h" +#include "test_env.h" + +namespace art { +namespace Test1927ExceptionEvent { + +static void ThrowNative(JNIEnv* env) { + ScopedLocalRef<jclass> exception(env, env->FindClass("art/Test1927$TestException")); + env->ThrowNew(exception.get(), "from native"); +} + +static void CallMethod(JNIEnv* env, jclass test, const char* name) { + jmethodID m = env->GetStaticMethodID(test, name, "()V"); + env->CallStaticVoidMethod(test, m); +} + +static void ClearAndPrintException(JNIEnv* env, jclass test) { + jthrowable e = env->ExceptionOccurred(); + env->ExceptionClear(); + jmethodID m = env->GetStaticMethodID(test, "printException", "(Ljava/lang/Throwable;)V"); + env->CallStaticVoidMethod(test, m, e); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1927_terminal_1N(JNIEnv* env, jclass) { + ThrowNative(env); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1927_test_1N(JNIEnv* env, jclass test) { + ThrowNative(env); + ClearAndPrintException(env, test); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1927_test_1N_1J(JNIEnv* env, jclass test) { + CallMethod(env, test, "terminal_J"); + ClearAndPrintException(env, test); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1927_test_1N_1N(JNIEnv* env, jclass test) { + CallMethod(env, test, "terminal_N"); + ClearAndPrintException(env, test); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1927_intermediate_1N_1J(JNIEnv* env, jclass test) { + CallMethod(env, test, "terminal_J"); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1927_intermediate_1N_1N(JNIEnv* env, jclass test) { + CallMethod(env, test, "terminal_N"); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1927_test_1N_1J_1J(JNIEnv* env, jclass test) { + CallMethod(env, test, "intermediate_J_J"); + ClearAndPrintException(env, test); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1927_test_1N_1J_1N(JNIEnv* env, jclass test) { + CallMethod(env, test, "intermediate_J_N"); + ClearAndPrintException(env, test); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1927_test_1N_1N_1J(JNIEnv* env, jclass test) { + CallMethod(env, test, "intermediate_N_J"); + ClearAndPrintException(env, test); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1927_test_1N_1N_1N(JNIEnv* env, jclass test) { + CallMethod(env, test, "intermediate_N_N"); + ClearAndPrintException(env, test); +} + +} // namespace Test1927ExceptionEvent +} // namespace art diff --git a/test/1927-exception-event/expected.txt b/test/1927-exception-event/expected.txt new file mode 100644 index 0000000000..be8f39c29a --- /dev/null +++ b/test/1927-exception-event/expected.txt @@ -0,0 +1,278 @@ +class art.Test1927$TestException +Running test_J +main: public static void art.Test1927.test_J() @ line = 110 throws class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static void art.Test1927.test_J() @ line = 110 + public static void art.Test1927.run() throws java.lang.Exception @ line = 239 + Will be caught by: public static void art.Test1927.test_J() @ line = 111 +main: public static void art.Test1927.test_J() @ line = 111 caught class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 + public static void art.Test1927.test_J() @ line = 111 + public static void art.Test1927.run() throws java.lang.Exception @ line = 239 +Caught exception: art.Test1927$TestException: from java +Running test_N() +Caught exception: art.Test1927$TestException: from native +Running test_J_J() +main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static void art.Test1927.terminal_J() @ line = 103 + public static void art.Test1927.test_J_J() @ line = 121 + public static void art.Test1927.run() throws java.lang.Exception @ line = 243 + Will be caught by: public static void art.Test1927.test_J_J() @ line = 122 +main: public static void art.Test1927.test_J_J() @ line = 122 caught class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 + public static void art.Test1927.test_J_J() @ line = 122 + public static void art.Test1927.run() throws java.lang.Exception @ line = 243 +Caught exception: art.Test1927$TestException: from java +Running test_J_N() +main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static native void art.Test1927.terminal_N() @ line = -1 + public static void art.Test1927.test_J_N() @ line = 129 + public static void art.Test1927.run() throws java.lang.Exception @ line = 245 + Will be caught by: public static void art.Test1927.test_J_N() @ line = 130 +main: public static void art.Test1927.test_J_N() @ line = 130 caught class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 + public static void art.Test1927.test_J_N() @ line = 130 + public static void art.Test1927.run() throws java.lang.Exception @ line = 245 +Caught exception: art.Test1927$TestException: from native +Running test_N_J() +main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static void art.Test1927.terminal_J() @ line = 103 + public static native void art.Test1927.test_N_J() @ line = -1 + public static void art.Test1927.run() throws java.lang.Exception @ line = 247 + Will be caught by: <UNKNOWN> +Caught exception: art.Test1927$TestException: from java +Running test_N_N() +main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static native void art.Test1927.terminal_N() @ line = -1 + public static native void art.Test1927.test_N_N() @ line = -1 + public static void art.Test1927.run() throws java.lang.Exception @ line = 249 + Will be caught by: <UNKNOWN> +Caught exception: art.Test1927$TestException: from native +Running test_J_J_J() +main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static void art.Test1927.terminal_J() @ line = 103 + public static void art.Test1927.intermediate_J_J() @ line = 138 + public static void art.Test1927.test_J_J_J() @ line = 145 + public static void art.Test1927.run() throws java.lang.Exception @ line = 251 + Will be caught by: public static void art.Test1927.test_J_J_J() @ line = 146 +main: public static void art.Test1927.test_J_J_J() @ line = 146 caught class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 + public static void art.Test1927.test_J_J_J() @ line = 146 + public static void art.Test1927.run() throws java.lang.Exception @ line = 251 +Caught exception: art.Test1927$TestException: from java +Running test_J_J_N() +main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static native void art.Test1927.terminal_N() @ line = -1 + public static void art.Test1927.intermediate_J_N() @ line = 139 + public static void art.Test1927.test_J_J_N() @ line = 153 + public static void art.Test1927.run() throws java.lang.Exception @ line = 253 + Will be caught by: public static void art.Test1927.test_J_J_N() @ line = 154 +main: public static void art.Test1927.test_J_J_N() @ line = 154 caught class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 + public static void art.Test1927.test_J_J_N() @ line = 154 + public static void art.Test1927.run() throws java.lang.Exception @ line = 253 +Caught exception: art.Test1927$TestException: from native +Running test_J_N_J() +main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static void art.Test1927.terminal_J() @ line = 103 + public static native void art.Test1927.intermediate_N_J() @ line = -1 + public static void art.Test1927.test_J_N_J() @ line = 161 + public static void art.Test1927.run() throws java.lang.Exception @ line = 255 + Will be caught by: public static void art.Test1927.test_J_N_J() @ line = 162 +main: public static void art.Test1927.test_J_N_J() @ line = 162 caught class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 + public static void art.Test1927.test_J_N_J() @ line = 162 + public static void art.Test1927.run() throws java.lang.Exception @ line = 255 +Caught exception: art.Test1927$TestException: from java +Running test_J_N_N() +main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static native void art.Test1927.terminal_N() @ line = -1 + public static native void art.Test1927.intermediate_N_N() @ line = -1 + public static void art.Test1927.test_J_N_N() @ line = 169 + public static void art.Test1927.run() throws java.lang.Exception @ line = 257 + Will be caught by: public static void art.Test1927.test_J_N_N() @ line = 170 +main: public static void art.Test1927.test_J_N_N() @ line = 170 caught class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 + public static void art.Test1927.test_J_N_N() @ line = 170 + public static void art.Test1927.run() throws java.lang.Exception @ line = 257 +Caught exception: art.Test1927$TestException: from native +Running test_N_J_J() +main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static void art.Test1927.terminal_J() @ line = 103 + public static void art.Test1927.intermediate_J_J() @ line = 138 + public static native void art.Test1927.test_N_J_J() @ line = -1 + public static void art.Test1927.run() throws java.lang.Exception @ line = 259 + Will be caught by: <UNKNOWN> +Caught exception: art.Test1927$TestException: from java +Running test_N_J_N() +main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static native void art.Test1927.terminal_N() @ line = -1 + public static void art.Test1927.intermediate_J_N() @ line = 139 + public static native void art.Test1927.test_N_J_N() @ line = -1 + public static void art.Test1927.run() throws java.lang.Exception @ line = 261 + Will be caught by: <UNKNOWN> +Caught exception: art.Test1927$TestException: from native +Running test_N_N_J() +main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static void art.Test1927.terminal_J() @ line = 103 + public static native void art.Test1927.intermediate_N_J() @ line = -1 + public static native void art.Test1927.test_N_N_J() @ line = -1 + public static void art.Test1927.run() throws java.lang.Exception @ line = 263 + Will be caught by: <UNKNOWN> +Caught exception: art.Test1927$TestException: from java +Running test_N_N_N() +main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static native void art.Test1927.terminal_N() @ line = -1 + public static native void art.Test1927.intermediate_N_N() @ line = -1 + public static native void art.Test1927.test_N_N_N() @ line = -1 + public static void art.Test1927.run() throws java.lang.Exception @ line = 265 + Will be caught by: <UNKNOWN> +Caught exception: art.Test1927$TestException: from native +Running test_extra_N_J_J() +main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static void art.Test1927.terminal_J() @ line = 103 + public static void art.Test1927.intermediate_J_J() @ line = 138 + public static native void art.Test1927.test_N_J_J() @ line = -1 + public static void art.Test1927.test_extra_N_J_J() @ line = 182 + public static void art.Test1927.run() throws java.lang.Exception @ line = 267 + Will be caught by: public static void art.Test1927.test_extra_N_J_J() @ line = 183 +Caught exception: art.Test1927$TestException: from java +Running test_extra_N_J_N() +main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static native void art.Test1927.terminal_N() @ line = -1 + public static void art.Test1927.intermediate_J_N() @ line = 139 + public static native void art.Test1927.test_N_J_N() @ line = -1 + public static void art.Test1927.test_extra_N_J_N() @ line = 189 + public static void art.Test1927.run() throws java.lang.Exception @ line = 269 + Will be caught by: public static void art.Test1927.test_extra_N_J_N() @ line = 190 +Caught exception: art.Test1927$TestException: from native +Running test_extra_N_N_J() +main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static void art.Test1927.terminal_J() @ line = 103 + public static native void art.Test1927.intermediate_N_J() @ line = -1 + public static native void art.Test1927.test_N_N_J() @ line = -1 + public static void art.Test1927.test_extra_N_N_J() @ line = 196 + public static void art.Test1927.run() throws java.lang.Exception @ line = 271 + Will be caught by: public static void art.Test1927.test_extra_N_N_J() @ line = 197 +Caught exception: art.Test1927$TestException: from java +Running test_extra_N_N_N() +main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1927.PrintStack() @ line = 28 + public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 + public static native void art.Test1927.terminal_N() @ line = -1 + public static native void art.Test1927.intermediate_N_N() @ line = -1 + public static native void art.Test1927.test_N_N_N() @ line = -1 + public static void art.Test1927.test_extra_N_N_N() @ line = 203 + public static void art.Test1927.run() throws java.lang.Exception @ line = 273 + Will be caught by: public static void art.Test1927.test_extra_N_N_N() @ line = 204 +Caught exception: art.Test1927$TestException: from native diff --git a/test/1927-exception-event/info.txt b/test/1927-exception-event/info.txt new file mode 100644 index 0000000000..a74167fe15 --- /dev/null +++ b/test/1927-exception-event/info.txt @@ -0,0 +1,3 @@ +Test basic JVMTI exception event functionality + +Ensures that we can receive exception and exception catch events from JVMTI. diff --git a/test/1927-exception-event/run b/test/1927-exception-event/run new file mode 100755 index 0000000000..51875a7e86 --- /dev/null +++ b/test/1927-exception-event/run @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Ask for stack traces to be dumped to a file rather than to stdout. +./default-run "$@" --jvmti diff --git a/test/1927-exception-event/src/Main.java b/test/1927-exception-event/src/Main.java new file mode 100644 index 0000000000..5b9b31b847 --- /dev/null +++ b/test/1927-exception-event/src/Main.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + public static void main(String[] args) throws Exception { + art.Test1927.run(); + } +} diff --git a/test/1927-exception-event/src/art/Breakpoint.java b/test/1927-exception-event/src/art/Breakpoint.java new file mode 100644 index 0000000000..bbb89f707f --- /dev/null +++ b/test/1927-exception-event/src/art/Breakpoint.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.lang.reflect.Executable; +import java.util.HashSet; +import java.util.Set; +import java.util.Objects; + +public class Breakpoint { + public static class Manager { + public static class BP { + public final Executable method; + public final long location; + + public BP(Executable method) { + this(method, getStartLocation(method)); + } + + public BP(Executable method, long location) { + this.method = method; + this.location = location; + } + + @Override + public boolean equals(Object other) { + return (other instanceof BP) && + method.equals(((BP)other).method) && + location == ((BP)other).location; + } + + @Override + public String toString() { + return method.toString() + " @ " + getLine(); + } + + @Override + public int hashCode() { + return Objects.hash(method, location); + } + + public int getLine() { + try { + LineNumber[] lines = getLineNumberTable(method); + int best = -1; + for (LineNumber l : lines) { + if (l.location > location) { + break; + } else { + best = l.line; + } + } + return best; + } catch (Exception e) { + return -1; + } + } + } + + private Set<BP> breaks = new HashSet<>(); + + public void setBreakpoints(BP... bs) { + for (BP b : bs) { + if (breaks.add(b)) { + Breakpoint.setBreakpoint(b.method, b.location); + } + } + } + public void setBreakpoint(Executable method, long location) { + setBreakpoints(new BP(method, location)); + } + + public void clearBreakpoints(BP... bs) { + for (BP b : bs) { + if (breaks.remove(b)) { + Breakpoint.clearBreakpoint(b.method, b.location); + } + } + } + public void clearBreakpoint(Executable method, long location) { + clearBreakpoints(new BP(method, location)); + } + + public void clearAllBreakpoints() { + clearBreakpoints(breaks.toArray(new BP[0])); + } + } + + public static void startBreakpointWatch(Class<?> methodClass, + Executable breakpointReached, + Thread thr) { + startBreakpointWatch(methodClass, breakpointReached, false, thr); + } + + /** + * Enables the trapping of breakpoint events. + * + * If allowRecursive == true then breakpoints will be sent even if one is currently being handled. + */ + public static native void startBreakpointWatch(Class<?> methodClass, + Executable breakpointReached, + boolean allowRecursive, + Thread thr); + public static native void stopBreakpointWatch(Thread thr); + + public static final class LineNumber implements Comparable<LineNumber> { + public final long location; + public final int line; + + private LineNumber(long loc, int line) { + this.location = loc; + this.line = line; + } + + public boolean equals(Object other) { + return other instanceof LineNumber && ((LineNumber)other).line == line && + ((LineNumber)other).location == location; + } + + public int compareTo(LineNumber other) { + int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line)); + if (v != 0) { + return v; + } else { + return Long.valueOf(location).compareTo(Long.valueOf(other.location)); + } + } + } + + public static native void setBreakpoint(Executable m, long loc); + public static void setBreakpoint(Executable m, LineNumber l) { + setBreakpoint(m, l.location); + } + + public static native void clearBreakpoint(Executable m, long loc); + public static void clearBreakpoint(Executable m, LineNumber l) { + clearBreakpoint(m, l.location); + } + + private static native Object[] getLineNumberTableNative(Executable m); + public static LineNumber[] getLineNumberTable(Executable m) { + Object[] nativeTable = getLineNumberTableNative(m); + long[] location = (long[])(nativeTable[0]); + int[] lines = (int[])(nativeTable[1]); + if (lines.length != location.length) { + throw new Error("Lines and locations have different lengths!"); + } + LineNumber[] out = new LineNumber[lines.length]; + for (int i = 0; i < lines.length; i++) { + out[i] = new LineNumber(location[i], lines[i]); + } + return out; + } + + public static native long getStartLocation(Executable m); + + public static int locationToLine(Executable m, long location) { + try { + Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m); + int best = -1; + for (Breakpoint.LineNumber l : lines) { + if (l.location > location) { + break; + } else { + best = l.line; + } + } + return best; + } catch (Exception e) { + return -1; + } + } + + public static long lineToLocation(Executable m, int line) throws Exception { + try { + Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m); + for (Breakpoint.LineNumber l : lines) { + if (l.line == line) { + return l.location; + } + } + throw new Exception("Unable to find line " + line + " in " + m); + } catch (Exception e) { + throw new Exception("Unable to get line number info for " + m, e); + } + } +} + diff --git a/test/1927-exception-event/src/art/Exceptions.java b/test/1927-exception-event/src/art/Exceptions.java new file mode 100644 index 0000000000..2c959ec83f --- /dev/null +++ b/test/1927-exception-event/src/art/Exceptions.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class Exceptions { + public static native void setupExceptionTracing( + Class<?> methodClass, + Class<?> exceptionClass, + Method exceptionEventMethod, + Method exceptionCaughtEventMethod); + + public static native void enableExceptionCatchEvent(Thread thr); + public static native void enableExceptionEvent(Thread thr); + public static native void disableExceptionCatchEvent(Thread thr); + public static native void disableExceptionEvent(Thread thr); +} diff --git a/test/1927-exception-event/src/art/StackTrace.java b/test/1927-exception-event/src/art/StackTrace.java new file mode 100644 index 0000000000..b12c3df66b --- /dev/null +++ b/test/1927-exception-event/src/art/StackTrace.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.lang.reflect.Field; +import java.lang.reflect.Executable; + +public class StackTrace { + public static class StackFrameData { + public final Thread thr; + public final Executable method; + public final long current_location; + public final int depth; + + public StackFrameData(Thread thr, Executable e, long loc, int depth) { + this.thr = thr; + this.method = e; + this.current_location = loc; + this.depth = depth; + } + @Override + public String toString() { + return String.format( + "StackFrameData { thr: '%s', method: '%s', loc: %d, depth: %d }", + this.thr, + this.method, + this.current_location, + this.depth); + } + } + + public static native int GetStackDepth(Thread thr); + + private static native StackFrameData[] nativeGetStackTrace(Thread thr); + + public static StackFrameData[] GetStackTrace(Thread thr) { + // The RI seems to give inconsistent (and sometimes nonsensical) results if the thread is not + // suspended. The spec says that not being suspended is fine but since we want this to be + // consistent we will suspend for the RI. + boolean suspend_thread = + !System.getProperty("java.vm.name").equals("Dalvik") && + !thr.equals(Thread.currentThread()); + if (suspend_thread) { + Suspension.suspend(thr); + } + StackFrameData[] out = nativeGetStackTrace(thr); + if (suspend_thread) { + Suspension.resume(thr); + } + return out; + } +} + diff --git a/test/1927-exception-event/src/art/Suspension.java b/test/1927-exception-event/src/art/Suspension.java new file mode 100644 index 0000000000..16e62ccac9 --- /dev/null +++ b/test/1927-exception-event/src/art/Suspension.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +public class Suspension { + // Suspends a thread using jvmti. + public native static void suspend(Thread thr); + + // Resumes a thread using jvmti. + public native static void resume(Thread thr); + + public native static boolean isSuspended(Thread thr); + + public native static int[] suspendList(Thread... threads); + public native static int[] resumeList(Thread... threads); +} diff --git a/test/1927-exception-event/src/art/Test1927.java b/test/1927-exception-event/src/art/Test1927.java new file mode 100644 index 0000000000..c2d13bb4ee --- /dev/null +++ b/test/1927-exception-event/src/art/Test1927.java @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.util.Arrays; +import java.util.Objects; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; + +public class Test1927 { + private static boolean PRINT_FULL_EXCEPTION = false; + private static void PrintStack() { + System.out.println("\tCurrent Stack:"); + for (StackTrace.StackFrameData e : StackTrace.GetStackTrace(Thread.currentThread())) { + if (Objects.equals(e.method.getDeclaringClass().getPackage(), Test1927.class.getPackage())) { + System.out.println("\t\t" + e.method + " @ line = " + + Breakpoint.locationToLine(e.method, e.current_location)); + } + } + } + + public static void ExceptionCatchEvent(Thread thr, + Executable catch_method, + long catch_location, + Throwable exception) { + System.out.println(thr.getName() + ": " + catch_method + " @ line = " + + Breakpoint.locationToLine(catch_method, catch_location) + " caught " + + exception.getClass() + ": " + exception.getMessage()); + PrintStack(); + if (PRINT_FULL_EXCEPTION) { + System.out.print("exception is: "); + exception.printStackTrace(System.out); + } + } + + public static void ExceptionEvent(Thread thr, + Executable throw_method, + long throw_location, + Throwable exception, + Executable catch_method, + long catch_location) { + System.out.println(thr.getName() + ": " + throw_method + " @ line = " + + Breakpoint.locationToLine(throw_method, throw_location) + " throws " + + exception.getClass() + ": " + exception.getMessage()); + String catch_message; + if (catch_method == null) { + catch_message = "<UNKNOWN>"; + } else { + catch_message = catch_method.toString() + " @ line = " + + Breakpoint.locationToLine(catch_method, catch_location); + } + PrintStack(); + System.out.println("\tWill be caught by: " + catch_message); + if (PRINT_FULL_EXCEPTION) { + System.out.print("exception is: "); + exception.printStackTrace(System.out); + } + } + + public static class TestException extends Error { + public TestException(String s) { super(s); } + public TestException() { super("from java"); } + } + + // Possibilities + // ( -> is a JNI/Java call.) + // Furthest left catches/clears the exception + // Furthest right throws it. + // J + // N + // J -> J + // J -> N + // N -> J + // N -> N + // J -> J -> J + // J -> J -> N + // J -> N -> J + // J -> N -> N + // N -> J -> J + // N -> J -> N + // N -> N -> J + // N -> N -> N + // extra -> N -> J -> J + // extra -> N -> J -> N + // extra -> N -> N -> J + // extra -> N -> N -> N + + public static void terminal_J() { + throw new TestException(); + } + + public static native void terminal_N(); + + public static void test_J() { + try { + throw new TestException(); + } catch (TestException e) { + printException(e); + } + } + + // Do test_J but native + public static native void test_N(); + + public static void test_J_J() { + try { + terminal_J(); + } catch (TestException e) { + printException(e); + } + } + + public static void test_J_N() { + try { + terminal_N(); + } catch (TestException e) { + printException(e); + } + } + + public static native void test_N_J(); + public static native void test_N_N(); + + public static void intermediate_J_J() { terminal_J(); } + public static void intermediate_J_N() { terminal_N(); } + public static native void intermediate_N_J(); + public static native void intermediate_N_N(); + + public static void test_J_J_J() { + try { + intermediate_J_J(); + } catch (TestException e) { + printException(e); + } + } + + public static void test_J_J_N() { + try { + intermediate_J_N(); + } catch (TestException e) { + printException(e); + } + } + + public static void test_J_N_J() { + try { + intermediate_N_J(); + } catch (TestException e) { + printException(e); + } + } + + public static void test_J_N_N() { + try { + intermediate_N_N(); + } catch (TestException e) { + printException(e); + } + } + + public static native void test_N_J_J(); + public static native void test_N_J_N(); + public static native void test_N_N_J(); + public static native void test_N_N_N(); + + public static void test_extra_N_J_J() { + try { + test_N_J_J(); + } catch (TestException e) { + printException(e); + } + } + public static void test_extra_N_J_N() { + try { + test_N_J_N(); + } catch (TestException e) { + printException(e); + } + } + public static void test_extra_N_N_J() { + try { + test_N_N_J(); + } catch (TestException e) { + printException(e); + } + } + public static void test_extra_N_N_N() { + try { + test_N_N_N(); + } catch (TestException e) { + printException(e); + } + } + + public static void printException(Throwable e) { + System.out.println("Caught exception: " + e); + if (PRINT_FULL_EXCEPTION) { + e.printStackTrace(System.out); + } + } + + public static void run() throws Exception { + // Make sure classes are loaded first. + System.out.println(TestException.class.toString()); + Exceptions.setupExceptionTracing( + Test1927.class, + TestException.class, + Test1927.class.getDeclaredMethod( + "ExceptionEvent", + Thread.class, + Executable.class, + Long.TYPE, + Throwable.class, + Executable.class, + Long.TYPE), + Test1927.class.getDeclaredMethod( + "ExceptionCatchEvent", + Thread.class, + Executable.class, + Long.TYPE, + Throwable.class)); + Exceptions.enableExceptionEvent(Thread.currentThread()); + Exceptions.enableExceptionCatchEvent(Thread.currentThread()); + System.out.println("Running test_J"); + test_J(); + System.out.println("Running test_N()"); + test_N(); + System.out.println("Running test_J_J()"); + test_J_J(); + System.out.println("Running test_J_N()"); + test_J_N(); + System.out.println("Running test_N_J()"); + test_N_J(); + System.out.println("Running test_N_N()"); + test_N_N(); + System.out.println("Running test_J_J_J()"); + test_J_J_J(); + System.out.println("Running test_J_J_N()"); + test_J_J_N(); + System.out.println("Running test_J_N_J()"); + test_J_N_J(); + System.out.println("Running test_J_N_N()"); + test_J_N_N(); + System.out.println("Running test_N_J_J()"); + test_N_J_J(); + System.out.println("Running test_N_J_N()"); + test_N_J_N(); + System.out.println("Running test_N_N_J()"); + test_N_N_J(); + System.out.println("Running test_N_N_N()"); + test_N_N_N(); + System.out.println("Running test_extra_N_J_J()"); + test_extra_N_J_J(); + System.out.println("Running test_extra_N_J_N()"); + test_extra_N_J_N(); + System.out.println("Running test_extra_N_N_J()"); + test_extra_N_N_J(); + System.out.println("Running test_extra_N_N_N()"); + test_extra_N_N_N(); + Exceptions.disableExceptionCatchEvent(Thread.currentThread()); + Exceptions.disableExceptionEvent(Thread.currentThread()); + } +} diff --git a/test/1928-exception-event-exception/expected.txt b/test/1928-exception-event-exception/expected.txt new file mode 100644 index 0000000000..1692d042e4 --- /dev/null +++ b/test/1928-exception-event-exception/expected.txt @@ -0,0 +1,236 @@ +Test "art.Test1928$DoThrowClass": Running with handler "art.Test1928$DoNothingHandler" +main: public static void art.Test1928.doThrow() @ line = 110 throws class art.Test1928$TestException: doThrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1928.PrintStack() @ line = 35 + public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 + public static void art.Test1928.doThrow() @ line = 110 + public void art.Test1928$DoThrowClass.run() @ line = 114 + public static void art.Test1928.run() throws java.lang.Exception @ line = 196 + Will be caught by: public static void art.Test1928.run() throws java.lang.Exception @ line = 199 +exception is: art.Test1928$TestException: doThrow + at art.Test1928.doThrow(Test1928.java:110) + at art.Test1928$DoThrowClass.run(Test1928.java:114) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) + Doing nothing! +Test "art.Test1928$DoThrowClass": Caught error art.Test1928$TestException:"doThrow" with handler "art.Test1928$DoNothingHandler" +art.Test1928$TestException: doThrow + at art.Test1928.doThrow(Test1928.java:110) + at art.Test1928$DoThrowClass.run(Test1928.java:114) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Test "art.Test1928$DoThrowClass": Finished running with handler "art.Test1928$DoNothingHandler" +Test "art.Test1928$DoThrowCatchBaseTestException": Running with handler "art.Test1928$DoNothingHandler" +main: public static void art.Test1928.throwCatchBaseTestException() @ line = 119 throws class art.Test1928$TestException: throwCatchBaseTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1928.PrintStack() @ line = 35 + public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 + public static void art.Test1928.throwCatchBaseTestException() @ line = 119 + public void art.Test1928$DoThrowCatchBaseTestException.run() @ line = 129 + public static void art.Test1928.run() throws java.lang.Exception @ line = 196 + Will be caught by: public static void art.Test1928.throwCatchBaseTestException() @ line = 120 +exception is: art.Test1928$TestException: throwCatchBaseTestException + at art.Test1928.throwCatchBaseTestException(Test1928.java:119) + at art.Test1928$DoThrowCatchBaseTestException.run(Test1928.java:129) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) + Doing nothing! +Caught art.Test1928$TestException: "throwCatchBaseTestException" +art.Test1928$TestException: throwCatchBaseTestException + at art.Test1928.throwCatchBaseTestException(Test1928.java:119) + at art.Test1928$DoThrowCatchBaseTestException.run(Test1928.java:129) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Test "art.Test1928$DoThrowCatchBaseTestException": No error caught with handler "art.Test1928$DoNothingHandler" +Test "art.Test1928$DoThrowCatchBaseTestException": Finished running with handler "art.Test1928$DoNothingHandler" +Test "art.Test1928$DoThrowCatchTestException": Running with handler "art.Test1928$DoNothingHandler" +main: public static void art.Test1928.throwCatchTestException() @ line = 134 throws class art.Test1928$TestException: throwCatchTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1928.PrintStack() @ line = 35 + public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 + public static void art.Test1928.throwCatchTestException() @ line = 134 + public void art.Test1928$DoThrowCatchTestException.run() @ line = 144 + public static void art.Test1928.run() throws java.lang.Exception @ line = 196 + Will be caught by: public static void art.Test1928.throwCatchTestException() @ line = 135 +exception is: art.Test1928$TestException: throwCatchTestException + at art.Test1928.throwCatchTestException(Test1928.java:134) + at art.Test1928$DoThrowCatchTestException.run(Test1928.java:144) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) + Doing nothing! +Caught art.Test1928$TestException: "throwCatchTestException" +art.Test1928$TestException: throwCatchTestException + at art.Test1928.throwCatchTestException(Test1928.java:134) + at art.Test1928$DoThrowCatchTestException.run(Test1928.java:144) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Test "art.Test1928$DoThrowCatchTestException": No error caught with handler "art.Test1928$DoNothingHandler" +Test "art.Test1928$DoThrowCatchTestException": Finished running with handler "art.Test1928$DoNothingHandler" +Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Running with handler "art.Test1928$DoNothingHandler" +main: public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149 throws class art.Test1928$TestException: throwCatchTestExceptionNoRethrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1928.PrintStack() @ line = 35 + public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 + public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149 + public void art.Test1928$DoThrowCatchTestExceptionNoRethrow.run() @ line = 159 + public static void art.Test1928.run() throws java.lang.Exception @ line = 196 + Will be caught by: public static void art.Test1928.run() throws java.lang.Exception @ line = 199 +exception is: art.Test1928$TestException: throwCatchTestExceptionNoRethrow + at art.Test1928.throwCatchTestExceptionNoRethrow(Test1928.java:149) + at art.Test1928$DoThrowCatchTestExceptionNoRethrow.run(Test1928.java:159) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) + Doing nothing! +Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1928$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1928$DoNothingHandler" +art.Test1928$TestException: throwCatchTestExceptionNoRethrow + at art.Test1928.throwCatchTestExceptionNoRethrow(Test1928.java:149) + at art.Test1928$DoThrowCatchTestExceptionNoRethrow.run(Test1928.java:159) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1928$DoNothingHandler" +Test "art.Test1928$DoThrowClass": Running with handler "art.Test1928$ThrowCatchBase" +main: public static void art.Test1928.doThrow() @ line = 110 throws class art.Test1928$TestException: doThrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1928.PrintStack() @ line = 35 + public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 + public static void art.Test1928.doThrow() @ line = 110 + public void art.Test1928$DoThrowClass.run() @ line = 114 + public static void art.Test1928.run() throws java.lang.Exception @ line = 196 + Will be caught by: public static void art.Test1928.run() throws java.lang.Exception @ line = 199 +exception is: art.Test1928$TestException: doThrow + at art.Test1928.doThrow(Test1928.java:110) + at art.Test1928$DoThrowClass.run(Test1928.java:114) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) + Throwing BaseTestException and catching it! +Caught art.Test1928$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1928.doThrow() @ line = 110" +art.Test1928$BaseTestException: ThrowBaseHandler during throw from public static void art.Test1928.doThrow() @ line = 110 + at art.Test1928$ThrowCatchBase.exceptionOccurred(Test1928.java:99) + at art.Test1928.ExceptionEvent(Test1928.java:66) + at art.Test1928.doThrow(Test1928.java:110) + at art.Test1928$DoThrowClass.run(Test1928.java:114) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Caused by: art.Test1928$TestException: doThrow + ... 4 more +Test "art.Test1928$DoThrowClass": Caught error art.Test1928$TestException:"doThrow" with handler "art.Test1928$ThrowCatchBase" +art.Test1928$TestException: doThrow + at art.Test1928.doThrow(Test1928.java:110) + at art.Test1928$DoThrowClass.run(Test1928.java:114) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Test "art.Test1928$DoThrowClass": Finished running with handler "art.Test1928$ThrowCatchBase" +Test "art.Test1928$DoThrowCatchBaseTestException": Running with handler "art.Test1928$ThrowCatchBase" +main: public static void art.Test1928.throwCatchBaseTestException() @ line = 119 throws class art.Test1928$TestException: throwCatchBaseTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1928.PrintStack() @ line = 35 + public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 + public static void art.Test1928.throwCatchBaseTestException() @ line = 119 + public void art.Test1928$DoThrowCatchBaseTestException.run() @ line = 129 + public static void art.Test1928.run() throws java.lang.Exception @ line = 196 + Will be caught by: public static void art.Test1928.throwCatchBaseTestException() @ line = 120 +exception is: art.Test1928$TestException: throwCatchBaseTestException + at art.Test1928.throwCatchBaseTestException(Test1928.java:119) + at art.Test1928$DoThrowCatchBaseTestException.run(Test1928.java:129) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) + Throwing BaseTestException and catching it! +Caught art.Test1928$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1928.throwCatchBaseTestException() @ line = 119" +art.Test1928$BaseTestException: ThrowBaseHandler during throw from public static void art.Test1928.throwCatchBaseTestException() @ line = 119 + at art.Test1928$ThrowCatchBase.exceptionOccurred(Test1928.java:99) + at art.Test1928.ExceptionEvent(Test1928.java:66) + at art.Test1928.throwCatchBaseTestException(Test1928.java:119) + at art.Test1928$DoThrowCatchBaseTestException.run(Test1928.java:129) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Caused by: art.Test1928$TestException: throwCatchBaseTestException + ... 4 more +Caught art.Test1928$TestException: "throwCatchBaseTestException" +art.Test1928$TestException: throwCatchBaseTestException + at art.Test1928.throwCatchBaseTestException(Test1928.java:119) + at art.Test1928$DoThrowCatchBaseTestException.run(Test1928.java:129) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Test "art.Test1928$DoThrowCatchBaseTestException": No error caught with handler "art.Test1928$ThrowCatchBase" +Test "art.Test1928$DoThrowCatchBaseTestException": Finished running with handler "art.Test1928$ThrowCatchBase" +Test "art.Test1928$DoThrowCatchTestException": Running with handler "art.Test1928$ThrowCatchBase" +main: public static void art.Test1928.throwCatchTestException() @ line = 134 throws class art.Test1928$TestException: throwCatchTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1928.PrintStack() @ line = 35 + public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 + public static void art.Test1928.throwCatchTestException() @ line = 134 + public void art.Test1928$DoThrowCatchTestException.run() @ line = 144 + public static void art.Test1928.run() throws java.lang.Exception @ line = 196 + Will be caught by: public static void art.Test1928.throwCatchTestException() @ line = 135 +exception is: art.Test1928$TestException: throwCatchTestException + at art.Test1928.throwCatchTestException(Test1928.java:134) + at art.Test1928$DoThrowCatchTestException.run(Test1928.java:144) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) + Throwing BaseTestException and catching it! +Caught art.Test1928$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1928.throwCatchTestException() @ line = 134" +art.Test1928$BaseTestException: ThrowBaseHandler during throw from public static void art.Test1928.throwCatchTestException() @ line = 134 + at art.Test1928$ThrowCatchBase.exceptionOccurred(Test1928.java:99) + at art.Test1928.ExceptionEvent(Test1928.java:66) + at art.Test1928.throwCatchTestException(Test1928.java:134) + at art.Test1928$DoThrowCatchTestException.run(Test1928.java:144) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Caused by: art.Test1928$TestException: throwCatchTestException + ... 4 more +Caught art.Test1928$TestException: "throwCatchTestException" +art.Test1928$TestException: throwCatchTestException + at art.Test1928.throwCatchTestException(Test1928.java:134) + at art.Test1928$DoThrowCatchTestException.run(Test1928.java:144) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Test "art.Test1928$DoThrowCatchTestException": No error caught with handler "art.Test1928$ThrowCatchBase" +Test "art.Test1928$DoThrowCatchTestException": Finished running with handler "art.Test1928$ThrowCatchBase" +Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Running with handler "art.Test1928$ThrowCatchBase" +main: public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149 throws class art.Test1928$TestException: throwCatchTestExceptionNoRethrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1928.PrintStack() @ line = 35 + public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 + public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149 + public void art.Test1928$DoThrowCatchTestExceptionNoRethrow.run() @ line = 159 + public static void art.Test1928.run() throws java.lang.Exception @ line = 196 + Will be caught by: public static void art.Test1928.run() throws java.lang.Exception @ line = 199 +exception is: art.Test1928$TestException: throwCatchTestExceptionNoRethrow + at art.Test1928.throwCatchTestExceptionNoRethrow(Test1928.java:149) + at art.Test1928$DoThrowCatchTestExceptionNoRethrow.run(Test1928.java:159) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) + Throwing BaseTestException and catching it! +Caught art.Test1928$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149" +art.Test1928$BaseTestException: ThrowBaseHandler during throw from public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149 + at art.Test1928$ThrowCatchBase.exceptionOccurred(Test1928.java:99) + at art.Test1928.ExceptionEvent(Test1928.java:66) + at art.Test1928.throwCatchTestExceptionNoRethrow(Test1928.java:149) + at art.Test1928$DoThrowCatchTestExceptionNoRethrow.run(Test1928.java:159) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Caused by: art.Test1928$TestException: throwCatchTestExceptionNoRethrow + ... 4 more +Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1928$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1928$ThrowCatchBase" +art.Test1928$TestException: throwCatchTestExceptionNoRethrow + at art.Test1928.throwCatchTestExceptionNoRethrow(Test1928.java:149) + at art.Test1928$DoThrowCatchTestExceptionNoRethrow.run(Test1928.java:159) + at art.Test1928.run(Test1928.java:196) + at Main.main(Main.java:19) +Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1928$ThrowCatchBase" diff --git a/test/1928-exception-event-exception/info.txt b/test/1928-exception-event-exception/info.txt new file mode 100644 index 0000000000..ef8474616a --- /dev/null +++ b/test/1928-exception-event-exception/info.txt @@ -0,0 +1,5 @@ +Test basic JVMTI exception event functionality. + +Ensures we can throw exceptions during the exception event without causing +problems. Note that we do not allow exceptions to propogate past the event, +matching RI behavior. See b/65049545. diff --git a/test/1928-exception-event-exception/run b/test/1928-exception-event-exception/run new file mode 100755 index 0000000000..51875a7e86 --- /dev/null +++ b/test/1928-exception-event-exception/run @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Ask for stack traces to be dumped to a file rather than to stdout. +./default-run "$@" --jvmti diff --git a/test/1928-exception-event-exception/src/Main.java b/test/1928-exception-event-exception/src/Main.java new file mode 100644 index 0000000000..11cc773041 --- /dev/null +++ b/test/1928-exception-event-exception/src/Main.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + public static void main(String[] args) throws Exception { + art.Test1928.run(); + } +} diff --git a/test/1928-exception-event-exception/src/art/Breakpoint.java b/test/1928-exception-event-exception/src/art/Breakpoint.java new file mode 100644 index 0000000000..bbb89f707f --- /dev/null +++ b/test/1928-exception-event-exception/src/art/Breakpoint.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.lang.reflect.Executable; +import java.util.HashSet; +import java.util.Set; +import java.util.Objects; + +public class Breakpoint { + public static class Manager { + public static class BP { + public final Executable method; + public final long location; + + public BP(Executable method) { + this(method, getStartLocation(method)); + } + + public BP(Executable method, long location) { + this.method = method; + this.location = location; + } + + @Override + public boolean equals(Object other) { + return (other instanceof BP) && + method.equals(((BP)other).method) && + location == ((BP)other).location; + } + + @Override + public String toString() { + return method.toString() + " @ " + getLine(); + } + + @Override + public int hashCode() { + return Objects.hash(method, location); + } + + public int getLine() { + try { + LineNumber[] lines = getLineNumberTable(method); + int best = -1; + for (LineNumber l : lines) { + if (l.location > location) { + break; + } else { + best = l.line; + } + } + return best; + } catch (Exception e) { + return -1; + } + } + } + + private Set<BP> breaks = new HashSet<>(); + + public void setBreakpoints(BP... bs) { + for (BP b : bs) { + if (breaks.add(b)) { + Breakpoint.setBreakpoint(b.method, b.location); + } + } + } + public void setBreakpoint(Executable method, long location) { + setBreakpoints(new BP(method, location)); + } + + public void clearBreakpoints(BP... bs) { + for (BP b : bs) { + if (breaks.remove(b)) { + Breakpoint.clearBreakpoint(b.method, b.location); + } + } + } + public void clearBreakpoint(Executable method, long location) { + clearBreakpoints(new BP(method, location)); + } + + public void clearAllBreakpoints() { + clearBreakpoints(breaks.toArray(new BP[0])); + } + } + + public static void startBreakpointWatch(Class<?> methodClass, + Executable breakpointReached, + Thread thr) { + startBreakpointWatch(methodClass, breakpointReached, false, thr); + } + + /** + * Enables the trapping of breakpoint events. + * + * If allowRecursive == true then breakpoints will be sent even if one is currently being handled. + */ + public static native void startBreakpointWatch(Class<?> methodClass, + Executable breakpointReached, + boolean allowRecursive, + Thread thr); + public static native void stopBreakpointWatch(Thread thr); + + public static final class LineNumber implements Comparable<LineNumber> { + public final long location; + public final int line; + + private LineNumber(long loc, int line) { + this.location = loc; + this.line = line; + } + + public boolean equals(Object other) { + return other instanceof LineNumber && ((LineNumber)other).line == line && + ((LineNumber)other).location == location; + } + + public int compareTo(LineNumber other) { + int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line)); + if (v != 0) { + return v; + } else { + return Long.valueOf(location).compareTo(Long.valueOf(other.location)); + } + } + } + + public static native void setBreakpoint(Executable m, long loc); + public static void setBreakpoint(Executable m, LineNumber l) { + setBreakpoint(m, l.location); + } + + public static native void clearBreakpoint(Executable m, long loc); + public static void clearBreakpoint(Executable m, LineNumber l) { + clearBreakpoint(m, l.location); + } + + private static native Object[] getLineNumberTableNative(Executable m); + public static LineNumber[] getLineNumberTable(Executable m) { + Object[] nativeTable = getLineNumberTableNative(m); + long[] location = (long[])(nativeTable[0]); + int[] lines = (int[])(nativeTable[1]); + if (lines.length != location.length) { + throw new Error("Lines and locations have different lengths!"); + } + LineNumber[] out = new LineNumber[lines.length]; + for (int i = 0; i < lines.length; i++) { + out[i] = new LineNumber(location[i], lines[i]); + } + return out; + } + + public static native long getStartLocation(Executable m); + + public static int locationToLine(Executable m, long location) { + try { + Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m); + int best = -1; + for (Breakpoint.LineNumber l : lines) { + if (l.location > location) { + break; + } else { + best = l.line; + } + } + return best; + } catch (Exception e) { + return -1; + } + } + + public static long lineToLocation(Executable m, int line) throws Exception { + try { + Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m); + for (Breakpoint.LineNumber l : lines) { + if (l.line == line) { + return l.location; + } + } + throw new Exception("Unable to find line " + line + " in " + m); + } catch (Exception e) { + throw new Exception("Unable to get line number info for " + m, e); + } + } +} + diff --git a/test/1928-exception-event-exception/src/art/Exceptions.java b/test/1928-exception-event-exception/src/art/Exceptions.java new file mode 100644 index 0000000000..2c959ec83f --- /dev/null +++ b/test/1928-exception-event-exception/src/art/Exceptions.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class Exceptions { + public static native void setupExceptionTracing( + Class<?> methodClass, + Class<?> exceptionClass, + Method exceptionEventMethod, + Method exceptionCaughtEventMethod); + + public static native void enableExceptionCatchEvent(Thread thr); + public static native void enableExceptionEvent(Thread thr); + public static native void disableExceptionCatchEvent(Thread thr); + public static native void disableExceptionEvent(Thread thr); +} diff --git a/test/1928-exception-event-exception/src/art/StackTrace.java b/test/1928-exception-event-exception/src/art/StackTrace.java new file mode 100644 index 0000000000..b12c3df66b --- /dev/null +++ b/test/1928-exception-event-exception/src/art/StackTrace.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.lang.reflect.Field; +import java.lang.reflect.Executable; + +public class StackTrace { + public static class StackFrameData { + public final Thread thr; + public final Executable method; + public final long current_location; + public final int depth; + + public StackFrameData(Thread thr, Executable e, long loc, int depth) { + this.thr = thr; + this.method = e; + this.current_location = loc; + this.depth = depth; + } + @Override + public String toString() { + return String.format( + "StackFrameData { thr: '%s', method: '%s', loc: %d, depth: %d }", + this.thr, + this.method, + this.current_location, + this.depth); + } + } + + public static native int GetStackDepth(Thread thr); + + private static native StackFrameData[] nativeGetStackTrace(Thread thr); + + public static StackFrameData[] GetStackTrace(Thread thr) { + // The RI seems to give inconsistent (and sometimes nonsensical) results if the thread is not + // suspended. The spec says that not being suspended is fine but since we want this to be + // consistent we will suspend for the RI. + boolean suspend_thread = + !System.getProperty("java.vm.name").equals("Dalvik") && + !thr.equals(Thread.currentThread()); + if (suspend_thread) { + Suspension.suspend(thr); + } + StackFrameData[] out = nativeGetStackTrace(thr); + if (suspend_thread) { + Suspension.resume(thr); + } + return out; + } +} + diff --git a/test/1928-exception-event-exception/src/art/Suspension.java b/test/1928-exception-event-exception/src/art/Suspension.java new file mode 100644 index 0000000000..16e62ccac9 --- /dev/null +++ b/test/1928-exception-event-exception/src/art/Suspension.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +public class Suspension { + // Suspends a thread using jvmti. + public native static void suspend(Thread thr); + + // Resumes a thread using jvmti. + public native static void resume(Thread thr); + + public native static boolean isSuspended(Thread thr); + + public native static int[] suspendList(Thread... threads); + public native static int[] resumeList(Thread... threads); +} diff --git a/test/1928-exception-event-exception/src/art/Test1928.java b/test/1928-exception-event-exception/src/art/Test1928.java new file mode 100644 index 0000000000..aec88a4079 --- /dev/null +++ b/test/1928-exception-event-exception/src/art/Test1928.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.util.Arrays; +import java.util.Objects; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; + +public class Test1928 { + public static boolean PRINT_FULL_EXCEPTION = true; + public static ExceptionHandler HANDLER = null; + + public static interface ExceptionHandler { + public void exceptionOccurred( + Executable m, long loc, Throwable exception, Executable catch_m, long catch_l); + } + + private static void PrintStack() { + System.out.println("\tCurrent Stack:"); + for (StackTrace.StackFrameData e : StackTrace.GetStackTrace(Thread.currentThread())) { + if (Objects.equals(e.method.getDeclaringClass().getPackage(), Test1928.class.getPackage())) { + System.out.println("\t\t" + e.method + " @ line = " + + Breakpoint.locationToLine(e.method, e.current_location)); + } + } + } + + public static void ExceptionEvent(Thread thr, + Executable throw_method, + long throw_location, + Throwable exception, + Executable catch_method, + long catch_location) { + System.out.println(thr.getName() + ": " + throw_method + " @ line = " + + Breakpoint.locationToLine(throw_method, throw_location) + " throws " + + exception.getClass() + ": " + exception.getMessage()); + String catch_message; + if (catch_method == null) { + catch_message = "<UNKNOWN>"; + } else { + catch_message = catch_method.toString() + " @ line = " + + Breakpoint.locationToLine(catch_method, catch_location); + } + PrintStack(); + System.out.println("\tWill be caught by: " + catch_message); + if (PRINT_FULL_EXCEPTION) { + System.out.print("exception is: "); + exception.printStackTrace(System.out); + } + if (HANDLER != null) { + HANDLER.exceptionOccurred( + throw_method, throw_location, exception, catch_method, catch_location); + } + } + + public static class BaseTestException extends Error { + public BaseTestException(String e) { super(e); } + public BaseTestException(String e, Throwable t) { super(e, t); } + } + public static class TestException extends BaseTestException { + public TestException(String e) { super(e); } + public TestException(String e, Throwable t) { super(e, t); } + } + + public static class TestExceptionNoRethrow extends TestException { + public TestExceptionNoRethrow(String e) { super(e); } + public TestExceptionNoRethrow(String e, Throwable t) { super(e, t); } + } + + public static class DoNothingHandler implements ExceptionHandler { + public void exceptionOccurred( + Executable m, long loc, Throwable exception, Executable catch_m, long catch_l) { + System.out.println("\tDoing nothing!"); + return; + } + } + + public static class ThrowCatchBase implements ExceptionHandler { + public void exceptionOccurred( + Executable m, long loc, Throwable exception, Executable catch_m, long catch_l) { + System.out.println("\tThrowing BaseTestException and catching it!"); + try { + throw new BaseTestException("ThrowBaseHandler during throw from " + m + " @ line = " + + Breakpoint.locationToLine(m, loc), exception); + } catch (BaseTestException t) { + System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } + } + + public static void doThrow() { + throw new TestException("doThrow"); + } + + public static class DoThrowClass implements Runnable { + public void run() { doThrow(); } + } + + public static void throwCatchBaseTestException() { + try { + throw new TestException("throwCatchBaseTestException"); + } catch (BaseTestException t) { + System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } + + public static class DoThrowCatchBaseTestException implements Runnable { + public void run() { throwCatchBaseTestException(); } + } + + public static void throwCatchTestException() { + try { + throw new TestException("throwCatchTestException"); + } catch (TestException t) { + System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } + + public static class DoThrowCatchTestException implements Runnable { + public void run() { throwCatchTestException(); } + } + + public static void throwCatchTestExceptionNoRethrow() { + try { + throw new TestException("throwCatchTestExceptionNoRethrow"); + } catch (TestExceptionNoRethrow t) { + System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } + + public static class DoThrowCatchTestExceptionNoRethrow implements Runnable { + public void run() { throwCatchTestExceptionNoRethrow(); } + } + + public static void run() throws Exception { + // Set up + Exceptions.setupExceptionTracing( + Test1928.class, + TestException.class, + Test1928.class.getDeclaredMethod( + "ExceptionEvent", + Thread.class, + Executable.class, + Long.TYPE, + Throwable.class, + Executable.class, + Long.TYPE), + null); + Exceptions.enableExceptionEvent(Thread.currentThread()); + + ExceptionHandler[] handlers = new ExceptionHandler[] { + new DoNothingHandler(), + new ThrowCatchBase(), + }; + + Runnable[] tests = new Runnable[] { + new DoThrowClass(), + new DoThrowCatchBaseTestException(), + new DoThrowCatchTestException(), + new DoThrowCatchTestExceptionNoRethrow(), + }; + + for (ExceptionHandler handler : handlers) { + for (Runnable test : tests) { + try { + HANDLER = handler; + System.out.printf("Test \"%s\": Running with handler \"%s\"\n", + test.getClass().getName(), handler.getClass().getName()); + test.run(); + System.out.printf("Test \"%s\": No error caught with handler \"%s\"\n", + test.getClass().getName(), handler.getClass().getName()); + } catch (Throwable e) { + System.out.printf("Test \"%s\": Caught error %s:\"%s\" with handler \"%s\"\n", + test.getClass().getName(), + e.getClass().getName(), + e.getMessage(), + handler.getClass().getName()); + if (PRINT_FULL_EXCEPTION) { + e.printStackTrace(System.out); + } + } + System.out.printf("Test \"%s\": Finished running with handler \"%s\"\n", + test.getClass().getName(), handler.getClass().getName()); + HANDLER = null; + } + } + Exceptions.disableExceptionEvent(Thread.currentThread()); + } +} diff --git a/test/1929-exception-catch-exception/expected.txt b/test/1929-exception-catch-exception/expected.txt new file mode 100644 index 0000000000..7c23a31439 --- /dev/null +++ b/test/1929-exception-catch-exception/expected.txt @@ -0,0 +1,302 @@ +Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$DoNothingHandler" +main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.run() throws java.lang.Exception @ line = 283 +Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$DoNothingHandler" +main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 caught class art.Test1929$TestException: throwCatchBaseTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.throwCatchBaseTestException() @ line = 140 + public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 + Doing nothing! +Caught art.Test1929$TestException: "throwCatchBaseTestException" +Test "art.Test1929$DoThrowCatchBaseTestException": No error caught with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$DoNothingHandler" +main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 + public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197 + public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 +Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$DoNothingHandler" +main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.throwCatchTestException() @ line = 207 + public void art.Test1929$DoThrowCatchTestException.run() @ line = 216 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 + Doing nothing! +Caught art.Test1929$TestException: "throwCatchTestException" +Test "art.Test1929$DoThrowCatchTestException": No error caught with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$DoNothingHandler" +main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 + public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222 + public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 +Caught art.Test1929$TestException: "throwCatchTestExceptionTwice" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$DoNothingHandler" +main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.run() throws java.lang.Exception @ line = 283 +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$DoNothingHandler" +Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ThrowCatchBase" +main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.run() throws java.lang.Exception @ line = 283 +Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$ThrowCatchBase" +main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 caught class art.Test1929$TestException: throwCatchBaseTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.throwCatchBaseTestException() @ line = 140 + public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 + Throwing BaseTestException and catching it! +Caught art.Test1929$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1929.throwCatchBaseTestException() @ line = 140" +Caught art.Test1929$TestException: "throwCatchBaseTestException" +Test "art.Test1929$DoThrowCatchBaseTestException": No error caught with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowCatchBase" +main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 + public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197 + public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 +Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$ThrowCatchBase" +main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.throwCatchTestException() @ line = 207 + public void art.Test1929$DoThrowCatchTestException.run() @ line = 216 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 + Throwing BaseTestException and catching it! +Caught art.Test1929$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 207" +Caught art.Test1929$TestException: "throwCatchTestException" +Test "art.Test1929$DoThrowCatchTestException": No error caught with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowCatchBase" +main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 + public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222 + public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 +Caught art.Test1929$TestException: "throwCatchTestExceptionTwice" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$ThrowCatchBase" +main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.run() throws java.lang.Exception @ line = 283 +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$ThrowCatchBase" +Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler" +main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.run() throws java.lang.Exception @ line = 283 +Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler" +main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 caught class art.Test1929$TestException: throwCatchBaseTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.throwCatchBaseTestException() @ line = 140 + public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 + Throwing BaseTestException! +Test "art.Test1929$DoThrowCatchBaseTestException": Caught error art.Test1929$BaseTestException:"ThrowBaseHandler during throw from public static void art.Test1929.throwCatchBaseTestException() @ line = 140" with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler" +main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 + public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197 + public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 +Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler" +main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.throwCatchTestException() @ line = 207 + public void art.Test1929$DoThrowCatchTestException.run() @ line = 216 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 + Throwing BaseTestException! +Test "art.Test1929$DoThrowCatchTestException": Caught error art.Test1929$BaseTestException:"ThrowBaseHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 207" with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler" +main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 + public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222 + public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 +Caught art.Test1929$TestException: "throwCatchTestExceptionTwice" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler" +main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.run() throws java.lang.Exception @ line = 283 +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler" +Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.run() throws java.lang.Exception @ line = 283 +Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 caught class art.Test1929$TestException: throwCatchBaseTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.throwCatchBaseTestException() @ line = 140 + public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 + Throwing TestExceptionNoRethrow! +Test "art.Test1929$DoThrowCatchBaseTestException": Caught error art.Test1929$TestExceptionNoRethrow:"ThrowTestExceptionNoRethrowHandler during throw from public static void art.Test1929.throwCatchBaseTestException() @ line = 140" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 + public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197 + public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 +Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.throwCatchTestException() @ line = 207 + public void art.Test1929$DoThrowCatchTestException.run() @ line = 216 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 + Throwing TestExceptionNoRethrow! +Test "art.Test1929$DoThrowCatchTestException": Caught error art.Test1929$TestExceptionNoRethrow:"ThrowTestExceptionNoRethrowHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 207" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 + public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222 + public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226 + public static void art.Test1929.run() throws java.lang.Exception @ line = 280 +Caught art.Test1929$TestException: "throwCatchTestExceptionTwice" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow + Current Stack: + private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + private static void art.Test1929.PrintStack() @ line = 52 + public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 + public static void art.Test1929.run() throws java.lang.Exception @ line = 283 +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" +Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler" diff --git a/test/1929-exception-catch-exception/info.txt b/test/1929-exception-catch-exception/info.txt new file mode 100644 index 0000000000..2d9b3a0eb3 --- /dev/null +++ b/test/1929-exception-catch-exception/info.txt @@ -0,0 +1 @@ +Test JVMTI behavior when throwing exceptions during the Exception catch Event. diff --git a/test/1929-exception-catch-exception/run b/test/1929-exception-catch-exception/run new file mode 100755 index 0000000000..51875a7e86 --- /dev/null +++ b/test/1929-exception-catch-exception/run @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Ask for stack traces to be dumped to a file rather than to stdout. +./default-run "$@" --jvmti diff --git a/test/1929-exception-catch-exception/smali/art/Test1929$Impl.smali b/test/1929-exception-catch-exception/smali/art/Test1929$Impl.smali new file mode 100644 index 0000000000..4edd56f690 --- /dev/null +++ b/test/1929-exception-catch-exception/smali/art/Test1929$Impl.smali @@ -0,0 +1,363 @@ +# Copyright (C) 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# The standard dx/jack/d8 all would leave the move-exception instructions outside of either catch +# block. This is different from the RI which will leave the corresponding aload. +# +# See b/65203529 for more information. + +.class public final Lart/Test1929$Impl; +.super Ljava/lang/Object; +.source "Test1929.java" + + +# annotations +.annotation system Ldalvik/annotation/EnclosingClass; + value = Lart/Test1929; +.end annotation + +.annotation system Ldalvik/annotation/InnerClass; + accessFlags = 0x19 + name = "Impl" +.end annotation + + +# direct methods +.method private constructor <init>()V + .registers 1 + + .prologue + .line 152 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + + return-void +.end method + +.method public static throwCatchBaseTestExceptionTwiceImpl()V + .registers 4 + + .prologue + .line 156 + :try_start_0 + new-instance v1, Lart/Test1929$TestException; + + const-string v2, "throwCatchBaseTestExceptionTwice" + + invoke-direct {v1, v2}, Lart/Test1929$TestException;-><init>(Ljava/lang/String;)V + + throw v1 + :try_end_8 + .catch Lart/Test1929$BaseTestException; {:try_start_0 .. :try_end_8} :catch_8 + + .line 157 + :catch_8 + # This try needs to include the move-exception + :try_start_9 + move-exception v0 + + .line 158 + .local v0, "t":Lart/Test1929$BaseTestException; + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + new-instance v2, Ljava/lang/StringBuilder; + + invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V + + const-string v3, "Caught " + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v0}, Ljava/lang/Object;->getClass()Ljava/lang/Class; + + move-result-object v3 + + invoke-virtual {v3}, Ljava/lang/Class;->getName()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + const-string v3, ": \"" + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v0}, Lart/Test1929$BaseTestException;->getMessage()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + const-string v3, "\"" + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + + move-result-object v2 + + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V + + .line 159 + sget-boolean v1, Lart/Test1929;->PRINT_FULL_EXCEPTION:Z + + if-eqz v1, :cond_46 + + .line 160 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + invoke-virtual {v0, v1}, Lart/Test1929$BaseTestException;->printStackTrace(Ljava/io/PrintStream;)V + :try_end_46 + .catch Lart/Test1929$BaseTestException; {:try_start_9 .. :try_end_46} :catch_47 + + .line 169 + :cond_46 + :goto_46 + return-void + + .line 163 + :catch_47 + move-exception v0 + + .line 164 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + new-instance v2, Ljava/lang/StringBuilder; + + invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V + + const-string v3, "2nd Caught " + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v0}, Ljava/lang/Object;->getClass()Ljava/lang/Class; + + move-result-object v3 + + invoke-virtual {v3}, Ljava/lang/Class;->getName()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + const-string v3, ": \"" + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v0}, Lart/Test1929$BaseTestException;->getMessage()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + const-string v3, "\"" + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + + move-result-object v2 + + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V + + .line 165 + sget-boolean v1, Lart/Test1929;->PRINT_FULL_EXCEPTION:Z + + if-eqz v1, :cond_46 + + .line 166 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + invoke-virtual {v0, v1}, Lart/Test1929$BaseTestException;->printStackTrace(Ljava/io/PrintStream;)V + + goto :goto_46 +.end method + +.method public static throwCatchTestExceptionTwiceImpl()V + .registers 4 + + .prologue + .line 174 + :try_start_0 + new-instance v1, Lart/Test1929$TestException; + + const-string v2, "throwCatchTestExceptionTwice" + + invoke-direct {v1, v2}, Lart/Test1929$TestException;-><init>(Ljava/lang/String;)V + + throw v1 + :try_end_8 + .catch Lart/Test1929$TestException; {:try_start_0 .. :try_end_8} :catch_8 + + .line 175 + :catch_8 + # This try needs to include the move-exception + :try_start_9 + move-exception v0 + + .line 176 + .local v0, "t":Lart/Test1929$TestException; + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + new-instance v2, Ljava/lang/StringBuilder; + + invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V + + const-string v3, "Caught " + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v0}, Ljava/lang/Object;->getClass()Ljava/lang/Class; + + move-result-object v3 + + invoke-virtual {v3}, Ljava/lang/Class;->getName()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + const-string v3, ": \"" + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v0}, Lart/Test1929$TestException;->getMessage()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + const-string v3, "\"" + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + + move-result-object v2 + + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V + + .line 177 + sget-boolean v1, Lart/Test1929;->PRINT_FULL_EXCEPTION:Z + + if-eqz v1, :cond_46 + + .line 178 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + invoke-virtual {v0, v1}, Lart/Test1929$TestException;->printStackTrace(Ljava/io/PrintStream;)V + :try_end_46 + .catch Lart/Test1929$TestException; {:try_start_9 .. :try_end_46} :catch_47 + + .line 187 + :cond_46 + :goto_46 + return-void + + .line 181 + :catch_47 + move-exception v0 + + .line 182 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + new-instance v2, Ljava/lang/StringBuilder; + + invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V + + const-string v3, "2nd Caught " + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v0}, Ljava/lang/Object;->getClass()Ljava/lang/Class; + + move-result-object v3 + + invoke-virtual {v3}, Ljava/lang/Class;->getName()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + const-string v3, ": \"" + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v0}, Lart/Test1929$TestException;->getMessage()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + const-string v3, "\"" + + invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v2 + + invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + + move-result-object v2 + + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V + + .line 183 + sget-boolean v1, Lart/Test1929;->PRINT_FULL_EXCEPTION:Z + + if-eqz v1, :cond_46 + + .line 184 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + invoke-virtual {v0, v1}, Lart/Test1929$TestException;->printStackTrace(Ljava/io/PrintStream;)V + + goto :goto_46 +.end method diff --git a/test/1929-exception-catch-exception/src/Main.java b/test/1929-exception-catch-exception/src/Main.java new file mode 100644 index 0000000000..4651bac3b1 --- /dev/null +++ b/test/1929-exception-catch-exception/src/Main.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + public static void main(String[] args) throws Exception { + art.Test1929.run(); + } +} diff --git a/test/1929-exception-catch-exception/src/art/Breakpoint.java b/test/1929-exception-catch-exception/src/art/Breakpoint.java new file mode 100644 index 0000000000..bbb89f707f --- /dev/null +++ b/test/1929-exception-catch-exception/src/art/Breakpoint.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.lang.reflect.Executable; +import java.util.HashSet; +import java.util.Set; +import java.util.Objects; + +public class Breakpoint { + public static class Manager { + public static class BP { + public final Executable method; + public final long location; + + public BP(Executable method) { + this(method, getStartLocation(method)); + } + + public BP(Executable method, long location) { + this.method = method; + this.location = location; + } + + @Override + public boolean equals(Object other) { + return (other instanceof BP) && + method.equals(((BP)other).method) && + location == ((BP)other).location; + } + + @Override + public String toString() { + return method.toString() + " @ " + getLine(); + } + + @Override + public int hashCode() { + return Objects.hash(method, location); + } + + public int getLine() { + try { + LineNumber[] lines = getLineNumberTable(method); + int best = -1; + for (LineNumber l : lines) { + if (l.location > location) { + break; + } else { + best = l.line; + } + } + return best; + } catch (Exception e) { + return -1; + } + } + } + + private Set<BP> breaks = new HashSet<>(); + + public void setBreakpoints(BP... bs) { + for (BP b : bs) { + if (breaks.add(b)) { + Breakpoint.setBreakpoint(b.method, b.location); + } + } + } + public void setBreakpoint(Executable method, long location) { + setBreakpoints(new BP(method, location)); + } + + public void clearBreakpoints(BP... bs) { + for (BP b : bs) { + if (breaks.remove(b)) { + Breakpoint.clearBreakpoint(b.method, b.location); + } + } + } + public void clearBreakpoint(Executable method, long location) { + clearBreakpoints(new BP(method, location)); + } + + public void clearAllBreakpoints() { + clearBreakpoints(breaks.toArray(new BP[0])); + } + } + + public static void startBreakpointWatch(Class<?> methodClass, + Executable breakpointReached, + Thread thr) { + startBreakpointWatch(methodClass, breakpointReached, false, thr); + } + + /** + * Enables the trapping of breakpoint events. + * + * If allowRecursive == true then breakpoints will be sent even if one is currently being handled. + */ + public static native void startBreakpointWatch(Class<?> methodClass, + Executable breakpointReached, + boolean allowRecursive, + Thread thr); + public static native void stopBreakpointWatch(Thread thr); + + public static final class LineNumber implements Comparable<LineNumber> { + public final long location; + public final int line; + + private LineNumber(long loc, int line) { + this.location = loc; + this.line = line; + } + + public boolean equals(Object other) { + return other instanceof LineNumber && ((LineNumber)other).line == line && + ((LineNumber)other).location == location; + } + + public int compareTo(LineNumber other) { + int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line)); + if (v != 0) { + return v; + } else { + return Long.valueOf(location).compareTo(Long.valueOf(other.location)); + } + } + } + + public static native void setBreakpoint(Executable m, long loc); + public static void setBreakpoint(Executable m, LineNumber l) { + setBreakpoint(m, l.location); + } + + public static native void clearBreakpoint(Executable m, long loc); + public static void clearBreakpoint(Executable m, LineNumber l) { + clearBreakpoint(m, l.location); + } + + private static native Object[] getLineNumberTableNative(Executable m); + public static LineNumber[] getLineNumberTable(Executable m) { + Object[] nativeTable = getLineNumberTableNative(m); + long[] location = (long[])(nativeTable[0]); + int[] lines = (int[])(nativeTable[1]); + if (lines.length != location.length) { + throw new Error("Lines and locations have different lengths!"); + } + LineNumber[] out = new LineNumber[lines.length]; + for (int i = 0; i < lines.length; i++) { + out[i] = new LineNumber(location[i], lines[i]); + } + return out; + } + + public static native long getStartLocation(Executable m); + + public static int locationToLine(Executable m, long location) { + try { + Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m); + int best = -1; + for (Breakpoint.LineNumber l : lines) { + if (l.location > location) { + break; + } else { + best = l.line; + } + } + return best; + } catch (Exception e) { + return -1; + } + } + + public static long lineToLocation(Executable m, int line) throws Exception { + try { + Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m); + for (Breakpoint.LineNumber l : lines) { + if (l.line == line) { + return l.location; + } + } + throw new Exception("Unable to find line " + line + " in " + m); + } catch (Exception e) { + throw new Exception("Unable to get line number info for " + m, e); + } + } +} + diff --git a/test/1929-exception-catch-exception/src/art/Exceptions.java b/test/1929-exception-catch-exception/src/art/Exceptions.java new file mode 100644 index 0000000000..2c959ec83f --- /dev/null +++ b/test/1929-exception-catch-exception/src/art/Exceptions.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class Exceptions { + public static native void setupExceptionTracing( + Class<?> methodClass, + Class<?> exceptionClass, + Method exceptionEventMethod, + Method exceptionCaughtEventMethod); + + public static native void enableExceptionCatchEvent(Thread thr); + public static native void enableExceptionEvent(Thread thr); + public static native void disableExceptionCatchEvent(Thread thr); + public static native void disableExceptionEvent(Thread thr); +} diff --git a/test/1929-exception-catch-exception/src/art/StackTrace.java b/test/1929-exception-catch-exception/src/art/StackTrace.java new file mode 100644 index 0000000000..b12c3df66b --- /dev/null +++ b/test/1929-exception-catch-exception/src/art/StackTrace.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.lang.reflect.Field; +import java.lang.reflect.Executable; + +public class StackTrace { + public static class StackFrameData { + public final Thread thr; + public final Executable method; + public final long current_location; + public final int depth; + + public StackFrameData(Thread thr, Executable e, long loc, int depth) { + this.thr = thr; + this.method = e; + this.current_location = loc; + this.depth = depth; + } + @Override + public String toString() { + return String.format( + "StackFrameData { thr: '%s', method: '%s', loc: %d, depth: %d }", + this.thr, + this.method, + this.current_location, + this.depth); + } + } + + public static native int GetStackDepth(Thread thr); + + private static native StackFrameData[] nativeGetStackTrace(Thread thr); + + public static StackFrameData[] GetStackTrace(Thread thr) { + // The RI seems to give inconsistent (and sometimes nonsensical) results if the thread is not + // suspended. The spec says that not being suspended is fine but since we want this to be + // consistent we will suspend for the RI. + boolean suspend_thread = + !System.getProperty("java.vm.name").equals("Dalvik") && + !thr.equals(Thread.currentThread()); + if (suspend_thread) { + Suspension.suspend(thr); + } + StackFrameData[] out = nativeGetStackTrace(thr); + if (suspend_thread) { + Suspension.resume(thr); + } + return out; + } +} + diff --git a/test/1929-exception-catch-exception/src/art/Suspension.java b/test/1929-exception-catch-exception/src/art/Suspension.java new file mode 100644 index 0000000000..16e62ccac9 --- /dev/null +++ b/test/1929-exception-catch-exception/src/art/Suspension.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +public class Suspension { + // Suspends a thread using jvmti. + public native static void suspend(Thread thr); + + // Resumes a thread using jvmti. + public native static void resume(Thread thr); + + public native static boolean isSuspended(Thread thr); + + public native static int[] suspendList(Thread... threads); + public native static int[] resumeList(Thread... threads); +} diff --git a/test/1929-exception-catch-exception/src/art/Test1929.java b/test/1929-exception-catch-exception/src/art/Test1929.java new file mode 100644 index 0000000000..07d2087a0f --- /dev/null +++ b/test/1929-exception-catch-exception/src/art/Test1929.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Objects; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; + +public class Test1929 { + public static boolean PRINT_FULL_EXCEPTION = false; + public static ExceptionHandler HANDLER = null; + public static Collection<Executable> TEST_METHODS; + + public static void doNothing() {}; + static { + try { + TEST_METHODS = Arrays.asList( + Test1929.class.getDeclaredMethod("doThrow"), + Test1929.class.getDeclaredMethod("throwCatchBaseTestException"), + Test1929.class.getDeclaredMethod("throwCatchBaseTestExceptionTwice"), + Test1929.class.getDeclaredMethod("throwCatchTestException"), + Test1929.class.getDeclaredMethod("throwCatchTestExceptionTwice"), + Test1929.class.getDeclaredMethod("throwCatchTestExceptionNoRethrow")); + } catch (Exception e) { + throw new Error("Unable to list test methods!", e); + } + } + + public static interface ExceptionHandler { + public void exceptionOccurred( + Executable m, long loc, Throwable exception); + } + + private static void PrintStack() { + System.out.println("\tCurrent Stack:"); + for (StackTrace.StackFrameData e : StackTrace.GetStackTrace(Thread.currentThread())) { + if (Objects.equals(e.method.getDeclaringClass().getPackage(), Test1929.class.getPackage())) { + System.out.println("\t\t" + e.method + " @ line = " + + Breakpoint.locationToLine(e.method, e.current_location)); + } + } + } + + public static void ExceptionCatchEvent( + Thread thr, Executable method, long location, Throwable exception) { + System.out.println(thr.getName() + ": " + method + " @ line = " + + Breakpoint.locationToLine(method, location) + " caught " + + exception.getClass() + ": " + exception.getMessage()); + PrintStack(); + if (PRINT_FULL_EXCEPTION) { + System.out.print("exception is: "); + exception.printStackTrace(System.out); + } + if (HANDLER != null && TEST_METHODS.contains(method)) { + HANDLER.exceptionOccurred(method, location, exception); + } + } + + public static class BaseTestException extends Error { + public BaseTestException(String e) { super(e); } + public BaseTestException(String e, Throwable t) { super(e, t); } + } + public static class TestException extends BaseTestException { + public TestException(String e) { super(e); } + public TestException(String e, Throwable t) { super(e, t); } + } + + public static class TestExceptionNoRethrow extends TestException { + public TestExceptionNoRethrow(String e) { super(e); } + public TestExceptionNoRethrow(String e, Throwable t) { super(e, t); } + } + + public static class DoNothingHandler implements ExceptionHandler { + public void exceptionOccurred(Executable m, long loc, Throwable exception) { + System.out.println("\tDoing nothing!"); + return; + } + } + + public static class ThrowCatchBase implements ExceptionHandler { + public void exceptionOccurred(Executable m, long loc, Throwable exception) { + System.out.println("\tThrowing BaseTestException and catching it!"); + try { + throw new BaseTestException("ThrowBaseHandler during throw from " + m + " @ line = " + + Breakpoint.locationToLine(m, loc), exception); + } catch (BaseTestException t) { + System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } + } + public static class ThrowBaseTestExceptionHandler implements ExceptionHandler { + public void exceptionOccurred(Executable m, long loc, Throwable exception) { + System.out.println("\tThrowing BaseTestException!"); + throw new BaseTestException("ThrowBaseHandler during throw from " + m + " @ line = " + + Breakpoint.locationToLine(m, loc), exception); + } + } + + public static class ThrowTestExceptionNoRethrowHandler implements ExceptionHandler { + public void exceptionOccurred(Executable m, long loc, Throwable exception) { + if (exception instanceof TestExceptionNoRethrow) { + System.out.println("\tInstance of TestExceptionNoRethrow was thrown. Not throwing again."); + } else { + System.out.println("\tThrowing TestExceptionNoRethrow!"); + throw new TestExceptionNoRethrow("ThrowTestExceptionNoRethrowHandler during throw from " + + m + " @ line = " + Breakpoint.locationToLine(m, loc), exception); + } + } + } + public static void doThrow() { + throw new TestException("doThrow"); + } + + public static class DoThrowClass implements Runnable { + public void run() { doThrow(); } + } + + public static void throwCatchBaseTestException() { + try { + throw new TestException("throwCatchBaseTestException"); + } catch (BaseTestException t) { + System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } + + public static class DoThrowCatchBaseTestException implements Runnable { + public void run() { throwCatchBaseTestException(); } + } + + // dx/d8/jack all do an optimization around catch blocks that (while legal) breaks assumptions + // this test relies on so we have the actual implementation be corrected smali. This does work + // for RI however. + public static final class Impl { + private Impl() {} + public static void throwCatchBaseTestExceptionTwiceImpl() { + try { + try { + throw new TestException("throwCatchBaseTestExceptionTwice"); + } catch (BaseTestException t) { + System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } catch (BaseTestException t) { + System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } + + public static void throwCatchTestExceptionTwiceImpl() { + try { + try { + throw new TestException("throwCatchTestExceptionTwice"); + } catch (TestException t) { + System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } catch (TestException t) { + System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } + } + + public static void throwCatchBaseTestExceptionTwice() { + // The implementation of this has to change depending upon the runtime slightly due to compiler + // optimizations present in DX/D8/Jack. + Impl.throwCatchBaseTestExceptionTwiceImpl(); + } + + public static class DoThrowCatchBaseTestExceptionTwice implements Runnable { + public void run() { throwCatchBaseTestExceptionTwice(); } + } + + public static void throwCatchTestException() { + try { + throw new TestException("throwCatchTestException"); + } catch (TestException t) { + System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } + + public static class DoThrowCatchTestException implements Runnable { + public void run() { throwCatchTestException(); } + } + + public static void throwCatchTestExceptionTwice() { + // The implementation of this has to change depending upon the runtime slightly due to compiler + // optimizations present in DX/D8/Jack. + Impl.throwCatchTestExceptionTwiceImpl(); + } + + public static class DoThrowCatchTestExceptionTwice implements Runnable { + public void run() { throwCatchTestExceptionTwice(); } + } + + public static void throwCatchTestExceptionNoRethrow() { + try { + throw new TestException("throwCatchTestExceptionNoRethrow"); + } catch (TestExceptionNoRethrow t) { + System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); + if (PRINT_FULL_EXCEPTION) { + t.printStackTrace(System.out); + } + } + } + + public static class DoThrowCatchTestExceptionNoRethrow implements Runnable { + public void run() { throwCatchTestExceptionNoRethrow(); } + } + + public static void run() throws Exception { + // Set up breakpoints + Exceptions.setupExceptionTracing( + Test1929.class, + TestException.class, + null, + Test1929.class.getDeclaredMethod( + "ExceptionCatchEvent", + Thread.class, + Executable.class, + Long.TYPE, + Throwable.class)); + Exceptions.enableExceptionCatchEvent(Thread.currentThread()); + + ExceptionHandler[] handlers = new ExceptionHandler[] { + new DoNothingHandler(), + new ThrowCatchBase(), + new ThrowBaseTestExceptionHandler(), + new ThrowTestExceptionNoRethrowHandler(), + }; + + Runnable[] tests = new Runnable[] { + new DoThrowClass(), + new DoThrowCatchBaseTestException(), + new DoThrowCatchBaseTestExceptionTwice(), + new DoThrowCatchTestException(), + new DoThrowCatchTestExceptionTwice(), + new DoThrowCatchTestExceptionNoRethrow(), + }; + + for (ExceptionHandler handler : handlers) { + for (Runnable test : tests) { + try { + HANDLER = handler; + System.out.printf("Test \"%s\": Running breakpoint with handler \"%s\"\n", + test.getClass().getName(), handler.getClass().getName()); + test.run(); + System.out.printf("Test \"%s\": No error caught with handler \"%s\"\n", + test.getClass().getName(), handler.getClass().getName()); + } catch (Throwable e) { + System.out.printf("Test \"%s\": Caught error %s:\"%s\" with handler \"%s\"\n", + test.getClass().getName(), + e.getClass().getName(), + e.getMessage(), + handler.getClass().getName()); + if (PRINT_FULL_EXCEPTION) { + e.printStackTrace(System.out); + } + } + System.out.printf("Test \"%s\": Finished running with handler \"%s\"\n", + test.getClass().getName(), handler.getClass().getName()); + HANDLER = null; + } + } + Exceptions.disableExceptionCatchEvent(Thread.currentThread()); + } +} diff --git a/test/Android.bp b/test/Android.bp index 2aed50c455..2a88af11d6 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -254,6 +254,7 @@ art_cc_defaults { "ti-agent/suspension_helper.cc", "ti-agent/stack_trace_helper.cc", "ti-agent/trace_helper.cc", + "ti-agent/exceptions_helper.cc", // This is the list of non-special OnLoad things and excludes BCI and anything that depends // on ART internals. "903-hello-tagging/tagging.cc", @@ -298,6 +299,7 @@ art_cc_defaults { "1922-owned-monitors-info/owned_monitors.cc", "1924-frame-pop-toggle/frame_pop_toggle.cc", "1926-missed-frame-pop/frame_pop_missed.cc", + "1927-exception-event/exception_event.cc" ], shared_libs: [ "libbase", diff --git a/test/ti-agent/exceptions_helper.cc b/test/ti-agent/exceptions_helper.cc new file mode 100644 index 0000000000..74f7ecc881 --- /dev/null +++ b/test/ti-agent/exceptions_helper.cc @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_helper.h" + +#include "jni.h" +#include "jvmti.h" + +#include "jvmti_helper.h" +#include "scoped_local_ref.h" +#include "test_env.h" + +namespace art { + +namespace common_exceptions { + +struct ExceptionsData { + jclass test_klass; + jclass exception_klass; + jmethodID exception_event; + jmethodID exception_catch_event; +}; + +static void exceptionCB(jvmtiEnv* jvmti, + JNIEnv* jnienv, + jthread thread, + jmethodID throw_method, + jlocation throw_location, + jobject throwable, + jmethodID catch_method, + jlocation catch_location) { + ExceptionsData* data = nullptr; + if (JvmtiErrorToException(jnienv, jvmti, + jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) { + return; + } + DCHECK(throwable != nullptr); + if (!jnienv->IsInstanceOf(throwable, data->exception_klass)) { + return; + } + jthrowable e = jnienv->ExceptionOccurred(); + jnienv->ExceptionClear(); + CHECK(data->exception_event != nullptr); + jobject throw_method_arg = GetJavaMethod(jvmti, jnienv, throw_method); + jobject catch_method_arg = + catch_method != nullptr ? GetJavaMethod(jvmti, jnienv, catch_method) : nullptr; + jnienv->CallStaticVoidMethod(data->test_klass, + data->exception_event, + thread, + throw_method_arg, + static_cast<jlong>(throw_location), + throwable, + catch_method_arg, + static_cast<jlong>(catch_location)); + jnienv->DeleteLocalRef(throw_method_arg); + if (catch_method_arg != nullptr) { + jnienv->DeleteLocalRef(catch_method_arg); + } + if (e != nullptr) { + jnienv->Throw(e); + } +} + + +static void exceptionCatchCB(jvmtiEnv* jvmti, + JNIEnv* jnienv, + jthread thread, + jmethodID catch_method, + jlocation catch_location, + jobject throwable) { + ExceptionsData* data = nullptr; + if (JvmtiErrorToException(jnienv, jvmti, + jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) { + return; + } + if (!jnienv->IsSameObject(data->exception_klass, jnienv->GetObjectClass(throwable))) { + return; + } + jthrowable e = jnienv->ExceptionOccurred(); + jnienv->ExceptionClear(); + CHECK(data->exception_catch_event != nullptr); + jobject catch_method_arg = GetJavaMethod(jvmti, jnienv, catch_method); + jnienv->CallStaticVoidMethod(data->test_klass, + data->exception_catch_event, + thread, + catch_method_arg, + static_cast<jlong>(catch_location), + throwable); + jnienv->DeleteLocalRef(catch_method_arg); + if (e != nullptr) { + jnienv->Throw(e); + } +} + +extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_setupExceptionTracing( + JNIEnv* env, + jclass exception ATTRIBUTE_UNUSED, + jclass klass, + jclass except, + jobject exception_event, + jobject exception_catch_event) { + ExceptionsData* data = nullptr; + if (JvmtiErrorToException(env, + jvmti_env, + jvmti_env->Allocate(sizeof(ExceptionsData), + reinterpret_cast<unsigned char**>(&data)))) { + return; + } + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_generate_exception_events = 1; + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) { + return; + } + memset(data, 0, sizeof(ExceptionsData)); + data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(klass)); + data->exception_klass = reinterpret_cast<jclass>(env->NewGlobalRef(except)); + data->exception_event = + exception_event != nullptr ? env->FromReflectedMethod(exception_event) : nullptr; + data->exception_catch_event = + exception_catch_event != nullptr ? env->FromReflectedMethod(exception_catch_event) : nullptr; + + ExceptionsData* old_data = nullptr; + if (JvmtiErrorToException(env, jvmti_env, + jvmti_env->GetEnvironmentLocalStorage( + reinterpret_cast<void**>(&old_data)))) { + return; + } else if (old_data != nullptr && old_data->test_klass != nullptr) { + ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException")); + env->ThrowNew(rt_exception.get(), "Environment already has local storage set!"); + return; + } + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) { + return; + } + + jvmtiEventCallbacks cb; + memset(&cb, 0, sizeof(cb)); + cb.Exception = exceptionCB; + cb.ExceptionCatch = exceptionCatchCB; + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)))) { + return; + } +} + +extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_enableExceptionCatchEvent( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) { + JvmtiErrorToException(env, + jvmti_env, + jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, + JVMTI_EVENT_EXCEPTION_CATCH, + thr)); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_enableExceptionEvent( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) { + JvmtiErrorToException(env, + jvmti_env, + jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, + JVMTI_EVENT_EXCEPTION, + thr)); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_disableExceptionCatchEvent( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) { + JvmtiErrorToException(env, + jvmti_env, + jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, + JVMTI_EVENT_EXCEPTION_CATCH, + thr)); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_disableExceptionEvent( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) { + JvmtiErrorToException(env, + jvmti_env, + jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, + JVMTI_EVENT_EXCEPTION, + thr)); +} + +} // namespace common_exceptions + + +} // namespace art |