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-{ARM,ARM64,X86,X86_64}: int Main.testSimple(int) builder (after)
45   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
46 
47   /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (before)
48   /// CHECK-NOT:            X86ComputeBaseMethodAddress
49 
50   /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (after)
51   /// CHECK:                X86ComputeBaseMethodAddress
52   /// CHECK-NOT:            X86ComputeBaseMethodAddress
53 
testSimple(int x)54   public static int testSimple(int x) {
55     // This call should use PC-relative .bss array load to retrieve the target method.
56     return $noinline$foo(x);
57   }
58 
59   /// CHECK-START-{ARM,ARM64,X86,X86_64}: int Main.testDiamond(boolean, int) builder (after)
60   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
61   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
62 
63   /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (before)
64   /// CHECK-NOT:            X86ComputeBaseMethodAddress
65 
66   /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after)
67   /// CHECK:                X86ComputeBaseMethodAddress
68   /// CHECK-NOT:            X86ComputeBaseMethodAddress
69 
70   /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after)
71   /// CHECK:                X86ComputeBaseMethodAddress
72   /// CHECK-NEXT:           If
73 
testDiamond(boolean negate, int x)74   public static int testDiamond(boolean negate, int x) {
75     // These calls should use PC-relative loads to retrieve the target method.
76     // PC-relative bases used by X86 should be pulled before the If.
77     if (negate) {
78       return $noinline$foo(-x);
79     } else {
80       return $noinline$foo(x);
81     }
82   }
83 
84   /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (before)
85   /// CHECK-NOT:            X86ComputeBaseMethodAddress
86 
87   /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after)
88   /// CHECK:                X86ComputeBaseMethodAddress
89   /// CHECK-NOT:            X86ComputeBaseMethodAddress
90 
91   /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after)
92   /// CHECK:                InvokeStaticOrDirect
93   /// CHECK-NOT:            InvokeStaticOrDirect
94 
95   /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after)
96   /// CHECK:                ArrayLength
97   /// CHECK-NEXT:           X86ComputeBaseMethodAddress
98   /// CHECK-NEXT:           Goto
99   /// CHECK:                begin_block
100   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
101 
testLoop(int[] array, int x)102   public static int testLoop(int[] array, int x) {
103     // PC-relative bases used by X86 should be pulled before the loop.
104     for (int i : array) {
105       x += $noinline$foo(i);
106     }
107     return x;
108   }
109 
110   /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (before)
111   /// CHECK-NOT:            X86ComputeBaseMethodAddress
112 
113   /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (after)
114   /// CHECK:                If
115   /// CHECK:                begin_block
116   /// CHECK:                ArrayLength
117   /// CHECK-NEXT:           X86ComputeBaseMethodAddress
118   /// CHECK-NEXT:           Goto
119 
testLoopWithDiamond(int[] array, boolean negate, int x)120   public static int testLoopWithDiamond(int[] array, boolean negate, int x) {
121     // PC-relative bases used by X86 should be pulled before the loop but not outside the if.
122     if (array != null) {
123       for (int i : array) {
124         if (negate) {
125           x += $noinline$foo(-i);
126         } else {
127           x += $noinline$foo(i);
128         }
129       }
130     }
131     return x;
132   }
133 
134   /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.String Main.$noinline$getBootImageString() builder (after)
135   /// CHECK:                LoadString load_kind:BootImageRelRo
136 
$noinline$getBootImageString()137   public static String $noinline$getBootImageString() {
138     // Prevent inlining to avoid the string comparison being optimized away.
139     if (doThrow) { throw new Error(); }
140     // Empty string is known to be in the boot image.
141     return "";
142   }
143 
144   /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.String Main.$noinline$getNonBootImageString() builder (after)
145   /// CHECK:                LoadString load_kind:BssEntry
146 
147   /// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() pc_relative_fixups_x86 (before)
148   /// CHECK-NOT:            X86ComputeBaseMethodAddress
149 
150   /// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() pc_relative_fixups_x86 (after)
151   /// CHECK-DAG:            X86ComputeBaseMethodAddress
152   /// CHECK-DAG:            LoadString load_kind:BssEntry
153 
$noinline$getNonBootImageString()154   public static String $noinline$getNonBootImageString() {
155     // Prevent inlining to avoid the string comparison being optimized away.
156     if (doThrow) { throw new Error(); }
157     // This string is not in the boot image.
158     return "non-boot-image-string";
159   }
160 
161   /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.Class Main.$noinline$getStringClass() builder (after)
162   /// CHECK:                LoadClass load_kind:BootImageRelRo class_name:java.lang.String
163 
$noinline$getStringClass()164   public static Class<?> $noinline$getStringClass() {
165     // Prevent inlining to avoid the string comparison being optimized away.
166     if (doThrow) { throw new Error(); }
167     // String class is known to be in the boot image.
168     return String.class;
169   }
170 
171   /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.Class Main.$noinline$getOtherClass() builder (after)
172   /// CHECK:                LoadClass load_kind:BssEntry class_name:Other
173 
174   /// CHECK-START-X86: java.lang.Class Main.$noinline$getOtherClass() pc_relative_fixups_x86 (before)
175   /// CHECK-NOT:            X86ComputeBaseMethodAddress
176 
177   /// CHECK-START-X86: java.lang.Class Main.$noinline$getOtherClass() pc_relative_fixups_x86 (after)
178   /// CHECK-DAG:            X86ComputeBaseMethodAddress
179   /// CHECK-DAG:            LoadClass load_kind:BssEntry class_name:Other
180 
$noinline$getOtherClass()181   public static Class<?> $noinline$getOtherClass() {
182     // Prevent inlining to avoid the string comparison being optimized away.
183     if (doThrow) { throw new Error(); }
184     // Other class is not in the boot image.
185     return Other.class;
186   }
187 
188   /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.String Main.$noinline$toHexString(int) builder (after)
189   /// CHECK:                InvokeStaticOrDirect method_load_kind:BootImageRelRo
$noinline$toHexString(int value)190   public static String $noinline$toHexString(int value) {
191     return Integer.toString(value, 16);
192   }
193 
194   /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.String Main.$noinline$toHexStringIndirect(int) builder (after)
195   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
196 
197   /// CHECK-START-X86: java.lang.String Main.$noinline$toHexStringIndirect(int) pc_relative_fixups_x86 (before)
198   /// CHECK-NOT:            X86ComputeBaseMethodAddress
199 
200   /// CHECK-START-X86: java.lang.String Main.$noinline$toHexStringIndirect(int) pc_relative_fixups_x86 (after)
201   /// CHECK-DAG:            X86ComputeBaseMethodAddress
202   /// CHECK-DAG:            InvokeStaticOrDirect method_load_kind:BssEntry
$noinline$toHexStringIndirect(int value)203   public static String $noinline$toHexStringIndirect(int value) {
204     return $noinline$toHexString(value);
205   }
206 
main(String[] args)207   public static void main(String[] args) {
208     assertIntEquals(1, testSimple(1));
209     assertIntEquals(1, testDiamond(false, 1));
210     assertIntEquals(-1, testDiamond(true, 1));
211     assertIntEquals(3, testLoop(new int[]{ 2 }, 1));
212     assertIntEquals(8, testLoop(new int[]{ 3, 4 }, 1));
213     assertIntEquals(1, testLoopWithDiamond(null, false, 1));
214     assertIntEquals(3, testLoopWithDiamond(new int[]{ 2 }, false, 1));
215     assertIntEquals(-6, testLoopWithDiamond(new int[]{ 3, 4 }, true, 1));
216     assertStringEquals("", $noinline$getBootImageString());
217     assertStringEquals("non-boot-image-string", $noinline$getNonBootImageString());
218     assertClassEquals(String.class, $noinline$getStringClass());
219     assertClassEquals(Other.class, $noinline$getOtherClass());
220     assertStringEquals("12345678", $noinline$toHexString(0x12345678));
221     assertStringEquals("76543210", $noinline$toHexStringIndirect(0x76543210));
222   }
223 }
224 
225 class Other {
226 }
227