| /* |
| * 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() { |
| // clang-format off |
| 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 |
| }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} |
| // clang-format on |
| } |
| |
| /** |
| * Confirms that we can have more than 32 non-nested monitors in one |
| * method. |
| */ |
| void notNested() { |
| // clang-format off |
| 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 |
| // clang-format on |
| } |
| |
| /* 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); |
| } |