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 $noinline$objectReturned(new Main()); 37 ensureJitCompiled(Main.class, "$noinline$objectReturned"); 38 Object o = $noinline$objectReturned(new SubMain()); 39 // We used to get 0xebadde09 in 'o' here and therefore crash 40 // both interpreter and compiled code. 41 if (o instanceof Cloneable) { 42 System.out.println("Unexpected object type " + o.getClass()); 43 } 44 } 45 doCheck()46 public boolean doCheck() { 47 return false; 48 } 49 $noinline$intUpdate(Main m)50 public static void $noinline$intUpdate(Main m) { 51 int a = 0; 52 // We used to kill 'a' when the inline cache of 'doCheck' only 53 // contains 'Main' (which makes the only branch using 'a' dead). 54 // So the deoptimization at the inline cache was incorrectly assuming 55 // 'a' was dead. 56 for (int i = 0; i < 5000; i++) { 57 if (m.doCheck()) { 58 a++; 59 // We make this branch the only true user of the 'a' phi. All other uses 60 // of 'a' are phi updates. 61 myIntStatic = a; 62 } else if (myIntStatic == 42) { 63 a = 1; 64 } 65 } 66 } 67 $noinline$objectUpdate(Main m)68 public static void $noinline$objectUpdate(Main m) { 69 Object o = new Object(); 70 // We used to kill 'o' when the inline cache of 'doCheck' only 71 // contains 'Main' (which makes the only branch using 'o' dead). 72 // So the deoptimization at the inline cache was incorrectly assuming 73 // 'o' was dead. 74 // This lead to a NPE on the 'toString' call just after deoptimizing. 75 for (int i = 0; i < 5000; i++) { 76 if (m.doCheck()) { 77 // We make this branch the only true user of the 'o' phi. All other uses 78 // of 'o' are phi updates. 79 o.toString(); 80 } else if (myIntStatic == 42) { 81 o = m; 82 } 83 } 84 } 85 $noinline$loopIncrement(Main m)86 public static void $noinline$loopIncrement(Main m) { 87 int k = 0; 88 // We used to kill 'k' and replace it with 5000 when the inline cache 89 // of 'doCheck' only contains 'Main'. 90 // So the deoptimization at the inline cache was incorrectly assuming 91 // 'k' was 5000. 92 for (int i = 0; i < 5000; i++, k++) { 93 if (m.doCheck()) { 94 // We make this branch the only true user of the 'k' phi. All other uses 95 // of 'k' are phi updates. 96 myIntStatic = k; 97 } 98 } 99 if (k != 5000) { 100 throw new Error("Expected 5000, got " + k); 101 } 102 } 103 $noinline$objectReturned(Main m)104 public static Object $noinline$objectReturned(Main m) { 105 Object o = new Object(); 106 // We used to kill 'o' when the inline cache of 'doCheck' only 107 // contains 'Main' (which makes the only branch using 'o' dead). 108 // So the deoptimization at the inline cache was incorrectly assuming 109 // 'o' was dead. 110 // We also need to make 'o' escape through a return instruction, as mterp 111 // executes the same code for return and return-object, and the 0xebadde09 112 // sentinel for dead value is only pushed to non-object dex registers. 113 Object myReturnValue = null; 114 for (int i = 0; i < 5000; i++) { 115 if (m.doCheck()) { 116 // We make this branch the only true user of the 'o' phi. All other uses 117 // of 'o' are phi updates. 118 myReturnValue = o; 119 } else if (myIntStatic == 42) { 120 o = m; 121 } 122 } 123 return myReturnValue; 124 } 125 126 public static int myIntStatic = 0; 127 ensureJitCompiled(Class<?> itf, String name)128 public static native void ensureJitCompiled(Class<?> itf, String name); 129 } 130 131 class SubMain extends Main { doCheck()132 public boolean doCheck() { 133 return true; 134 } 135 } 136