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