1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19 import java.lang.reflect.Modifier;
20 
21 /*
22  * Entry point and tests that are expected to succeed.
23  */
24 public class Main {
25     /**
26      * Drives tests.
27      */
main(String[] args)28     public static void main(String[] args) throws Exception {
29         System.loadLibrary(args[0]);
30         if (!hasOatFile() || runtimeIsSoftFail() || isInterpreted()) {
31             // Some tests ensure that the verifier was able to guarantee balanced locking by
32             // asserting that the test function is running as compiled code. But skip this now,
33             // as this seems to be a non-compiled code test configuration.
34             disableStackFrameAsserts();
35         }
36 
37         ensureJitCompiled(Main.class, "recursiveSync");
38         ensureJitCompiled(Main.class, "nestedMayThrow");
39         ensureJitCompiled(Main.class, "constantLock");
40         ensureJitCompiled(Main.class, "notExcessiveNesting");
41         ensureJitCompiled(Main.class, "notNested");
42         ensureJitCompiled(TwoPath.class, "twoPath");
43         ensureJitCompiled(Class.forName("OK"), "runNoMonitors");
44         ensureJitCompiled(Class.forName("OK"), "runStraightLine");
45         ensureJitCompiled(Class.forName("OK"), "runBalancedJoin");
46         ensureJitCompiled(Class.forName("NullLocks"), "run");
47 
48         Main m = new Main();
49 
50         m.recursiveSync(0);
51 
52         m.nestedMayThrow(false);
53         try {
54             m.nestedMayThrow(true);
55             System.out.println("nestedThrow(true) did not throw");
56         } catch (MyException me) {}
57         System.out.println("nestedMayThrow ok");
58 
59         m.constantLock();
60         System.out.println("constantLock ok");
61 
62         m.notExcessiveNesting();
63 
64         m.notNested();
65         System.out.println("notNested ok");
66 
67         Object obj1 = new Object();
68         Object obj2 = new Object();
69 
70         TwoPath.twoPath(obj1, obj2, 0);
71         System.out.println("twoPath ok");
72 
73         m.triplet(obj1, obj2, 0);
74         System.out.println("triplet ok");
75 
76         runSmaliTests();
77     }
78 
79     /**
80      * Recursive synchronized method.
81      */
recursiveSync(int iter)82     synchronized void recursiveSync(int iter) {
83         assertIsManaged();
84         if (iter < 40) {
85             recursiveSync(iter+1);
86         } else {
87             System.out.println("recursiveSync ok");
88         }
89     }
90 
91     /**
92      * Tests simple nesting, with and without a throw.
93      */
nestedMayThrow(boolean doThrow)94     void nestedMayThrow(boolean doThrow) {
95         assertIsManaged();
96         synchronized (this) {
97             synchronized (Main.class) {
98                 synchronized (new Object()) {
99                     synchronized(Class.class) {
100                         if (doThrow) {
101                             throw new MyException();
102                         }
103                     }
104                 }
105             }
106         }
107     }
108 
109     /**
110      * Exercises bug 3215458.
111      */
constantLock()112     void constantLock() {
113         assertIsManaged();
114         Class<?> thing = Thread.class;
115         synchronized (Thread.class) {}
116     }
117 
118     /**
119      * Confirms that we can have 32 nested monitors on one method.
120      */
notExcessiveNesting()121     void notExcessiveNesting() {
122         assertIsManaged();
123         synchronized (this) {   // 1
124         synchronized (this) {   // 2
125         synchronized (this) {   // 3
126         synchronized (this) {   // 4
127         synchronized (this) {   // 5
128         synchronized (this) {   // 6
129         synchronized (this) {   // 7
130         synchronized (this) {   // 8
131         synchronized (this) {   // 9
132         synchronized (this) {   // 10
133         synchronized (this) {   // 11
134         synchronized (this) {   // 12
135         synchronized (this) {   // 13
136         synchronized (this) {   // 14
137         synchronized (this) {   // 15
138         synchronized (this) {   // 16
139         synchronized (this) {   // 17
140         synchronized (this) {   // 18
141         synchronized (this) {   // 19
142         synchronized (this) {   // 20
143         synchronized (this) {   // 21
144         synchronized (this) {   // 22
145         synchronized (this) {   // 23
146         synchronized (this) {   // 24
147         synchronized (this) {   // 25
148         synchronized (this) {   // 26
149         synchronized (this) {   // 27
150         synchronized (this) {   // 28
151         synchronized (this) {   // 29
152         synchronized (this) {   // 30
153         synchronized (this) {   // 31
154         synchronized (this) {   // 32
155         }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
156     }
157 
158     /**
159      * Confirms that we can have more than 32 non-nested monitors in one
160      * method.
161      */
notNested()162     void notNested() {
163         assertIsManaged();
164         synchronized (this) {}  // 1
165         synchronized (this) {}  // 2
166         synchronized (this) {}  // 3
167         synchronized (this) {}  // 4
168         synchronized (this) {}  // 5
169         synchronized (this) {}  // 6
170         synchronized (this) {}  // 7
171         synchronized (this) {}  // 8
172         synchronized (this) {}  // 9
173         synchronized (this) {}  // 10
174         synchronized (this) {}  // 11
175         synchronized (this) {}  // 12
176         synchronized (this) {}  // 13
177         synchronized (this) {}  // 14
178         synchronized (this) {}  // 15
179         synchronized (this) {}  // 16
180         synchronized (this) {}  // 17
181         synchronized (this) {}  // 18
182         synchronized (this) {}  // 19
183         synchronized (this) {}  // 20
184         synchronized (this) {}  // 21
185         synchronized (this) {}  // 22
186         synchronized (this) {}  // 23
187         synchronized (this) {}  // 24
188         synchronized (this) {}  // 25
189         synchronized (this) {}  // 26
190         synchronized (this) {}  // 27
191         synchronized (this) {}  // 28
192         synchronized (this) {}  // 29
193         synchronized (this) {}  // 30
194         synchronized (this) {}  // 31
195         synchronized (this) {}  // 32
196         synchronized (this) {}  // 33
197         synchronized (this) {}  // 34
198     }
199 
200     /* does nothing but ensure that the compiler doesn't discard an object */
doNothing(Object obj)201     private void doNothing(Object obj) {}
202 
203     /**
204      * Lock the monitor two or three times, and make use of the locked or
205      * unlocked object.
206      */
triplet(Object obj1, Object obj2, int x)207     public void triplet(Object obj1, Object obj2, int x) {
208         Object localObj;
209 
210         synchronized (obj1) {
211             synchronized(obj1) {
212                 if (x == 0) {
213                     synchronized(obj1) {
214                         localObj = obj2;
215                     }
216                 } else {
217                     localObj = obj1;
218                 }
219             }
220         }
221 
222         doNothing(localObj);
223     }
224 
225     // Smali testing code.
runSmaliTests()226     private static void runSmaliTests() {
227         runTest("OK", new Object[] { new Object(), new Object() }, null);
228         runTest("TooDeep", new Object[] { new Object() }, null);
229         runTest("NotStructuredOverUnlock", new Object[] { new Object() },
230                 IllegalMonitorStateException.class);
231         runTest("NotStructuredUnderUnlock", new Object[] { new Object() },
232                 IllegalMonitorStateException.class);
233         runTest("UnbalancedJoin", new Object[] { new Object(), new Object() }, null);
234         runTest("UnbalancedStraight", new Object[] { new Object(), new Object() }, null);
235         runTest("NullLocks", new Object[] { false }, null);
236         runTest("NullLocks", new Object[] { true }, NullPointerException.class);
237     }
238 
runTest(String className, Object[] parameters, Class<?> excType)239     private static void runTest(String className, Object[] parameters, Class<?> excType) {
240         try {
241             Class<?> c = Class.forName(className);
242 
243             Method[] methods = c.getDeclaredMethods();
244 
245             // For simplicity we assume that test methods are not overloaded. So searching by name
246             // will give us the method we need to run.
247             Method method = null;
248             for (Method m : methods) {
249                 if (m.getName().equals("run")) {
250                     method = m;
251                     break;
252                 }
253             }
254 
255             if (method == null) {
256                 System.out.println("Could not find test method for " + className);
257             } else if (!Modifier.isStatic(method.getModifiers())) {
258                 System.out.println("Test method for " + className + " is not static.");
259             } else {
260                 method.invoke(null, parameters);
261                 if (excType != null) {
262                     System.out.println("Expected an exception in " + className);
263                 }
264             }
265         } catch (Throwable exc) {
266             if (excType == null) {
267                 System.out.println("Did not expect exception " + exc + " for " + className);
268                 exc.printStackTrace(System.out);
269             } else if (exc instanceof InvocationTargetException && exc.getCause() != null &&
270                        exc.getCause().getClass().equals(excType)) {
271                 // Expected exception is wrapped in InvocationTargetException.
272             } else if (!excType.equals(exc.getClass())) {
273                 System.out.println("Expected " + excType.getName() + ", but got " + exc.getClass());
274             } else {
275               // Expected exception, do nothing.
276             }
277         }
278     }
279 
280     // Helpers for the smali code.
assertIsInterpreted()281     public static native void assertIsInterpreted();
assertIsManaged()282     public static native void assertIsManaged();
hasOatFile()283     public static native boolean hasOatFile();
runtimeIsSoftFail()284     public static native boolean runtimeIsSoftFail();
isInterpreted()285     public static native boolean isInterpreted();
disableStackFrameAsserts()286     public static native void disableStackFrameAsserts();
ensureJitCompiled(Class<?> itf, String method_name)287     private static native void ensureJitCompiled(Class<?> itf, String method_name);
288 }
289