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 class SubA extends Super { getValue()18 int getValue() { return 42; } someSubclassesThrow()19 void someSubclassesThrow() throws Error { throw new Error("I always throw"); } 20 } 21 22 class SubB extends Super { getValue()23 int getValue() { return 38; } someSubclassesThrow()24 void someSubclassesThrow() { System.out.println("I don't throw"); } 25 } 26 27 class SubD extends Super { getValue()28 int getValue() { return 10; } someSubclassesThrow()29 void someSubclassesThrow() { System.out.println("I don't throw"); } 30 } 31 32 class SubE extends Super { getValue()33 int getValue() { return -4; } someSubclassesThrow()34 void someSubclassesThrow() { System.out.println("I don't throw"); } 35 } 36 37 public class Main { 38 39 /// CHECK-START: int Main.inlineMonomorphicSubA(Super) inliner (before) 40 /// CHECK: InvokeVirtual method_name:Super.getValue 41 42 /// CHECK-START: int Main.inlineMonomorphicSubA(Super) inliner (after) 43 /// CHECK: <<SubARet:i\d+>> IntConstant 42 44 /// CHECK: <<Obj:l\d+>> NullCheck 45 /// CHECK: <<ObjClass:l\d+>> InstanceFieldGet [<<Obj>>] field_name:java.lang.Object.shadow$_klass_ 46 /// CHECK: <<InlineClass:l\d+>> LoadClass class_name:SubA 47 /// CHECK: <<Test:z\d+>> NotEqual [<<InlineClass>>,<<ObjClass>>] 48 /// CHECK: <<DefaultRet:i\d+>> InvokeVirtual [<<Obj>>] method_name:Super.getValue 49 50 /// CHECK: <<Ret:i\d+>> Phi [<<SubARet>>,<<DefaultRet>>] 51 /// CHECK: Return [<<Ret>>] 52 53 /// CHECK-NOT: Deoptimize inlineMonomorphicSubA(Super a)54 public static int inlineMonomorphicSubA(Super a) { 55 return a.getValue(); 56 } 57 58 /// CHECK-START: int Main.inlinePolymophicSubASubB(Super) inliner (before) 59 /// CHECK: InvokeVirtual method_name:Super.getValue 60 61 // Note that the order in which the types are added to the inline cache in the profile matters. 62 63 /// CHECK-START: int Main.inlinePolymophicSubASubB(Super) inliner (after) 64 /// CHECK-DAG: <<SubARet:i\d+>> IntConstant 42 65 /// CHECK-DAG: <<SubBRet:i\d+>> IntConstant 38 66 /// CHECK-DAG: <<Obj:l\d+>> NullCheck 67 /// CHECK-DAG: <<ObjClassSubA:l\d+>> InstanceFieldGet [<<Obj>>] field_name:java.lang.Object.shadow$_klass_ 68 /// CHECK-DAG: <<InlineClassSubA:l\d+>> LoadClass class_name:SubA 69 /// CHECK-DAG: <<TestSubA:z\d+>> NotEqual [<<InlineClassSubA>>,<<ObjClassSubA>>] 70 /// CHECK-DAG: If [<<TestSubA>>] 71 72 /// CHECK-DAG: <<ObjClassSubB:l\d+>> InstanceFieldGet field_name:java.lang.Object.shadow$_klass_ 73 /// CHECK-DAG: <<InlineClassSubB:l\d+>> LoadClass class_name:SubB 74 /// CHECK-DAG: <<TestSubB:z\d+>> NotEqual [<<InlineClassSubB>>,<<ObjClassSubB>>] 75 /// CHECK-DAG: <<DefaultRet:i\d+>> InvokeVirtual [<<Obj>>] method_name:Super.getValue 76 77 /// CHECK-DAG: <<FirstMerge:i\d+>> Phi [<<SubBRet>>,<<DefaultRet>>] 78 /// CHECK-DAG: <<Ret:i\d+>> Phi [<<SubARet>>,<<FirstMerge>>] 79 /// CHECK-DAG: Return [<<Ret>>] 80 81 /// CHECK-NOT: Deoptimize inlinePolymophicSubASubB(Super a)82 public static int inlinePolymophicSubASubB(Super a) { 83 return a.getValue(); 84 } 85 86 /// CHECK-START: int Main.inlinePolymophicCrossDexSubASubC(Super) inliner (before) 87 /// CHECK: InvokeVirtual method_name:Super.getValue 88 89 // Note that the order in which the types are added to the inline cache in the profile matters. 90 91 /// CHECK-START: int Main.inlinePolymophicCrossDexSubASubC(Super) inliner (after) 92 /// CHECK-DAG: <<SubARet:i\d+>> IntConstant 42 93 /// CHECK-DAG: <<SubCRet:i\d+>> IntConstant 24 94 /// CHECK-DAG: <<Obj:l\d+>> NullCheck 95 /// CHECK-DAG: <<ObjClassSubA:l\d+>> InstanceFieldGet [<<Obj>>] field_name:java.lang.Object.shadow$_klass_ 96 /// CHECK-DAG: <<InlineClassSubA:l\d+>> LoadClass class_name:SubA 97 /// CHECK-DAG: <<TestSubA:z\d+>> NotEqual [<<InlineClassSubA>>,<<ObjClassSubA>>] 98 /// CHECK-DAG: If [<<TestSubA>>] 99 100 /// CHECK-DAG: <<ObjClassSubC:l\d+>> InstanceFieldGet field_name:java.lang.Object.shadow$_klass_ 101 /// CHECK-DAG: <<InlineClassSubC:l\d+>> LoadClass class_name:SubC 102 /// CHECK-DAG: <<TestSubC:z\d+>> NotEqual [<<InlineClassSubC>>,<<ObjClassSubC>>] 103 /// CHECK-DAG: <<DefaultRet:i\d+>> InvokeVirtual [<<Obj>>] method_name:Super.getValue 104 105 /// CHECK-DAG: <<FirstMerge:i\d+>> Phi [<<SubCRet>>,<<DefaultRet>>] 106 /// CHECK-DAG: <<Ret:i\d+>> Phi [<<SubARet>>,<<FirstMerge>>] 107 /// CHECK-DAG: Return [<<Ret>>] 108 109 /// CHECK-NOT: Deoptimize inlinePolymophicCrossDexSubASubC(Super a)110 public static int inlinePolymophicCrossDexSubASubC(Super a) { 111 return a.getValue(); 112 } 113 114 /// CHECK-START: int Main.inlineMegamorphic(Super) inliner (before) 115 /// CHECK: InvokeVirtual method_name:Super.getValue 116 117 /// CHECK-START: int Main.inlineMegamorphic(Super) inliner (after) 118 /// CHECK: InvokeVirtual method_name:Super.getValue inlineMegamorphic(Super a)119 public static int inlineMegamorphic(Super a) { 120 return a.getValue(); 121 } 122 123 /// CHECK-START: int Main.inlineMissingTypes(Super) inliner (before) 124 /// CHECK: InvokeVirtual method_name:Super.getValue 125 126 /// CHECK-START: int Main.inlineMissingTypes(Super) inliner (after) 127 /// CHECK: InvokeVirtual method_name:Super.getValue inlineMissingTypes(Super a)128 public static int inlineMissingTypes(Super a) { 129 return a.getValue(); 130 } 131 132 /// CHECK-START: int Main.noInlineCache(Super) inliner (before) 133 /// CHECK: InvokeVirtual method_name:Super.getValue 134 135 /// CHECK-START: int Main.noInlineCache(Super) inliner (after) 136 /// CHECK: InvokeVirtual method_name:Super.getValue noInlineCache(Super a)137 public static int noInlineCache(Super a) { 138 return a.getValue(); 139 } 140 141 // We shouldn't inline `someSubclassesThrow` since we are trying a monomorphic inline and it 142 // always throws for SubA. However, we shouldn't mark it as `always_throws` since we speculatively 143 // tried to inline and other subclasses (e.g. SubB) can call noInlineSomeSubclassesThrow and they 144 // don't throw. 145 146 /// CHECK-START: void Main.noInlineSomeSubclassesThrow(Super) inliner (before) 147 /// CHECK: InvokeVirtual method_name:Super.someSubclassesThrow always_throws:false 148 149 /// CHECK-START: void Main.noInlineSomeSubclassesThrow(Super) inliner (after) 150 /// CHECK: InvokeVirtual method_name:Super.someSubclassesThrow always_throws:false noInlineSomeSubclassesThrow(Super a)151 public static void noInlineSomeSubclassesThrow(Super a) throws Error { 152 a.someSubclassesThrow(); 153 } 154 testInlineMonomorphic()155 public static void testInlineMonomorphic() { 156 if (inlineMonomorphicSubA(new SubA()) != 42) { 157 throw new Error("Expected 42"); 158 } 159 160 // Call with a different type than the one from the inline cache. 161 if (inlineMonomorphicSubA(new SubB()) != 38) { 162 throw new Error("Expected 38"); 163 } 164 } 165 testInlinePolymorhic()166 public static void testInlinePolymorhic() { 167 if (inlinePolymophicSubASubB(new SubA()) != 42) { 168 throw new Error("Expected 42"); 169 } 170 171 if (inlinePolymophicSubASubB(new SubB()) != 38) { 172 throw new Error("Expected 38"); 173 } 174 175 // Call with a different type than the one from the inline cache. 176 if (inlinePolymophicSubASubB(new SubC()) != 24) { 177 throw new Error("Expected 25"); 178 } 179 180 if (inlinePolymophicCrossDexSubASubC(new SubA()) != 42) { 181 throw new Error("Expected 42"); 182 } 183 184 if (inlinePolymophicCrossDexSubASubC(new SubC()) != 24) { 185 throw new Error("Expected 24"); 186 } 187 188 // Call with a different type than the one from the inline cache. 189 if (inlinePolymophicCrossDexSubASubC(new SubB()) != 38) { 190 throw new Error("Expected 38"); 191 } 192 } 193 testInlineMegamorphic()194 public static void testInlineMegamorphic() { 195 if (inlineMegamorphic(new SubA()) != 42) { 196 throw new Error("Expected 42"); 197 } 198 } 199 200 testNoInlineCache()201 public static void testNoInlineCache() { 202 if (noInlineCache(new SubA()) != 42) { 203 throw new Error("Expected 42"); 204 } 205 } 206 $noinline$testsomeSubclassesThrow()207 private static void $noinline$testsomeSubclassesThrow() throws Exception { 208 try { 209 noInlineSomeSubclassesThrow(new SubA()); 210 throw new Exception("Unreachable"); 211 } catch (Error expected) { 212 } 213 noInlineSomeSubclassesThrow(new SubB()); 214 } 215 main(String[] args)216 public static void main(String[] args) throws Exception { 217 testInlineMonomorphic(); 218 testInlinePolymorhic(); 219 testInlineMegamorphic(); 220 testNoInlineCache(); 221 $noinline$testsomeSubclassesThrow(); 222 } 223 } 224