diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/1941-dispose-stress/dispose_stress.cc | 59 | ||||
| -rw-r--r-- | test/1941-dispose-stress/expected.txt | 1 | ||||
| -rw-r--r-- | test/1941-dispose-stress/info.txt | 3 | ||||
| -rwxr-xr-x | test/1941-dispose-stress/run | 18 | ||||
| -rw-r--r-- | test/1941-dispose-stress/src/Main.java | 21 | ||||
| -rw-r--r-- | test/1941-dispose-stress/src/art/Breakpoint.java | 202 | ||||
| -rw-r--r-- | test/1941-dispose-stress/src/art/Test1941.java | 72 | ||||
| -rw-r--r-- | test/1941-dispose-stress/src/art/Trace.java | 68 | ||||
| -rw-r--r-- | test/Android.bp | 1 |
9 files changed, 445 insertions, 0 deletions
diff --git a/test/1941-dispose-stress/dispose_stress.cc b/test/1941-dispose-stress/dispose_stress.cc new file mode 100644 index 0000000000..e8fcc775e9 --- /dev/null +++ b/test/1941-dispose-stress/dispose_stress.cc @@ -0,0 +1,59 @@ +/* + * 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 <atomic> + +#include "android-base/logging.h" +#include "jni.h" +#include "scoped_local_ref.h" +#include "scoped_primitive_array.h" + +#include "jvmti.h" + +// Test infrastructure +#include "jvmti_helper.h" +#include "test_env.h" + +namespace art { +namespace Test1941DisposeStress { + +extern "C" JNIEXPORT jlong JNICALL Java_art_Test1941_AllocEnv(JNIEnv* env, jclass) { + JavaVM* vm = nullptr; + if (env->GetJavaVM(&vm) != 0) { + ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException")); + env->ThrowNew(rt_exception.get(), "Unable to get JavaVM"); + return -1; + } + jvmtiEnv* new_env = nullptr; + if (vm->GetEnv(reinterpret_cast<void**>(&new_env), JVMTI_VERSION_1_0) != 0) { + ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException")); + env->ThrowNew(rt_exception.get(), "Unable to create new jvmtiEnv"); + return -1; + } + return static_cast<jlong>(reinterpret_cast<intptr_t>(new_env)); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1941_FreeEnv(JNIEnv* env, + jclass, + jlong jvmti_env_ptr) { + JvmtiErrorToException(env, + jvmti_env, + reinterpret_cast<jvmtiEnv*>(jvmti_env_ptr)->DisposeEnvironment()); +} + +} // namespace Test1941DisposeStress +} // namespace art + diff --git a/test/1941-dispose-stress/expected.txt b/test/1941-dispose-stress/expected.txt new file mode 100644 index 0000000000..ca2eddc7b8 --- /dev/null +++ b/test/1941-dispose-stress/expected.txt @@ -0,0 +1 @@ +fib(20) is 6765 diff --git a/test/1941-dispose-stress/info.txt b/test/1941-dispose-stress/info.txt new file mode 100644 index 0000000000..e4a584e46f --- /dev/null +++ b/test/1941-dispose-stress/info.txt @@ -0,0 +1,3 @@ +Test basic JVMTI single step functionality. + +Ensures that we can receive single step events from JVMTI. diff --git a/test/1941-dispose-stress/run b/test/1941-dispose-stress/run new file mode 100755 index 0000000000..51875a7e86 --- /dev/null +++ b/test/1941-dispose-stress/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/1941-dispose-stress/src/Main.java b/test/1941-dispose-stress/src/Main.java new file mode 100644 index 0000000000..2fe6b818a0 --- /dev/null +++ b/test/1941-dispose-stress/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.Test1941.run(); + } +} diff --git a/test/1941-dispose-stress/src/art/Breakpoint.java b/test/1941-dispose-stress/src/art/Breakpoint.java new file mode 100644 index 0000000000..bbb89f707f --- /dev/null +++ b/test/1941-dispose-stress/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/1941-dispose-stress/src/art/Test1941.java b/test/1941-dispose-stress/src/art/Test1941.java new file mode 100644 index 0000000000..d5a9de6cab --- /dev/null +++ b/test/1941-dispose-stress/src/art/Test1941.java @@ -0,0 +1,72 @@ +/* + * 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.lang.reflect.Executable; +import java.lang.reflect.Method; + +public class Test1941 { + public static final boolean PRINT_CNT = false; + public static long CNT = 0; + + // Method with multiple paths we can break on. + public static long fib(long f) { + if (f < 0) { + throw new IllegalArgumentException("Bad argument f < 0: f = " + f); + } else if (f == 0) { + return 0; + } else if (f == 1) { + return 1; + } else { + return fib(f - 1) + fib(f - 2); + } + } + + public static void notifySingleStep(Thread thr, Executable e, long loc) { + // Don't bother actually doing anything. + } + + public static void LoopAllocFreeEnv() { + while (!Thread.interrupted()) { + CNT++; + long env = AllocEnv(); + FreeEnv(env); + } + } + + public static native long AllocEnv(); + public static native void FreeEnv(long env); + + public static void run() throws Exception { + Thread thr = new Thread(Test1941::LoopAllocFreeEnv, "LoopNative"); + thr.start(); + Trace.enableSingleStepTracing(Test1941.class, + Test1941.class.getDeclaredMethod( + "notifySingleStep", Thread.class, Executable.class, Long.TYPE), + null); + + System.out.println("fib(20) is " + fib(20)); + + thr.interrupt(); + thr.join(); + Trace.disableTracing(null); + if (PRINT_CNT) { + System.out.println("Number of envs created/destroyed: " + CNT); + } + } +} diff --git a/test/1941-dispose-stress/src/art/Trace.java b/test/1941-dispose-stress/src/art/Trace.java new file mode 100644 index 0000000000..8999bb1368 --- /dev/null +++ b/test/1941-dispose-stress/src/art/Trace.java @@ -0,0 +1,68 @@ +/* + * 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 Trace { + public static native void enableTracing(Class<?> methodClass, + Method entryMethod, + Method exitMethod, + Method fieldAccess, + Method fieldModify, + Method singleStep, + Thread thr); + public static native void disableTracing(Thread thr); + + public static void enableFieldTracing(Class<?> methodClass, + Method fieldAccess, + Method fieldModify, + Thread thr) { + enableTracing(methodClass, null, null, fieldAccess, fieldModify, null, thr); + } + + public static void enableMethodTracing(Class<?> methodClass, + Method entryMethod, + Method exitMethod, + Thread thr) { + enableTracing(methodClass, entryMethod, exitMethod, null, null, null, thr); + } + + public static void enableSingleStepTracing(Class<?> methodClass, + Method singleStep, + Thread thr) { + enableTracing(methodClass, null, null, null, null, singleStep, thr); + } + + public static native void watchFieldAccess(Field f); + public static native void watchFieldModification(Field f); + public static native void watchAllFieldAccesses(); + public static native void watchAllFieldModifications(); + + // the names, arguments, and even line numbers of these functions are embedded in the tests so we + // need to add to the bottom and not modify old ones to maintain compat. + public static native void enableTracing2(Class<?> methodClass, + Method entryMethod, + Method exitMethod, + Method fieldAccess, + Method fieldModify, + Method singleStep, + Method ThreadStart, + Method ThreadEnd, + Thread thr); +} diff --git a/test/Android.bp b/test/Android.bp index ba24119e9c..8f29251907 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -259,6 +259,7 @@ art_cc_defaults { "1932-monitor-events-misc/monitor_misc.cc", "1934-jvmti-signal-thread/signal_threads.cc", "1939-proxy-frames/local_instance.cc", + "1941-dispose-stress/dispose_stress.cc", ], shared_libs: [ "libbase", |