diff options
-rw-r--r-- | openjdkjvmti/events.cc | 10 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 30 | ||||
-rw-r--r-- | test/988-method-trace/expected.txt | 38 | ||||
-rw-r--r-- | test/988-method-trace/src/art/Test988.java | 71 |
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. } |