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  public static void assertIntEquals(int expected, int result) {
20    if (expected != result) {
21      throw new Error("Expected: " + expected + ", found: " + result);
22    }
23  }
24
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
31  public static boolean doThrow = false;
32
33  private static int $noinline$foo(int x) {
34    if (doThrow) { throw new Error(); }
35    return x;
36  }
37
38  /// CHECK-START: int Main.testSimple(int) sharpening (before)
39  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_via_method
40
41  /// CHECK-START-ARM: int Main.testSimple(int) sharpening (after)
42  /// CHECK-NOT:            ArmDexCacheArraysBase
43  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
44
45  /// CHECK-START-ARM64: int Main.testSimple(int) sharpening (after)
46  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
47
48  /// CHECK-START-X86: int Main.testSimple(int) sharpening (after)
49  /// CHECK-NOT:            X86ComputeBaseMethodAddress
50  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
51
52  /// CHECK-START-X86_64: int Main.testSimple(int) sharpening (after)
53  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
54
55  /// CHECK-START-ARM: int Main.testSimple(int) dex_cache_array_fixups_arm (after)
56  /// CHECK:                ArmDexCacheArraysBase
57  /// CHECK-NOT:            ArmDexCacheArraysBase
58
59  /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (after)
60  /// CHECK:                X86ComputeBaseMethodAddress
61  /// CHECK-NOT:            X86ComputeBaseMethodAddress
62
63  public static int testSimple(int x) {
64    // This call should use PC-relative dex cache array load to retrieve the target method.
65    return $noinline$foo(x);
66  }
67
68  /// CHECK-START: int Main.testDiamond(boolean, int) sharpening (before)
69  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_via_method
70
71  /// CHECK-START-ARM: int Main.testDiamond(boolean, int) sharpening (after)
72  /// CHECK-NOT:            ArmDexCacheArraysBase
73  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
74  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
75
76  /// CHECK-START-ARM64: int Main.testDiamond(boolean, int) sharpening (after)
77  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
78  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
79
80  /// CHECK-START-X86: int Main.testDiamond(boolean, int) sharpening (after)
81  /// CHECK-NOT:            X86ComputeBaseMethodAddress
82  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
83  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
84
85  /// CHECK-START-X86_64: int Main.testDiamond(boolean, int) sharpening (after)
86  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
87  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
88
89  /// CHECK-START-ARM: int Main.testDiamond(boolean, int) dex_cache_array_fixups_arm (after)
90  /// CHECK:                ArmDexCacheArraysBase
91  /// CHECK-NOT:            ArmDexCacheArraysBase
92
93  /// CHECK-START-ARM: int Main.testDiamond(boolean, int) dex_cache_array_fixups_arm (after)
94  /// CHECK:                ArmDexCacheArraysBase
95  /// CHECK-NEXT:           If
96
97  /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after)
98  /// CHECK:                X86ComputeBaseMethodAddress
99  /// CHECK-NOT:            X86ComputeBaseMethodAddress
100
101  /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after)
102  /// CHECK:                X86ComputeBaseMethodAddress
103  /// CHECK-NEXT:           If
104
105  public static int testDiamond(boolean negate, int x) {
106    // These calls should use PC-relative dex cache array loads to retrieve the target method.
107    // PC-relative bases used by X86 and ARM should be pulled before the If.
108    if (negate) {
109      return $noinline$foo(-x);
110    } else {
111      return $noinline$foo(x);
112    }
113  }
114
115  /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (before)
116  /// CHECK-NOT:            X86ComputeBaseMethodAddress
117
118  /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after)
119  /// CHECK:                X86ComputeBaseMethodAddress
120  /// CHECK-NOT:            X86ComputeBaseMethodAddress
121
122  /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after)
123  /// CHECK:                InvokeStaticOrDirect
124  /// CHECK-NOT:            InvokeStaticOrDirect
125
126  /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after)
127  /// CHECK:                ArrayLength
128  /// CHECK-NEXT:           X86ComputeBaseMethodAddress
129  /// CHECK-NEXT:           Goto
130  /// CHECK:                begin_block
131  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
132
133  /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (before)
134  /// CHECK-NOT:            ArmDexCacheArraysBase
135
136  /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (after)
137  /// CHECK:                ArmDexCacheArraysBase
138  /// CHECK-NOT:            ArmDexCacheArraysBase
139
140  /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (after)
141  /// CHECK:                InvokeStaticOrDirect
142  /// CHECK-NOT:            InvokeStaticOrDirect
143
144  /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (after)
145  /// CHECK:                ArrayLength
146  /// CHECK-NEXT:           ArmDexCacheArraysBase
147  /// CHECK-NEXT:           Goto
148  /// CHECK:                begin_block
149  /// CHECK:                InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative
150
151  public static int testLoop(int[] array, int x) {
152    // PC-relative bases used by X86 and ARM should be pulled before the loop.
153    for (int i : array) {
154      x += $noinline$foo(i);
155    }
156    return x;
157  }
158
159  /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (before)
160  /// CHECK-NOT:            X86ComputeBaseMethodAddress
161
162  /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (after)
163  /// CHECK:                If
164  /// CHECK:                begin_block
165  /// CHECK:                ArrayLength
166  /// CHECK-NEXT:           X86ComputeBaseMethodAddress
167  /// CHECK-NEXT:           Goto
168
169  /// CHECK-START-ARM: int Main.testLoopWithDiamond(int[], boolean, int) dex_cache_array_fixups_arm (before)
170  /// CHECK-NOT:            ArmDexCacheArraysBase
171
172  /// CHECK-START-ARM: int Main.testLoopWithDiamond(int[], boolean, int) dex_cache_array_fixups_arm (after)
173  /// CHECK:                If
174  /// CHECK:                begin_block
175  /// CHECK:                ArrayLength
176  /// CHECK-NEXT:           ArmDexCacheArraysBase
177  /// CHECK-NEXT:           Goto
178
179  public static int testLoopWithDiamond(int[] array, boolean negate, int x) {
180    // PC-relative bases used by X86 and ARM should be pulled before the loop
181    // but not outside the if.
182    if (array != null) {
183      for (int i : array) {
184        if (negate) {
185          x += $noinline$foo(-i);
186        } else {
187          x += $noinline$foo(i);
188        }
189      }
190    }
191    return x;
192  }
193
194  /// CHECK-START: java.lang.String Main.$noinline$getBootImageString() sharpening (before)
195  /// CHECK:                LoadString load_kind:DexCacheViaMethod
196
197  /// CHECK-START-X86: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
198  // Note: load kind depends on PIC/non-PIC
199  // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
200  /// CHECK:                LoadString load_kind:{{BootImageAddress|DexCachePcRelative|DexCacheViaMethod}}
201
202  /// CHECK-START-X86_64: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
203  // Note: load kind depends on PIC/non-PIC
204  // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
205  /// CHECK:                LoadString load_kind:{{BootImageAddress|DexCachePcRelative|DexCacheViaMethod}}
206
207  /// CHECK-START-ARM: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
208  // Note: load kind depends on PIC/non-PIC
209  // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
210  /// CHECK:                LoadString load_kind:{{BootImageAddress|DexCachePcRelative|DexCacheViaMethod}}
211
212  /// CHECK-START-ARM64: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
213  // Note: load kind depends on PIC/non-PIC
214  // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress.
215  /// CHECK:                LoadString load_kind:{{BootImageAddress|DexCachePcRelative|DexCacheViaMethod}}
216
217  public static String $noinline$getBootImageString() {
218    // Prevent inlining to avoid the string comparison being optimized away.
219    if (doThrow) { throw new Error(); }
220    // Empty string is known to be in the boot image.
221    return "";
222  }
223
224  /// CHECK-START: java.lang.String Main.$noinline$getNonBootImageString() sharpening (before)
225  /// CHECK:                LoadString load_kind:DexCacheViaMethod
226
227  /// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
228  /// CHECK:                LoadString load_kind:DexCachePcRelative
229
230  /// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() pc_relative_fixups_x86 (after)
231  /// CHECK-DAG:            X86ComputeBaseMethodAddress
232  /// CHECK-DAG:            LoadString load_kind:DexCachePcRelative
233
234  /// CHECK-START-X86_64: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
235  /// CHECK:                LoadString load_kind:DexCachePcRelative
236
237  /// CHECK-START-ARM: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
238  /// CHECK:                LoadString load_kind:DexCachePcRelative
239
240  /// CHECK-START-ARM: java.lang.String Main.$noinline$getNonBootImageString() dex_cache_array_fixups_arm (after)
241  /// CHECK-DAG:            ArmDexCacheArraysBase
242  /// CHECK-DAG:            LoadString load_kind:DexCachePcRelative
243
244  /// CHECK-START-ARM64: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
245  /// CHECK:                LoadString load_kind:DexCachePcRelative
246
247  public static String $noinline$getNonBootImageString() {
248    // Prevent inlining to avoid the string comparison being optimized away.
249    if (doThrow) { throw new Error(); }
250    // This string is not in the boot image.
251    return "non-boot-image-string";
252  }
253
254  public static void main(String[] args) {
255    assertIntEquals(1, testSimple(1));
256    assertIntEquals(1, testDiamond(false, 1));
257    assertIntEquals(-1, testDiamond(true, 1));
258    assertIntEquals(3, testLoop(new int[]{ 2 }, 1));
259    assertIntEquals(8, testLoop(new int[]{ 3, 4 }, 1));
260    assertIntEquals(1, testLoopWithDiamond(null, false, 1));
261    assertIntEquals(3, testLoopWithDiamond(new int[]{ 2 }, false, 1));
262    assertIntEquals(-6, testLoopWithDiamond(new int[]{ 3, 4 }, true, 1));
263    assertStringEquals("", $noinline$getBootImageString());
264    assertStringEquals("non-boot-image-string", $noinline$getNonBootImageString());
265  }
266}
267