/* * 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); }