1 /* 2 * Copyright (C) 2017 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 { main(String[] args)18 public static void main(String[] args) throws Exception { 19 System.loadLibrary(args[0]); 20 21 $noinline$intUpdate(new Main()); 22 ensureJitCompiled(Main.class, "$noinline$intUpdate"); 23 $noinline$intUpdate(new SubMain()); 24 if (myIntStatic != 5000) { 25 throw new Error("Expected 5000, got " + myIntStatic); 26 } 27 28 $noinline$objectUpdate(new Main()); 29 ensureJitCompiled(Main.class, "$noinline$objectUpdate"); 30 $noinline$objectUpdate(new SubMain()); 31 32 $noinline$loopIncrement(new Main()); 33 ensureJitCompiled(Main.class, "$noinline$loopIncrement"); 34 $noinline$loopIncrement(new SubMain()); 35 } 36 doCheck()37 public boolean doCheck() { 38 return false; 39 } 40 $noinline$intUpdate(Main m)41 public static void $noinline$intUpdate(Main m) { 42 int a = 0; 43 // We used to kill 'a' when the inline cache of 'doCheck' only 44 // contains 'Main' (which makes the only branch using 'a' dead). 45 // So the deoptimization at the inline cache was incorrectly assuming 46 // 'a' was dead. 47 for (int i = 0; i < 5000; i++) { 48 if (m.doCheck()) { 49 a++; 50 // We make this branch the only true user of the 'a' phi. All other uses 51 // of 'a' are phi updates. 52 myIntStatic = a; 53 } else if (myIntStatic == 42) { 54 a = 1; 55 } 56 } 57 } 58 $noinline$objectUpdate(Main m)59 public static void $noinline$objectUpdate(Main m) { 60 Object o = new Object(); 61 // We used to kill 'o' when the inline cache of 'doCheck' only 62 // contains 'Main' (which makes the only branch using 'a' dead). 63 // So the deoptimization at the inline cache was incorrectly assuming 64 // 'o' was dead. 65 // This lead to a NPE on the 'toString' call just after deoptimizing. 66 for (int i = 0; i < 5000; i++) { 67 if (m.doCheck()) { 68 // We make this branch the only true user of the 'o' phi. All other uses 69 // of 'o' are phi updates. 70 o.toString(); 71 } else if (myIntStatic == 42) { 72 o = m; 73 } 74 } 75 } 76 $noinline$loopIncrement(Main m)77 public static void $noinline$loopIncrement(Main m) { 78 int k = 0; 79 // We used to kill 'k' and replace it with 5000 when the inline cache 80 // of 'doCheck' only contains 'Main'. 81 // So the deoptimization at the inline cache was incorrectly assuming 82 // 'k' was 5000. 83 for (int i = 0; i < 5000; i++, k++) { 84 if (m.doCheck()) { 85 // We make this branch the only true user of the 'a' phi. All other uses 86 // of 'a' are phi updates. 87 myIntStatic = k; 88 } 89 } 90 if (k != 5000) { 91 throw new Error("Expected 5000, got " + k); 92 } 93 } 94 95 public static int myIntStatic = 0; 96 ensureJitCompiled(Class<?> itf, String name)97 public static native void ensureJitCompiled(Class<?> itf, String name); 98 } 99 100 class SubMain extends Main { doCheck()101 public boolean doCheck() { 102 return true; 103 } 104 } 105