summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--openjdkjvmti/events.cc10
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc30
-rw-r--r--test/988-method-trace/expected.txt38
-rw-r--r--test/988-method-trace/src/art/Test988.java71
4 files changed, 112 insertions, 37 deletions
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index 5cb4299293..f71a5dc72d 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -504,8 +504,9 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE {
if (!method->IsRuntimeMethod() &&
event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMethodExit)) {
- DCHECK_EQ(method->GetReturnTypePrimitive(), art::Primitive::kPrimNot)
- << method->PrettyMethod();
+ DCHECK_EQ(
+ method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize)->GetReturnTypePrimitive(),
+ art::Primitive::kPrimNot) << method->PrettyMethod();
DCHECK(!self->IsExceptionPending());
jvalue val;
art::JNIEnvExt* jnienv = self->GetJniEnv();
@@ -530,8 +531,9 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE {
if (!method->IsRuntimeMethod() &&
event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMethodExit)) {
- DCHECK_NE(method->GetReturnTypePrimitive(), art::Primitive::kPrimNot)
- << method->PrettyMethod();
+ DCHECK_NE(
+ method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize)->GetReturnTypePrimitive(),
+ art::Primitive::kPrimNot) << method->PrettyMethod();
DCHECK(!self->IsExceptionPending());
jvalue val;
art::JNIEnvExt* jnienv = self->GetJniEnv();
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index a4dea37f68..379292db71 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -948,8 +948,36 @@ extern "C" uint64_t artQuickProxyInvokeHandler(
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();
}
diff --git a/test/988-method-trace/expected.txt b/test/988-method-trace/expected.txt
index 6e16722d53..75ee112c60 100644
--- a/test/988-method-trace/expected.txt
+++ b/test/988-method-trace/expected.txt
@@ -145,10 +145,10 @@ fibonacci(5)=5
......=> private static java.lang.Object java.lang.Throwable.nativeFillInStackTrace()
......<= private static java.lang.Object java.lang.Throwable.nativeFillInStackTrace() -> <class [Ljava.lang.Object;: <non-deterministic>>
.....<= public synchronized java.lang.Throwable java.lang.Throwable.fillInStackTrace() -> <class java.lang.Error: java.lang.Error: Bad argument: -19 < 0
- art.Test988.iter_fibonacci(Test988.java:235)
- art.Test988$IterOp.applyAsInt(Test988.java:230)
- art.Test988.doFibTest(Test988.java:339)
- art.Test988.run(Test988.java:304)
+ art.Test988.iter_fibonacci(Test988.java:255)
+ art.Test988$IterOp.applyAsInt(Test988.java:250)
+ art.Test988.doFibTest(Test988.java:378)
+ art.Test988.run(Test988.java:336)
<additional hidden frames>
>
....<= public java.lang.Throwable(java.lang.String) -> <null: null>
@@ -165,10 +165,10 @@ fibonacci(5)=5
...<= private void java.util.ArrayList.ensureExplicitCapacity(int) -> <null: null>
..<= private void java.util.ArrayList.ensureCapacityInternal(int) -> <null: null>
fibonacci(-19) -> java.lang.Error: Bad argument: -19 < 0
- art.Test988.iter_fibonacci(Test988.java:235)
- art.Test988$IterOp.applyAsInt(Test988.java:230)
- art.Test988.doFibTest(Test988.java:339)
- art.Test988.run(Test988.java:304)
+ art.Test988.iter_fibonacci(Test988.java:255)
+ art.Test988$IterOp.applyAsInt(Test988.java:250)
+ art.Test988.doFibTest(Test988.java:378)
+ art.Test988.run(Test988.java:336)
<additional hidden frames>
.<= public boolean java.util.ArrayList.add(java.lang.Object) -> <class java.lang.Boolean: true>
@@ -248,10 +248,10 @@ fibonacci(-19) -> java.lang.Error: Bad argument: -19 < 0
......=> private static java.lang.Object java.lang.Throwable.nativeFillInStackTrace()
......<= private static java.lang.Object java.lang.Throwable.nativeFillInStackTrace() -> <class [Ljava.lang.Object;: <non-deterministic>>
.....<= public synchronized java.lang.Throwable java.lang.Throwable.fillInStackTrace() -> <class java.lang.Error: java.lang.Error: Bad argument: -19 < 0
- art.Test988.fibonacci(Test988.java:257)
- art.Test988$RecurOp.applyAsInt(Test988.java:252)
- art.Test988.doFibTest(Test988.java:339)
- art.Test988.run(Test988.java:305)
+ art.Test988.fibonacci(Test988.java:277)
+ art.Test988$RecurOp.applyAsInt(Test988.java:272)
+ art.Test988.doFibTest(Test988.java:378)
+ art.Test988.run(Test988.java:337)
<additional hidden frames>
>
....<= public java.lang.Throwable(java.lang.String) -> <null: null>
@@ -268,14 +268,20 @@ fibonacci(-19) -> java.lang.Error: Bad argument: -19 < 0
...<= private void java.util.ArrayList.ensureExplicitCapacity(int) -> <null: null>
..<= private void java.util.ArrayList.ensureCapacityInternal(int) -> <null: null>
fibonacci(-19) -> java.lang.Error: Bad argument: -19 < 0
- art.Test988.fibonacci(Test988.java:257)
- art.Test988$RecurOp.applyAsInt(Test988.java:252)
- art.Test988.doFibTest(Test988.java:339)
- art.Test988.run(Test988.java:305)
+ art.Test988.fibonacci(Test988.java:277)
+ art.Test988$RecurOp.applyAsInt(Test988.java:272)
+ art.Test988.doFibTest(Test988.java:378)
+ art.Test988.run(Test988.java:337)
<additional hidden frames>
.<= public boolean java.util.ArrayList.add(java.lang.Object) -> <class java.lang.Boolean: true>
<= public static void art.Test988.doFibTest(int,java.util.function.IntUnaryOperator) -> <null: null>
+=> public final void <non-deterministic-type 0>.run()
+.=> private static java.lang.Object java.lang.reflect.Proxy.invoke(java.lang.reflect.Proxy,java.lang.reflect.Method,java.lang.Object[]) throws java.lang.Throwable
+..=> public java.lang.Object art.Test988$TestRunnableInvokeHandler.invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object[]) throws java.lang.Throwable
+..<= public java.lang.Object art.Test988$TestRunnableInvokeHandler.invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object[]) throws java.lang.Throwable -> <null: null>
+.<= private static java.lang.Object java.lang.reflect.Proxy.invoke(java.lang.reflect.Proxy,java.lang.reflect.Method,java.lang.Object[]) throws java.lang.Throwable -> <null: null>
+<= public final void <non-deterministic-type 0>.run() -> <null: null>
=> static void art.Test988$IntrinsicsTest.doTest()
.=> static void art.Test988Intrinsics.test()
..=> public static long java.lang.Double.doubleToRawLongBits(double)
diff --git a/test/988-method-trace/src/art/Test988.java b/test/988-method-trace/src/art/Test988.java
index d7eda524c4..5720d1d87d 100644
--- a/test/988-method-trace/src/art/Test988.java
+++ b/test/988-method-trace/src/art/Test988.java
@@ -18,20 +18,25 @@ package art;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.util.Arrays;
+import java.lang.reflect.Executable;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Set;
+import java.lang.reflect.Proxy;
import java.util.ArrayList;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
-import java.util.function.IntUnaryOperator;
+import java.util.List;
+import java.util.Set;
import java.util.function.Function;
+import java.util.function.IntUnaryOperator;
public class Test988 {
// Methods with non-deterministic output that should not be printed.
static Set<Method> NON_DETERMINISTIC_OUTPUT_METHODS = new HashSet<>();
static Set<Method> NON_DETERMINISTIC_OUTPUT_TYPE_METHODS = new HashSet<>();
+ static List<Class<?>> NON_DETERMINISTIC_TYPE_NAMES = new ArrayList<>();
static {
try {
@@ -42,6 +47,10 @@ public class Test988 {
NON_DETERMINISTIC_OUTPUT_METHODS.add(Thread.class.getDeclaredMethod("currentThread"));
NON_DETERMINISTIC_OUTPUT_TYPE_METHODS.add(Thread.class.getDeclaredMethod("currentThread"));
} catch (Exception e) {}
+ try {
+ NON_DETERMINISTIC_TYPE_NAMES.add(
+ Proxy.getProxyClass(Test988.class.getClassLoader(), new Class[] { Runnable.class }));
+ } catch (Exception e) {}
}
static interface Printable {
@@ -49,9 +58,9 @@ public class Test988 {
}
static final class MethodEntry implements Printable {
- private Object m;
+ private Executable m;
private int cnt;
- public MethodEntry(Object m, int cnt) {
+ public MethodEntry(Executable m, int cnt) {
this.m = m;
this.cnt = cnt;
}
@@ -124,18 +133,26 @@ public class Test988 {
}
}
- static String methodToString(Object m) {
+ static String methodToString(Executable m) {
// Make the output more similar between ART and RI,
// by removing the 'native' specifier from methods.
- String methodStr = m.toString();
+ String methodStr;
+ if (NON_DETERMINISTIC_TYPE_NAMES.contains(m.getDeclaringClass())) {
+ methodStr = m.toString().replace(m.getDeclaringClass().getName(),
+ "<non-deterministic-type " +
+ NON_DETERMINISTIC_TYPE_NAMES.indexOf(m.getDeclaringClass()) +
+ ">");
+ } else {
+ methodStr = m.toString();
+ }
return methodStr.replaceFirst(" native", "");
}
static final class MethodReturn implements Printable {
- private Object m;
+ private Executable m;
private Object val;
private int cnt;
- public MethodReturn(Object m, Object val, int cnt) {
+ public MethodReturn(Executable m, Object val, int cnt) {
this.m = m;
this.val = val;
this.cnt = cnt;
@@ -155,6 +172,9 @@ public class Test988 {
String klass_print;
if (klass == null) {
klass_print = "null";
+ } else if (NON_DETERMINISTIC_TYPE_NAMES.contains(klass)) {
+ klass_print = "<non-deterministic-class " +
+ NON_DETERMINISTIC_TYPE_NAMES.indexOf(klass) + ">";
} else if (NON_DETERMINISTIC_OUTPUT_TYPE_METHODS.contains(m)) {
klass_print = "<non-deterministic>";
} else {
@@ -166,9 +186,9 @@ public class Test988 {
}
static final class MethodThrownThrough implements Printable {
- private Object m;
+ private Executable m;
private int cnt;
- public MethodThrownThrough(Object m, int cnt) {
+ public MethodThrownThrough(Executable m, int cnt) {
this.m = m;
this.cnt = cnt;
}
@@ -262,10 +282,16 @@ public class Test988 {
}
}
+ static final class TestRunnableInvokeHandler implements InvocationHandler {
+ public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
+ return null;
+ }
+ }
+
static final int METHOD_TRACING_IGNORE_DEPTH = 2;
static boolean sMethodTracingIgnore = false;
- public static void notifyMethodEntry(Object m) {
+ public static void notifyMethodEntry(Executable m) {
// Called by native code when a method is entered. This method is ignored by the native
// entry and exit hooks.
cnt++;
@@ -275,7 +301,7 @@ public class Test988 {
results.add(new MethodEntry(m, cnt - 1));
}
- public static void notifyMethodExit(Object m, boolean exception, Object result) {
+ public static void notifyMethodExit(Executable m, boolean exception, Object result) {
cnt--;
if (cnt > METHOD_TRACING_IGNORE_DEPTH && sMethodTracingIgnore) {
@@ -293,17 +319,25 @@ public class Test988 {
// call this here so it is linked. It doesn't actually do anything here.
loadAllClasses();
Trace.disableTracing(Thread.currentThread());
+ // Call this prior to starting tracing since its implementation is so deep into reflection
+ // that it will be changing all the time and difficult to keep up with.
+ Runnable runnable = (Runnable)Proxy.newProxyInstance(
+ Test988.class.getClassLoader(),
+ new Class[]{ Runnable.class },
+ new TestRunnableInvokeHandler());
Trace.enableMethodTracing(
Test988.class,
- Test988.class.getDeclaredMethod("notifyMethodEntry", Object.class),
+ Test988.class.getDeclaredMethod("notifyMethodEntry", Executable.class),
Test988.class.getDeclaredMethod(
- "notifyMethodExit", Object.class, Boolean.TYPE, Object.class),
+ "notifyMethodExit", Executable.class, Boolean.TYPE, Object.class),
Thread.currentThread());
doFibTest(30, new IterOp());
doFibTest(5, new RecurOp());
doFibTest(-19, new IterOp());
doFibTest(-19, new RecurOp());
+ runnable.run();
+
sMethodTracingIgnore = true;
IntrinsicsTest.doTest();
sMethodTracingIgnore = false;
@@ -325,6 +359,11 @@ public class Test988 {
RecurOp.class.toString();
IterOp.class.toString();
StringBuilder.class.toString();
+ Runnable.class.toString();
+ TestRunnableInvokeHandler.class.toString();
+ Proxy.class.toString();
+ Proxy.getProxyClass(
+ Test988.class.getClassLoader(), new Class[] { Runnable.class }).toString();
IntrinsicsTest.initialize(); // ensure <clinit> is executed prior to tracing.
}