Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2016 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.Method;
     18 import java.util.Arrays;
     19 import java.util.Comparator;
     20 import java.util.HashMap;
     21 
     22 class DummyObject {
     23     public static boolean sHashCodeInvoked = false;
     24     private int i;
     25 
     26     public DummyObject(int i) {
     27         this.i = i;
     28     }
     29 
     30     public boolean equals(Object obj) {
     31         return (obj instanceof DummyObject) && (i == ((DummyObject)obj).i);
     32     }
     33 
     34     public int hashCode() {
     35         sHashCodeInvoked = true;
     36         Main.assertIsManaged();
     37         Main.deoptimizeAll();
     38         Main.assertIsInterpreted();
     39         Main.assertCallerIsManaged();  // Caller is from framework code HashMap.
     40         return i % 64;
     41     }
     42 }
     43 
     44 public class Main {
     45     static boolean sFlag = false;
     46 
     47     public static native void deoptimizeAll();
     48     public static native void undeoptimizeAll();
     49     public static native void assertIsInterpreted();
     50     public static native void assertIsManaged();
     51     public static native void assertCallerIsInterpreted();
     52     public static native void assertCallerIsManaged();
     53     public static native void disableStackFrameAsserts();
     54     public static native boolean hasOatFile();
     55     public static native boolean isInterpreted();
     56 
     57     public static void execute(Runnable runnable) throws Exception {
     58       Thread t = new Thread(runnable);
     59       t.start();
     60       t.join();
     61     }
     62 
     63     public static void main(String[] args) throws Exception {
     64         System.loadLibrary(args[0]);
     65         // Only test stack frames in compiled mode.
     66         if (!hasOatFile() || isInterpreted()) {
     67           disableStackFrameAsserts();
     68         }
     69         final HashMap<DummyObject, Long> map = new HashMap<DummyObject, Long>();
     70 
     71         // Single-frame deoptimization that covers partial fragment.
     72         execute(new Runnable() {
     73             public void run() {
     74                 int[] arr = new int[3];
     75                 assertIsManaged();
     76                 int res = $noinline$run1(arr);
     77                 assertIsManaged();  // Only single frame is deoptimized.
     78                 if (res != 79) {
     79                     System.out.println("Failure 1!");
     80                     System.exit(0);
     81                 }
     82             }
     83         });
     84 
     85         // Single-frame deoptimization that covers a full fragment.
     86         execute(new Runnable() {
     87             public void run() {
     88                 try {
     89                     int[] arr = new int[3];
     90                     assertIsManaged();
     91                     // Use reflection to call $noinline$run2 so that it does
     92                     // full-fragment deoptimization since that is an upcall.
     93                     Class<?> cls = Class.forName("Main");
     94                     Method method = cls.getDeclaredMethod("$noinline$run2", int[].class);
     95                     double res = (double)method.invoke(Main.class, arr);
     96                     assertIsManaged();  // Only single frame is deoptimized.
     97                     if (res != 79.3d) {
     98                         System.out.println("Failure 2!");
     99                         System.exit(0);
    100                     }
    101                 } catch (Exception e) {
    102                     e.printStackTrace();
    103                 }
    104             }
    105         });
    106 
    107         // Full-fragment deoptimization.
    108         execute(new Runnable() {
    109             public void run() {
    110                 assertIsManaged();
    111                 float res = $noinline$run3B();
    112                 assertIsInterpreted();  // Every deoptimizeable method is deoptimized.
    113                 if (res != 0.034f) {
    114                     System.out.println("Failure 3!");
    115                     System.exit(0);
    116                 }
    117             }
    118         });
    119 
    120         undeoptimizeAll();  // Make compiled code useable again.
    121 
    122         // Partial-fragment deoptimization.
    123         execute(new Runnable() {
    124             public void run() {
    125                 try {
    126                     assertIsManaged();
    127                     map.put(new DummyObject(10), Long.valueOf(100));
    128                     assertIsInterpreted();  // Every deoptimizeable method is deoptimized.
    129                 } catch (Exception e) {
    130                     e.printStackTrace();
    131                 }
    132             }
    133         });
    134 
    135         undeoptimizeAll();  // Make compiled code useable again.
    136 
    137         if (!DummyObject.sHashCodeInvoked) {
    138             System.out.println("hashCode() method not invoked!");
    139         }
    140         if (map.get(new DummyObject(10)) != 100) {
    141             System.out.println("Wrong hashmap value!");
    142         }
    143         System.out.println("Finishing");
    144     }
    145 
    146     public static int $noinline$run1(int[] arr) {
    147         assertIsManaged();
    148         // Prevent inlining.
    149         if (sFlag) {
    150             throw new Error();
    151         }
    152         boolean caught = false;
    153         // BCE will use deoptimization for the code below.
    154         try {
    155             arr[0] = 1;
    156             arr[1] = 1;
    157             arr[2] = 1;
    158             // This causes AIOOBE and triggers deoptimization from compiled code.
    159             arr[3] = 1;
    160         } catch (ArrayIndexOutOfBoundsException e) {
    161             assertIsInterpreted(); // Single-frame deoptimization triggered.
    162             caught = true;
    163         }
    164         if (!caught) {
    165             System.out.println("Expected exception");
    166         }
    167         assertIsInterpreted();
    168         return 79;
    169     }
    170 
    171     public static double $noinline$run2(int[] arr) {
    172         assertIsManaged();
    173         // Prevent inlining.
    174         if (sFlag) {
    175             throw new Error();
    176         }
    177         boolean caught = false;
    178         // BCE will use deoptimization for the code below.
    179         try {
    180             arr[0] = 1;
    181             arr[1] = 1;
    182             arr[2] = 1;
    183             // This causes AIOOBE and triggers deoptimization from compiled code.
    184             arr[3] = 1;
    185         } catch (ArrayIndexOutOfBoundsException e) {
    186             assertIsInterpreted();  // Single-frame deoptimization triggered.
    187             caught = true;
    188         }
    189         if (!caught) {
    190             System.out.println("Expected exception");
    191         }
    192         assertIsInterpreted();
    193         return 79.3d;
    194     }
    195 
    196     public static float $noinline$run3A() {
    197         assertIsManaged();
    198         // Prevent inlining.
    199         if (sFlag) {
    200             throw new Error();
    201         }
    202         // Deoptimize callers.
    203         deoptimizeAll();
    204         assertIsInterpreted();
    205         assertCallerIsInterpreted();  // $noinline$run3B is deoptimizeable.
    206         return 0.034f;
    207     }
    208 
    209     public static float $noinline$run3B() {
    210         assertIsManaged();
    211         // Prevent inlining.
    212         if (sFlag) {
    213             throw new Error();
    214         }
    215         float res = $noinline$run3A();
    216         assertIsInterpreted();
    217         return res;
    218     }
    219 }
    220