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 
17 public class Main {
18 
assertIntEquals(int expected, int result)19   public static void assertIntEquals(int expected, int result) {
20     if (expected != result) {
21       throw new Error("Expected: " + expected + ", found: " + result);
22     }
23   }
24 
assertStringEquals(String expected, String result)25   public static void assertStringEquals(String expected, String result) {
26     if (expected != null ? !expected.equals(result) : result != null) {
27       throw new Error("Expected: " + expected + ", found: " + result);
28     }
29   }
30 
assertClassEquals(Class<?> expected, Class<?> result)31   public static void assertClassEquals(Class<?> expected, Class<?> result) {
32     if (expected != result) {
33       throw new Error("Expected: " + expected + ", found: " + result);
34     }
35   }
36 
37   public static boolean doThrow = false;
38 
$noinline$foo(int x)39   private static int $noinline$foo(int x) {
40     if (doThrow) { throw new Error(); }
41     return x;
42   }
43 
44   /// CHECK-START: int Main.testSimple(int) sharpening (before)
45   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_via_method
46 
47   /// CHECK-START-ARM: int Main.testSimple(int) sharpening (after)
48   /// CHECK-NOT:            ArmDexCacheArraysBase
49   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
50 
51   /// CHECK-START-ARM64: int Main.testSimple(int) sharpening (after)
52   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
53 
54   /// CHECK-START-MIPS: int Main.testSimple(int) sharpening (after)
55   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
56 
57   /// CHECK-START-MIPS64: int Main.testSimple(int) sharpening (after)
58   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
59 
60   /// CHECK-START-X86: int Main.testSimple(int) sharpening (after)
61   /// CHECK-NOT:            X86ComputeBaseMethodAddress
62   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
63 
64   /// CHECK-START-X86_64: int Main.testSimple(int) sharpening (after)
65   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
66 
67   /// CHECK-START-ARM: int Main.testSimple(int) dex_cache_array_fixups_arm (after)
68   /// CHECK:                ArmDexCacheArraysBase
69   /// CHECK-NOT:            ArmDexCacheArraysBase
70 
71   /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (after)
72   /// CHECK:                X86ComputeBaseMethodAddress
73   /// CHECK-NOT:            X86ComputeBaseMethodAddress
74 
testSimple(int x)75   public static int testSimple(int x) {
76     // This call should use PC-relative dex cache array load to retrieve the target method.
77     return $noinline$foo(x);
78   }
79 
80   /// CHECK-START: int Main.testDiamond(boolean, int) sharpening (before)
81   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_via_method
82 
83   /// CHECK-START-ARM: int Main.testDiamond(boolean, int) sharpening (after)
84   /// CHECK-NOT:            ArmDexCacheArraysBase
85   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
86   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
87 
88   /// CHECK-START-ARM64: int Main.testDiamond(boolean, int) sharpening (after)
89   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
90   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
91 
92   /// CHECK-START-MIPS: int Main.testDiamond(boolean, int) sharpening (after)
93   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
94   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
95 
96   /// CHECK-START-MIPS64: int Main.testDiamond(boolean, int) sharpening (after)
97   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
98   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
99 
100   /// CHECK-START-X86: int Main.testDiamond(boolean, int) sharpening (after)
101   /// CHECK-NOT:            X86ComputeBaseMethodAddress
102   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
103   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
104 
105   /// CHECK-START-X86_64: int Main.testDiamond(boolean, int) sharpening (after)
106   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
107   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
108 
109   /// CHECK-START-ARM: int Main.testDiamond(boolean, int) dex_cache_array_fixups_arm (after)
110   /// CHECK:                ArmDexCacheArraysBase
111   /// CHECK-NOT:            ArmDexCacheArraysBase
112 
113   /// CHECK-START-ARM: int Main.testDiamond(boolean, int) dex_cache_array_fixups_arm (after)
114   /// CHECK:                ArmDexCacheArraysBase
115   /// CHECK-NEXT:           If
116 
117   /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after)
118   /// CHECK:                X86ComputeBaseMethodAddress
119   /// CHECK-NOT:            X86ComputeBaseMethodAddress
120 
121   /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after)
122   /// CHECK:                X86ComputeBaseMethodAddress
123   /// CHECK-NEXT:           If
124 
testDiamond(boolean negate, int x)125   public static int testDiamond(boolean negate, int x) {
126     // These calls should use PC-relative dex cache array loads to retrieve the target method.
127     // PC-relative bases used by ARM, MIPS and X86 should be pulled before the If.
128     if (negate) {
129       return $noinline$foo(-x);
130     } else {
131       return $noinline$foo(x);
132     }
133   }
134 
135   /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (before)
136   /// CHECK-NOT:            X86ComputeBaseMethodAddress
137 
138   /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after)
139   /// CHECK:                X86ComputeBaseMethodAddress
140   /// CHECK-NOT:            X86ComputeBaseMethodAddress
141 
142   /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after)
143   /// CHECK:                InvokeStaticOrDirect
144   /// CHECK-NOT:            InvokeStaticOrDirect
145 
146   /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after)
147   /// CHECK:                ArrayLength
148   /// CHECK-NEXT:           X86ComputeBaseMethodAddress
149   /// CHECK-NEXT:           Goto
150   /// CHECK:                begin_block
151   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
152 
153   /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (before)
154   /// CHECK-NOT:            ArmDexCacheArraysBase
155 
156   /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (after)
157   /// CHECK:                ArmDexCacheArraysBase
158   /// CHECK-NOT:            ArmDexCacheArraysBase
159 
160   /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (after)
161   /// CHECK:                InvokeStaticOrDirect
162   /// CHECK-NOT:            InvokeStaticOrDirect
163 
164   /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (after)
165   /// CHECK:                ArrayLength
166   /// CHECK-NEXT:           ArmDexCacheArraysBase
167   /// CHECK-NEXT:           Goto
168   /// CHECK:                begin_block
169   /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
170 
testLoop(int[] array, int x)171   public static int testLoop(int[] array, int x) {
172     // PC-relative bases used by ARM, MIPS and X86 should be pulled before the loop.
173     for (int i : array) {
174       x += $noinline$foo(i);
175     }
176     return x;
177   }
178 
179   /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (before)
180   /// CHECK-NOT:            X86ComputeBaseMethodAddress
181 
182   /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (after)
183   /// CHECK:                If
184   /// CHECK:                begin_block
185   /// CHECK:                ArrayLength
186   /// CHECK-NEXT:           X86ComputeBaseMethodAddress
187   /// CHECK-NEXT:           Goto
188 
189   /// CHECK-START-ARM: int Main.testLoopWithDiamond(int[], boolean, int) dex_cache_array_fixups_arm (before)
190   /// CHECK-NOT:            ArmDexCacheArraysBase
191 
192   /// CHECK-START-ARM: int Main.testLoopWithDiamond(int[], boolean, int) dex_cache_array_fixups_arm (after)
193   /// CHECK:                If
194   /// CHECK:                begin_block
195   /// CHECK:                ArrayLength
196   /// CHECK-NEXT:           ArmDexCacheArraysBase
197   /// CHECK-NEXT:           Goto
198 
testLoopWithDiamond(int[] array, boolean negate, int x)199   public static int testLoopWithDiamond(int[] array, boolean negate, int x) {
200     // PC-relative bases used by ARM, MIPS and X86 should be pulled before the loop
201     // but not outside the if.
202     if (array != null) {
203       for (int i : array) {
204         if (negate) {
205           x += $noinline$foo(-i);
206         } else {
207           x += $noinline$foo(i);
208         }
209       }
210     }
211     return x;
212   }
213 
214   /// CHECK-START: java.lang.String Main.$noinline$getBootImageString() sharpening (before)
215   /// CHECK:                LoadString load_kind:DexCacheViaMethod
216 
217   /// CHECK-START-X86: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
218   // Note: load kind depends on PIC/non-PIC
219   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
220   /// CHECK:                LoadString load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}}
221 
222   /// CHECK-START-X86_64: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
223   // Note: load kind depends on PIC/non-PIC
224   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
225   /// CHECK:                LoadString load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}}
226 
227   /// CHECK-START-ARM: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
228   // Note: load kind depends on PIC/non-PIC
229   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
230   /// CHECK:                LoadString load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}}
231 
232   /// CHECK-START-ARM64: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
233   // Note: load kind depends on PIC/non-PIC
234   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
235   /// CHECK:                LoadString load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}}
236 
237   /// CHECK-START-MIPS: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
238   // Note: load kind depends on PIC/non-PIC
239   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
240   /// CHECK:                LoadString load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}}
241 
242   /// CHECK-START-MIPS64: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
243   // Note: load kind depends on PIC/non-PIC
244   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
245   /// CHECK:                LoadString load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}}
246 
$noinline$getBootImageString()247   public static String $noinline$getBootImageString() {
248     // Prevent inlining to avoid the string comparison being optimized away.
249     if (doThrow) { throw new Error(); }
250     // Empty string is known to be in the boot image.
251     return "";
252   }
253 
254   /// CHECK-START: java.lang.String Main.$noinline$getNonBootImageString() sharpening (before)
255   /// CHECK:                LoadString load_kind:DexCacheViaMethod
256 
257   /// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
258   /// CHECK:                LoadString load_kind:BssEntry
259 
260   /// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() pc_relative_fixups_x86 (after)
261   /// CHECK-DAG:            X86ComputeBaseMethodAddress
262   /// CHECK-DAG:            LoadString load_kind:BssEntry
263 
264   /// CHECK-START-X86_64: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
265   /// CHECK:                LoadString load_kind:BssEntry
266 
267   /// CHECK-START-ARM: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
268   /// CHECK:                LoadString load_kind:BssEntry
269 
270   /// CHECK-START-ARM64: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
271   /// CHECK:                LoadString load_kind:BssEntry
272 
273   /// CHECK-START-MIPS: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
274   /// CHECK:                LoadString load_kind:BssEntry
275 
276   /// CHECK-START-MIPS64: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
277   /// CHECK:                LoadString load_kind:BssEntry
278 
$noinline$getNonBootImageString()279   public static String $noinline$getNonBootImageString() {
280     // Prevent inlining to avoid the string comparison being optimized away.
281     if (doThrow) { throw new Error(); }
282     // This string is not in the boot image.
283     return "non-boot-image-string";
284   }
285 
286   /// CHECK-START-X86: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
287   // Note: load kind depends on PIC/non-PIC
288   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
289   /// CHECK:                LoadClass load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}} class_name:java.lang.String
290 
291   /// CHECK-START-X86_64: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
292   // Note: load kind depends on PIC/non-PIC
293   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
294   /// CHECK:                LoadClass load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}} class_name:java.lang.String
295 
296   /// CHECK-START-ARM: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
297   // Note: load kind depends on PIC/non-PIC
298   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
299   /// CHECK:                LoadClass load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}} class_name:java.lang.String
300 
301   /// CHECK-START-ARM64: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
302   // Note: load kind depends on PIC/non-PIC
303   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
304   /// CHECK:                LoadClass load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}} class_name:java.lang.String
305 
306   /// CHECK-START-MIPS: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
307   // Note: load kind depends on PIC/non-PIC
308   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
309   /// CHECK:                LoadClass load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}} class_name:java.lang.String
310 
311   /// CHECK-START-MIPS64: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
312   // Note: load kind depends on PIC/non-PIC
313   // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
314   /// CHECK:                LoadClass load_kind:{{BootImageAddress|BssEntry|DexCacheViaMethod}} class_name:java.lang.String
315 
$noinline$getStringClass()316   public static Class<?> $noinline$getStringClass() {
317     // Prevent inlining to avoid the string comparison being optimized away.
318     if (doThrow) { throw new Error(); }
319     // String class is known to be in the boot image.
320     return String.class;
321   }
322 
323   /// CHECK-START-X86: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
324   /// CHECK:                LoadClass load_kind:BssEntry class_name:Other
325 
326   /// CHECK-START-X86: java.lang.Class Main.$noinline$getOtherClass() pc_relative_fixups_x86 (after)
327   /// CHECK-DAG:            X86ComputeBaseMethodAddress
328   /// CHECK-DAG:            LoadClass load_kind:BssEntry class_name:Other
329 
330   /// CHECK-START-X86_64: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
331   /// CHECK:                LoadClass load_kind:BssEntry class_name:Other
332 
333   /// CHECK-START-ARM: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
334   /// CHECK:                LoadClass load_kind:BssEntry class_name:Other
335 
336   /// CHECK-START-ARM64: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
337   /// CHECK:                LoadClass load_kind:BssEntry class_name:Other
338 
339   /// CHECK-START-MIPS: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
340   /// CHECK:                LoadClass load_kind:BssEntry class_name:Other
341 
342   /// CHECK-START-MIPS64: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
343   /// CHECK:                LoadClass load_kind:BssEntry class_name:Other
344 
$noinline$getOtherClass()345   public static Class<?> $noinline$getOtherClass() {
346     // Prevent inlining to avoid the string comparison being optimized away.
347     if (doThrow) { throw new Error(); }
348     // Other class is not in the boot image.
349     return Other.class;
350   }
351 
main(String[] args)352   public static void main(String[] args) {
353     assertIntEquals(1, testSimple(1));
354     assertIntEquals(1, testDiamond(false, 1));
355     assertIntEquals(-1, testDiamond(true, 1));
356     assertIntEquals(3, testLoop(new int[]{ 2 }, 1));
357     assertIntEquals(8, testLoop(new int[]{ 3, 4 }, 1));
358     assertIntEquals(1, testLoopWithDiamond(null, false, 1));
359     assertIntEquals(3, testLoopWithDiamond(new int[]{ 2 }, false, 1));
360     assertIntEquals(-6, testLoopWithDiamond(new int[]{ 3, 4 }, true, 1));
361     assertStringEquals("", $noinline$getBootImageString());
362     assertStringEquals("non-boot-image-string", $noinline$getNonBootImageString());
363     assertClassEquals(String.class, $noinline$getStringClass());
364     assertClassEquals(Other.class, $noinline$getOtherClass());
365   }
366 }
367 
368 class Other {
369 }
370