blob: c23d9d37162f183e0a966924e6905430f7a78b2d [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 Geoffray38207af2015-06-01 15:46:22 +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)
70 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
71 /// CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
Nicolas Geoffray38207af2015-06-01 15:46:22 +010072 /// CHECK-DAG: 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)
75 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
76 /// CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
Nicolas Geoffray38207af2015-06-01 15:46:22 +010077 /// CHECK-DAG: 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)
86 /// CHECK-DAG: InvokeStaticOrDirect
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() {
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
David Brazdila06d66a2015-05-28 11:14:54 +0100117 /// CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() builder (after)
118 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain4c0eb422015-04-24 16:43:49 +0100119
David Brazdila06d66a2015-05-28 11:14:54 +0100120 /// CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() builder (after)
121 /// CHECK-NOT: LoadClass
122 /// CHECK-NOT: ClinitCheck
Roland Levillain4c0eb422015-04-24 16:43:49 +0100123
David Brazdila06d66a2015-05-28 11:14:54 +0100124 /// CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() inliner (after)
125 /// CHECK-NOT: LoadClass
126 /// CHECK-NOT: ClinitCheck
127 /// CHECK-NOT: InvokeStaticOrDirect
Roland Levillain4c0eb422015-04-24 16:43:49 +0100128
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
David Brazdila06d66a2015-05-28 11:14:54 +0100152 /// CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() builder (after)
153 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain4c0eb422015-04-24 16:43:49 +0100154
David Brazdila06d66a2015-05-28 11:14:54 +0100155 /// CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() builder (after)
156 /// CHECK-NOT: LoadClass
157 /// CHECK-NOT: ClinitCheck
Roland Levillain4c0eb422015-04-24 16:43:49 +0100158
David Brazdila06d66a2015-05-28 11:14:54 +0100159 /// CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() inliner (after)
160 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain4c0eb422015-04-24 16:43:49 +0100161
David Brazdila06d66a2015-05-28 11:14:54 +0100162 /// CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() inliner (after)
163 /// CHECK-NOT: LoadClass
164 /// CHECK-NOT: ClinitCheck
Roland Levillain4c0eb422015-04-24 16:43:49 +0100165
166 static class ClassWithClinit4 {
167 static void invokeStaticNotInlined() {
168 // The invocation of invokeStaticNotInlined triggers the
169 // initialization of ClassWithClinit4, meaning that the
Nicolas Geoffrayd23eeef2015-05-18 22:31:29 +0100170 // call to staticMethod below does not need a clinit
Roland Levillain4c0eb422015-04-24 16:43:49 +0100171 // 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
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100189 /*
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
David Brazdila06d66a2015-05-28 11:14:54 +0100195 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after)
196 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100197
David Brazdila06d66a2015-05-28 11:14:54 +0100198 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after)
199 /// CHECK-NOT: LoadClass
200 /// CHECK-NOT: ClinitCheck
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100201
David Brazdila06d66a2015-05-28 11:14:54 +0100202 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() inliner (after)
203 /// CHECK-NOT: LoadClass
204 /// CHECK-NOT: ClinitCheck
205 /// CHECK-NOT: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100206
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
David Brazdila06d66a2015-05-28 11:14:54 +0100228 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after)
229 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100230
David Brazdila06d66a2015-05-28 11:14:54 +0100231 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after)
232 /// CHECK-NOT: LoadClass
233 /// CHECK-NOT: ClinitCheck
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100234
David Brazdila06d66a2015-05-28 11:14:54 +0100235 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after)
236 /// CHECK-DAG: InvokeStaticOrDirect
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100237
David Brazdila06d66a2015-05-28 11:14:54 +0100238 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after)
239 /// CHECK-NOT: LoadClass
240 /// CHECK-NOT: ClinitCheck
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100241
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
Calin Juravle0ba218d2015-05-19 18:46:01 +0100263
264 /*
265 * Verify that if we have a static call immediately after the load class
266 * we don't do generate a clinit check.
267 */
268
David Brazdila06d66a2015-05-28 11:14:54 +0100269 /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before)
270 /// CHECK-DAG: <<IntConstant:i\d+>> IntConstant 0
271 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
272 /// CHECK-DAG: InvokeStaticOrDirect
273 /// CHECK-DAG: StaticFieldSet [<<LoadClass>>,<<IntConstant>>]
Calin Juravle0ba218d2015-05-19 18:46:01 +0100274
David Brazdila06d66a2015-05-28 11:14:54 +0100275 /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before)
276 /// CHECK-NOT: ClinitCheck
Calin Juravle0ba218d2015-05-19 18:46:01 +0100277
278 static void noClinitBecauseOfInvokeStatic() {
279 ClassWithClinit2.staticMethod();
280 ClassWithClinit2.doThrow = false;
281 }
282
283 /*
284 * Verify that if the static call is after a field access, the load class
285 * will generate a clinit check.
286 */
287
David Brazdila06d66a2015-05-28 11:14:54 +0100288 /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before)
289 /// CHECK-DAG: <<IntConstant:i\d+>> IntConstant 0
290 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:true
291 /// CHECK-DAG: StaticFieldSet [<<LoadClass>>,<<IntConstant>>]
292 /// CHECK-DAG: InvokeStaticOrDirect
Calin Juravle0ba218d2015-05-19 18:46:01 +0100293
David Brazdila06d66a2015-05-28 11:14:54 +0100294 /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before)
295 /// CHECK-NOT: ClinitCheck
Calin Juravle0ba218d2015-05-19 18:46:01 +0100296 static void clinitBecauseOfFieldAccess() {
297 ClassWithClinit2.doThrow = false;
298 ClassWithClinit2.staticMethod();
299 }
300
Roland Levillain4c0eb422015-04-24 16:43:49 +0100301 // TODO: Add a test for the case of a static method whose declaring
302 // class type index is not available (i.e. when `storage_index`
303 // equals `DexFile::kDexNoIndex` in
304 // art::HGraphBuilder::BuildInvoke).
305
306 public static void main(String[] args) {
307 invokeStaticInlined();
308 invokeStaticNotInlined();
309 ClassWithClinit3.invokeStaticInlined();
310 ClassWithClinit4.invokeStaticNotInlined();
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100311 SubClassOfClassWithClinit5.invokeStaticInlined();
312 SubClassOfClassWithClinit6.invokeStaticNotInlined();
Roland Levillain4c0eb422015-04-24 16:43:49 +0100313 }
314}