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