Main.java revision c57397b2b87c7e6f28f4eee3c996d091e7dc0b01
1/* 2 * Copyright (C) 2015 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 17public class Main { 18 19 /* 20 * Ensure an inlined static invoke explicitly triggers the 21 * initialization check of the called method's declaring class, and 22 * that the corresponding load class instruction does not get 23 * removed before register allocation & code generation. 24 */ 25 26 // CHECK-START: void Main.invokeStaticInlined() builder (after) 27 // CHECK-DAG: <<LoadClass:l\d+>> LoadClass 28 // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>] 29 // CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>] 30 31 // CHECK-START: void Main.invokeStaticInlined() inliner (after) 32 // CHECK-DAG: <<LoadClass:l\d+>> LoadClass 33 // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>] 34 35 // CHECK-START: void Main.invokeStaticInlined() inliner (after) 36 // CHECK-NOT: InvokeStaticOrDirect 37 38 // The following checks ensure the clinit check instruction added by 39 // the builder is pruned by the PrepareForRegisterAllocation, while 40 // the load class instruction is preserved. As the control flow 41 // graph is not dumped after (nor before) this step, we check the 42 // CFG as it is before the next pass (liveness analysis) instead. 43 44 // CHECK-START: void Main.invokeStaticInlined() liveness (before) 45 // CHECK-DAG: LoadClass 46 47 // CHECK-START: void Main.invokeStaticInlined() liveness (before) 48 // CHECK-NOT: ClinitCheck 49 // CHECK-NOT: InvokeStaticOrDirect 50 51 static void invokeStaticInlined() { 52 ClassWithClinit1.$opt$inline$StaticMethod(); 53 } 54 55 static class ClassWithClinit1 { 56 static { 57 System.out.println("Main$ClassWithClinit1's static initializer"); 58 } 59 60 static void $opt$inline$StaticMethod() { 61 } 62 } 63 64 /* 65 * Ensure a non-inlined static invoke eventually has an implicit 66 * initialization check of the called method's declaring class. 67 */ 68 69 // CHECK-START: void Main.invokeStaticNotInlined() builder (after) 70 // CHECK-DAG: <<LoadClass:l\d+>> LoadClass 71 // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>] 72 // CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>] 73 74 // CHECK-START: void Main.invokeStaticNotInlined() inliner (after) 75 // CHECK-DAG: <<LoadClass:l\d+>> LoadClass 76 // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>] 77 // CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>] 78 79 // The following checks ensure the clinit check and load class 80 // instructions added by the builder are pruned by the 81 // PrepareForRegisterAllocation. As the control flow graph is not 82 // dumped after (nor before) this step, we check the CFG as it is 83 // before the next pass (liveness analysis) instead. 84 85 // CHECK-START: void Main.invokeStaticNotInlined() liveness (before) 86 // CHECK-DAG: InvokeStaticOrDirect 87 88 // CHECK-START: void Main.invokeStaticNotInlined() liveness (before) 89 // CHECK-NOT: LoadClass 90 // CHECK-NOT: ClinitCheck 91 92 static void invokeStaticNotInlined() { 93 ClassWithClinit2.staticMethod(); 94 } 95 96 static class ClassWithClinit2 { 97 static { 98 System.out.println("Main$ClassWithClinit2's static initializer"); 99 } 100 101 static boolean doThrow = false; 102 103 static void staticMethod() { 104 if (doThrow) { 105 // Try defeating inlining. 106 throw new Error(); 107 } 108 } 109 } 110 111 /* 112 * Ensure an inlined call to a static method whose declaring class 113 * is statically known to have been initialized does not require an 114 * explicit clinit check. 115 */ 116 117 // CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() builder (after) 118 // CHECK-DAG: InvokeStaticOrDirect 119 120 // CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() builder (after) 121 // CHECK-NOT: LoadClass 122 // CHECK-NOT: ClinitCheck 123 124 // CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() inliner (after) 125 // CHECK-NOT: LoadClass 126 // CHECK-NOT: ClinitCheck 127 // CHECK-NOT: InvokeStaticOrDirect 128 129 static class ClassWithClinit3 { 130 static void invokeStaticInlined() { 131 // The invocation of invokeStaticInlined triggers the 132 // initialization of ClassWithClinit3, meaning that the 133 // hereinbelow call to $opt$inline$StaticMethod does not need a 134 // clinit check. 135 $opt$inline$StaticMethod(); 136 } 137 138 static { 139 System.out.println("Main$ClassWithClinit3's static initializer"); 140 } 141 142 static void $opt$inline$StaticMethod() { 143 } 144 } 145 146 /* 147 * Ensure an non-inlined call to a static method whose declaring 148 * class is statically known to have been initialized does not 149 * require an explicit clinit check. 150 */ 151 152 // CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() builder (after) 153 // CHECK-DAG: InvokeStaticOrDirect 154 155 // CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() builder (after) 156 // CHECK-NOT: LoadClass 157 // CHECK-NOT: ClinitCheck 158 159 // CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() inliner (after) 160 // CHECK-DAG: InvokeStaticOrDirect 161 162 // CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() inliner (after) 163 // CHECK-NOT: LoadClass 164 // CHECK-NOT: ClinitCheck 165 166 static class ClassWithClinit4 { 167 static void invokeStaticNotInlined() { 168 // The invocation of invokeStaticNotInlined triggers the 169 // initialization of ClassWithClinit4, meaning that the 170 // hereinbelow call to staticMethod does not need a clinit 171 // check. 172 staticMethod(); 173 } 174 175 static { 176 System.out.println("Main$ClassWithClinit4's static initializer"); 177 } 178 179 static boolean doThrow = false; 180 181 static void staticMethod() { 182 if (doThrow) { 183 // Try defeating inlining. 184 throw new Error(); 185 } 186 } 187 } 188 189 /* 190 * Ensure an inlined call to a static method whose declaring class 191 * is a super class of the caller's class does not require an 192 * explicit clinit check. 193 */ 194 195 // CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after) 196 // CHECK-DAG: InvokeStaticOrDirect 197 198 // CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after) 199 // CHECK-NOT: LoadClass 200 // CHECK-NOT: ClinitCheck 201 202 // CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() inliner (after) 203 // CHECK-NOT: LoadClass 204 // CHECK-NOT: ClinitCheck 205 // CHECK-NOT: InvokeStaticOrDirect 206 207 static class ClassWithClinit5 { 208 static void $opt$inline$StaticMethod() { 209 } 210 211 static { 212 System.out.println("Main$ClassWithClinit5's static initializer"); 213 } 214 } 215 216 static class SubClassOfClassWithClinit5 extends ClassWithClinit5 { 217 static void invokeStaticInlined() { 218 ClassWithClinit5.$opt$inline$StaticMethod(); 219 } 220 } 221 222 /* 223 * Ensure an non-inlined call to a static method whose declaring 224 * class is a super class of the caller's class does not require an 225 * explicit clinit check. 226 */ 227 228 // CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after) 229 // CHECK-DAG: InvokeStaticOrDirect 230 231 // CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after) 232 // CHECK-NOT: LoadClass 233 // CHECK-NOT: ClinitCheck 234 235 // CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after) 236 // CHECK-DAG: InvokeStaticOrDirect 237 238 // CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after) 239 // CHECK-NOT: LoadClass 240 // CHECK-NOT: ClinitCheck 241 242 static class ClassWithClinit6 { 243 static boolean doThrow = false; 244 245 static void staticMethod() { 246 if (doThrow) { 247 // Try defeating inlining. 248 throw new Error(); 249 } 250 } 251 252 static { 253 System.out.println("Main$ClassWithClinit6's static initializer"); 254 } 255 } 256 257 static class SubClassOfClassWithClinit6 extends ClassWithClinit6 { 258 static void invokeStaticNotInlined() { 259 ClassWithClinit6.staticMethod(); 260 } 261 } 262 263 // TODO: Add a test for the case of a static method whose declaring 264 // class type index is not available (i.e. when `storage_index` 265 // equals `DexFile::kDexNoIndex` in 266 // art::HGraphBuilder::BuildInvoke). 267 268 public static void main(String[] args) { 269 invokeStaticInlined(); 270 invokeStaticNotInlined(); 271 ClassWithClinit3.invokeStaticInlined(); 272 ClassWithClinit4.invokeStaticNotInlined(); 273 SubClassOfClassWithClinit5.invokeStaticInlined(); 274 SubClassOfClassWithClinit6.invokeStaticNotInlined(); 275 } 276} 277