blob: b1bc51e89dfe270fda27a41a835813de077a7ef1 [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
228 static class ClassWithClinit4Instance {
229 void invokeStaticNotInlined() {
230 // ClinitCheck required.
231 $noinline$staticMethod();
232 }
233
234 static {
235 System.out.println("Main$ClassWithClinit4Instance's static initializer");
236 }
Roland Levillain4c0eb422015-04-24 16:43:49 +0100237
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100238 static void $noinline$staticMethod() {
Roland Levillain4c0eb422015-04-24 16:43:49 +0100239 }
240 }
241
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100242 /*
Vladimir Marko51b8aaf2017-06-09 15:17:05 +0100243 * We used to remove clinit check for calls to static methods in a superclass. However, this
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100244 * is not a valid optimization when instances of erroneous classes can escape, therefore
245 * we avoid this optimization for classes with non-trivial initialization. b/62478025
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100246 */
247
David Brazdila06d66a2015-05-28 11:14:54 +0100248 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after)
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100249 /// CHECK-DAG: LoadClass
250 /// CHECK-DAG: ClinitCheck
David Brazdila06d66a2015-05-28 11:14:54 +0100251 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100252
David Brazdila06d66a2015-05-28 11:14:54 +0100253 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() inliner (after)
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100254 /// CHECK-DAG: LoadClass
255 /// CHECK-DAG: ClinitCheck
David Brazdila06d66a2015-05-28 11:14:54 +0100256 /// CHECK-NOT: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100257
258 static class ClassWithClinit5 {
259 static void $opt$inline$StaticMethod() {
260 }
261
262 static {
263 System.out.println("Main$ClassWithClinit5's static initializer");
264 }
265 }
266
267 static class SubClassOfClassWithClinit5 extends ClassWithClinit5 {
268 static void invokeStaticInlined() {
269 ClassWithClinit5.$opt$inline$StaticMethod();
270 }
271 }
272
273 /*
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100274 * Ensure an inlined call to a static method whose declaring class is a super class
275 * of the caller's class does not require an explicit clinit check if the declaring
276 * class has a trivial initialization. b/62478025
277 */
278
279 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() builder (after)
280 /// CHECK-DAG: InvokeStaticOrDirect
281
282 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() builder (after)
283 /// CHECK-NOT: LoadClass
284 /// CHECK-NOT: ClinitCheck
285
286 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() inliner (after)
287 /// CHECK-NOT: LoadClass
288 /// CHECK-NOT: ClinitCheck
289 /// CHECK-NOT: InvokeStaticOrDirect
290
291 static class ClassWithoutClinit5 { // Mimicks ClassWithClinit5 but without the <clinit>.
292 static void $opt$inline$StaticMethod() {
293 }
294 }
295
296 static class SubClassOfClassWithoutClinit5 extends ClassWithoutClinit5 {
297 static {
298 System.out.println("Main$SubClassOfClassWithoutClinit5's static initializer");
299 }
300
301 static void invokeStaticInlined() {
302 ClassWithoutClinit5.$opt$inline$StaticMethod();
303 }
304 }
305
306 /*
Vladimir Marko51b8aaf2017-06-09 15:17:05 +0100307 * We used to remove clinit check for calls to static methods in a superclass. However, this
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100308 * is not a valid optimization when instances of erroneous classes can escape, therefore
309 * we avoid this optimization for classes with non-trivial initialization. b/62478025
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100310 */
311
David Brazdila06d66a2015-05-28 11:14:54 +0100312 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after)
313 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100314
David Brazdila06d66a2015-05-28 11:14:54 +0100315 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after)
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100316 /// CHECK-DAG: LoadClass
317 /// CHECK-DAG: ClinitCheck
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100318
David Brazdila06d66a2015-05-28 11:14:54 +0100319 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after)
Vladimir Marko51b8aaf2017-06-09 15:17:05 +0100320 /// CHECK-DAG: LoadClass
321 /// CHECK-DAG: ClinitCheck
David Brazdila06d66a2015-05-28 11:14:54 +0100322 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100323
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100324 static class ClassWithClinit6 {
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100325 static void $noinline$staticMethod() {
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100326 }
327
328 static {
329 System.out.println("Main$ClassWithClinit6's static initializer");
330 }
331 }
332
333 static class SubClassOfClassWithClinit6 extends ClassWithClinit6 {
334 static void invokeStaticNotInlined() {
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100335 ClassWithClinit6.$noinline$staticMethod();
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100336 }
337 }
338
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100339 /*
340 * Ensure a non-inlined call to a static method whose declaring class is a super class
341 * of the caller's class does not require an explicit clinit check if the declaring
342 * class has a trivial initialization. b/62478025
343 */
344
345 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() builder (after)
346 /// CHECK-DAG: InvokeStaticOrDirect
347
348 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() builder (after)
349 /// CHECK-NOT: LoadClass
350 /// CHECK-NOT: ClinitCheck
351
352 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() inliner (after)
353 /// CHECK-DAG: InvokeStaticOrDirect
354
355 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() inliner (after)
356 /// CHECK-NOT: LoadClass
357 /// CHECK-NOT: ClinitCheck
358
359 static class ClassWithoutClinit6 { // Mimicks ClassWithClinit6 but without the <clinit>.
360 static void $noinline$staticMethod() {
361 }
362 }
363
364 static class SubClassOfClassWithoutClinit6 extends ClassWithoutClinit6 {
365 static {
366 System.out.println("Main$SubClassOfClassWithoutClinit6's static initializer");
367 }
368
369 static void invokeStaticNotInlined() {
370 ClassWithoutClinit6.$noinline$staticMethod();
371 }
372 }
Calin Juravle0ba218d2015-05-19 18:46:01 +0100373
374 /*
375 * Verify that if we have a static call immediately after the load class
376 * we don't do generate a clinit check.
377 */
378
David Brazdila06d66a2015-05-28 11:14:54 +0100379 /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before)
380 /// CHECK-DAG: <<IntConstant:i\d+>> IntConstant 0
381 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
Vladimir Markofbb184a2015-11-13 14:47:00 +0000382 /// CHECK-DAG: InvokeStaticOrDirect clinit_check:implicit
David Brazdila06d66a2015-05-28 11:14:54 +0100383 /// CHECK-DAG: StaticFieldSet [<<LoadClass>>,<<IntConstant>>]
Calin Juravle0ba218d2015-05-19 18:46:01 +0100384
David Brazdila06d66a2015-05-28 11:14:54 +0100385 /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before)
386 /// CHECK-NOT: ClinitCheck
Calin Juravle0ba218d2015-05-19 18:46:01 +0100387
388 static void noClinitBecauseOfInvokeStatic() {
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100389 ClassWithClinit2.$noinline$staticMethod();
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100390 ClassWithClinit2.staticField = false;
Calin Juravle0ba218d2015-05-19 18:46:01 +0100391 }
392
393 /*
394 * Verify that if the static call is after a field access, the load class
395 * will generate a clinit check.
396 */
397
David Brazdila06d66a2015-05-28 11:14:54 +0100398 /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before)
399 /// CHECK-DAG: <<IntConstant:i\d+>> IntConstant 0
400 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:true
401 /// CHECK-DAG: StaticFieldSet [<<LoadClass>>,<<IntConstant>>]
Vladimir Markofbb184a2015-11-13 14:47:00 +0000402 /// CHECK-DAG: InvokeStaticOrDirect clinit_check:none
Calin Juravle0ba218d2015-05-19 18:46:01 +0100403
David Brazdila06d66a2015-05-28 11:14:54 +0100404 /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before)
405 /// CHECK-NOT: ClinitCheck
Calin Juravle0ba218d2015-05-19 18:46:01 +0100406 static void clinitBecauseOfFieldAccess() {
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100407 ClassWithClinit2.staticField = false;
Guillaume "Vermeille" Sancheze918d382015-06-03 15:32:41 +0100408 ClassWithClinit2.$noinline$staticMethod();
Calin Juravle0ba218d2015-05-19 18:46:01 +0100409 }
410
Vladimir Markofbb184a2015-11-13 14:47:00 +0000411 /*
412 * Verify that LoadClass from const-class is not merged with
413 * later invoke-static (or it's ClinitCheck).
414 */
415
416 /// CHECK-START: void Main.constClassAndInvokeStatic(java.lang.Iterable) liveness (before)
417 /// CHECK: LoadClass gen_clinit_check:false
418 /// CHECK: InvokeStaticOrDirect clinit_check:implicit
419
420 /// CHECK-START: void Main.constClassAndInvokeStatic(java.lang.Iterable) liveness (before)
421 /// CHECK-NOT: ClinitCheck
422
Vladimir Markoc7591b42016-06-29 14:59:07 +0100423 static void constClassAndInvokeStatic(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000424 $opt$inline$ignoreClass(ClassWithClinit7.class);
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000425 ClassWithClinit7.$noinline$someStaticMethod(it);
Vladimir Markofbb184a2015-11-13 14:47:00 +0000426 }
427
Vladimir Markoc7591b42016-06-29 14:59:07 +0100428 static void $opt$inline$ignoreClass(Class<?> c) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000429 }
430
431 static class ClassWithClinit7 {
432 static {
433 System.out.println("Main$ClassWithClinit7's static initializer");
434 }
435
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000436 static void $noinline$someStaticMethod(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000437 it.iterator();
438 }
439 }
440
441 /*
442 * Verify that LoadClass from sget is not merged with later invoke-static.
443 */
444
445 /// CHECK-START: void Main.sgetAndInvokeStatic(java.lang.Iterable) liveness (before)
446 /// CHECK: LoadClass gen_clinit_check:true
447 /// CHECK: InvokeStaticOrDirect clinit_check:none
448
449 /// CHECK-START: void Main.sgetAndInvokeStatic(java.lang.Iterable) liveness (before)
450 /// CHECK-NOT: ClinitCheck
451
Vladimir Markoc7591b42016-06-29 14:59:07 +0100452 static void sgetAndInvokeStatic(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000453 $opt$inline$ignoreInt(ClassWithClinit8.value);
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000454 ClassWithClinit8.$noinline$someStaticMethod(it);
Vladimir Markofbb184a2015-11-13 14:47:00 +0000455 }
456
457 static void $opt$inline$ignoreInt(int i) {
458 }
459
460 static class ClassWithClinit8 {
461 public static int value = 0;
462 static {
463 System.out.println("Main$ClassWithClinit8's static initializer");
464 }
465
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000466 static void $noinline$someStaticMethod(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000467 it.iterator();
468 }
469 }
470
471 /*
472 * Verify that LoadClass from const-class, ClinitCheck from sget and
473 * InvokeStaticOrDirect from invoke-static are not merged.
474 */
475
476 /// CHECK-START: void Main.constClassSgetAndInvokeStatic(java.lang.Iterable) liveness (before)
477 /// CHECK: LoadClass gen_clinit_check:false
478 /// CHECK: ClinitCheck
479 /// CHECK: InvokeStaticOrDirect clinit_check:none
480
Vladimir Markoc7591b42016-06-29 14:59:07 +0100481 static void constClassSgetAndInvokeStatic(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000482 $opt$inline$ignoreClass(ClassWithClinit9.class);
483 $opt$inline$ignoreInt(ClassWithClinit9.value);
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000484 ClassWithClinit9.$noinline$someStaticMethod(it);
Vladimir Markofbb184a2015-11-13 14:47:00 +0000485 }
486
487 static class ClassWithClinit9 {
488 public static int value = 0;
489 static {
490 System.out.println("Main$ClassWithClinit9's static initializer");
491 }
492
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000493 static void $noinline$someStaticMethod(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000494 it.iterator();
495 }
496 }
497
498 /*
499 * Verify that LoadClass from a fully-inlined invoke-static is not merged
500 * with InvokeStaticOrDirect from a later invoke-static to the same method.
501 */
502
503 /// CHECK-START: void Main.inlinedInvokeStaticViaNonStatic(java.lang.Iterable) liveness (before)
504 /// CHECK: LoadClass gen_clinit_check:true
505 /// CHECK: InvokeStaticOrDirect clinit_check:none
506
507 /// CHECK-START: void Main.inlinedInvokeStaticViaNonStatic(java.lang.Iterable) liveness (before)
508 /// CHECK-NOT: ClinitCheck
509
Vladimir Markoc7591b42016-06-29 14:59:07 +0100510 static void inlinedInvokeStaticViaNonStatic(Iterable<?> it) {
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000511 if (it != null) {
512 inlinedInvokeStaticViaNonStaticHelper(null);
513 inlinedInvokeStaticViaNonStaticHelper(it);
514 }
Vladimir Markofbb184a2015-11-13 14:47:00 +0000515 }
516
Vladimir Markoc7591b42016-06-29 14:59:07 +0100517 static void inlinedInvokeStaticViaNonStaticHelper(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000518 ClassWithClinit10.inlinedForNull(it);
519 }
520
521 static class ClassWithClinit10 {
522 public static int value = 0;
523 static {
524 System.out.println("Main$ClassWithClinit10's static initializer");
525 }
526
Vladimir Markoc7591b42016-06-29 14:59:07 +0100527 static void inlinedForNull(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000528 if (it != null) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000529 it.iterator();
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000530 // We're not inlining methods that always throw.
531 throw new Error("");
Vladimir Markofbb184a2015-11-13 14:47:00 +0000532 }
533 }
534 }
535
536 /*
537 * Check that the LoadClass from an invoke-static C.foo() doesn't get merged with
538 * an invoke-static inside C.foo(). This would mess up the stack walk in the
539 * resolution trampoline where we would have to load C (if C isn't loaded yet)
540 * which is not permitted there.
541 *
542 * Note: In case of failure, we would get an failed assertion during compilation,
543 * so we wouldn't really get to the checker tests below.
544 */
545
546 /// CHECK-START: void Main.inlinedInvokeStaticViaStatic(java.lang.Iterable) liveness (before)
547 /// CHECK: LoadClass gen_clinit_check:true
548 /// CHECK: InvokeStaticOrDirect clinit_check:none
549
550 /// CHECK-START: void Main.inlinedInvokeStaticViaStatic(java.lang.Iterable) liveness (before)
551 /// CHECK-NOT: ClinitCheck
552
Vladimir Markoc7591b42016-06-29 14:59:07 +0100553 static void inlinedInvokeStaticViaStatic(Iterable<?> it) {
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000554 if (it != null) {
555 ClassWithClinit11.callInlinedForNull(it);
556 }
Vladimir Markofbb184a2015-11-13 14:47:00 +0000557 }
558
559 static class ClassWithClinit11 {
560 public static int value = 0;
561 static {
562 System.out.println("Main$ClassWithClinit11's static initializer");
563 }
564
Vladimir Markoc7591b42016-06-29 14:59:07 +0100565 static void callInlinedForNull(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000566 inlinedForNull(it);
567 }
568
Vladimir Markoc7591b42016-06-29 14:59:07 +0100569 static void inlinedForNull(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000570 it.iterator();
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000571 if (it != null) {
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000572 // We're not inlining methods that always throw.
573 throw new Error("");
Nicolas Geoffray5bf7bac2016-07-06 14:18:23 +0000574 }
Vladimir Markofbb184a2015-11-13 14:47:00 +0000575 }
576 }
577
578 /*
579 * A test similar to inlinedInvokeStaticViaStatic() but doing the indirect invoke
580 * twice with the first one to be fully inlined.
581 */
582
583 /// CHECK-START: void Main.inlinedInvokeStaticViaStaticTwice(java.lang.Iterable) liveness (before)
584 /// CHECK: LoadClass gen_clinit_check:true
585 /// CHECK: InvokeStaticOrDirect clinit_check:none
586
587 /// CHECK-START: void Main.inlinedInvokeStaticViaStaticTwice(java.lang.Iterable) liveness (before)
588 /// CHECK-NOT: ClinitCheck
589
Vladimir Markoc7591b42016-06-29 14:59:07 +0100590 static void inlinedInvokeStaticViaStaticTwice(Iterable<?> it) {
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000591 if (it != null) {
592 ClassWithClinit12.callInlinedForNull(null);
593 ClassWithClinit12.callInlinedForNull(it);
594 }
Vladimir Markofbb184a2015-11-13 14:47:00 +0000595 }
596
597 static class ClassWithClinit12 {
598 public static int value = 0;
599 static {
600 System.out.println("Main$ClassWithClinit12's static initializer");
601 }
602
Vladimir Markoc7591b42016-06-29 14:59:07 +0100603 static void callInlinedForNull(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000604 inlinedForNull(it);
605 }
606
Vladimir Markoc7591b42016-06-29 14:59:07 +0100607 static void inlinedForNull(Iterable<?> it) {
Vladimir Markofbb184a2015-11-13 14:47:00 +0000608 if (it != null) {
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000609 // We're not inlining methods that always throw.
610 throw new Error("");
Vladimir Markofbb184a2015-11-13 14:47:00 +0000611 }
612 }
613 }
614
Vladimir Markoc7591b42016-06-29 14:59:07 +0100615 static class ClassWithClinit13 {
616 static {
617 System.out.println("Main$ClassWithClinit13's static initializer");
618 }
619
620 public static void $inline$forwardToGetIterator(Iterable<?> it) {
621 $noinline$getIterator(it);
622 }
623
624 public static void $noinline$getIterator(Iterable<?> it) {
Vladimir Markoc7591b42016-06-29 14:59:07 +0100625 it.iterator();
626 }
627 }
628
629 // TODO: Write checker statements.
630 static Object $noinline$testInliningAndNewInstance(Iterable<?> it) {
Vladimir Markoc7591b42016-06-29 14:59:07 +0100631 ClassWithClinit13.$inline$forwardToGetIterator(it);
632 return new ClassWithClinit13();
633 }
634
Roland Levillain4c0eb422015-04-24 16:43:49 +0100635 // TODO: Add a test for the case of a static method whose declaring
636 // class type index is not available (i.e. when `storage_index`
Andreas Gampee2abbc62017-09-15 11:59:26 -0700637 // equals `dex::kDexNoIndex` in
Roland Levillain4c0eb422015-04-24 16:43:49 +0100638 // art::HGraphBuilder::BuildInvoke).
639
640 public static void main(String[] args) {
641 invokeStaticInlined();
642 invokeStaticNotInlined();
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100643 ClassWithClinit3Static.invokeStaticInlined();
644 new ClassWithClinit3Instance().invokeStaticInlined();
645 ClassWithClinit4Static.invokeStaticNotInlined();
646 new ClassWithClinit4Instance().invokeStaticNotInlined();
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100647 SubClassOfClassWithClinit5.invokeStaticInlined();
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100648 SubClassOfClassWithoutClinit5.invokeStaticInlined();
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100649 SubClassOfClassWithClinit6.invokeStaticNotInlined();
Vladimir Marko2ab1bdd2018-07-12 09:59:56 +0100650 SubClassOfClassWithoutClinit6.invokeStaticNotInlined();
Vladimir Markofbb184a2015-11-13 14:47:00 +0000651 Iterable it = new Iterable() { public java.util.Iterator iterator() { return null; } };
652 constClassAndInvokeStatic(it);
653 sgetAndInvokeStatic(it);
654 constClassSgetAndInvokeStatic(it);
Nicolas Geoffrayfdb7d632017-02-08 15:07:18 +0000655 try {
656 inlinedInvokeStaticViaNonStatic(it);
657 } catch (Error e) {
658 // Expected
659 }
660 try {
661 inlinedInvokeStaticViaStatic(it);
662 } catch (Error e) {
663 // Expected
664 }
665 try{
666 inlinedInvokeStaticViaStaticTwice(it);
667 } catch (Error e) {
668 // Expected
669 }
Vladimir Markoc7591b42016-06-29 14:59:07 +0100670 $noinline$testInliningAndNewInstance(it);
Roland Levillain4c0eb422015-04-24 16:43:49 +0100671 }
672}