Add method tracing JVMTI callbacks
Add MethodEntryHook and MethodExitHook callbacks and associated
capabilities.
Split --jvmti-stress option in run-test into --jvmti-trace-stress and
--jvmti-redefine-stress to test each different component.
NB 3 differences from RI found:
1) RI will call methodExitHook again if the method exit hook throws
an exception. This can easily cause an infinite loop and the test
is specifically tweaked to prevent this from happening on the RI.
2) RI always includes the method being exited in the stack trace of
errors thrown in the hooks. In ART we will not include the method
if it is native. This is due to the way we call native methods
and would be extremely difficult to change.
3) The RI will allow exceptions thrown in the MethodEnterHook to be
caught by the entered method in some situations. This occurs with
the tryCatchExit test in 989. In ART this does not happen.
Bug: 34414073
Test: ./test.py --host -j40
Test: ART_TEST_FULL=true DEXTER_BINARY="/path/to/dexter" \
./test/testrunner/testrunner.py --host -j40 -t 988
Test: ART_TEST_FULL=true DEXTER_BINARY="/path/to/dexter" \
./test/testrunner/testrunner.py --host -j40 -t 989
Test: lunch aosp_angler-userdebug; \
m -j40 droid build-art && \
fastboot -w flashall && \
./test.py --target -j4
Change-Id: Iab229353fae23c2ea27c2b698c831627a9f861b1
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 32a2378..45788e7 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -26,13 +26,13 @@
namespace art {
namespace interpreter {
-#define HANDLE_PENDING_EXCEPTION() \
+#define HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instr) \
do { \
DCHECK(self->IsExceptionPending()); \
self->AllowThreadSuspension(); \
uint32_t found_dex_pc = FindNextInstructionFollowingException(self, shadow_frame, \
inst->GetDexPc(insns), \
- instrumentation); \
+ instr); \
if (found_dex_pc == DexFile::kDexNoIndex) { \
/* Structured locking is to be enforced for abnormal termination, too. */ \
DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame); \
@@ -47,6 +47,8 @@
} \
} while (false)
+#define HANDLE_PENDING_EXCEPTION() HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instrumentation)
+
#define POSSIBLY_HANDLE_PENDING_EXCEPTION(_is_exception_pending, _next_function) \
do { \
if (UNLIKELY(_is_exception_pending)) { \
@@ -218,6 +220,10 @@
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), inst->GetDexPc(insns),
result);
+ if (UNLIKELY(self->IsExceptionPending())) {
+ // Don't send another method exit event.
+ HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+ }
}
if (interpret_one_instruction) {
/* Signal mterp to return to caller */
@@ -235,6 +241,10 @@
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), inst->GetDexPc(insns),
result);
+ if (UNLIKELY(self->IsExceptionPending())) {
+ // Don't send another method exit event.
+ HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+ }
}
if (interpret_one_instruction) {
/* Signal mterp to return to caller */
@@ -253,6 +263,10 @@
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), inst->GetDexPc(insns),
result);
+ if (UNLIKELY(self->IsExceptionPending())) {
+ // Don't send another method exit event.
+ HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+ }
}
if (interpret_one_instruction) {
/* Signal mterp to return to caller */
@@ -270,6 +284,10 @@
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), inst->GetDexPc(insns),
result);
+ if (UNLIKELY(self->IsExceptionPending())) {
+ // Don't send another method exit event.
+ HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+ }
}
if (interpret_one_instruction) {
/* Signal mterp to return to caller */
@@ -307,6 +325,10 @@
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), inst->GetDexPc(insns),
result);
+ if (UNLIKELY(self->IsExceptionPending())) {
+ // Don't send another method exit event.
+ HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+ }
// Re-load since it might have moved during the MethodExitEvent.
result.SetL(shadow_frame.GetVRegReference(ref_idx));
}