blob: 5b9ebc808ce739410890369859787f0f849e546c [file] [log] [blame]
Roland Levillain4c0eb422015-04-24 16:43:49 +01001/*
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
David Brazdila06d66a2015-05-28 11:14:54 +010026 /// CHECK-START: void Main.invokeStaticInlined() builder (after)
27 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
28 /// CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
Nicolas Geoffraybdb2ecc2018-09-18 14:33:55 +010029 /// CHECK-DAG: InvokeStaticOrDirect [{{([ij]\d+,)?}}<<ClinitCheck>>]
Roland Levillain4c0eb422015-04-24 16:43:49 +010030
David Brazdila06d66a2015-05-28 11:14:54 +010031 /// CHECK-START: void Main.invokeStaticInlined() inliner (after)
32 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
33 /// CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
Roland Levillain4c0eb422015-04-24 16:43:49 +010034
David Brazdila06d66a2015-05-28 11:14:54 +010035 /// CHECK-START: void Main.invokeStaticInlined() inliner (after)
36 /// CHECK-NOT: InvokeStaticOrDirect
Roland Levillain4c0eb422015-04-24 16:43:49 +010037
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
David Brazdila06d66a2015-05-28 11:14:54 +010044 /// CHECK-START: void Main.invokeStaticInlined() liveness (before)
45 /// CHECK-DAG: LoadClass gen_clinit_check:true
Roland Levillain4c0eb422015-04-24 16:43:49 +010046
David Brazdila06d66a2015-05-28 11:14:54 +010047 /// CHECK-START: void Main.invokeStaticInlined() liveness (before)
48 /// CHECK-NOT: ClinitCheck
49 /// CHECK-NOT: InvokeStaticOrDirect
Roland Levillain4c0eb422015-04-24 16:43:49 +010050
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
David Brazdila06d66a2015-05-28 11:14:54 +010069 /// CHECK-START: void Main.invokeStaticNotInlined() builder (after)
Vladimir Markob554b5a2015-11-06 12:57:55 +000070 /// CHECK: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
71 /// CHECK: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
Nicolas Geoffraybdb2ecc2018-09-18 14:33:55 +010072 /// CHECK: InvokeStaticOrDirect [{{([ij]\d+,)?}}<<ClinitCheck>>]
Roland Levillain4c0eb422015-04-24 16:43:49 +010073
David Brazdila06d66a2015-05-28 11:14:54 +010074 /// CHECK-START: void Main.invokeStaticNotInlined() inliner (after)
Vladimir Markob554b5a2015-11-06 12:57:55 +000075 /// CHECK: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
76 /// CHECK: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
77 /// CHECK: InvokeStaticOrDirect [{{([ij]\d+,)?}}<<ClinitCheck>>]
Roland Levillain4c0eb422015-04-24 16:43:49 +010078
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
David Brazdila06d66a2015-05-28 11:14:54 +010085 /// CHECK-START: void Main.invokeStaticNotInlined() liveness (before)
Vladimir Markofbb184a2015-11-13 14:47:00 +000086 /// CHECK: InvokeStaticOrDirect clinit_check:implicit
Roland Levillain4c0eb422015-04-24 16:43:49 +010087
David Brazdila06d66a2015-05-28 11:14:54 +010088 /// CHECK-START: void Main.invokeStaticNotInlined() liveness (before)
89 /// CHECK-NOT: LoadClass
90 /// CHECK-NOT: ClinitCheck
Roland Levillain4c0eb422015-04-24 16:43:49 +010091
92 static void invokeStaticNotInlined() {
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +010093 ClassWithClinit2.$noinline$staticMethod();
Roland Levillain4c0eb422015-04-24 16:43:49 +010094 }
95
96 static class ClassWithClinit2 {
97 static {
98 System.out.println("Main$ClassWithClinit2's static initializer");
99 }
100
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100101 static boolean staticField = false;
Roland Levillain4c0eb422015-04-24 16:43:49 +0100102
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100103 static void $noinline$staticMethod() {
Roland Levillain4c0eb422015-04-24 16:43:49 +0100104 }
105 }
106
107 /*
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100108 * Ensure an inlined call from a static method to a static method
109 * of the same class does not require an explicit clinit check
110 * (already initialized or initializing in the same thread).
Roland Levillain4c0eb422015-04-24 16:43:49 +0100111 */
112
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100113 /// CHECK-START: void Main$ClassWithClinit3Static.invokeStaticInlined() builder (after)
David Brazdila06d66a2015-05-28 11:14:54 +0100114 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain4c0eb422015-04-24 16:43:49 +0100115
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100116 /// CHECK-START: void Main$ClassWithClinit3Static.invokeStaticInlined() builder (after)
David Brazdila06d66a2015-05-28 11:14:54 +0100117 /// CHECK-NOT: LoadClass
118 /// CHECK-NOT: ClinitCheck
Roland Levillain4c0eb422015-04-24 16:43:49 +0100119
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100120 /// CHECK-START: void Main$ClassWithClinit3Static.invokeStaticInlined() inliner (after)
David Brazdila06d66a2015-05-28 11:14:54 +0100121 /// CHECK-NOT: LoadClass
122 /// CHECK-NOT: ClinitCheck
123 /// CHECK-NOT: InvokeStaticOrDirect
Roland Levillain4c0eb422015-04-24 16:43:49 +0100124
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100125 static class ClassWithClinit3Static {
Roland Levillain4c0eb422015-04-24 16:43:49 +0100126 static void invokeStaticInlined() {
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100127 // The invocation of invokeStaticInlined happens only after a clinit check
128 // of ClassWithClinit3Static, meaning that the hereinbelow call to
129 // $opt$inline$StaticMethod does not need another clinit check.
Roland Levillain4c0eb422015-04-24 16:43:49 +0100130 $opt$inline$StaticMethod();
131 }
132
133 static {
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100134 System.out.println("Main$ClassWithClinit3Static's static initializer");
Roland Levillain4c0eb422015-04-24 16:43:49 +0100135 }
136
137 static void $opt$inline$StaticMethod() {
138 }
139 }
140
141 /*
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100142 * Ensure an inlined call from an instance method to a static method
143 * of the same class actually requires an explicit clinit check when
144 * the class has a non-trivial initialization as we could be executing
145 * the instance method on an escaped object of an erroneous class. b/62478025
Roland Levillain4c0eb422015-04-24 16:43:49 +0100146 */
147
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100148 /// CHECK-START: void Main$ClassWithClinit3Instance.invokeStaticInlined() builder (after)
149 /// CHECK-DAG: LoadClass
150 /// CHECK-DAG: ClinitCheck
David Brazdila06d66a2015-05-28 11:14:54 +0100151 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain4c0eb422015-04-24 16:43:49 +0100152
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100153 /// CHECK-START: void Main$ClassWithClinit3Instance.invokeStaticInlined() inliner (after)
154 /// CHECK-DAG: LoadClass
155 /// CHECK-DAG: ClinitCheck
156
157 /// CHECK-START: void Main$ClassWithClinit3Instance.invokeStaticInlined() inliner (after)
158 /// CHECK-NOT: InvokeStaticOrDirect
159
160 static class ClassWithClinit3Instance {
161 void invokeStaticInlined() {
162 // ClinitCheck required.
163 $opt$inline$StaticMethod();
164 }
165
166 static {
167 System.out.println("Main$ClassWithClinit3Instance's static initializer");
168 }
169
170 static void $opt$inline$StaticMethod() {
171 }
172 }
173
174 /*
175 * Ensure a non-inlined call from a static method to a static method
176 * of the same class does not require an explicit clinit check
177 * (already initialized or initializing in the same thread).
178 */
179
180 /// CHECK-START: void Main$ClassWithClinit4Static.invokeStaticNotInlined() builder (after)
181 /// CHECK-DAG: InvokeStaticOrDirect
182
183 /// CHECK-START: void Main$ClassWithClinit4Static.invokeStaticNotInlined() builder (after)
David Brazdila06d66a2015-05-28 11:14:54 +0100184 /// CHECK-NOT: LoadClass
185 /// CHECK-NOT: ClinitCheck
Roland Levillain4c0eb422015-04-24 16:43:49 +0100186
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100187 /// CHECK-START: void Main$ClassWithClinit4Static.invokeStaticNotInlined() inliner (after)
David Brazdila06d66a2015-05-28 11:14:54 +0100188 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain4c0eb422015-04-24 16:43:49 +0100189
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100190 /// CHECK-START: void Main$ClassWithClinit4Static.invokeStaticNotInlined() inliner (after)
David Brazdila06d66a2015-05-28 11:14:54 +0100191 /// CHECK-NOT: LoadClass
192 /// CHECK-NOT: ClinitCheck
Roland Levillain4c0eb422015-04-24 16:43:49 +0100193
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100194 static class ClassWithClinit4Static {
Roland Levillain4c0eb422015-04-24 16:43:49 +0100195 static void invokeStaticNotInlined() {
196 // The invocation of invokeStaticNotInlined triggers the
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100197 // initialization of ClassWithClinit4Static, meaning that the
Nicolas Geoffrayd23eeef2015-05-18 22:31:29 +0100198 // call to staticMethod below does not need a clinit
Roland Levillain4c0eb422015-04-24 16:43:49 +0100199 // check.
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100200 $noinline$staticMethod();
Roland Levillain4c0eb422015-04-24 16:43:49 +0100201 }
202
203 static {
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100204 System.out.println("Main$ClassWithClinit4Static's static initializer");
Roland Levillain4c0eb422015-04-24 16:43:49 +0100205 }
206
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100207 static void $noinline$staticMethod() {
208 }
209 }
210
211 /*
212 * Ensure a non-inlined call from an instance method to a static method
213 * of the same class actually requires an explicit clinit check when
214 * the class has a non-trivial initialization as we could be executing
215 * the instance method on an escaped object of an erroneous class. b/62478025
216 */
217
218 /// CHECK-START: void Main$ClassWithClinit4Instance.invokeStaticNotInlined() builder (after)
219 /// CHECK-DAG: LoadClass
220 /// CHECK-DAG: ClinitCheck
221 /// CHECK-DAG: InvokeStaticOrDirect
222
223 /// CHECK-START: void Main$ClassWithClinit4Instance.invokeStaticNotInlined() inliner (after)
224 /// CHECK-DAG: LoadClass
225 /// CHECK-DAG: ClinitCheck
226 /// CHECK-DAG: InvokeStaticOrDirect
227
Vladimir Marko78da5e22019-05-30 14:14:34 +0100228 // The following checks ensure the clinit check and load class
229 // instructions added by the builder are pruned by the
230 // PrepareForRegisterAllocation. As the control flow graph is not
231 // dumped after (nor before) this step, we check the CFG as it is
232 // before the next pass (liveness analysis) instead.
233
234 /// CHECK-START: void Main$ClassWithClinit4Instance.invokeStaticNotInlined() liveness (before)
235 /// CHECK: InvokeStaticOrDirect clinit_check:implicit
236
237 /// CHECK-START: void Main$ClassWithClinit4Instance.invokeStaticNotInlined() liveness (before)
238 /// CHECK-NOT: LoadClass
239 /// CHECK-NOT: ClinitCheck
240
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100241 static class ClassWithClinit4Instance {
242 void invokeStaticNotInlined() {
243 // ClinitCheck required.
244 $noinline$staticMethod();
245 }
246
247 static {
248 System.out.println("Main$ClassWithClinit4Instance's static initializer");
249 }
Roland Levillain4c0eb422015-04-24 16:43:49 +0100250
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100251 static void $noinline$staticMethod() {
Roland Levillain4c0eb422015-04-24 16:43:49 +0100252 }
253 }
254
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100255 /*
Vladimir Marko51b8aaf2017-06-09 15:17:05 +0100256 * We used to remove clinit check for calls to static methods in a superclass. However, this
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100257 * is not a valid optimization when instances of erroneous classes can escape, therefore
258 * we avoid this optimization for classes with non-trivial initialization. b/62478025
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100259 */
260
David Brazdila06d66a2015-05-28 11:14:54 +0100261 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after)
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100262 /// CHECK-DAG: LoadClass
263 /// CHECK-DAG: ClinitCheck
David Brazdila06d66a2015-05-28 11:14:54 +0100264 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100265
David Brazdila06d66a2015-05-28 11:14:54 +0100266 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() inliner (after)
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100267 /// CHECK-DAG: LoadClass
268 /// CHECK-DAG: ClinitCheck
David Brazdila06d66a2015-05-28 11:14:54 +0100269 /// CHECK-NOT: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100270
271 static class ClassWithClinit5 {
272 static void $opt$inline$StaticMethod() {
273 }
274
275 static {
276 System.out.println("Main$ClassWithClinit5's static initializer");
277 }
278 }
279
280 static class SubClassOfClassWithClinit5 extends ClassWithClinit5 {
281 static void invokeStaticInlined() {
282 ClassWithClinit5.$opt$inline$StaticMethod();
283 }
284 }
285
286 /*
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100287 * Ensure an inlined call to a static method whose declaring class is a super class
288 * of the caller's class does not require an explicit clinit check if the declaring
289 * class has a trivial initialization. b/62478025
290 */
291
292 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() builder (after)
293 /// CHECK-DAG: InvokeStaticOrDirect
294
295 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() builder (after)
296 /// CHECK-NOT: LoadClass
297 /// CHECK-NOT: ClinitCheck
298
299 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() inliner (after)
300 /// CHECK-NOT: LoadClass
301 /// CHECK-NOT: ClinitCheck
302 /// CHECK-NOT: InvokeStaticOrDirect
303
304 static class ClassWithoutClinit5 { // Mimicks ClassWithClinit5 but without the <clinit>.
305 static void $opt$inline$StaticMethod() {
306 }
307 }
308
309 static class SubClassOfClassWithoutClinit5 extends ClassWithoutClinit5 {
310 static {
311 System.out.println("Main$SubClassOfClassWithoutClinit5's static initializer");
312 }
313
314 static void invokeStaticInlined() {
315 ClassWithoutClinit5.$opt$inline$StaticMethod();
316 }
317 }
318
319 /*
Vladimir Marko51b8aaf2017-06-09 15:17:05 +0100320 * We used to remove clinit check for calls to static methods in a superclass. However, this
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100321 * is not a valid optimization when instances of erroneous classes can escape, therefore
322 * we avoid this optimization for classes with non-trivial initialization. b/62478025
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100323 */
324
David Brazdila06d66a2015-05-28 11:14:54 +0100325 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after)
326 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100327
David Brazdila06d66a2015-05-28 11:14:54 +0100328 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after)
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100329 /// CHECK-DAG: LoadClass
330 /// CHECK-DAG: ClinitCheck
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100331
David Brazdila06d66a2015-05-28 11:14:54 +0100332 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after)
Vladimir Marko51b8aaf2017-06-09 15:17:05 +0100333 /// CHECK-DAG: LoadClass
334 /// CHECK-DAG: ClinitCheck
David Brazdila06d66a2015-05-28 11:14:54 +0100335 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100336
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100337 static class ClassWithClinit6 {
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100338 static void $noinline$staticMethod() {
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100339 }
340
341 static {
342 System.out.println("Main$ClassWithClinit6's static initializer");
343 }
344 }
345
346 static class SubClassOfClassWithClinit6 extends ClassWithClinit6 {
347 static void invokeStaticNotInlined() {
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100348 ClassWithClinit6.$noinline$staticMethod();
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100349 }
350 }
351
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100352 /*
353 * Ensure a non-inlined call to a static method whose declaring class is a super class
354 * of the caller's class does not require an explicit clinit check if the declaring
355 * class has a trivial initialization. b/62478025
356 */
357
358 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() builder (after)
359 /// CHECK-DAG: InvokeStaticOrDirect
360
361 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() builder (after)
362 /// CHECK-NOT: LoadClass
363 /// CHECK-NOT: ClinitCheck
364
365 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() inliner (after)
366 /// CHECK-DAG: InvokeStaticOrDirect
367
368 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() inliner (after)
369 /// CHECK-NOT: LoadClass
370 /// CHECK-NOT: ClinitCheck
371
372 static class ClassWithoutClinit6 { // Mimicks ClassWithClinit6 but without the <clinit>.
373 static void $noinline$staticMethod() {
374 }
375 }
376
377 static class SubClassOfClassWithoutClinit6 extends ClassWithoutClinit6 {
378 static {
379 System.out.println("Main$SubClassOfClassWithoutClinit6's static initializer");
380 }
381
382 static void invokeStaticNotInlined() {
383 ClassWithoutClinit6.$noinline$staticMethod();
384 }
385 }
Calin Juravle0ba218d2015-05-19 18:46:01 +0100386
387 /*
388 * Verify that if we have a static call immediately after the load class
389 * we don't do generate a clinit check.
390 */
391
David Brazdila06d66a2015-05-28 11:14:54 +0100392 /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before)
393 /// CHECK-DAG: <<IntConstant:i\d+>> IntConstant 0
394 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
Vladimir Markofbb184a2015-11-13 14:47:00 +0000395 /// CHECK-DAG: InvokeStaticOrDirect clinit_check:implicit
David Brazdila06d66a2015-05-28 11:14:54 +0100396 /// CHECK-DAG: StaticFieldSet [<<LoadClass>>,<<IntConstant>>]
Calin Juravle0ba218d2015-05-19 18:46:01 +0100397
David Brazdila06d66a2015-05-28 11:14:54 +0100398 /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before)
399 /// CHECK-NOT: ClinitCheck
Calin Juravle0ba218d2015-05-19 18:46:01 +0100400
401 static void noClinitBecauseOfInvokeStatic() {
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100402 ClassWithClinit2.$noinline$staticMethod();
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100403 ClassWithClinit2.staticField = false;
Calin Juravle0ba218d2015-05-19 18:46:01 +0100404 }
405
406 /*
407 * Verify that if the static call is after a field access, the load class
408 * will generate a clinit check.
409 */
410
David Brazdila06d66a2015-05-28 11:14:54 +0100411 /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before)
412 /// CHECK-DAG: <<IntConstant:i\d+>> IntConstant 0
413 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:true
414 /// CHECK-DAG: StaticFieldSet [<<LoadClass>>,<<IntConstant>>]
Vladimir Markofbb184a2015-11-13 14:47:00 +0000415 /// CHECK-DAG: InvokeStaticOrDirect clinit_check:none
Calin Juravle0ba218d2015-05-19 18:46:01 +0100416
David Brazdila06d66a2015-05-28 11:14:54 +0100417 /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before)
418 /// CHECK-NOT: ClinitCheck
Calin Juravle0ba218d2015-05-19 18:46:01 +0100419 static void clinitBecauseOfFieldAccess() {
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100420 ClassWithClinit2.staticField = false;
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100421 ClassWithClinit2.$noinline$staticMethod();
Calin Juravle0ba218d2015-05-19 18:46:01 +0100422 }
423
Vladimir Markofbb184a2015-11-13 14:47:00 +0000424 /*
425 * Verify that LoadClass from const-class is not merged with
426 * later invoke-static (or it's ClinitCheck).
427 */
428
429 /// CHECK-START: void Main.constClassAndInvokeStatic(java.lang.Iterable) liveness (before)
430 /// CHECK: LoadClass gen_clinit_check:false
431 /// CHECK: InvokeStaticOrDirect clinit_check:implicit
432
433 /// CHECK-START: void Main.constClassAndInvokeStatic(java.lang.Iterable) liveness (before)
434 /// CHECK-NOT: ClinitCheck
435
Vladimir Markoc7591b42016-06-29 14:59:07 +0100436 static void constClassAndInvokeStatic(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000437 $opt$inline$ignoreClass(ClassWithClinit7.class);
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000438 ClassWithClinit7.$noinline$someStaticMethod(it);
Vladimir Markofbb184a2015-11-13 14:47:00 +0000439 }
440
Vladimir Markoc7591b42016-06-29 14:59:07 +0100441 static void $opt$inline$ignoreClass(Class<?> c) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000442 }
443
444 static class ClassWithClinit7 {
445 static {
446 System.out.println("Main$ClassWithClinit7's static initializer");
447 }
448
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000449 static void $noinline$someStaticMethod(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000450 it.iterator();
451 }
452 }
453
454 /*
455 * Verify that LoadClass from sget is not merged with later invoke-static.
456 */
457
458 /// CHECK-START: void Main.sgetAndInvokeStatic(java.lang.Iterable) liveness (before)
459 /// CHECK: LoadClass gen_clinit_check:true
460 /// CHECK: InvokeStaticOrDirect clinit_check:none
461
462 /// CHECK-START: void Main.sgetAndInvokeStatic(java.lang.Iterable) liveness (before)
463 /// CHECK-NOT: ClinitCheck
464
Vladimir Markoc7591b42016-06-29 14:59:07 +0100465 static void sgetAndInvokeStatic(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000466 $opt$inline$ignoreInt(ClassWithClinit8.value);
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000467 ClassWithClinit8.$noinline$someStaticMethod(it);
Vladimir Markofbb184a2015-11-13 14:47:00 +0000468 }
469
470 static void $opt$inline$ignoreInt(int i) {
471 }
472
473 static class ClassWithClinit8 {
474 public static int value = 0;
475 static {
476 System.out.println("Main$ClassWithClinit8's static initializer");
477 }
478
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000479 static void $noinline$someStaticMethod(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000480 it.iterator();
481 }
482 }
483
484 /*
485 * Verify that LoadClass from const-class, ClinitCheck from sget and
486 * InvokeStaticOrDirect from invoke-static are not merged.
487 */
488
489 /// CHECK-START: void Main.constClassSgetAndInvokeStatic(java.lang.Iterable) liveness (before)
490 /// CHECK: LoadClass gen_clinit_check:false
491 /// CHECK: ClinitCheck
492 /// CHECK: InvokeStaticOrDirect clinit_check:none
493
Vladimir Markoc7591b42016-06-29 14:59:07 +0100494 static void constClassSgetAndInvokeStatic(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000495 $opt$inline$ignoreClass(ClassWithClinit9.class);
496 $opt$inline$ignoreInt(ClassWithClinit9.value);
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000497 ClassWithClinit9.$noinline$someStaticMethod(it);
Vladimir Markofbb184a2015-11-13 14:47:00 +0000498 }
499
500 static class ClassWithClinit9 {
501 public static int value = 0;
502 static {
503 System.out.println("Main$ClassWithClinit9's static initializer");
504 }
505
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000506 static void $noinline$someStaticMethod(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000507 it.iterator();
508 }
509 }
510
511 /*
512 * Verify that LoadClass from a fully-inlined invoke-static is not merged
513 * with InvokeStaticOrDirect from a later invoke-static to the same method.
514 */
515
516 /// CHECK-START: void Main.inlinedInvokeStaticViaNonStatic(java.lang.Iterable) liveness (before)
517 /// CHECK: LoadClass gen_clinit_check:true
518 /// CHECK: InvokeStaticOrDirect clinit_check:none
519
520 /// CHECK-START: void Main.inlinedInvokeStaticViaNonStatic(java.lang.Iterable) liveness (before)
521 /// CHECK-NOT: ClinitCheck
522
Vladimir Markoc7591b42016-06-29 14:59:07 +0100523 static void inlinedInvokeStaticViaNonStatic(Iterable<?> it) {
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000524 if (it != null) {
525 inlinedInvokeStaticViaNonStaticHelper(null);
526 inlinedInvokeStaticViaNonStaticHelper(it);
527 }
Vladimir Markofbb184a2015-11-13 14:47:00 +0000528 }
529
Vladimir Markoc7591b42016-06-29 14:59:07 +0100530 static void inlinedInvokeStaticViaNonStaticHelper(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000531 ClassWithClinit10.inlinedForNull(it);
532 }
533
534 static class ClassWithClinit10 {
535 public static int value = 0;
536 static {
537 System.out.println("Main$ClassWithClinit10's static initializer");
538 }
539
Vladimir Markoc7591b42016-06-29 14:59:07 +0100540 static void inlinedForNull(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000541 if (it != null) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000542 it.iterator();
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000543 // We're not inlining methods that always throw.
544 throw new Error("");
Vladimir Markofbb184a2015-11-13 14:47:00 +0000545 }
546 }
547 }
548
549 /*
550 * Check that the LoadClass from an invoke-static C.foo() doesn't get merged with
551 * an invoke-static inside C.foo(). This would mess up the stack walk in the
552 * resolution trampoline where we would have to load C (if C isn't loaded yet)
553 * which is not permitted there.
554 *
555 * Note: In case of failure, we would get an failed assertion during compilation,
556 * so we wouldn't really get to the checker tests below.
557 */
558
559 /// CHECK-START: void Main.inlinedInvokeStaticViaStatic(java.lang.Iterable) liveness (before)
560 /// CHECK: LoadClass gen_clinit_check:true
561 /// CHECK: InvokeStaticOrDirect clinit_check:none
562
563 /// CHECK-START: void Main.inlinedInvokeStaticViaStatic(java.lang.Iterable) liveness (before)
564 /// CHECK-NOT: ClinitCheck
565
Vladimir Markoc7591b42016-06-29 14:59:07 +0100566 static void inlinedInvokeStaticViaStatic(Iterable<?> it) {
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000567 if (it != null) {
568 ClassWithClinit11.callInlinedForNull(it);
569 }
Vladimir Markofbb184a2015-11-13 14:47:00 +0000570 }
571
572 static class ClassWithClinit11 {
573 public static int value = 0;
574 static {
575 System.out.println("Main$ClassWithClinit11's static initializer");
576 }
577
Vladimir Markoc7591b42016-06-29 14:59:07 +0100578 static void callInlinedForNull(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000579 inlinedForNull(it);
580 }
581
Vladimir Markoc7591b42016-06-29 14:59:07 +0100582 static void inlinedForNull(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000583 it.iterator();
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000584 if (it != null) {
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000585 // We're not inlining methods that always throw.
586 throw new Error("");
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000587 }
Vladimir Markofbb184a2015-11-13 14:47:00 +0000588 }
589 }
590
591 /*
592 * A test similar to inlinedInvokeStaticViaStatic() but doing the indirect invoke
593 * twice with the first one to be fully inlined.
594 */
595
596 /// CHECK-START: void Main.inlinedInvokeStaticViaStaticTwice(java.lang.Iterable) liveness (before)
597 /// CHECK: LoadClass gen_clinit_check:true
598 /// CHECK: InvokeStaticOrDirect clinit_check:none
599
600 /// CHECK-START: void Main.inlinedInvokeStaticViaStaticTwice(java.lang.Iterable) liveness (before)
601 /// CHECK-NOT: ClinitCheck
602
Vladimir Markoc7591b42016-06-29 14:59:07 +0100603 static void inlinedInvokeStaticViaStaticTwice(Iterable<?> it) {
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000604 if (it != null) {
605 ClassWithClinit12.callInlinedForNull(null);
606 ClassWithClinit12.callInlinedForNull(it);
607 }
Vladimir Markofbb184a2015-11-13 14:47:00 +0000608 }
609
610 static class ClassWithClinit12 {
611 public static int value = 0;
612 static {
613 System.out.println("Main$ClassWithClinit12's static initializer");
614 }
615
Vladimir Markoc7591b42016-06-29 14:59:07 +0100616 static void callInlinedForNull(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000617 inlinedForNull(it);
618 }
619
Vladimir Markoc7591b42016-06-29 14:59:07 +0100620 static void inlinedForNull(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000621 if (it != null) {
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000622 // We're not inlining methods that always throw.
623 throw new Error("");
Vladimir Markofbb184a2015-11-13 14:47:00 +0000624 }
625 }
626 }
627
Vladimir Markoc7591b42016-06-29 14:59:07 +0100628 static class ClassWithClinit13 {
629 static {
630 System.out.println("Main$ClassWithClinit13's static initializer");
631 }
632
633 public static void $inline$forwardToGetIterator(Iterable<?> it) {
634 $noinline$getIterator(it);
635 }
636
637 public static void $noinline$getIterator(Iterable<?> it) {
Vladimir Markoc7591b42016-06-29 14:59:07 +0100638 it.iterator();
639 }
640 }
641
642 // TODO: Write checker statements.
643 static Object $noinline$testInliningAndNewInstance(Iterable<?> it) {
Vladimir Markoc7591b42016-06-29 14:59:07 +0100644 ClassWithClinit13.$inline$forwardToGetIterator(it);
645 return new ClassWithClinit13();
646 }
647
Roland Levillain4c0eb422015-04-24 16:43:49 +0100648 // TODO: Add a test for the case of a static method whose declaring
649 // class type index is not available (i.e. when `storage_index`
Andreas Gampee2abbc62017-09-15 11:59:26 -0700650 // equals `dex::kDexNoIndex` in
Roland Levillain4c0eb422015-04-24 16:43:49 +0100651 // art::HGraphBuilder::BuildInvoke).
652
653 public static void main(String[] args) {
654 invokeStaticInlined();
655 invokeStaticNotInlined();
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100656 ClassWithClinit3Static.invokeStaticInlined();
657 new ClassWithClinit3Instance().invokeStaticInlined();
658 ClassWithClinit4Static.invokeStaticNotInlined();
659 new ClassWithClinit4Instance().invokeStaticNotInlined();
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100660 SubClassOfClassWithClinit5.invokeStaticInlined();
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100661 SubClassOfClassWithoutClinit5.invokeStaticInlined();
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100662 SubClassOfClassWithClinit6.invokeStaticNotInlined();
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100663 SubClassOfClassWithoutClinit6.invokeStaticNotInlined();
Vladimir Markofbb184a2015-11-13 14:47:00 +0000664 Iterable it = new Iterable() { public java.util.Iterator iterator() { return null; } };
665 constClassAndInvokeStatic(it);
666 sgetAndInvokeStatic(it);
667 constClassSgetAndInvokeStatic(it);
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000668 try {
669 inlinedInvokeStaticViaNonStatic(it);
670 } catch (Error e) {
671 // Expected
672 }
673 try {
674 inlinedInvokeStaticViaStatic(it);
675 } catch (Error e) {
676 // Expected
677 }
678 try{
679 inlinedInvokeStaticViaStaticTwice(it);
680 } catch (Error e) {
681 // Expected
682 }
Vladimir Markoc7591b42016-06-29 14:59:07 +0100683 $noinline$testInliningAndNewInstance(it);
Roland Levillain4c0eb422015-04-24 16:43:49 +0100684 }
685}