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         // clang-format off
123         assertIsManaged();
124         synchronized (this) {   // 1
125         synchronized (this) {   // 2
126         synchronized (this) {   // 3
127         synchronized (this) {   // 4
128         synchronized (this) {   // 5
129         synchronized (this) {   // 6
130         synchronized (this) {   // 7
131         synchronized (this) {   // 8
132         synchronized (this) {   // 9
133         synchronized (this) {   // 10
134         synchronized (this) {   // 11
135         synchronized (this) {   // 12
136         synchronized (this) {   // 13
137         synchronized (this) {   // 14
138         synchronized (this) {   // 15
139         synchronized (this) {   // 16
140         synchronized (this) {   // 17
141         synchronized (this) {   // 18
142         synchronized (this) {   // 19
143         synchronized (this) {   // 20
144         synchronized (this) {   // 21
145         synchronized (this) {   // 22
146         synchronized (this) {   // 23
147         synchronized (this) {   // 24
148         synchronized (this) {   // 25
149         synchronized (this) {   // 26
150         synchronized (this) {   // 27
151         synchronized (this) {   // 28
152         synchronized (this) {   // 29
153         synchronized (this) {   // 30
154         synchronized (this) {   // 31
155         synchronized (this) {   // 32
156         }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
157         // clang-format on
158     }
159 
160     /**
161      * Confirms that we can have more than 32 non-nested monitors in one
162      * method.
163      */
notNested()164     void notNested() {
165         // clang-format off
166         assertIsManaged();
167         synchronized (this) {}  // 1
168         synchronized (this) {}  // 2
169         synchronized (this) {}  // 3
170         synchronized (this) {}  // 4
171         synchronized (this) {}  // 5
172         synchronized (this) {}  // 6
173         synchronized (this) {}  // 7
174         synchronized (this) {}  // 8
175         synchronized (this) {}  // 9
176         synchronized (this) {}  // 10
177         synchronized (this) {}  // 11
178         synchronized (this) {}  // 12
179         synchronized (this) {}  // 13
180         synchronized (this) {}  // 14
181         synchronized (this) {}  // 15
182         synchronized (this) {}  // 16
183         synchronized (this) {}  // 17
184         synchronized (this) {}  // 18
185         synchronized (this) {}  // 19
186         synchronized (this) {}  // 20
187         synchronized (this) {}  // 21
188         synchronized (this) {}  // 22
189         synchronized (this) {}  // 23
190         synchronized (this) {}  // 24
191         synchronized (this) {}  // 25
192         synchronized (this) {}  // 26
193         synchronized (this) {}  // 27
194         synchronized (this) {}  // 28
195         synchronized (this) {}  // 29
196         synchronized (this) {}  // 30
197         synchronized (this) {}  // 31
198         synchronized (this) {}  // 32
199         synchronized (this) {}  // 33
200         synchronized (this) {}  // 34
201         // clang-format on
202     }
203 
204     /* does nothing but ensure that the compiler doesn't discard an object */
doNothing(Object obj)205     private void doNothing(Object obj) {}
206 
207     /**
208      * Lock the monitor two or three times, and make use of the locked or
209      * unlocked object.
210      */
triplet(Object obj1, Object obj2, int x)211     public void triplet(Object obj1, Object obj2, int x) {
212         Object localObj;
213 
214         synchronized (obj1) {
215             synchronized(obj1) {
216                 if (x == 0) {
217                     synchronized(obj1) {
218                         localObj = obj2;
219                     }
220                 } else {
221                     localObj = obj1;
222                 }
223             }
224         }
225 
226         doNothing(localObj);
227     }
228 
229     // Smali testing code.
runSmaliTests()230     private static void runSmaliTests() {
231         runTest("OK", new Object[] { new Object(), new Object() }, null);
232         runTest("TooDeep", new Object[] { new Object() }, null);
233         runTest("NotStructuredOverUnlock", new Object[] { new Object() },
234                 IllegalMonitorStateException.class);
235         runTest("NotStructuredUnderUnlock", new Object[] { new Object() },
236                 IllegalMonitorStateException.class);
237         runTest("UnbalancedJoin", new Object[] { new Object(), new Object() }, null);
238         runTest("UnbalancedStraight", new Object[] { new Object(), new Object() }, null);
239         runTest("NullLocks", new Object[] { false }, null);
240         runTest("NullLocks", new Object[] { true }, NullPointerException.class);
241     }
242 
runTest(String className, Object[] parameters, Class<?> excType)243     private static void runTest(String className, Object[] parameters, Class<?> excType) {
244         try {
245             Class<?> c = Class.forName(className);
246 
247             Method[] methods = c.getDeclaredMethods();
248 
249             // For simplicity we assume that test methods are not overloaded. So searching by name
250             // will give us the method we need to run.
251             Method method = null;
252             for (Method m : methods) {
253                 if (m.getName().equals("run")) {
254                     method = m;
255                     break;
256                 }
257             }
258 
259             if (method == null) {
260                 System.out.println("Could not find test method for " + className);
261             } else if (!Modifier.isStatic(method.getModifiers())) {
262                 System.out.println("Test method for " + className + " is not static.");
263             } else {
264                 method.invoke(null, parameters);
265                 if (excType != null) {
266                     System.out.println("Expected an exception in " + className);
267                 }
268             }
269         } catch (Throwable exc) {
270             if (excType == null) {
271                 System.out.println("Did not expect exception " + exc + " for " + className);
272                 exc.printStackTrace(System.out);
273             } else if (exc instanceof InvocationTargetException && exc.getCause() != null &&
274                        exc.getCause().getClass().equals(excType)) {
275                 // Expected exception is wrapped in InvocationTargetException.
276             } else if (!excType.equals(exc.getClass())) {
277                 System.out.println("Expected " + excType.getName() + ", but got " + exc.getClass());
278             } else {
279               // Expected exception, do nothing.
280             }
281         }
282     }
283 
284     // Helpers for the smali code.
assertIsInterpreted()285     public static native void assertIsInterpreted();
assertIsManaged()286     public static native void assertIsManaged();
hasOatFile()287     public static native boolean hasOatFile();
runtimeIsSoftFail()288     public static native boolean runtimeIsSoftFail();
isInterpreted()289     public static native boolean isInterpreted();
disableStackFrameAsserts()290     public static native void disableStackFrameAsserts();
ensureJitCompiled(Class<?> itf, String method_name)291     private static native void ensureJitCompiled(Class<?> itf, String method_name);
292 }
293