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