• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"), "runStraightLine2");
46         ensureJitCompiled(Class.forName("OK"), "runBalancedJoin");
47         ensureJitCompiled(Class.forName("NullLocks"), "run");
48 
49         Main m = new Main();
50 
51         m.recursiveSync(0);
52 
53         m.nestedMayThrow(false);
54         try {
55             m.nestedMayThrow(true);
56             System.out.println("nestedThrow(true) did not throw");
57         } catch (MyException me) {}
58         System.out.println("nestedMayThrow ok");
59 
60         m.constantLock();
61         System.out.println("constantLock ok");
62 
63         m.notExcessiveNesting();
64 
65         m.notNested();
66         System.out.println("notNested ok");
67 
68         Object obj1 = new Object();
69         Object obj2 = new Object();
70 
71         TwoPath.twoPath(obj1, obj2, 0);
72         System.out.println("twoPath ok");
73 
74         m.triplet(obj1, obj2, 0);
75         System.out.println("triplet ok");
76 
77         runSmaliTests();
78     }
79 
80     /**
81      * Recursive synchronized method.
82      */
recursiveSync(int iter)83     synchronized void recursiveSync(int iter) {
84         assertIsManaged();
85         if (iter < 40) {
86             recursiveSync(iter+1);
87         } else {
88             System.out.println("recursiveSync ok");
89         }
90     }
91 
92     /**
93      * Tests simple nesting, with and without a throw.
94      */
nestedMayThrow(boolean doThrow)95     void nestedMayThrow(boolean doThrow) {
96         assertIsManaged();
97         synchronized (this) {
98             synchronized (Main.class) {
99                 synchronized (new Object()) {
100                     synchronized(Class.class) {
101                         if (doThrow) {
102                             throw new MyException();
103                         }
104                     }
105                 }
106             }
107         }
108     }
109 
110     /**
111      * Exercises bug 3215458.
112      */
constantLock()113     void constantLock() {
114         assertIsManaged();
115         Class<?> thing = Thread.class;
116         synchronized (Thread.class) {}
117     }
118 
119     /**
120      * Confirms that we can have 32 nested monitors on one method.
121      */
notExcessiveNesting()122     void notExcessiveNesting() {
123         // clang-format off
124         assertIsManaged();
125         synchronized (this) {   // 1
126         synchronized (this) {   // 2
127         synchronized (this) {   // 3
128         synchronized (this) {   // 4
129         synchronized (this) {   // 5
130         synchronized (this) {   // 6
131         synchronized (this) {   // 7
132         synchronized (this) {   // 8
133         synchronized (this) {   // 9
134         synchronized (this) {   // 10
135         synchronized (this) {   // 11
136         synchronized (this) {   // 12
137         synchronized (this) {   // 13
138         synchronized (this) {   // 14
139         synchronized (this) {   // 15
140         synchronized (this) {   // 16
141         synchronized (this) {   // 17
142         synchronized (this) {   // 18
143         synchronized (this) {   // 19
144         synchronized (this) {   // 20
145         synchronized (this) {   // 21
146         synchronized (this) {   // 22
147         synchronized (this) {   // 23
148         synchronized (this) {   // 24
149         synchronized (this) {   // 25
150         synchronized (this) {   // 26
151         synchronized (this) {   // 27
152         synchronized (this) {   // 28
153         synchronized (this) {   // 29
154         synchronized (this) {   // 30
155         synchronized (this) {   // 31
156         synchronized (this) {   // 32
157         }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
158         // clang-format on
159     }
160 
161     /**
162      * Confirms that we can have more than 32 non-nested monitors in one
163      * method.
164      */
notNested()165     void notNested() {
166         // clang-format off
167         assertIsManaged();
168         synchronized (this) {}  // 1
169         synchronized (this) {}  // 2
170         synchronized (this) {}  // 3
171         synchronized (this) {}  // 4
172         synchronized (this) {}  // 5
173         synchronized (this) {}  // 6
174         synchronized (this) {}  // 7
175         synchronized (this) {}  // 8
176         synchronized (this) {}  // 9
177         synchronized (this) {}  // 10
178         synchronized (this) {}  // 11
179         synchronized (this) {}  // 12
180         synchronized (this) {}  // 13
181         synchronized (this) {}  // 14
182         synchronized (this) {}  // 15
183         synchronized (this) {}  // 16
184         synchronized (this) {}  // 17
185         synchronized (this) {}  // 18
186         synchronized (this) {}  // 19
187         synchronized (this) {}  // 20
188         synchronized (this) {}  // 21
189         synchronized (this) {}  // 22
190         synchronized (this) {}  // 23
191         synchronized (this) {}  // 24
192         synchronized (this) {}  // 25
193         synchronized (this) {}  // 26
194         synchronized (this) {}  // 27
195         synchronized (this) {}  // 28
196         synchronized (this) {}  // 29
197         synchronized (this) {}  // 30
198         synchronized (this) {}  // 31
199         synchronized (this) {}  // 32
200         synchronized (this) {}  // 33
201         synchronized (this) {}  // 34
202         // clang-format on
203     }
204 
205     /* does nothing but ensure that the compiler doesn't discard an object */
doNothing(Object obj)206     private void doNothing(Object obj) {}
207 
208     /**
209      * Lock the monitor two or three times, and make use of the locked or
210      * unlocked object.
211      */
triplet(Object obj1, Object obj2, int x)212     public void triplet(Object obj1, Object obj2, int x) {
213         Object localObj;
214 
215         synchronized (obj1) {
216             synchronized(obj1) {
217                 if (x == 0) {
218                     synchronized(obj1) {
219                         localObj = obj2;
220                     }
221                 } else {
222                     localObj = obj1;
223                 }
224             }
225         }
226 
227         doNothing(localObj);
228     }
229 
230     // Smali testing code.
runSmaliTests()231     private static void runSmaliTests() {
232         runTest("OK", new Object[] { new Object(), new Object() }, null);
233         runTest("TooDeep", new Object[] { new Object() }, null);
234         runTest("NotStructuredOverUnlock", new Object[] { new Object() },
235                 IllegalMonitorStateException.class);
236         runTest("NotStructuredUnderUnlock", new Object[] { new Object() },
237                 IllegalMonitorStateException.class);
238         runTest("UnbalancedJoin", new Object[] { new Object(), new Object() }, null);
239         runTest("UnbalancedStraight", new Object[] { new Object(), new Object() }, null);
240         runTest("NullLocks", new Object[] { false }, null);
241         runTest("NullLocks", new Object[] { true }, NullPointerException.class);
242     }
243 
runTest(String className, Object[] parameters, Class<?> excType)244     private static void runTest(String className, Object[] parameters, Class<?> excType) {
245         try {
246             Class<?> c = Class.forName(className);
247 
248             Method[] methods = c.getDeclaredMethods();
249 
250             // For simplicity we assume that test methods are not overloaded. So searching by name
251             // will give us the method we need to run.
252             Method method = null;
253             for (Method m : methods) {
254                 if (m.getName().equals("run")) {
255                     method = m;
256                     break;
257                 }
258             }
259 
260             if (method == null) {
261                 System.out.println("Could not find test method for " + className);
262             } else if (!Modifier.isStatic(method.getModifiers())) {
263                 System.out.println("Test method for " + className + " is not static.");
264             } else {
265                 method.invoke(null, parameters);
266                 if (excType != null) {
267                     System.out.println("Expected an exception in " + className);
268                 }
269             }
270         } catch (Throwable exc) {
271             if (excType == null) {
272                 System.out.println("Did not expect exception " + exc + " for " + className);
273                 exc.printStackTrace(System.out);
274             } else if (exc instanceof InvocationTargetException && exc.getCause() != null &&
275                        exc.getCause().getClass().equals(excType)) {
276                 // Expected exception is wrapped in InvocationTargetException.
277             } else if (!excType.equals(exc.getClass())) {
278                 System.out.println("Expected " + excType.getName() + ", but got " + exc.getClass());
279             } else {
280               // Expected exception, do nothing.
281             }
282         }
283     }
284 
285     // Helpers for the smali code.
assertIsInterpreted()286     public static native void assertIsInterpreted();
assertIsManaged()287     public static native void assertIsManaged();
hasOatFile()288     public static native boolean hasOatFile();
runtimeIsSoftFail()289     public static native boolean runtimeIsSoftFail();
isInterpreted()290     public static native boolean isInterpreted();
disableStackFrameAsserts()291     public static native void disableStackFrameAsserts();
ensureJitCompiled(Class<?> itf, String method_name)292     private static native void ensureJitCompiled(Class<?> itf, String method_name);
293 }
294