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 public class Main {
     18   public static void main(String[] args) {
     19     System.loadLibrary(args[0]);
     20     new SubMain();
     21     if ($noinline$returnInt() != 53) {
     22       throw new Error("Unexpected return value");
     23     }
     24     if ($noinline$returnFloat() != 42.2f) {
     25       throw new Error("Unexpected return value");
     26     }
     27     if ($noinline$returnDouble() != Double.longBitsToDouble(0xF000000000001111L)) {
     28       throw new Error("Unexpected return value ");
     29     }
     30     if ($noinline$returnLong() != 0xFFFF000000001111L) {
     31       throw new Error("Unexpected return value");
     32     }
     33 
     34     try {
     35       $noinline$deopt();
     36     } catch (Exception e) {}
     37     DeoptimizationController.stopDeoptimization();
     38 
     39     $noinline$inlineCache(new Main(), /* isSecondInvocation */ false);
     40     if ($noinline$inlineCache(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) {
     41       throw new Error("Unexpected return value");
     42     }
     43 
     44     $noinline$inlineCache2(new Main(), /* isSecondInvocation */ false);
     45     if ($noinline$inlineCache2(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) {
     46       throw new Error("Unexpected return value");
     47     }
     48 
     49     // Test polymorphic inline cache to the same target (inlineCache3).
     50     $noinline$inlineCache3(new Main(), /* isSecondInvocation */ false);
     51     $noinline$inlineCache3(new SubMain(), /* isSecondInvocation */ false);
     52     if ($noinline$inlineCache3(new SubMain(), /* isSecondInvocation */ true) != null) {
     53       throw new Error("Unexpected return value");
     54     }
     55 
     56     $noinline$stackOverflow(new Main(), /* isSecondInvocation */ false);
     57     $noinline$stackOverflow(new SubMain(), /* isSecondInvocation */ true);
     58 
     59     $opt$noinline$testOsrInlineLoop(null);
     60     System.out.println("b28210356 passed.");
     61   }
     62 
     63   public static int $noinline$returnInt() {
     64     if (doThrow) throw new Error("");
     65     int i = 0;
     66     for (; i < 100000; ++i) {
     67     }
     68     while (!isInOsrCode("$noinline$returnInt")) {}
     69     System.out.println(i);
     70     return 53;
     71   }
     72 
     73   public static float $noinline$returnFloat() {
     74     if (doThrow) throw new Error("");
     75     int i = 0;
     76     for (; i < 200000; ++i) {
     77     }
     78     while (!isInOsrCode("$noinline$returnFloat")) {}
     79     System.out.println(i);
     80     return 42.2f;
     81   }
     82 
     83   public static double $noinline$returnDouble() {
     84     if (doThrow) throw new Error("");
     85     int i = 0;
     86     for (; i < 300000; ++i) {
     87     }
     88     while (!isInOsrCode("$noinline$returnDouble")) {}
     89     System.out.println(i);
     90     return Double.longBitsToDouble(0xF000000000001111L);
     91   }
     92 
     93   public static long $noinline$returnLong() {
     94     if (doThrow) throw new Error("");
     95     int i = 0;
     96     for (; i < 400000; ++i) {
     97     }
     98     while (!isInOsrCode("$noinline$returnLong")) {}
     99     System.out.println(i);
    100     return 0xFFFF000000001111L;
    101   }
    102 
    103   public static void $noinline$deopt() {
    104     if (doThrow) throw new Error("");
    105     int i = 0;
    106     for (; i < 100000; ++i) {
    107     }
    108     while (!isInOsrCode("$noinline$deopt")) {}
    109     DeoptimizationController.startDeoptimization();
    110   }
    111 
    112   public static Class<?> $noinline$inlineCache(Main m, boolean isSecondInvocation) {
    113     // If we are running in non-JIT mode, or were unlucky enough to get this method
    114     // already JITted, just return the expected value.
    115     if (!isInInterpreter("$noinline$inlineCache")) {
    116       return SubMain.class;
    117     }
    118 
    119     ensureHasProfilingInfo("$noinline$inlineCache");
    120 
    121     // Ensure that we have OSR code to jump to.
    122     if (isSecondInvocation) {
    123       ensureHasOsrCode("$noinline$inlineCache");
    124     }
    125 
    126     // This call will be optimized in the OSR compiled code
    127     // to check and deoptimize if m is not of type 'Main'.
    128     Main other = m.inlineCache();
    129 
    130     // Jump to OSR compiled code. The second run
    131     // of this method will have 'm' as a SubMain, and the compiled
    132     // code we are jumping to will have wrongly optimize other as being a
    133     // 'Main'.
    134     if (isSecondInvocation) {
    135       while (!isInOsrCode("$noinline$inlineCache")) {}
    136     }
    137 
    138     // We used to wrongly optimize this call and assume 'other' was a 'Main'.
    139     return other.returnClass();
    140   }
    141 
    142   public static Class<?> $noinline$inlineCache2(Main m, boolean isSecondInvocation) {
    143     // If we are running in non-JIT mode, or were unlucky enough to get this method
    144     // already JITted, just return the expected value.
    145     if (!isInInterpreter("$noinline$inlineCache2")) {
    146       return SubMain.class;
    147     }
    148 
    149     ensureHasProfilingInfo("$noinline$inlineCache2");
    150 
    151     // Ensure that we have OSR code to jump to.
    152     if (isSecondInvocation) {
    153       ensureHasOsrCode("$noinline$inlineCache2");
    154     }
    155 
    156     // This call will be optimized in the OSR compiled code
    157     // to check and deoptimize if m is not of type 'Main'.
    158     Main other = m.inlineCache2();
    159 
    160     // Jump to OSR compiled code. The second run
    161     // of this method will have 'm' as a SubMain, and the compiled
    162     // code we are jumping to will have wrongly optimize other as being null.
    163     if (isSecondInvocation) {
    164       while (!isInOsrCode("$noinline$inlineCache2")) {}
    165     }
    166 
    167     // We used to wrongly optimize this code and assume 'other' was always null.
    168     return (other == null) ? null : other.returnClass();
    169   }
    170 
    171   public static Class<?> $noinline$inlineCache3(Main m, boolean isSecondInvocation) {
    172     // If we are running in non-JIT mode, or were unlucky enough to get this method
    173     // already JITted, just return the expected value.
    174     if (!isInInterpreter("$noinline$inlineCache3")) {
    175       return null;
    176     }
    177 
    178     ensureHasProfilingInfo("$noinline$inlineCache3");
    179 
    180     // Ensure that we have OSR code to jump to.
    181     if (isSecondInvocation) {
    182       ensureHasOsrCode("$noinline$inlineCache3");
    183     }
    184 
    185     // This call will be optimized in the OSR compiled code
    186     // to check and deoptimize if m is not of type 'Main'.
    187     Main other = m.inlineCache3();
    188 
    189     // Jump to OSR compiled code. The second run
    190     // of this method will have 'm' as a SubMain, and the compiled
    191     // code we are jumping to will have wrongly optimize other as being null.
    192     if (isSecondInvocation) {
    193       while (!isInOsrCode("$noinline$inlineCache3")) {}
    194     }
    195 
    196     // We used to wrongly optimize this code and assume 'other' was always null.
    197     return (other == null) ? null : other.returnClass();
    198   }
    199 
    200   public Main inlineCache() {
    201     return new Main();
    202   }
    203 
    204   public Main inlineCache2() {
    205     return null;
    206   }
    207 
    208   public Main inlineCache3() {
    209     return null;
    210   }
    211 
    212   public Class<?> returnClass() {
    213     return Main.class;
    214   }
    215 
    216   public void otherInlineCache() {
    217     return;
    218   }
    219 
    220   public static void $noinline$stackOverflow(Main m, boolean isSecondInvocation) {
    221     // If we are running in non-JIT mode, or were unlucky enough to get this method
    222     // already JITted, just return the expected value.
    223     if (!isInInterpreter("$noinline$stackOverflow")) {
    224       return;
    225     }
    226 
    227     // We need a ProfilingInfo object to populate the 'otherInlineCache' call.
    228     ensureHasProfilingInfo("$noinline$stackOverflow");
    229 
    230     if (isSecondInvocation) {
    231       // Ensure we have an OSR code and we jump to it.
    232       while (!isInOsrCode("$noinline$stackOverflow")) {}
    233     }
    234 
    235     for (int i = 0; i < (isSecondInvocation ? 10000000 : 1); ++i) {
    236       // The first invocation of $noinline$stackOverflow will populate the inline
    237       // cache with Main. The second invocation of the method, will see a SubMain
    238       // and will therefore trigger deoptimization.
    239       m.otherInlineCache();
    240     }
    241   }
    242 
    243   public static void $opt$noinline$testOsrInlineLoop(String[] args) {
    244     // Regression test for inlining a method with a loop to a method without a loop in OSR mode.
    245     if (doThrow) throw new Error();
    246     assertIntEquals(12, $opt$inline$testRemoveSuspendCheck(12, 5));
    247     // Since we cannot have a loop directly in this method, we need to force the OSR
    248     // compilation from native code.
    249     ensureHasProfilingInfo("$opt$noinline$testOsrInlineLoop");
    250     ensureHasOsrCode("$opt$noinline$testOsrInlineLoop");
    251   }
    252 
    253   public static int $opt$inline$testRemoveSuspendCheck(int x, int y) {
    254     // For this test we need an inlined loop and have DCE re-run loop analysis
    255     // after inlining.
    256     while (y > 0) {
    257       while ($opt$inline$inlineFalse() || !$opt$inline$inlineTrue()) {
    258         x++;
    259       }
    260       y--;
    261     }
    262     return x;
    263   }
    264 
    265   public static boolean $opt$inline$inlineTrue() {
    266     return true;
    267   }
    268 
    269   public static boolean $opt$inline$inlineFalse() {
    270     return false;
    271   }
    272 
    273   public static void assertIntEquals(int expected, int result) {
    274     if (expected != result) {
    275       throw new Error("Expected: " + expected + ", found: " + result);
    276     }
    277   }
    278 
    279   public static native boolean isInOsrCode(String methodName);
    280   public static native boolean isInInterpreter(String methodName);
    281   public static native void ensureHasProfilingInfo(String methodName);
    282   public static native void ensureHasOsrCode(String methodName);
    283 
    284   public static boolean doThrow = false;
    285 }
    286 
    287 class SubMain extends Main {
    288   public Class<?> returnClass() {
    289     return SubMain.class;
    290   }
    291 
    292   public Main inlineCache() {
    293     return new SubMain();
    294   }
    295 
    296   public Main inlineCache2() {
    297     return new SubMain();
    298   }
    299 
    300   public void otherInlineCache() {
    301     return;
    302   }
    303 }
    304