summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/168-vmstack-annotated/expected.txt0
-rw-r--r--test/168-vmstack-annotated/info.txt1
-rw-r--r--test/168-vmstack-annotated/run18
-rw-r--r--test/168-vmstack-annotated/src/Main.java225
-rw-r--r--test/672-checker-throw-method/expected.txt1
-rw-r--r--test/672-checker-throw-method/info.txt1
-rw-r--r--test/672-checker-throw-method/src/Main.java244
-rw-r--r--test/HiddenApi/Main.java26
-rw-r--r--test/knownfailures.json10
9 files changed, 525 insertions, 1 deletions
diff --git a/test/168-vmstack-annotated/expected.txt b/test/168-vmstack-annotated/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/168-vmstack-annotated/expected.txt
diff --git a/test/168-vmstack-annotated/info.txt b/test/168-vmstack-annotated/info.txt
new file mode 100644
index 0000000000..d849bc31ed
--- /dev/null
+++ b/test/168-vmstack-annotated/info.txt
@@ -0,0 +1 @@
+Regression test for b/68703210
diff --git a/test/168-vmstack-annotated/run b/test/168-vmstack-annotated/run
new file mode 100644
index 0000000000..93654113e6
--- /dev/null
+++ b/test/168-vmstack-annotated/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/168-vmstack-annotated/src/Main.java b/test/168-vmstack-annotated/src/Main.java
new file mode 100644
index 0000000000..8234f945c0
--- /dev/null
+++ b/test/168-vmstack-annotated/src/Main.java
@@ -0,0 +1,225 @@
+/*
+ * 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.lang.Thread.State;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+public class Main {
+
+ static class Runner implements Runnable {
+ List<Object> locks;
+ List<CyclicBarrier> barriers;
+
+ public Runner(List<Object> locks, List<CyclicBarrier> barriers) {
+ this.locks = locks;
+ this.barriers = barriers;
+ }
+
+ @Override
+ public void run() {
+ step(locks, barriers);
+ }
+
+ private void step(List<Object> l, List<CyclicBarrier> b) {
+ if (l.isEmpty()) {
+ // Nothing to do, sleep indefinitely.
+ try {
+ Thread.sleep(100000000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ Object lockObject = l.remove(0);
+ CyclicBarrier barrierObject = b.remove(0);
+
+ if (lockObject == null) {
+ // No lock object: only take barrier, recurse.
+ try {
+ barrierObject.await();
+ } catch (InterruptedException | BrokenBarrierException e) {
+ throw new RuntimeException(e);
+ }
+ step(l, b);
+ } else if (barrierObject != null) {
+ // Have barrier: sync, wait and recurse.
+ synchronized(lockObject) {
+ try {
+ barrierObject.await();
+ } catch (InterruptedException | BrokenBarrierException e) {
+ throw new RuntimeException(e);
+ }
+ step(l, b);
+ }
+ } else {
+ // Sync, and get next step (which is assumed to have object and barrier).
+ synchronized (lockObject) {
+ Object lockObject2 = l.remove(0);
+ CyclicBarrier barrierObject2 = b.remove(0);
+ synchronized(lockObject2) {
+ try {
+ barrierObject2.await();
+ } catch (InterruptedException | BrokenBarrierException e) {
+ throw new RuntimeException(e);
+ }
+ step(l, b);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ try {
+ testCluster1();
+ } catch (Exception e) {
+ Map<Thread,StackTraceElement[]> stacks = Thread.getAllStackTraces();
+ for (Map.Entry<Thread,StackTraceElement[]> entry : stacks.entrySet()) {
+ System.out.println(entry.getKey());
+ System.out.println(Arrays.toString(entry.getValue()));
+ }
+ throw e;
+ }
+ }
+
+ private static void testCluster1() throws Exception {
+ // Test setup (at deadlock):
+ //
+ // Thread 1:
+ // #0 step: synchornized(o3) { synchronized(o2) }
+ // #1 step: synchronized(o1)
+ //
+ // Thread 2:
+ // #0 step: synchronized(o1)
+ // #1 step: synchronized(o4) { synchronized(o2) }
+ //
+ LinkedList<Object> l1 = new LinkedList<>();
+ LinkedList<CyclicBarrier> b1 = new LinkedList<>();
+ LinkedList<Object> l2 = new LinkedList<>();
+ LinkedList<CyclicBarrier> b2 = new LinkedList<>();
+
+ Object o1 = new Object();
+ Object o2 = new Object();
+ Object o3 = new Object();
+ Object o4 = new Object();
+
+ l1.add(o1);
+ l1.add(o3);
+ l1.add(o2);
+ l2.add(o4);
+ l2.add(o2);
+ l2.add(o1);
+
+ CyclicBarrier c1 = new CyclicBarrier(3);
+ CyclicBarrier c2 = new CyclicBarrier(2);
+ b1.add(c1);
+ b1.add(null);
+ b1.add(c2);
+ b2.add(null);
+ b2.add(c1);
+ b2.add(c2);
+
+ Thread t1 = new Thread(new Runner(l1, b1));
+ t1.setDaemon(true);
+ t1.start();
+ Thread t2 = new Thread(new Runner(l2, b2));
+ t2.setDaemon(true);
+ t2.start();
+
+ c1.await();
+
+ waitNotRunnable(t1);
+ waitNotRunnable(t2);
+ Thread.sleep(250); // Unfortunately this seems necessary. :-(
+
+ // Thread 1.
+ {
+ Object[] stack1 = getAnnotatedStack(t1);
+ assertBlockedOn(stack1[0], o2); // Blocked on o2.
+ assertLocks(stack1[0], o3); // Locked o3.
+ assertStackTraceElementStep(stack1[0]);
+
+ assertBlockedOn(stack1[1], null); // Frame can't be blocked.
+ assertLocks(stack1[1], o1); // Locked o1.
+ assertStackTraceElementStep(stack1[1]);
+ }
+
+ // Thread 2.
+ {
+ Object[] stack2 = getAnnotatedStack(t2);
+ assertBlockedOn(stack2[0], o1); // Blocked on o1.
+ assertLocks(stack2[0]); // Nothing locked.
+ assertStackTraceElementStep(stack2[0]);
+
+ assertBlockedOn(stack2[1], null); // Frame can't be blocked.
+ assertLocks(stack2[1], o4, o2); // Locked o4, o2.
+ assertStackTraceElementStep(stack2[1]);
+ }
+ }
+
+ private static void waitNotRunnable(Thread t) throws InterruptedException {
+ while (t.getState() == State.RUNNABLE) {
+ Thread.sleep(100);
+ }
+ }
+
+ private static Object[] getAnnotatedStack(Thread t) throws Exception {
+ Class<?> vmStack = Class.forName("dalvik.system.VMStack");
+ Method m = vmStack.getDeclaredMethod("getAnnotatedThreadStackTrace", Thread.class);
+ return (Object[]) m.invoke(null, t);
+ }
+
+ private static void assertEquals(Object o1, Object o2) {
+ if (o1 != o2) {
+ throw new RuntimeException("Expected " + o1 + " == " + o2);
+ }
+ }
+ private static void assertLocks(Object fromTrace, Object... locks) throws Exception {
+ Object fieldValue = fromTrace.getClass().getDeclaredMethod("getHeldLocks").
+ invoke(fromTrace);
+ assertEquals((Object[]) fieldValue,
+ (locks == null) ? null : (locks.length == 0 ? null : locks));
+ }
+ private static void assertBlockedOn(Object fromTrace, Object block) throws Exception {
+ Object fieldValue = fromTrace.getClass().getDeclaredMethod("getBlockedOn").
+ invoke(fromTrace);
+ assertEquals(fieldValue, block);
+ }
+ private static void assertEquals(Object[] o1, Object[] o2) {
+ if (!Arrays.equals(o1, o2)) {
+ throw new RuntimeException(
+ "Expected " + Arrays.toString(o1) + " == " + Arrays.toString(o2));
+ }
+ }
+ private static void assertStackTraceElementStep(Object o) throws Exception {
+ Object fieldValue = o.getClass().getDeclaredMethod("getStackTraceElement").invoke(o);
+ if (fieldValue instanceof StackTraceElement) {
+ StackTraceElement elem = (StackTraceElement) fieldValue;
+ if (!elem.getMethodName().equals("step")) {
+ throw new RuntimeException("Expected step method");
+ }
+ return;
+ }
+ throw new RuntimeException("Expected StackTraceElement " + fieldValue + " / " + o);
+ }
+}
+
diff --git a/test/672-checker-throw-method/expected.txt b/test/672-checker-throw-method/expected.txt
new file mode 100644
index 0000000000..b0aad4deb5
--- /dev/null
+++ b/test/672-checker-throw-method/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/672-checker-throw-method/info.txt b/test/672-checker-throw-method/info.txt
new file mode 100644
index 0000000000..250810be15
--- /dev/null
+++ b/test/672-checker-throw-method/info.txt
@@ -0,0 +1 @@
+Test detecting throwing methods for code sinking.
diff --git a/test/672-checker-throw-method/src/Main.java b/test/672-checker-throw-method/src/Main.java
new file mode 100644
index 0000000000..ceb5eb784c
--- /dev/null
+++ b/test/672-checker-throw-method/src/Main.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2018 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 detecting throwing methods for code sinking.
+ */
+public class Main {
+
+ //
+ // Some "runtime library" methods.
+ //
+
+ static private void doThrow(String par) {
+ throw new Error("you are null: " + par);
+ }
+
+ static private void checkNotNullDirect(Object obj, String par) {
+ if (obj == null)
+ throw new Error("you are null: " + par);
+ }
+
+ static private void checkNotNullSplit(Object obj, String par) {
+ if (obj == null)
+ doThrow(par);
+ }
+
+ //
+ // Various ways of enforcing non-null parameter.
+ // In all cases, par should be subject to code sinking.
+ //
+
+ /// CHECK-START: void Main.doit1(int[]) code_sinking (before)
+ /// CHECK: begin_block
+ /// CHECK: <<Str:l\d+>> LoadString
+ /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: If [<<Tst>>]
+ /// CHECK: end_block
+ /// CHECK: begin_block
+ /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: Throw
+ /// CHECK: end_block
+ //
+ /// CHECK-START: void Main.doit1(int[]) code_sinking (after)
+ /// CHECK: begin_block
+ /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: If [<<Tst>>]
+ /// CHECK: end_block
+ /// CHECK: begin_block
+ /// CHECK: <<Str:l\d+>> LoadString
+ /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: Throw
+ /// CHECK: end_block
+ static public void doit1(int[] a) {
+ String par = "a";
+ if (a == null)
+ throw new Error("you are null: " + par);
+ for (int i = 0; i < a.length; i++) {
+ a[i] = 1;
+ }
+ }
+
+ /// CHECK-START: void Main.doit2(int[]) code_sinking (before)
+ /// CHECK: begin_block
+ /// CHECK: <<Str:l\d+>> LoadString
+ /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: If [<<Tst>>]
+ /// CHECK: end_block
+ /// CHECK: begin_block
+ /// CHECK: InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
+ /// CHECK: end_block
+ //
+ /// CHECK-START: void Main.doit2(int[]) code_sinking (after)
+ /// CHECK: begin_block
+ /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: If [<<Tst>>]
+ /// CHECK: end_block
+ /// CHECK: begin_block
+ /// CHECK: <<Str:l\d+>> LoadString
+ /// CHECK: InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
+ /// CHECK: end_block
+ static public void doit2(int[] a) {
+ String par = "a";
+ if (a == null)
+ doThrow(par);
+ for (int i = 0; i < a.length; i++) {
+ a[i] = 2;
+ }
+ }
+
+ /// CHECK-START: void Main.doit3(int[]) code_sinking (before)
+ /// CHECK: begin_block
+ /// CHECK: <<Str:l\d+>> LoadString
+ /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: If [<<Tst>>]
+ /// CHECK: end_block
+ /// CHECK: begin_block
+ /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: Throw
+ /// CHECK: end_block
+ //
+ /// CHECK-START: void Main.doit3(int[]) code_sinking (after)
+ /// CHECK: begin_block
+ /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: If [<<Tst>>]
+ /// CHECK: end_block
+ /// CHECK: begin_block
+ /// CHECK: <<Str:l\d+>> LoadString
+ /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: Throw
+ /// CHECK: end_block
+ static public void doit3(int[] a) {
+ String par = "a";
+ checkNotNullDirect(a, par);
+ for (int i = 0; i < a.length; i++) {
+ a[i] = 3;
+ }
+ }
+
+ /// CHECK-START: void Main.doit4(int[]) code_sinking (before)
+ /// CHECK: begin_block
+ /// CHECK: <<Str:l\d+>> LoadString
+ /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: If [<<Tst>>]
+ /// CHECK: end_block
+ /// CHECK: begin_block
+ /// CHECK: InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
+ /// CHECK: end_block
+ //
+ /// CHECK-START: void Main.doit4(int[]) code_sinking (after)
+ /// CHECK: begin_block
+ /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: If [<<Tst>>]
+ /// CHECK: end_block
+ /// CHECK: begin_block
+ /// CHECK: <<Str:l\d+>> LoadString
+ /// CHECK: InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
+ /// CHECK: end_block
+ static public void doit4(int[] a) {
+ String par = "a";
+ checkNotNullSplit(a, par); // resembles Kotlin runtime lib
+ // (test is lined, doThrow is not)
+ for (int i = 0; i < a.length; i++) {
+ a[i] = 4;
+ }
+ }
+
+ // Ensures Phi values are merged properly.
+ static public int doit5(int[] a) {
+ int t = 100;
+ String par = "a";
+ if (a == null) {
+ doThrow(par);
+ } else {
+ t = 1000;
+ }
+ for (int i = 0; i < a.length; i++) {
+ a[i] = 5;
+ }
+ // Phi on t, even though doThrow never reaches.
+ return t;
+ }
+
+ //
+ // Test driver.
+ //
+
+ static public void main(String[] args) {
+ int[] a = new int[100];
+ for (int i = 0; i < 100; i++) {
+ a[i] = 0;
+ }
+
+ try {
+ doit1(null);
+ System.out.println("should not reach this!");
+ } catch (Error e) {
+ doit1(a);
+ }
+ for (int i = 0; i < 100; i++) {
+ expectEquals(1, a[i]);
+ }
+
+ try {
+ doit2(null);
+ System.out.println("should not reach this!");
+ } catch (Error e) {
+ doit2(a);
+ }
+ for (int i = 0; i < 100; i++) {
+ expectEquals(2, a[i]);
+ }
+
+ try {
+ doit3(null);
+ System.out.println("should not reach this!");
+ } catch (Error e) {
+ doit3(a);
+ }
+ for (int i = 0; i < 100; i++) {
+ expectEquals(3, a[i]);
+ }
+
+ try {
+ doit4(null);
+ System.out.println("should not reach this!");
+ } catch (Error e) {
+ doit4(a);
+ }
+ for (int i = 0; i < 100; i++) {
+ expectEquals(4, a[i]);
+ }
+
+ try {
+ doit5(null);
+ System.out.println("should not reach this!");
+ } catch (Error e) {
+ expectEquals(1000, doit5(a));
+ }
+ for (int i = 0; i < 100; i++) {
+ expectEquals(5, a[i]);
+ }
+
+ 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/HiddenApi/Main.java b/test/HiddenApi/Main.java
new file mode 100644
index 0000000000..187dd6e599
--- /dev/null
+++ b/test/HiddenApi/Main.java
@@ -0,0 +1,26 @@
+/*
+ * 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 int ifield;
+ private static Object sfield;
+
+ void imethod(long x) {}
+ public static void smethod(Object x) {}
+
+ public native void inmethod(char x);
+ protected native static void snmethod(Integer x);
+}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 9db8e9df0a..b39d6072fa 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -412,7 +412,8 @@
{
"tests": [
"961-default-iface-resolution-gen",
- "964-default-iface-init-gen"
+ "964-default-iface-init-gen",
+ "968-default-partial-compile-gen"
],
"description": ["Tests that just take too long with jvmti-stress"],
"variant": "jvmti-stress | redefine-stress | trace-stress | step-stress"
@@ -647,6 +648,13 @@
"bug": "b/64683522"
},
{
+ "tests": ["628-vdex",
+ "629-vdex-speed",
+ "634-vdex-duplicate"],
+ "variant": "cdex-fast",
+ "description": ["Tests that depend on input-vdex are not supported with compact dex"]
+ },
+ {
"tests": "661-oat-writer-layout",
"variant": "interp-ac | interpreter | jit | no-dex2oat | no-prebuild | no-image | trace | redefine-stress | jvmti-stress",
"description": ["Test is designed to only check --compiler-filter=speed"]