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