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