content: /*
   * 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) {
          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();
          }
  
          Main m = new Main();
  
          m.recursiveSync(0);
  
          m.nestedMayThrow(false);
          try {
              m.nestedMayThrow(true);
              System.err.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();
  }
  