289 lines
9.9 KiB
Java
289 lines
9.9 KiB
Java
/*
|
|
* Copyright (C) 2010 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.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.Modifier;
|
|
|
|
/*
|
|
* Entry point and tests that are expected to succeed.
|
|
*/
|
|
public class Main {
|
|
/**
|
|
* Drives tests.
|
|
*/
|
|
public static void main(String[] args) throws Exception {
|
|
System.loadLibrary(args[0]);
|
|
if (!hasOatFile() || runtimeIsSoftFail() || isInterpreted()) {
|
|
// Some tests ensure that the verifier was able to guarantee balanced locking by
|
|
// asserting that the test function is running as compiled code. But skip this now,
|
|
// as this seems to be a non-compiled code test configuration.
|
|
disableStackFrameAsserts();
|
|
}
|
|
|
|
ensureJitCompiled(Main.class, "recursiveSync");
|
|
ensureJitCompiled(Main.class, "nestedMayThrow");
|
|
ensureJitCompiled(Main.class, "constantLock");
|
|
ensureJitCompiled(Main.class, "notExcessiveNesting");
|
|
ensureJitCompiled(Main.class, "notNested");
|
|
ensureJitCompiled(TwoPath.class, "twoPath");
|
|
ensureJitCompiled(Class.forName("OK"), "runNoMonitors");
|
|
ensureJitCompiled(Class.forName("OK"), "runStraightLine");
|
|
ensureJitCompiled(Class.forName("OK"), "runBalancedJoin");
|
|
ensureJitCompiled(Class.forName("NullLocks"), "run");
|
|
|
|
Main m = new Main();
|
|
|
|
m.recursiveSync(0);
|
|
|
|
m.nestedMayThrow(false);
|
|
try {
|
|
m.nestedMayThrow(true);
|
|
System.out.println("nestedThrow(true) did not throw");
|
|
} catch (MyException me) {}
|
|
System.out.println("nestedMayThrow ok");
|
|
|
|
m.constantLock();
|
|
System.out.println("constantLock ok");
|
|
|
|
m.notExcessiveNesting();
|
|
|
|
m.notNested();
|
|
System.out.println("notNested ok");
|
|
|
|
Object obj1 = new Object();
|
|
Object obj2 = new Object();
|
|
|
|
TwoPath.twoPath(obj1, obj2, 0);
|
|
System.out.println("twoPath ok");
|
|
|
|
m.triplet(obj1, obj2, 0);
|
|
System.out.println("triplet ok");
|
|
|
|
runSmaliTests();
|
|
}
|
|
|
|
/**
|
|
* Recursive synchronized method.
|
|
*/
|
|
synchronized void recursiveSync(int iter) {
|
|
assertIsManaged();
|
|
if (iter < 40) {
|
|
recursiveSync(iter+1);
|
|
} else {
|
|
System.out.println("recursiveSync ok");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tests simple nesting, with and without a throw.
|
|
*/
|
|
void nestedMayThrow(boolean doThrow) {
|
|
assertIsManaged();
|
|
synchronized (this) {
|
|
synchronized (Main.class) {
|
|
synchronized (new Object()) {
|
|
synchronized(Class.class) {
|
|
if (doThrow) {
|
|
throw new MyException();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Exercises bug 3215458.
|
|
*/
|
|
void constantLock() {
|
|
assertIsManaged();
|
|
Class<?> thing = Thread.class;
|
|
synchronized (Thread.class) {}
|
|
}
|
|
|
|
/**
|
|
* Confirms that we can have 32 nested monitors on one method.
|
|
*/
|
|
void notExcessiveNesting() {
|
|
assertIsManaged();
|
|
synchronized (this) { // 1
|
|
synchronized (this) { // 2
|
|
synchronized (this) { // 3
|
|
synchronized (this) { // 4
|
|
synchronized (this) { // 5
|
|
synchronized (this) { // 6
|
|
synchronized (this) { // 7
|
|
synchronized (this) { // 8
|
|
synchronized (this) { // 9
|
|
synchronized (this) { // 10
|
|
synchronized (this) { // 11
|
|
synchronized (this) { // 12
|
|
synchronized (this) { // 13
|
|
synchronized (this) { // 14
|
|
synchronized (this) { // 15
|
|
synchronized (this) { // 16
|
|
synchronized (this) { // 17
|
|
synchronized (this) { // 18
|
|
synchronized (this) { // 19
|
|
synchronized (this) { // 20
|
|
synchronized (this) { // 21
|
|
synchronized (this) { // 22
|
|
synchronized (this) { // 23
|
|
synchronized (this) { // 24
|
|
synchronized (this) { // 25
|
|
synchronized (this) { // 26
|
|
synchronized (this) { // 27
|
|
synchronized (this) { // 28
|
|
synchronized (this) { // 29
|
|
synchronized (this) { // 30
|
|
synchronized (this) { // 31
|
|
synchronized (this) { // 32
|
|
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
|
|
}
|
|
|
|
/**
|
|
* Confirms that we can have more than 32 non-nested monitors in one
|
|
* method.
|
|
*/
|
|
void notNested() {
|
|
assertIsManaged();
|
|
synchronized (this) {} // 1
|
|
synchronized (this) {} // 2
|
|
synchronized (this) {} // 3
|
|
synchronized (this) {} // 4
|
|
synchronized (this) {} // 5
|
|
synchronized (this) {} // 6
|
|
synchronized (this) {} // 7
|
|
synchronized (this) {} // 8
|
|
synchronized (this) {} // 9
|
|
synchronized (this) {} // 10
|
|
synchronized (this) {} // 11
|
|
synchronized (this) {} // 12
|
|
synchronized (this) {} // 13
|
|
synchronized (this) {} // 14
|
|
synchronized (this) {} // 15
|
|
synchronized (this) {} // 16
|
|
synchronized (this) {} // 17
|
|
synchronized (this) {} // 18
|
|
synchronized (this) {} // 19
|
|
synchronized (this) {} // 20
|
|
synchronized (this) {} // 21
|
|
synchronized (this) {} // 22
|
|
synchronized (this) {} // 23
|
|
synchronized (this) {} // 24
|
|
synchronized (this) {} // 25
|
|
synchronized (this) {} // 26
|
|
synchronized (this) {} // 27
|
|
synchronized (this) {} // 28
|
|
synchronized (this) {} // 29
|
|
synchronized (this) {} // 30
|
|
synchronized (this) {} // 31
|
|
synchronized (this) {} // 32
|
|
synchronized (this) {} // 33
|
|
synchronized (this) {} // 34
|
|
}
|
|
|
|
/* does nothing but ensure that the compiler doesn't discard an object */
|
|
private void doNothing(Object obj) {}
|
|
|
|
/**
|
|
* Lock the monitor two or three times, and make use of the locked or
|
|
* unlocked object.
|
|
*/
|
|
public void triplet(Object obj1, Object obj2, int x) {
|
|
Object localObj;
|
|
|
|
synchronized (obj1) {
|
|
synchronized(obj1) {
|
|
if (x == 0) {
|
|
synchronized(obj1) {
|
|
localObj = obj2;
|
|
}
|
|
} else {
|
|
localObj = obj1;
|
|
}
|
|
}
|
|
}
|
|
|
|
doNothing(localObj);
|
|
}
|
|
|
|
// Smali testing code.
|
|
private static void runSmaliTests() {
|
|
runTest("OK", new Object[] { new Object(), new Object() }, null);
|
|
runTest("TooDeep", new Object[] { new Object() }, null);
|
|
runTest("NotStructuredOverUnlock", new Object[] { new Object() },
|
|
IllegalMonitorStateException.class);
|
|
runTest("NotStructuredUnderUnlock", new Object[] { new Object() },
|
|
IllegalMonitorStateException.class);
|
|
runTest("UnbalancedJoin", new Object[] { new Object(), new Object() }, null);
|
|
runTest("UnbalancedStraight", new Object[] { new Object(), new Object() }, null);
|
|
runTest("NullLocks", new Object[] { false }, null);
|
|
runTest("NullLocks", new Object[] { true }, NullPointerException.class);
|
|
}
|
|
|
|
private static void runTest(String className, Object[] parameters, Class<?> excType) {
|
|
try {
|
|
Class<?> c = Class.forName(className);
|
|
|
|
Method[] methods = c.getDeclaredMethods();
|
|
|
|
// For simplicity we assume that test methods are not overloaded. So searching by name
|
|
// will give us the method we need to run.
|
|
Method method = null;
|
|
for (Method m : methods) {
|
|
if (m.getName().equals("run")) {
|
|
method = m;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (method == null) {
|
|
System.out.println("Could not find test method for " + className);
|
|
} else if (!Modifier.isStatic(method.getModifiers())) {
|
|
System.out.println("Test method for " + className + " is not static.");
|
|
} else {
|
|
method.invoke(null, parameters);
|
|
if (excType != null) {
|
|
System.out.println("Expected an exception in " + className);
|
|
}
|
|
}
|
|
} catch (Throwable exc) {
|
|
if (excType == null) {
|
|
System.out.println("Did not expect exception " + exc + " for " + className);
|
|
exc.printStackTrace(System.out);
|
|
} else if (exc instanceof InvocationTargetException && exc.getCause() != null &&
|
|
exc.getCause().getClass().equals(excType)) {
|
|
// Expected exception is wrapped in InvocationTargetException.
|
|
} else if (!excType.equals(exc.getClass())) {
|
|
System.out.println("Expected " + excType.getName() + ", but got " + exc.getClass());
|
|
} else {
|
|
// Expected exception, do nothing.
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helpers for the smali code.
|
|
public static native void assertIsInterpreted();
|
|
public static native void assertIsManaged();
|
|
public static native boolean hasOatFile();
|
|
public static native boolean runtimeIsSoftFail();
|
|
public static native boolean isInterpreted();
|
|
public static native void disableStackFrameAsserts();
|
|
private static native void ensureJitCompiled(Class<?> itf, String method_name);
|
|
}
|