JVMTI Exception and ExceptionCatch events
Add support for the JVMTI can_generate_exception_events capability.
This includes the Exception and ExceptionCatch events and all their
associated behaviors.
Test: ./test.py --host -j50
Bug: 62821960
Bug: 65049545
Change-Id: I21cc8522c01033cdeb47bf34fa433bf04bf7ca5c
diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h
index d74e25b..93eee28 100644
--- a/openjdkjvmti/art_jvmti.h
+++ b/openjdkjvmti/art_jvmti.h
@@ -236,7 +236,7 @@
.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 acef682..c41e15e 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -48,6 +48,7 @@
#include "nativehelper/ScopedLocalRef.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
+#include "stack.h"
#include "thread-inl.h"
#include "thread_list.h"
#include "ti_phase.h"
@@ -552,10 +553,123 @@
}
}
+ static void FindCatchMethodsFromThrow(art::Thread* self,
+ art::Handle<art::mirror::Throwable> exception,
+ /*out*/ art::ArtMethod** out_method,
+ /*out*/ uint32_t* dex_pc)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ // Finds the location where this exception will most likely be caught. We ignore intervening
+ // native frames (which could catch the exception) and return the closest java frame with a
+ // compatible catch statement.
+ class CatchLocationFinder FINAL : public art::StackVisitor {
+ public:
+ CatchLocationFinder(art::Thread* target,
+ art::Handle<art::mirror::Class> exception_class,
+ art::Context* context,
+ /*out*/ art::ArtMethod** out_catch_method,
+ /*out*/ uint32_t* out_catch_pc)
+ REQUIRES_SHARED(art::Locks::mutator_lock_)
+ : StackVisitor(target, context, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+ exception_class_(exception_class),
+ catch_method_ptr_(out_catch_method),
+ catch_dex_pc_ptr_(out_catch_pc) {}
+
+ bool VisitFrame() OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ art::ArtMethod* method = GetMethod();
+ DCHECK(method != nullptr);
+ if (method->IsRuntimeMethod()) {
+ return true;
+ }
+
+ if (!method->IsNative()) {
+ uint32_t cur_dex_pc = GetDexPc();
+ if (cur_dex_pc == art::DexFile::kDexNoIndex) {
+ // This frame looks opaque. Just keep on going.
+ return true;
+ }
+ bool has_no_move_exception = false;
+ uint32_t found_dex_pc = method->FindCatchBlock(
+ exception_class_, cur_dex_pc, &has_no_move_exception);
+ if (found_dex_pc != art::DexFile::kDexNoIndex) {
+ // We found the catch. Store the result and return.
+ *catch_method_ptr_ = method;
+ *catch_dex_pc_ptr_ = found_dex_pc;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ art::Handle<art::mirror::Class> exception_class_;
+ art::ArtMethod** catch_method_ptr_;
+ uint32_t* catch_dex_pc_ptr_;
+
+ DISALLOW_COPY_AND_ASSIGN(CatchLocationFinder);
+ };
+
+ art::StackHandleScope<1> hs(self);
+ *out_method = nullptr;
+ *dex_pc = 0;
+ std::unique_ptr<art::Context> context(art::Context::Create());
+
+ CatchLocationFinder clf(self,
+ hs.NewHandle(exception->GetClass()),
+ context.get(),
+ /*out*/ out_method,
+ /*out*/ dex_pc);
+ clf.WalkStack(/* include_transitions */ false);
+ }
+
// Call-back when an exception is thrown.
- void ExceptionThrown(art::Thread* self ATTRIBUTE_UNUSED,
- art::Handle<art::mirror::Throwable> exception_object ATTRIBUTE_UNUSED)
+ void ExceptionThrown(art::Thread* self, art::Handle<art::mirror::Throwable> exception_object)
REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE {
+ DCHECK(self->IsExceptionThrownByCurrentMethod(exception_object.Get()));
+ // The instrumentation events get rid of this for us.
+ DCHECK(!self->IsExceptionPending());
+ if (event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kException)) {
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ art::ArtMethod* catch_method;
+ uint32_t catch_pc;
+ FindCatchMethodsFromThrow(self, exception_object, &catch_method, &catch_pc);
+ uint32_t dex_pc = 0;
+ art::ArtMethod* method = self->GetCurrentMethod(&dex_pc,
+ /* check_suspended */ true,
+ /* abort_on_error */ art::kIsDebugBuild);
+ ScopedLocalRef<jobject> exception(jnienv,
+ AddLocalRef<jobject>(jnienv, exception_object.Get()));
+ RunEventCallback<ArtJvmtiEvent::kException>(
+ self,
+ jnienv,
+ art::jni::EncodeArtMethod(method),
+ static_cast<jlocation>(dex_pc),
+ exception.get(),
+ art::jni::EncodeArtMethod(catch_method),
+ static_cast<jlocation>(catch_pc));
+ }
+ return;
+ }
+
+ // Call-back when an exception is handled.
+ void ExceptionHandled(art::Thread* self, art::Handle<art::mirror::Throwable> exception_object)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE {
+ // Since the exception has already been handled there shouldn't be one pending.
+ DCHECK(!self->IsExceptionPending());
+ if (event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kExceptionCatch)) {
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ uint32_t dex_pc;
+ art::ArtMethod* method = self->GetCurrentMethod(&dex_pc,
+ /* check_suspended */ true,
+ /* abort_on_error */ art::kIsDebugBuild);
+ ScopedLocalRef<jobject> exception(jnienv,
+ AddLocalRef<jobject>(jnienv, exception_object.Get()));
+ RunEventCallback<ArtJvmtiEvent::kExceptionCatch>(
+ self,
+ jnienv,
+ art::jni::EncodeArtMethod(method),
+ static_cast<jlocation>(dex_pc),
+ exception.get());
+ }
return;
}
@@ -598,6 +712,10 @@
return art::instrumentation::Instrumentation::kDexPcMoved;
case ArtJvmtiEvent::kFramePop:
return art::instrumentation::Instrumentation::kWatchedFramePop;
+ case ArtJvmtiEvent::kException:
+ return art::instrumentation::Instrumentation::kExceptionThrown;
+ case ArtJvmtiEvent::kExceptionCatch:
+ return art::instrumentation::Instrumentation::kExceptionHandled;
default:
LOG(FATAL) << "Unknown event ";
return 0;
@@ -677,6 +795,8 @@
case ArtJvmtiEvent::kMethodExit:
case ArtJvmtiEvent::kFieldAccess:
case ArtJvmtiEvent::kFieldModification:
+ case ArtJvmtiEvent::kException:
+ case ArtJvmtiEvent::kExceptionCatch:
SetupTraceListener(method_trace_listener_.get(), event, enable);
return;
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index fe0bad2..af56810 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -262,6 +262,13 @@
<< " " << 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 05384b4..6e457a4 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -108,6 +108,7 @@
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 @@
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 @@
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 @@
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 114db76..fec027e 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -130,6 +130,10 @@
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 @@
kBranch = 0x80,
kInvokeVirtualOrInterface = 0x100,
kWatchedFramePop = 0x200,
+ kExceptionHandled = 0x400,
};
enum class InstrumentationLevel {
@@ -349,12 +354,16 @@
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 @@
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 @@
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 @@
// 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 @@
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 7390f4f..9b77d12 100644
--- a/runtime/instrumentation_test.cc
+++ b/runtime/instrumentation_test.cc
@@ -48,6 +48,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
(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 @@
// 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 @@
/*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 9cb74f7..86fe33d 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -522,10 +522,8 @@
// 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.
@@ -570,7 +568,6 @@
// the deoptimization.
}
if (new_dex_pc != DexFile::kDexNoIndex) {
- shadow_frame->SetDexPC(new_dex_pc);
value = Execute(self, code_item, *shadow_frame, value);
}
ShadowFrame* old_frame = shadow_frame;
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index ae461fd..0028b21 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -416,35 +416,57 @@
#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 5b942f2..82e12f5 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -462,9 +462,17 @@
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 f352960..69e091b 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -30,10 +30,7 @@
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 @@
} \
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 88254a8..b8a7a2a 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -490,15 +490,7 @@
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 d7673f3..b30de79 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -811,6 +811,12 @@
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 8b0931d..49d5b22 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -181,6 +181,8 @@
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 0000000..3197bcd
--- /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 0000000..be8f39c
--- /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 0000000..a74167f
--- /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 0000000..51875a7
--- /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 0000000..5b9b31b
--- /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 0000000..bbb89f7
--- /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 0000000..2c959ec
--- /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 0000000..b12c3df
--- /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 0000000..16e62cc
--- /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 0000000..c2d13bb
--- /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 0000000..1692d04
--- /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 0000000..ef84746
--- /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 0000000..51875a7
--- /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 0000000..11cc773
--- /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 0000000..bbb89f7
--- /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 0000000..2c959ec
--- /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 0000000..b12c3df
--- /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 0000000..16e62cc
--- /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 0000000..aec88a4
--- /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 0000000..7c23a31
--- /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 0000000..2d9b3a0
--- /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 0000000..51875a7
--- /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 0000000..4edd56f
--- /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 0000000..4651bac
--- /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 0000000..bbb89f7
--- /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 0000000..2c959ec
--- /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 0000000..b12c3df
--- /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 0000000..16e62cc
--- /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 0000000..07d2087
--- /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 2aed50c..2a88af1 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -254,6 +254,7 @@
"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 @@
"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 0000000..74f7ecc
--- /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