Ensure proxy methods are reported by instrumentation

Previously we would not report proxy methods to instrumentation in all
cases. Specifically if the instrumentation trampolines were not
installed we would never report proxy method entry or exit. This fixes
that and ensures that proxy methods are always reported to
instrumentation regardless of what instrumentation method is being
used. It also ensures that these methods will only ever be reported
once per entry.

Test: ./test.py --host
Test: ./test/testrunner/testrunner.py \
         --host \
         --run-test-option='--with-agent libtifast.so=MethodEntry,MethodExit'

Change-Id: I78f1d4b3b3f242e8915989ab26f7c204baab08e5
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index a4dea37..379292d 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -948,8 +948,36 @@
   jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_reflect_method);
 
   // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
-  // that performs allocations.
+  // that performs allocations or instrumentation events.
+  instrumentation::Instrumentation* instr = Runtime::Current()->GetInstrumentation();
+  if (instr->HasMethodEntryListeners()) {
+    instr->MethodEnterEvent(soa.Self(),
+                            soa.Decode<mirror::Object>(rcvr_jobj).Ptr(),
+                            proxy_method,
+                            0);
+    if (soa.Self()->IsExceptionPending()) {
+      instr->MethodUnwindEvent(self,
+                               soa.Decode<mirror::Object>(rcvr_jobj).Ptr(),
+                               proxy_method,
+                               0);
+      return 0;
+    }
+  }
   JValue result = InvokeProxyInvocationHandler(soa, shorty, rcvr_jobj, interface_method_jobj, args);
+  if (soa.Self()->IsExceptionPending()) {
+    if (instr->HasMethodUnwindListeners()) {
+      instr->MethodUnwindEvent(self,
+                               soa.Decode<mirror::Object>(rcvr_jobj).Ptr(),
+                               proxy_method,
+                               0);
+    }
+  } else if (instr->HasMethodExitListeners()) {
+    instr->MethodExitEvent(self,
+                           soa.Decode<mirror::Object>(rcvr_jobj).Ptr(),
+                           proxy_method,
+                           0,
+                           result);
+  }
   return result.GetJ();
 }