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