blob: 61199a719b6a2b372d3fd1b7ed6998e7ccc830fd [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
26 // CHECK-START: void Main.invokeStaticInlined() builder (after)
David Brazdilc2c48ff2015-05-15 14:24:31 +010027 // CHECK-DAG: <<LoadClass:l\d+>> LoadClass
David Brazdilc57397b2015-05-15 16:01:59 +010028 // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
29 // CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>]
Roland Levillain4c0eb422015-04-24 16:43:49 +010030
31 // CHECK-START: void Main.invokeStaticInlined() inliner (after)
David Brazdilc2c48ff2015-05-15 14:24:31 +010032 // CHECK-DAG: <<LoadClass:l\d+>> LoadClass
David Brazdilc57397b2015-05-15 16:01:59 +010033 // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
Roland Levillain4c0eb422015-04-24 16:43:49 +010034
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)
David Brazdilc2c48ff2015-05-15 14:24:31 +010070 // CHECK-DAG: <<LoadClass:l\d+>> LoadClass
David Brazdilc57397b2015-05-15 16:01:59 +010071 // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
72 // CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>]
Roland Levillain4c0eb422015-04-24 16:43:49 +010073
74 // CHECK-START: void Main.invokeStaticNotInlined() inliner (after)
David Brazdilc2c48ff2015-05-15 14:24:31 +010075 // CHECK-DAG: <<LoadClass:l\d+>> LoadClass
David Brazdilc57397b2015-05-15 16:01:59 +010076 // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
77 // CHECK-DAG: InvokeStaticOrDirect [<<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
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
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
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
Roland Levillain4c0eb422015-04-24 16:43:49 +0100263 // 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();
Roland Levillain5f02c6c2015-04-24 19:14:22 +0100273 SubClassOfClassWithClinit5.invokeStaticInlined();
274 SubClassOfClassWithClinit6.invokeStaticNotInlined();
Roland Levillain4c0eb422015-04-24 16:43:49 +0100275 }
276}