summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/071-dexfile-get-static-size/build30
-rw-r--r--test/071-dexfile-get-static-size/expected.txt4
-rw-r--r--test/071-dexfile-get-static-size/info.txt3
-rw-r--r--test/071-dexfile-get-static-size/src/Main.java62
-rw-r--r--test/071-dexfile-get-static-size/test1.dexbin0 -> 1864 bytes
-rw-r--r--test/071-dexfile-get-static-size/test2.dexbin0 -> 1264 bytes
-rw-r--r--test/099-vmdebug/expected.txt6
-rw-r--r--test/099-vmdebug/info.txt2
-rw-r--r--test/099-vmdebug/src/Main.java61
-rw-r--r--test/137-cfi/cfi.cc19
-rw-r--r--test/166-bad-interface-super/expected.txt2
-rw-r--r--test/166-bad-interface-super/info.txt1
-rw-r--r--test/166-bad-interface-super/jasmin/BadSuper1.j17
-rw-r--r--test/166-bad-interface-super/jasmin/BadSuper2.j17
-rw-r--r--test/166-bad-interface-super/src/BaseClass.java18
-rw-r--r--test/166-bad-interface-super/src/BaseInterface.java18
-rw-r--r--test/166-bad-interface-super/src/Main.java31
-rw-r--r--test/167-visit-locks/expected.txt3
-rw-r--r--test/167-visit-locks/info.txt1
-rw-r--r--test/167-visit-locks/run18
-rw-r--r--test/167-visit-locks/smali/TestSync.smali119
-rw-r--r--test/167-visit-locks/src/Main.java29
-rw-r--r--test/167-visit-locks/visit_locks.cc74
-rw-r--r--test/1940-ddms-ext/expected.txt3
-rw-r--r--test/1940-ddms-ext/src-art/art/Test1940.java98
-rw-r--r--test/1941-dispose-stress/dispose_stress.cc59
-rw-r--r--test/1941-dispose-stress/expected.txt1
-rw-r--r--test/1941-dispose-stress/info.txt3
-rwxr-xr-xtest/1941-dispose-stress/run18
-rw-r--r--test/1941-dispose-stress/src/Main.java21
-rw-r--r--test/1941-dispose-stress/src/art/Breakpoint.java202
-rw-r--r--test/1941-dispose-stress/src/art/Test1941.java72
-rw-r--r--test/1941-dispose-stress/src/art/Trace.java68
-rw-r--r--test/655-jit-clinit/src/Main.java4
-rw-r--r--test/667-jit-jni-stub/expected.txt1
-rw-r--r--test/667-jit-jni-stub/info.txt1
-rw-r--r--test/667-jit-jni-stub/jit_jni_stub_test.cc63
-rwxr-xr-xtest/667-jit-jni-stub/run19
-rw-r--r--test/667-jit-jni-stub/src/Main.java180
-rw-r--r--test/669-checker-break/expected.txt1
-rw-r--r--test/669-checker-break/info.txt1
-rw-r--r--test/669-checker-break/src/Main.java328
-rw-r--r--test/711-checker-type-conversion/expected.txt0
-rw-r--r--test/711-checker-type-conversion/info.txt1
-rw-r--r--test/711-checker-type-conversion/src/Main.java77
-rw-r--r--test/Android.bp5
-rw-r--r--test/common/runtime_state.cc25
-rw-r--r--test/knownfailures.json6
-rwxr-xr-xtest/testrunner/testrunner.py18
49 files changed, 1774 insertions, 36 deletions
diff --git a/test/071-dexfile-get-static-size/build b/test/071-dexfile-get-static-size/build
new file mode 100755
index 0000000000..0bba66d065
--- /dev/null
+++ b/test/071-dexfile-get-static-size/build
@@ -0,0 +1,30 @@
+#!/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.
+
+./default-build "$@"
+
+# Create and add as resources to the test jar file:
+# 1. test1.dex
+# 2. test2.dex
+# 3. test-jar.jar, containing test1.dex as classes.dex
+# 4. multi-jar.jar, containing test1.dex as classes.dex and test2.dex as classes2.dex
+mkdir test-jar
+cp test1.dex test-jar/classes.dex
+cp test2.dex test-jar/classes2.dex
+zip -j test-jar.jar test-jar/classes.dex
+zip -j multi-jar.jar test-jar/classes.dex test-jar/classes2.dex
+jar uf ${TEST_NAME}.jar test1.dex test2.dex test-jar.jar multi-jar.jar
+
diff --git a/test/071-dexfile-get-static-size/expected.txt b/test/071-dexfile-get-static-size/expected.txt
new file mode 100644
index 0000000000..dfb77c3a2f
--- /dev/null
+++ b/test/071-dexfile-get-static-size/expected.txt
@@ -0,0 +1,4 @@
+Size for test1.dex: 1864
+Size for test2.dex: 1264
+Size for test-jar.jar: 1864
+Size for multi-jar.jar: 3128
diff --git a/test/071-dexfile-get-static-size/info.txt b/test/071-dexfile-get-static-size/info.txt
new file mode 100644
index 0000000000..5b528e81b4
--- /dev/null
+++ b/test/071-dexfile-get-static-size/info.txt
@@ -0,0 +1,3 @@
+Test DexFile.getStaticSizeOfDexFile API.
+
+test1.dex and test2.dex are arbitrary valid dex files.
diff --git a/test/071-dexfile-get-static-size/src/Main.java b/test/071-dexfile-get-static-size/src/Main.java
new file mode 100644
index 0000000000..4bf453801e
--- /dev/null
+++ b/test/071-dexfile-get-static-size/src/Main.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+public class Main {
+ private static void extractResource(String resource, String filename) throws Exception {
+ ClassLoader loader = Main.class.getClassLoader();
+ InputStream is = loader.getResourceAsStream(resource);
+ OutputStream os = new FileOutputStream(filename);
+ int read;
+ byte[] buf = new byte[4096];
+ while ((read = is.read(buf)) >= 0) {
+ os.write(buf, 0, read);
+ }
+ is.close();
+ os.close();
+ }
+
+ private static long getDexFileSize(String filename) throws Exception {
+ ClassLoader loader = Main.class.getClassLoader();
+ Class<?> DexFile = loader.loadClass("dalvik.system.DexFile");
+ Method DexFile_loadDex = DexFile.getMethod("loadDex",
+ String.class,
+ String.class,
+ Integer.TYPE);
+ Method DexFile_getStaticSizeOfDexFile = DexFile.getMethod("getStaticSizeOfDexFile");
+ Object dexFile = DexFile_loadDex.invoke(null, filename, null, 0);
+ return (Long) DexFile_getStaticSizeOfDexFile.invoke(dexFile);
+ }
+
+ private static void test(String resource) throws Exception {
+ String filename = System.getenv("DEX_LOCATION") + "/" + resource;
+ extractResource(resource, filename);
+ long size = getDexFileSize(filename);
+ System.out.println("Size for " + resource + ": " + size);
+ }
+
+ public static void main(String[] args) throws Exception {
+ test("test1.dex");
+ test("test2.dex");
+ test("test-jar.jar");
+ test("multi-jar.jar");
+ }
+}
diff --git a/test/071-dexfile-get-static-size/test1.dex b/test/071-dexfile-get-static-size/test1.dex
new file mode 100644
index 0000000000..84602d03c2
--- /dev/null
+++ b/test/071-dexfile-get-static-size/test1.dex
Binary files differ
diff --git a/test/071-dexfile-get-static-size/test2.dex b/test/071-dexfile-get-static-size/test2.dex
new file mode 100644
index 0000000000..a07c46ef59
--- /dev/null
+++ b/test/071-dexfile-get-static-size/test2.dex
Binary files differ
diff --git a/test/099-vmdebug/expected.txt b/test/099-vmdebug/expected.txt
index b8d72f66f8..f7801de62f 100644
--- a/test/099-vmdebug/expected.txt
+++ b/test/099-vmdebug/expected.txt
@@ -23,3 +23,9 @@ Instances of null 0
Instances of ClassA assignable 3
Array counts [2, 1, 0]
Array counts assignable [3, 1, 0]
+ClassD got 3, combined mask: 13
+ClassE got 2, combined mask: 18
+null got 0
+ClassD assignable got 5, combined mask: 31
+ClassE assignable got 2, combined mask: 18
+null assignable got 0
diff --git a/test/099-vmdebug/info.txt b/test/099-vmdebug/info.txt
index 7f88086986..873429e076 100644
--- a/test/099-vmdebug/info.txt
+++ b/test/099-vmdebug/info.txt
@@ -1 +1 @@
-Tests of private dalvik.system.VMDebug support for method tracing.
+Tests of dalvik.system.VMDebug APIs.
diff --git a/test/099-vmdebug/src/Main.java b/test/099-vmdebug/src/Main.java
index 90ad3155ca..e0d829a0d6 100644
--- a/test/099-vmdebug/src/Main.java
+++ b/test/099-vmdebug/src/Main.java
@@ -33,6 +33,7 @@ public class Main {
}
testMethodTracing();
testCountInstances();
+ testGetInstances();
testRuntimeStat();
testRuntimeStats();
}
@@ -249,6 +250,59 @@ public class Main {
System.out.println("Array counts assignable " + Arrays.toString(counts));
}
+ static class ClassD {
+ public int mask;
+
+ public ClassD(int mask) {
+ this.mask = mask;
+ }
+ }
+
+ static class ClassE extends ClassD {
+ public ClassE(int mask) {
+ super(mask);
+ }
+ }
+
+ private static void testGetInstances() throws Exception {
+ ArrayList<Object> l = new ArrayList<Object>();
+ l.add(new ClassD(0x01));
+ l.add(new ClassE(0x02));
+ l.add(new ClassD(0x04));
+ l.add(new ClassD(0x08));
+ l.add(new ClassE(0x10));
+ Runtime.getRuntime().gc();
+ Class<?>[] classes = new Class<?>[] {ClassD.class, ClassE.class, null};
+ Object[][] instances = VMDebug.getInstancesOfClasses(classes, false);
+
+ int mask = 0;
+ for (Object instance : instances[0]) {
+ mask |= ((ClassD)instance).mask;
+ }
+ System.out.println("ClassD got " + instances[0].length + ", combined mask: " + mask);
+
+ mask = 0;
+ for (Object instance : instances[1]) {
+ mask |= ((ClassD)instance).mask;
+ }
+ System.out.println("ClassE got " + instances[1].length + ", combined mask: " + mask);
+ System.out.println("null got " + instances[2].length);
+
+ instances = VMDebug.getInstancesOfClasses(classes, true);
+ mask = 0;
+ for (Object instance : instances[0]) {
+ mask |= ((ClassD)instance).mask;
+ }
+ System.out.println("ClassD assignable got " + instances[0].length + ", combined mask: " + mask);
+
+ mask = 0;
+ for (Object instance : instances[1]) {
+ mask |= ((ClassD)instance).mask;
+ }
+ System.out.println("ClassE assignable got " + instances[1].length + ", combined mask: " + mask);
+ System.out.println("null assignable got " + instances[2].length);
+ }
+
private static class VMDebug {
private static final Method startMethodTracingMethod;
private static final Method stopMethodTracingMethod;
@@ -257,6 +311,7 @@ public class Main {
private static final Method getRuntimeStatsMethod;
private static final Method countInstancesOfClassMethod;
private static final Method countInstancesOfClassesMethod;
+ private static final Method getInstancesOfClassesMethod;
static {
try {
Class<?> c = Class.forName("dalvik.system.VMDebug");
@@ -270,6 +325,8 @@ public class Main {
Class.class, Boolean.TYPE);
countInstancesOfClassesMethod = c.getDeclaredMethod("countInstancesOfClasses",
Class[].class, Boolean.TYPE);
+ getInstancesOfClassesMethod = c.getDeclaredMethod("getInstancesOfClasses",
+ Class[].class, Boolean.TYPE);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -300,5 +357,9 @@ public class Main {
return (long[]) countInstancesOfClassesMethod.invoke(
null, new Object[]{classes, assignable});
}
+ public static Object[][] getInstancesOfClasses(Class<?>[] classes, boolean assignable) throws Exception {
+ return (Object[][]) getInstancesOfClassesMethod.invoke(
+ null, new Object[]{classes, assignable});
+ }
}
}
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index 58b33be573..66270fd5c7 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -104,20 +104,6 @@ static void MoreErrorInfo(pid_t pid, bool sig_quit_on_fail) {
}
#endif
-// Currently we have to fall back to our own loader for the boot image when it's compiled PIC
-// because its base is zero. Thus in-process unwinding through it won't work. This is a helper
-// detecting this.
-#if __linux__
-static bool IsPicImage() {
- std::vector<gc::space::ImageSpace*> image_spaces =
- Runtime::Current()->GetHeap()->GetBootImageSpaces();
- CHECK(!image_spaces.empty()); // We should be running with an image.
- const OatFile* oat_file = image_spaces[0]->GetOatFile();
- CHECK(oat_file != nullptr); // We should have an oat file to go with the image.
- return oat_file->IsPic();
-}
-#endif
-
extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(
JNIEnv*,
jobject,
@@ -125,11 +111,6 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(
jint,
jboolean) {
#if __linux__
- if (IsPicImage()) {
- LOG(INFO) << "Image is pic, in-process unwinding check bypassed.";
- return JNI_TRUE;
- }
-
// TODO: What to do on Valgrind?
std::unique_ptr<Backtrace> bt(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, GetTid()));
diff --git a/test/166-bad-interface-super/expected.txt b/test/166-bad-interface-super/expected.txt
new file mode 100644
index 0000000000..c49f6d255f
--- /dev/null
+++ b/test/166-bad-interface-super/expected.txt
@@ -0,0 +1,2 @@
+Caught java.lang.ClassFormatError when trying to resolve BadSuper1.
+Caught java.lang.ClassFormatError when trying to resolve BadSuper2.
diff --git a/test/166-bad-interface-super/info.txt b/test/166-bad-interface-super/info.txt
new file mode 100644
index 0000000000..bcba8c0d89
--- /dev/null
+++ b/test/166-bad-interface-super/info.txt
@@ -0,0 +1 @@
+Test that linking an interface declaring a superclass other than j.l.Object throws CFE.
diff --git a/test/166-bad-interface-super/jasmin/BadSuper1.j b/test/166-bad-interface-super/jasmin/BadSuper1.j
new file mode 100644
index 0000000000..f96564ec73
--- /dev/null
+++ b/test/166-bad-interface-super/jasmin/BadSuper1.j
@@ -0,0 +1,17 @@
+; 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.
+
+.interface public BadSuper1
+.super BaseInterface
+
diff --git a/test/166-bad-interface-super/jasmin/BadSuper2.j b/test/166-bad-interface-super/jasmin/BadSuper2.j
new file mode 100644
index 0000000000..584bd2094d
--- /dev/null
+++ b/test/166-bad-interface-super/jasmin/BadSuper2.j
@@ -0,0 +1,17 @@
+; 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.
+
+.interface public BadSuper2
+.super BaseClass
+
diff --git a/test/166-bad-interface-super/src/BaseClass.java b/test/166-bad-interface-super/src/BaseClass.java
new file mode 100644
index 0000000000..6ea1ad3f3b
--- /dev/null
+++ b/test/166-bad-interface-super/src/BaseClass.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+class BaseClass {
+}
diff --git a/test/166-bad-interface-super/src/BaseInterface.java b/test/166-bad-interface-super/src/BaseInterface.java
new file mode 100644
index 0000000000..7872a43794
--- /dev/null
+++ b/test/166-bad-interface-super/src/BaseInterface.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+interface BaseInterface {
+}
diff --git a/test/166-bad-interface-super/src/Main.java b/test/166-bad-interface-super/src/Main.java
new file mode 100644
index 0000000000..3df2574678
--- /dev/null
+++ b/test/166-bad-interface-super/src/Main.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+class Main {
+ public static void main(String[] args) throws Exception {
+ tryResolveClassExpectingCFE("BadSuper1");
+ tryResolveClassExpectingCFE("BadSuper2");
+ }
+
+ public static void tryResolveClassExpectingCFE(String className) throws Exception {
+ try {
+ Class.forName(className);
+ } catch (ClassFormatError e) {
+ System.out.println(
+ "Caught " + e.getClass().getName() + " when trying to resolve " + className + ".");
+ }
+ }
+}
diff --git a/test/167-visit-locks/expected.txt b/test/167-visit-locks/expected.txt
new file mode 100644
index 0000000000..5157c64c83
--- /dev/null
+++ b/test/167-visit-locks/expected.txt
@@ -0,0 +1,3 @@
+JNI_OnLoad called
+First
+Second
diff --git a/test/167-visit-locks/info.txt b/test/167-visit-locks/info.txt
new file mode 100644
index 0000000000..d849bc31ed
--- /dev/null
+++ b/test/167-visit-locks/info.txt
@@ -0,0 +1 @@
+Regression test for b/68703210
diff --git a/test/167-visit-locks/run b/test/167-visit-locks/run
new file mode 100644
index 0000000000..93654113e6
--- /dev/null
+++ b/test/167-visit-locks/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+# Use a smaller heap so it's easier to potentially fill up.
+exec ${RUN} $@ --runtime-option -Xmx2m
diff --git a/test/167-visit-locks/smali/TestSync.smali b/test/167-visit-locks/smali/TestSync.smali
new file mode 100644
index 0000000000..5e68ad7003
--- /dev/null
+++ b/test/167-visit-locks/smali/TestSync.smali
@@ -0,0 +1,119 @@
+.class LTestSync;
+.super Ljava/lang/Object;
+.source "Main.java"
+
+
+# direct methods
+.method constructor <init>()V
+ .registers 1
+
+ .prologue
+ .line 6
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+.method public static run()V
+ # v0-v2 were generated by javac+dx for the original src code, keeping them.
+ # v10..v19 are for tracking, aliasing and manipulating the first lock.
+ # v20..v29 are for tracking, aliasing and manipulating the second lock.
+ .registers 30
+
+ .prologue
+ .line 8
+ const-string v1, "First"
+
+ .line 9
+ const-string v2, "Second"
+
+ move-object v10, v1
+ const v1, 0x1
+
+ .line 10
+ monitor-enter v10
+
+ # Introduce a range of dead copies.
+ move-object v11, v10
+ move-object v12, v10
+ move-object v13, v10
+ move-object v14, v10
+ move-object v15, v10
+ move-object/16 v16, v10
+ move-object/16 v17, v10
+ move-object/16 v18, v10
+
+ # Introduce a copy that we'll use for unlock.
+ move-object/16 v19, v10
+
+ # Clobber the original alias.
+ const v10, 0x3
+
+ move-object/16 v20, v2
+ const v2, 0x2
+
+ .line 11
+ :try_start_b
+ monitor-enter v20
+ :try_end_c
+
+ # Introduce a range of dead copies.
+ move-object/16 v21, v20
+ move-object/16 v22, v20
+ move-object/16 v23, v20
+ move-object/16 v24, v20
+ move-object/16 v25, v20
+ move-object/16 v26, v20
+ move-object/16 v27, v20
+
+ # Introduce another copy that we will hold live.
+ move-object/16 v28, v20
+
+ # Clobber the original alias.
+ const v20, 0x5
+
+ # Introduce another copy that we'll use for unlock.
+ move-object/16 v29, v28
+
+ .catchall {:try_start_b .. :try_end_c} :catchall_15
+
+ .line 12
+ :try_start_c
+ invoke-static/range { v28 }, LMain;->run(Ljava/lang/Object;)V
+
+ .line 13
+ monitor-exit v29
+ :try_end_10
+ .catchall {:try_start_c .. :try_end_10} :catchall_12
+
+ .line 14
+ :try_start_10
+ monitor-exit v19
+ :try_end_11
+ .catchall {:try_start_10 .. :try_end_11} :catchall_15
+
+ .line 15
+ return-void
+
+ .line 13
+ :catchall_12
+ move-exception v0
+
+ :try_start_13
+ monitor-exit v29
+ :try_end_14
+ .catchall {:try_start_13 .. :try_end_14} :catchall_12
+
+ :try_start_14
+ throw v0
+
+ .line 14
+ :catchall_15
+ move-exception v0
+
+ monitor-exit v19
+ :try_end_17
+ .catchall {:try_start_14 .. :try_end_17} :catchall_15
+
+ throw v0
+.end method
diff --git a/test/167-visit-locks/src/Main.java b/test/167-visit-locks/src/Main.java
new file mode 100644
index 0000000000..d8da92715a
--- /dev/null
+++ b/test/167-visit-locks/src/Main.java
@@ -0,0 +1,29 @@
+/*
+ * 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 {
+ System.loadLibrary(args[0]);
+
+ Class.forName("TestSync").getMethod("run").invoke(null);
+ }
+
+ public static void run(Object o) {
+ testVisitLocks();
+ }
+
+ public static native void testVisitLocks();
+}
diff --git a/test/167-visit-locks/visit_locks.cc b/test/167-visit-locks/visit_locks.cc
new file mode 100644
index 0000000000..e79c880639
--- /dev/null
+++ b/test/167-visit-locks/visit_locks.cc
@@ -0,0 +1,74 @@
+/*
+ * 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 "jni.h"
+
+#include <iostream>
+
+#include "android-base/logging.h"
+
+#include "arch/context.h"
+#include "art_method.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "mirror/object-inl.h"
+#include "mirror/string.h"
+#include "monitor.h"
+#include "scoped_thread_state_change-inl.h"
+#include "stack.h"
+#include "thread-current-inl.h"
+
+namespace art {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_testVisitLocks(JNIEnv*, jclass) {
+ ScopedObjectAccess soa(Thread::Current());
+
+ class VisitLocks : public StackVisitor {
+ public:
+ VisitLocks(Thread* thread, Context* context)
+ : StackVisitor(thread, context, StackWalkKind::kIncludeInlinedFrames) {
+ }
+
+ bool VisitFrame() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = GetMethod();
+
+ // Ignore runtime methods.
+ if (m == nullptr || m->IsRuntimeMethod()) {
+ return true;
+ }
+
+ if (m->PrettyMethod() == "void TestSync.run()") {
+ // Interesting frame.
+ Monitor::VisitLocks(this, Callback, nullptr);
+ return false;
+ }
+
+ return true;
+ }
+
+ static void Callback(mirror::Object* obj, void*) REQUIRES_SHARED(Locks::mutator_lock_) {
+ CHECK(obj != nullptr);
+ CHECK(obj->IsString());
+ std::cerr << obj->AsString()->ToModifiedUtf8() << std::endl;
+ }
+ };
+ Context* context = Context::Create();
+ VisitLocks vl(soa.Self(), context);
+ vl.WalkStack();
+ delete context;
+}
+
+} // namespace art
diff --git a/test/1940-ddms-ext/expected.txt b/test/1940-ddms-ext/expected.txt
index cf4ad50e90..62d3b7bd4c 100644
--- a/test/1940-ddms-ext/expected.txt
+++ b/test/1940-ddms-ext/expected.txt
@@ -5,3 +5,6 @@ MyDdmHandler: Chunk returned: Chunk(Type: 0xFADE7357, Len: 8, data: [0, 0, 0, 0,
JVMTI returned chunk: Chunk(Type: 0xFADE7357, Len: 8, data: [0, 0, 0, 0, 0, -128, 0, 37])
Sending chunk: Chunk(Type: 0xDEADBEEF, Len: 8, data: [9, 10, 11, 12, 13, 14, 15, 16])
Chunk published: Chunk(Type: 0xDEADBEEF, Len: 8, data: [9, 10, 11, 12, 13, 14, 15, 16])
+Saw expected thread events.
+Expected chunk type published: 1213221190
+Expected chunk type published: 1297109829
diff --git a/test/1940-ddms-ext/src-art/art/Test1940.java b/test/1940-ddms-ext/src-art/art/Test1940.java
index f0ee7102a9..9f79eaebba 100644
--- a/test/1940-ddms-ext/src-art/art/Test1940.java
+++ b/test/1940-ddms-ext/src-art/art/Test1940.java
@@ -17,6 +17,7 @@
package art;
import org.apache.harmony.dalvik.ddmc.*;
+import dalvik.system.VMDebug;
import java.lang.reflect.Method;
import java.util.Arrays;
@@ -30,6 +31,12 @@ public class Test1940 {
public static final int MY_DDMS_TYPE = 0xDEADBEEF;
public static final int MY_DDMS_RESPONSE_TYPE = 0xFADE7357;
+ public static final boolean PRINT_ALL_CHUNKS = false;
+
+ public static interface DdmHandler {
+ public void HandleChunk(int type, byte[] data);
+ }
+
public static final class TestError extends Error {
public TestError(String s) { super(s); }
}
@@ -69,11 +76,38 @@ public class Test1940 {
public static final ChunkHandler SINGLE_HANDLER = new MyDdmHandler();
+ public static DdmHandler CURRENT_HANDLER;
+
public static void HandlePublish(int type, byte[] data) {
- System.out.println("Chunk published: " + printChunk(new Chunk(type, data, 0, data.length)));
+ if (PRINT_ALL_CHUNKS) {
+ System.out.println(
+ "Unknown Chunk published: " + printChunk(new Chunk(type, data, 0, data.length)));
+ }
+ CURRENT_HANDLER.HandleChunk(type, data);
+ }
+
+ // TYPE Thread Create
+ public static final int TYPE_THCR = 0x54484352;
+ // Type Thread name
+ public static final int TYPE_THNM = 0x54484E4D;
+ // Type Thread death.
+ public static final int TYPE_THDE = 0x54484445;
+ // Type Heap info
+ public static final int TYPE_HPIF = 0x48504946;
+ // Type Trace Results
+ public static final int TYPE_MPSE = 0x4D505345;
+
+ public static boolean IsFromThread(Thread t, byte[] data) {
+ // DDMS always puts the thread-id as the first 4 bytes.
+ ByteBuffer b = ByteBuffer.wrap(data);
+ b.order(ByteOrder.BIG_ENDIAN);
+ return b.getInt() == (int) t.getId();
}
public static void run() throws Exception {
+ CURRENT_HANDLER = (type, data) -> {
+ System.out.println("Chunk published: " + printChunk(new Chunk(type, data, 0, data.length)));
+ };
initializeTest(
Test1940.class,
Test1940.class.getDeclaredMethod("HandlePublish", Integer.TYPE, new byte[0].getClass()));
@@ -90,8 +124,70 @@ public class Test1940 {
MY_DDMS_TYPE, new byte[] { 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }, 0, 8);
System.out.println("Sending chunk: " + printChunk(c));
DdmServer.sendChunk(c);
+
+ // Test thread chunks are sent.
+ final boolean[] types_seen = new boolean[] { false, false, false };
+ CURRENT_HANDLER = (type, cdata) -> {
+ switch (type) {
+ case TYPE_THCR:
+ types_seen[0] = true;
+ break;
+ case TYPE_THNM:
+ types_seen[1] = true;
+ break;
+ case TYPE_THDE:
+ types_seen[2] = true;
+ break;
+ default:
+ // We don't want to print other types.
+ break;
+ }
+ };
+ DdmVmInternal.threadNotify(true);
+ final Thread thr = new Thread(() -> { return; }, "THREAD");
+ thr.start();
+ thr.join();
+ DdmVmInternal.threadNotify(false);
+ // Make sure we saw at least one of Thread-create, Thread name, & thread death.
+ if (!types_seen[0] || !types_seen[1] || !types_seen[2]) {
+ System.out.println("Didn't see expected chunks for thread creation! got: " +
+ Arrays.toString(types_seen));
+ } else {
+ System.out.println("Saw expected thread events.");
+ }
+
+ // Test heap chunks are sent.
+ CURRENT_HANDLER = (type, cdata) -> {
+ // The actual data is far to noisy for this test as it includes information about global heap
+ // state.
+ if (type == TYPE_HPIF) {
+ System.out.println("Expected chunk type published: " + type);
+ }
+ };
+ final int HPIF_WHEN_NOW = 1;
+ if (!DdmVmInternal.heapInfoNotify(HPIF_WHEN_NOW)) {
+ System.out.println("Unexpected failure for heapInfoNotify!");
+ }
+
+ // method Tracing
+ CURRENT_HANDLER = (type, cdata) -> {
+ // This chunk includes timing and thread information so we just check the type.
+ if (type == TYPE_MPSE) {
+ System.out.println("Expected chunk type published: " + type);
+ }
+ };
+ VMDebug.startMethodTracingDdms(/*size: default*/0,
+ /*flags: none*/ 0,
+ /*sampling*/ false,
+ /*interval*/ 0);
+ doNothing();
+ doNothing();
+ doNothing();
+ doNothing();
+ VMDebug.stopMethodTracing();
}
+ private static void doNothing() {}
private static Chunk processChunk(byte[] val) {
return processChunk(new Chunk(MY_DDMS_TYPE, val, 0, val.length));
}
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/655-jit-clinit/src/Main.java b/test/655-jit-clinit/src/Main.java
index 44b315478f..2fb8f2a86e 100644
--- a/test/655-jit-clinit/src/Main.java
+++ b/test/655-jit-clinit/src/Main.java
@@ -23,7 +23,7 @@ public class Main {
Foo.hotMethod();
}
- public native static boolean isJitCompiled(Class<?> cls, String methodName);
+ public native static boolean hasJitCompiledEntrypoint(Class<?> cls, String methodName);
private native static boolean hasJit();
}
@@ -36,7 +36,7 @@ class Foo {
static {
array = new Object[10000];
- while (!Main.isJitCompiled(Foo.class, "hotMethod")) {
+ while (!Main.hasJitCompiledEntrypoint(Foo.class, "hotMethod")) {
Foo.hotMethod();
try {
// Sleep to give a chance for the JIT to compile `hotMethod`.
diff --git a/test/667-jit-jni-stub/expected.txt b/test/667-jit-jni-stub/expected.txt
new file mode 100644
index 0000000000..6a5618ebc6
--- /dev/null
+++ b/test/667-jit-jni-stub/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/667-jit-jni-stub/info.txt b/test/667-jit-jni-stub/info.txt
new file mode 100644
index 0000000000..6f25c44592
--- /dev/null
+++ b/test/667-jit-jni-stub/info.txt
@@ -0,0 +1 @@
+Tests for JITting and collecting JNI stubs.
diff --git a/test/667-jit-jni-stub/jit_jni_stub_test.cc b/test/667-jit-jni-stub/jit_jni_stub_test.cc
new file mode 100644
index 0000000000..82e06fc018
--- /dev/null
+++ b/test/667-jit-jni-stub/jit_jni_stub_test.cc
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#include <jni.h>
+
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
+#include "mirror/class.h"
+#include "mirror/string.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+
+// Local class declared as a friend of JitCodeCache so that we can access its internals.
+class JitJniStubTestHelper {
+ public:
+ static bool isNextJitGcFull(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
+ CHECK(Runtime::Current()->GetJit() != nullptr);
+ jit::JitCodeCache* cache = Runtime::Current()->GetJit()->GetCodeCache();
+ MutexLock mu(self, cache->lock_);
+ return cache->ShouldDoFullCollection();
+ }
+};
+
+// Calls through to a static method with signature "()V".
+extern "C" JNIEXPORT
+void Java_Main_callThrough(JNIEnv* env, jclass, jclass klass, jstring methodName) {
+ ScopedObjectAccess soa(Thread::Current());
+ std::string name = soa.Decode<mirror::String>(methodName)->ToModifiedUtf8();
+ jmethodID method = env->GetStaticMethodID(klass, name.c_str(), "()V");
+ CHECK(method != nullptr) << soa.Decode<mirror::Class>(klass)->PrettyDescriptor() << "." << name;
+ env->CallStaticVoidMethod(klass, method);
+}
+
+extern "C" JNIEXPORT
+void Java_Main_jitGc(JNIEnv*, jclass) {
+ CHECK(Runtime::Current()->GetJit() != nullptr);
+ jit::JitCodeCache* cache = Runtime::Current()->GetJit()->GetCodeCache();
+ ScopedObjectAccess soa(Thread::Current());
+ cache->GarbageCollectCache(Thread::Current());
+}
+
+extern "C" JNIEXPORT
+jboolean Java_Main_isNextJitGcFull(JNIEnv*, jclass) {
+ ScopedObjectAccess soa(Thread::Current());
+ return JitJniStubTestHelper::isNextJitGcFull(soa.Self());
+}
+
+} // namespace art
diff --git a/test/667-jit-jni-stub/run b/test/667-jit-jni-stub/run
new file mode 100755
index 0000000000..f235c6bc90
--- /dev/null
+++ b/test/667-jit-jni-stub/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+# Disable AOT compilation of JNI stubs.
+# Ensure this test is not subject to unexpected code collection.
+${RUN} "${@}" --no-prebuild --no-dex2oat --runtime-option -Xjitinitialsize:32M
diff --git a/test/667-jit-jni-stub/src/Main.java b/test/667-jit-jni-stub/src/Main.java
new file mode 100644
index 0000000000..b867970eab
--- /dev/null
+++ b/test/667-jit-jni-stub/src/Main.java
@@ -0,0 +1,180 @@
+/*
+ * 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 {
+ System.loadLibrary(args[0]);
+ if (isAotCompiled(Main.class, "hasJit")) {
+ throw new Error("This test must be run with --no-prebuild --no-dex2oat!");
+ }
+ if (!hasJit()) {
+ return;
+ }
+
+ testCompilationUseAndCollection();
+ testMixedFramesOnStack();
+ }
+
+ public static void testCompilationUseAndCollection() {
+ // Test that callThrough() can be JIT-compiled.
+ assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));
+ assertFalse(hasJitCompiledCode(Main.class, "callThrough"));
+ ensureCompiledCallThroughEntrypoint(/* call */ true);
+ assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
+ assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
+
+ // Use callThrough() once again now that the method has a JIT-compiled stub.
+ callThrough(Main.class, "doNothing");
+
+ // Test that GC with the JIT-compiled stub on the stack does not collect it.
+ // Also tests stack walk over the JIT-compiled stub.
+ callThrough(Main.class, "testGcWithCallThroughStubOnStack");
+
+ // Test that, when marking used methods before a full JIT GC, a single execution
+ // of the GenericJNI trampoline can save the compiled stub from being collected.
+ testSingleInvocationTriggersRecompilation();
+
+ // Test that the JNI compiled stub can actually be collected.
+ testStubCanBeCollected();
+ }
+
+ public static void testGcWithCallThroughStubOnStack() {
+ // Check that this method was called via JIT-compiled callThrough() stub.
+ assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
+ // This assertion also exercises stack walk over the JIT-compiled callThrough() stub.
+ assertTrue(new Throwable().getStackTrace()[1].getMethodName().equals("callThrough"));
+
+ doJitGcsUntilFullJitGcIsScheduled();
+ // The callThrough() on the stack above this method is using the compiled stub,
+ // so the JIT GC should not remove the compiled code.
+ jitGc();
+ assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
+ }
+
+ public static void testSingleInvocationTriggersRecompilation() {
+ // After scheduling a full JIT GC, single call through the GenericJNI
+ // trampoline should ensure that the compiled stub is used again.
+ doJitGcsUntilFullJitGcIsScheduled();
+ callThrough(Main.class, "doNothing");
+ ensureCompiledCallThroughEntrypoint(/* call */ false); // Wait for the compilation task to run.
+ assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
+ jitGc(); // This JIT GC should not collect the callThrough() stub.
+ assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
+ }
+
+ public static void testMixedFramesOnStack() {
+ // Starts without a compiled JNI stub for callThrough().
+ assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));
+ assertFalse(hasJitCompiledCode(Main.class, "callThrough"));
+ callThrough(Main.class, "testMixedFramesOnStackStage2");
+ // We have just returned through the JIT-compiled JNI stub, so it must still
+ // be compiled (though not necessarily with the entrypoint pointing to it).
+ assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
+ // Though the callThrough() is on the stack, that frame is using the GenericJNI
+ // and does not prevent the collection of the JNI stub.
+ testStubCanBeCollected();
+ }
+
+ public static void testMixedFramesOnStackStage2() {
+ // We cannot assert that callThrough() has no JIT compiled stub as that check
+ // may race against the compilation task. Just check the caller.
+ assertTrue(new Throwable().getStackTrace()[1].getMethodName().equals("callThrough"));
+ // Now ensure that the JNI stub is compiled and used.
+ ensureCompiledCallThroughEntrypoint(/* call */ true);
+ callThrough(Main.class, "testMixedFramesOnStackStage3");
+ }
+
+ public static void testMixedFramesOnStackStage3() {
+ // Check that this method was called via JIT-compiled callThrough() stub.
+ assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
+ // This assertion also exercises stack walk over the JIT-compiled callThrough() stub.
+ assertTrue(new Throwable().getStackTrace()[1].getMethodName().equals("callThrough"));
+ // For a good measure, try a JIT GC.
+ jitGc();
+ }
+
+ public static void testStubCanBeCollected() {
+ assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
+ doJitGcsUntilFullJitGcIsScheduled();
+ assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));
+ assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
+ jitGc(); // JIT GC without callThrough() on the stack should collect the callThrough() stub.
+ assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));
+ assertFalse(hasJitCompiledCode(Main.class, "callThrough"));
+ }
+
+ public static void doJitGcsUntilFullJitGcIsScheduled() {
+ // We enter with a compiled stub for callThrough() but we also need the entrypoint to be set.
+ assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
+ ensureCompiledCallThroughEntrypoint(/* call */ true);
+ // Perform JIT GC until the next GC is marked to do full collection.
+ do {
+ assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
+ callThrough(Main.class, "jitGc"); // JIT GC with callThrough() safely on the stack.
+ } while (!isNextJitGcFull());
+ // The JIT GC before the full collection resets entrypoints and waits to see
+ // if the methods are still in use.
+ assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));
+ assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
+ }
+
+ public static void ensureCompiledCallThroughEntrypoint(boolean call) {
+ int count = 0;
+ while (!hasJitCompiledEntrypoint(Main.class, "callThrough")) {
+ // If `call` is true, also exercise the `callThrough()` method to increase hotness.
+ int limit = call ? 1 << Math.min(count, 12) : 0;
+ for (int i = 0; i < limit; ++i) {
+ callThrough(Main.class, "doNothing");
+ }
+ try {
+ // Sleep to give a chance for the JIT to compile `hasJit` stub.
+ Thread.sleep(100);
+ } catch (Exception e) {
+ // Ignore
+ }
+ if (++count == 50) {
+ throw new Error("TIMEOUT");
+ }
+ };
+ }
+
+ public static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("Expected true!");
+ }
+ }
+
+ public static void assertFalse(boolean value) {
+ if (value) {
+ throw new AssertionError("Expected false!");
+ }
+ }
+
+ public static void doNothing() { }
+ public static void throwError() { throw new Error(); }
+
+ // Note that the callThrough()'s shorty differs from shorties of the other
+ // native methods used in this test because of the return type `void.`
+ public native static void callThrough(Class<?> cls, String methodName);
+
+ public native static void jitGc();
+ public native static boolean isNextJitGcFull();
+
+ public native static boolean isAotCompiled(Class<?> cls, String methodName);
+ public native static boolean hasJitCompiledEntrypoint(Class<?> cls, String methodName);
+ public native static boolean hasJitCompiledCode(Class<?> cls, String methodName);
+ private native static boolean hasJit();
+}
diff --git a/test/669-checker-break/expected.txt b/test/669-checker-break/expected.txt
new file mode 100644
index 0000000000..b0aad4deb5
--- /dev/null
+++ b/test/669-checker-break/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/669-checker-break/info.txt b/test/669-checker-break/info.txt
new file mode 100644
index 0000000000..3408b3b238
--- /dev/null
+++ b/test/669-checker-break/info.txt
@@ -0,0 +1 @@
+Test optimizations of "break" loops.
diff --git a/test/669-checker-break/src/Main.java b/test/669-checker-break/src/Main.java
new file mode 100644
index 0000000000..e59061b1aa
--- /dev/null
+++ b/test/669-checker-break/src/Main.java
@@ -0,0 +1,328 @@
+/*
+ * 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.
+ */
+
+/**
+ * Tests for optimizations of break-loops, i.e. loops that break
+ * out of a while-true loop when the end condition is satisfied.
+ * In particular, the tests focus on break-loops that can be
+ * rewritten into regular countable loops (this may improve certain
+ * loops generated by the Kotlin compiler for inclusive ranges).
+ */
+public class Main {
+
+ /// CHECK-START: int Main.breakLoop(int[]) induction_var_analysis (before)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Zero>>,<<AddI:i\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Bnd:i\d+>> BoundsCheck [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Nil>>,<<Bnd>>,<<One>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<NE:z\d+>> NotEqual [{{i\d+}},<<Phi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<NE>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddI>> Add [<<Phi>>,<<One>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: int Main.breakLoop(int[]) induction_var_analysis (after)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Zero>>,<<AddI:i\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<LE:z\d+>> LessThanOrEqual [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<LE>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Bnd:i\d+>> BoundsCheck [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Nil>>,<<Bnd>>,<<One>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddI>> Add [<<Phi>>,<<One>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-ARM64: int Main.breakLoop(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Four:i\d+>> IntConstant 4 loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<One>>] loop:none
+ /// CHECK-DAG: VecStore [<<Nil>>,<<Phi:i\d+>>,<<Rep>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi>>,<<Four>>] loop:<<Loop>> outer_loop:none
+ static int breakLoop(int[] a) {
+ int l = 0;
+ int u = a.length - 1;
+ int i = l;
+ if (l <= u) {
+ while (true) {
+ a[i] = 1;
+ if (i == u) break;
+ i++;
+ }
+ }
+ return i;
+ }
+
+ /// CHECK-START: int Main.breakLoopDown(int[]) induction_var_analysis (before)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<MOne:i\d+>> IntConstant -1 loop:none
+ /// CHECK-DAG: <<Two:i\d+>> IntConstant 2 loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [{{i\d+}},<<AddI:i\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Bnd:i\d+>> BoundsCheck [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Nil>>,<<Bnd>>,<<Two>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<NE:z\d+>> NotEqual [<<Phi>>,<<Zero>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<NE>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddI>> Add [<<Phi>>,<<MOne>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: int Main.breakLoopDown(int[]) induction_var_analysis (after)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<MOne:i\d+>> IntConstant -1 loop:none
+ /// CHECK-DAG: <<Two:i\d+>> IntConstant 2 loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [{{i\d+}},<<AddI:i\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<GE:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Zero>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<GE>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Bnd:i\d+>> BoundsCheck [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Nil>>,<<Bnd>>,<<Two>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddI>> Add [<<Phi>>,<<MOne>>] loop:<<Loop>> outer_loop:none
+ static int breakLoopDown(int[] a) {
+ int l = 0;
+ int u = a.length - 1;
+ int i = u;
+ if (u >= l) {
+ while (true) {
+ a[i] = 2;
+ if (i == l) break;
+ i--;
+ }
+ }
+ return i;
+ }
+
+ /// CHECK-START: int Main.breakLoopSafeConst(int[]) induction_var_analysis (before)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Three:i\d+>> IntConstant 3 loop:none
+ /// CHECK-DAG: <<L1:i\d+>> IntConstant 2147483631 loop:none
+ /// CHECK-DAG: <<L2:i\d+>> IntConstant 2147483646 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<L1>>,<<AddI:i\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Phi>>,<<L1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Bnd:i\d+>> BoundsCheck [<<Sub>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Nil>>,<<Bnd>>,<<Three>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<NE:z\d+>> NotEqual [<<Phi>>,<<L2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<NE>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddI>> Add [<<Phi>>,<<One>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: int Main.breakLoopSafeConst(int[]) induction_var_analysis (after)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Three:i\d+>> IntConstant 3 loop:none
+ /// CHECK-DAG: <<L1:i\d+>> IntConstant 2147483631 loop:none
+ /// CHECK-DAG: <<L2:i\d+>> IntConstant 2147483646 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<L1>>,<<AddI:i\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<LE:z\d+>> LessThanOrEqual [<<Phi>>,<<L2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Phi>>,<<L1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Bnd:i\d+>> BoundsCheck [<<Sub>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Nil>>,<<Bnd>>,<<Three>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddI>> Add [<<Phi>>,<<One>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-ARM64: int Main.breakLoopSafeConst(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Three:i\d+>> IntConstant 3 loop:none
+ /// CHECK-DAG: <<Four:i\d+>> IntConstant 4 loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Three>>] loop:none
+ /// CHECK-DAG: VecStore [<<Par>>,<<Phi:i\d+>>,<<Rep>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi>>,<<Four>>] loop:<<Loop>> outer_loop:none
+ static int breakLoopSafeConst(int[] a) {
+ int l = Integer.MAX_VALUE - 16;
+ int u = Integer.MAX_VALUE - 1;
+ int i = l;
+ if (l <= u) { // will be removed by simplifier
+ while (true) {
+ a[i - l] = 3;
+ if (i == u) break;
+ i++;
+ }
+ }
+ return i;
+ }
+
+ /// CHECK-START: int Main.breakLoopUnsafeConst(int[]) induction_var_analysis (before)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Four:i\d+>> IntConstant 4 loop:none
+ /// CHECK-DAG: <<L1:i\d+>> IntConstant 2147483632 loop:none
+ /// CHECK-DAG: <<L2:i\d+>> IntConstant 2147483647 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<L1>>,<<AddI:i\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Phi>>,<<L1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Bnd:i\d+>> BoundsCheck [<<Sub>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Nil>>,<<Bnd>>,<<Four>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<NE:z\d+>> NotEqual [<<Phi>>,<<L2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<NE>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddI>> Add [<<Phi>>,<<One>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: int Main.breakLoopUnsafeConst(int[]) induction_var_analysis (after)
+ /// CHECK-DAG: NotEqual
+ /// CHECK-NOT: LessThanOrEqual
+ static int breakLoopUnsafeConst(int[] a) {
+ int l = Integer.MAX_VALUE - 15;
+ int u = Integer.MAX_VALUE;
+ int i = l;
+ if (l <= u) { // will be removed by simplifier
+ while (true) {
+ a[i - l] = 4;
+ if (i == u) break; // rewriting exit not safe!
+ i++;
+ }
+ }
+ return i;
+ }
+
+ /// CHECK-START: int Main.breakLoopNastyPhi(int[]) induction_var_analysis (before)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Five:i\d+>> IntConstant 5 loop:none
+ /// CHECK-DAG: <<M123:i\d+>> IntConstant -123 loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Zero>>,<<AddI:i\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Wrap:i\d+>> Phi [<<M123>>,<<Phi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Bnd:i\d+>> BoundsCheck [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Nil>>,<<Bnd>>,<<Five>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<NE:z\d+>> NotEqual [{{i\d+}},<<Phi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<NE>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddI>> Add [<<Phi>>,<<One>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Comb:i\d+>> Phi [<<M123>>,<<Wrap>>] loop:none
+ /// CHECK-DAG: Return [<<Comb>>] loop:none
+ //
+ /// CHECK-START: int Main.breakLoopNastyPhi(int[]) induction_var_analysis (after)
+ /// CHECK-DAG: NotEqual
+ /// CHECK-NOT: LessThanOrEqual
+ static int breakLoopNastyPhi(int[] a) {
+ int l = 0;
+ int u = a.length - 1;
+ int x = -123;
+ if (l <= u) {
+ int i = l;
+ while (true) {
+ a[i] = 5;
+ if (i == u) break;
+ x = i;
+ i++;
+ }
+ }
+ return x; // keep another phi live
+ }
+
+ /// CHECK-START: int Main.breakLoopReduction(int[]) induction_var_analysis (before)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Zero>>,<<AddI:i\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Red:i\d+>> Phi [<<Zero>>,<<RedI:i\d+>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Bnd:i\d+>> BoundsCheck [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get:i\d+>> ArrayGet [<<Nil>>,<<Bnd>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<RedI>> Add [<<Red>>,<<Get>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<NE:z\d+>> NotEqual [{{i\d+}},<<Phi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<NE>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddI>> Add [<<Phi>>,<<One>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Comb:i\d+>> Phi [<<Zero>>,<<RedI>>] loop:none
+ /// CHECK-DAG: Return [<<Comb>>] loop:none
+ //
+ /// CHECK-START: int Main.breakLoopReduction(int[]) induction_var_analysis (after)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Nil:l\d+>> NullCheck [<<Par>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Zero>>,<<AddI:i\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Red:i\d+>> Phi [<<Zero>>,<<RedI:i\d+>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<LE:z\d+>> LessThanOrEqual [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<LE>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Bnd:i\d+>> BoundsCheck [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get:i\d+>> ArrayGet [<<Nil>>,<<Bnd>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<RedI>> Add [<<Red>>,<<Get>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddI>> Add [<<Phi>>,<<One>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Comb:i\d+>> Phi [<<Zero>>,<<Red>>] loop:none
+ /// CHECK-DAG: Return [<<Comb>>] loop:none
+ //
+ /// CHECK-START-ARM64: int Main.breakLoopReduction(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Par:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Exp:d\d+>> VecSetScalars [<<Zero>>] loop:none
+ /// CHECK-DAG: <<VPhi:d\d+>> Phi [<<Exp>>,<<VAdd:d\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<VLoad:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<VAdd>> VecAdd [<<VPhi>>,<<VLoad>>] loop:<<Loop>> outer_loop:none
+ static int breakLoopReduction(int[] a) {
+ int l = 0;
+ int u = a.length - 1;
+ int x = 0;
+ if (l <= u) {
+ int i = l;
+ while (true) {
+ x += a[i];
+ if (i == u) break;
+ i++;
+ }
+ }
+ return x;
+ }
+
+ //
+ // Test driver.
+ //
+
+ public static void main(String[] args) {
+ int[] a = new int[100];
+
+ expectEquals(99, breakLoop(a));
+ for (int i = 0; i < a.length; i++) {
+ expectEquals(1, a[i]);
+ }
+
+ expectEquals(0, breakLoopDown(a));
+ for (int i = 0; i < a.length; i++) {
+ expectEquals(2, a[i]);
+ }
+
+ expectEquals(Integer.MAX_VALUE - 1, breakLoopSafeConst(a));
+ for (int i = 0; i < a.length; i++) {
+ int e = i < 16 ? 3 : 2;
+ expectEquals(e, a[i]);
+ }
+
+ expectEquals(Integer.MAX_VALUE, breakLoopUnsafeConst(a));
+ for (int i = 0; i < a.length; i++) {
+ int e = i < 16 ? 4 : 2;
+ expectEquals(e, a[i]);
+ }
+
+ expectEquals(98, breakLoopNastyPhi(a));
+ for (int i = 0; i < a.length; i++) {
+ expectEquals(5, a[i]);
+ }
+
+ expectEquals(500, breakLoopReduction(a));
+
+ System.out.println("passed");
+ }
+
+ private static void expectEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+}
diff --git a/test/711-checker-type-conversion/expected.txt b/test/711-checker-type-conversion/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/711-checker-type-conversion/expected.txt
diff --git a/test/711-checker-type-conversion/info.txt b/test/711-checker-type-conversion/info.txt
new file mode 100644
index 0000000000..5b63572a76
--- /dev/null
+++ b/test/711-checker-type-conversion/info.txt
@@ -0,0 +1 @@
+Tests for type conversion elimination.
diff --git a/test/711-checker-type-conversion/src/Main.java b/test/711-checker-type-conversion/src/Main.java
new file mode 100644
index 0000000000..2c9c3a157e
--- /dev/null
+++ b/test/711-checker-type-conversion/src/Main.java
@@ -0,0 +1,77 @@
+/*
+ * 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 assertByteEquals(byte expected, byte result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ /// CHECK-START: byte Main.getByte1() constant_folding (before)
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK: Add
+ /// CHECK: TypeConversion
+
+ /// CHECK-START: byte Main.getByte1() constant_folding (after)
+ /// CHECK-NOT: TypeConversion
+ /// CHECK-NOT: Add
+
+ static byte getByte1() {
+ int i = -2;
+ int j = -3;
+ return (byte)((byte)i + (byte)j);
+ }
+
+ /// CHECK-START: byte Main.getByte2() constant_folding (before)
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK: Add
+ /// CHECK: TypeConversion
+
+ /// CHECK-START: byte Main.getByte2() constant_folding (after)
+ /// CHECK-NOT: TypeConversion
+ /// CHECK-NOT: Add
+
+ static byte getByte2() {
+ int i = -100;
+ int j = -101;
+ return (byte)((byte)i + (byte)j);
+ }
+
+ /// CHECK-START: byte Main.getByte3() constant_folding (before)
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK: Add
+ /// CHECK: TypeConversion
+
+ /// CHECK-START: byte Main.getByte2() constant_folding (after)
+ /// CHECK-NOT: TypeConversion
+ /// CHECK-NOT: Add
+
+ static byte getByte3() {
+ long i = 0xabcdabcdabcdL;
+ return (byte)((byte)i + (byte)i);
+ }
+
+ public static void main(String[] args) {
+ assertByteEquals(getByte1(), (byte)-5);
+ assertByteEquals(getByte2(), (byte)(-201));
+ assertByteEquals(getByte3(), (byte)(0xcd + 0xcd));
+ }
+}
diff --git a/test/Android.bp b/test/Android.bp
index ba24119e9c..01e424d5e3 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",
@@ -363,8 +364,9 @@ cc_defaults {
"141-class-unload/jni_unload.cc",
"148-multithread-gc-annotations/gc_coverage.cc",
"149-suspend-all-stress/suspend_all.cc",
- "203-multi-checkpoint/multi_checkpoint.cc",
"154-gc-loop/heap_interface.cc",
+ "167-visit-locks/visit_locks.cc",
+ "203-multi-checkpoint/multi_checkpoint.cc",
"454-get-vreg/get_vreg_jni.cc",
"457-regs/regs_jni.cc",
"461-get-reference-vreg/get_reference_vreg_jni.cc",
@@ -383,6 +385,7 @@ cc_defaults {
"656-annotation-lookup-generic-jni/test.cc",
"661-oat-writer-layout/oat_writer_layout.cc",
"664-aget-verifier/aget-verifier.cc",
+ "667-jit-jni-stub/jit_jni_stub_test.cc",
"708-jit-cache-churn/jit.cc",
],
shared_libs: [
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index df497c1181..34580800cc 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -152,10 +152,10 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isAotCompiled(JNIEnv* env,
return method->GetOatMethodQuickCode(kRuntimePointerSize) != nullptr;
}
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_isJitCompiled(JNIEnv* env,
- jclass,
- jclass cls,
- jstring method_name) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledEntrypoint(JNIEnv* env,
+ jclass,
+ jclass cls,
+ jstring method_name) {
jit::Jit* jit = GetJitIfEnabled();
if (jit == nullptr) {
return false;
@@ -169,6 +169,23 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isJitCompiled(JNIEnv* env,
return jit->GetCodeCache()->ContainsPc(method->GetEntryPointFromQuickCompiledCode());
}
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledCode(JNIEnv* env,
+ jclass,
+ jclass cls,
+ jstring method_name) {
+ jit::Jit* jit = GetJitIfEnabled();
+ if (jit == nullptr) {
+ return false;
+ }
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+ ScopedUtfChars chars(env, method_name);
+ CHECK(chars.c_str() != nullptr);
+ ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
+ chars.c_str(), kRuntimePointerSize);
+ return jit->GetCodeCache()->ContainsMethod(method);
+}
+
extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
jclass,
jclass cls,
diff --git a/test/knownfailures.json b/test/knownfailures.json
index c6b6574f1b..5b2ebf58a4 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -202,6 +202,12 @@
"bug": "http://b/34369284"
},
{
+ "tests": "1940-ddms-ext",
+ "description": ["Test expects to be able to start tracing but we cannot",
+ "do that if tracing is already ongoing."],
+ "variant": "trace | stream"
+ },
+ {
"tests": "137-cfi",
"description": ["This test unrolls and expects managed frames, but",
"tracing means we run the interpreter."],
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index e7503827f2..554b8a5429 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -874,7 +874,7 @@ def parse_option():
global run_all_configs
parser = argparse.ArgumentParser(description="Runs all or a subset of the ART test suite.")
- parser.add_argument('-t', '--test', dest='test', help='name of the test')
+ parser.add_argument('-t', '--test', action='append', dest='tests', help='name(s) of the test(s)')
parser.add_argument('-j', type=int, dest='n_thread')
parser.add_argument('--timeout', default=timeout, type=int, dest='timeout')
for variant in TOTAL_VARIANTS_SET:
@@ -906,10 +906,12 @@ def parse_option():
options = setup_env_for_build_target(target_config[options['build_target']],
parser, options)
- test = ''
+ tests = None
env.EXTRA_DISABLED_TESTS.update(set(options['skips']))
- if options['test']:
- test = parse_test_name(options['test'])
+ if options['tests']:
+ tests = set()
+ for test_name in options['tests']:
+ tests |= parse_test_name(test_name)
for variant_type in VARIANT_TYPE_DICT:
for variant in VARIANT_TYPE_DICT[variant_type]:
@@ -935,11 +937,11 @@ def parse_option():
if options['run_all']:
run_all_configs = True
- return test
+ return tests
def main():
gather_test_info()
- user_requested_test = parse_option()
+ user_requested_tests = parse_option()
setup_test_env()
if build:
build_targets = ''
@@ -956,8 +958,8 @@ def main():
build_command += ' dist'
if subprocess.call(build_command.split()):
sys.exit(1)
- if user_requested_test:
- test_runner_thread = threading.Thread(target=run_tests, args=(user_requested_test,))
+ if user_requested_tests:
+ test_runner_thread = threading.Thread(target=run_tests, args=(user_requested_tests,))
else:
test_runner_thread = threading.Thread(target=run_tests, args=(RUN_TEST_SET,))
test_runner_thread.daemon = True