| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| public class Main { |
| |
| public static void assertIntEquals(int expected, int result) { |
| if (expected != result) { |
| throw new Error("Expected: " + expected + ", found: " + result); |
| } |
| } |
| |
| public static void assertStringEquals(String expected, String result) { |
| if (expected != null ? !expected.equals(result) : result != null) { |
| throw new Error("Expected: " + expected + ", found: " + result); |
| } |
| } |
| |
| public static void assertClassEquals(Class<?> expected, Class<?> result) { |
| if (expected != result) { |
| throw new Error("Expected: " + expected + ", found: " + result); |
| } |
| } |
| |
| public static boolean doThrow = false; |
| |
| private static int $noinline$foo(int x) { |
| if (doThrow) { throw new Error(); } |
| return x; |
| } |
| |
| /// CHECK-START-{ARM,ARM64,X86,X86_64}: int Main.testSimple(int) builder (after) |
| /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry |
| |
| /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (before) |
| /// CHECK-NOT: X86ComputeBaseMethodAddress |
| |
| /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (after) |
| /// CHECK: X86ComputeBaseMethodAddress |
| /// CHECK-NOT: X86ComputeBaseMethodAddress |
| |
| public static int testSimple(int x) { |
| // This call should use PC-relative .bss array load to retrieve the target method. |
| return $noinline$foo(x); |
| } |
| |
| /// CHECK-START-{ARM,ARM64,X86,X86_64}: int Main.testDiamond(boolean, int) builder (after) |
| /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry |
| /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry |
| |
| /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (before) |
| /// CHECK-NOT: X86ComputeBaseMethodAddress |
| |
| /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after) |
| /// CHECK: X86ComputeBaseMethodAddress |
| /// CHECK-NOT: X86ComputeBaseMethodAddress |
| |
| /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after) |
| /// CHECK: X86ComputeBaseMethodAddress |
| /// CHECK-NEXT: If |
| |
| public static int testDiamond(boolean negate, int x) { |
| // These calls should use PC-relative loads to retrieve the target method. |
| // PC-relative bases used by X86 should be pulled before the If. |
| if (negate) { |
| return $noinline$foo(-x); |
| } else { |
| return $noinline$foo(x); |
| } |
| } |
| |
| /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (before) |
| /// CHECK-NOT: X86ComputeBaseMethodAddress |
| |
| /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after) |
| /// CHECK: X86ComputeBaseMethodAddress |
| /// CHECK-NOT: X86ComputeBaseMethodAddress |
| |
| /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after) |
| /// CHECK: InvokeStaticOrDirect |
| /// CHECK-NOT: InvokeStaticOrDirect |
| |
| /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after) |
| /// CHECK: ArrayLength |
| /// CHECK-NEXT: X86ComputeBaseMethodAddress |
| /// CHECK-NEXT: Goto |
| /// CHECK: begin_block |
| /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry |
| |
| public static int testLoop(int[] array, int x) { |
| // PC-relative bases used by X86 should be pulled before the loop. |
| for (int i : array) { |
| x += $noinline$foo(i); |
| } |
| return x; |
| } |
| |
| /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (before) |
| /// CHECK-NOT: X86ComputeBaseMethodAddress |
| |
| /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (after) |
| /// CHECK: If |
| /// CHECK: begin_block |
| /// CHECK: ArrayLength |
| /// CHECK-NEXT: X86ComputeBaseMethodAddress |
| /// CHECK-NEXT: Goto |
| |
| public static int testLoopWithDiamond(int[] array, boolean negate, int x) { |
| // PC-relative bases used by X86 should be pulled before the loop but not outside the if. |
| if (array != null) { |
| for (int i : array) { |
| if (negate) { |
| x += $noinline$foo(-i); |
| } else { |
| x += $noinline$foo(i); |
| } |
| } |
| } |
| return x; |
| } |
| |
| /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.String Main.$noinline$getBootImageString() builder (after) |
| /// CHECK: LoadString load_kind:BootImageRelRo |
| |
| public static String $noinline$getBootImageString() { |
| // Prevent inlining to avoid the string comparison being optimized away. |
| if (doThrow) { throw new Error(); } |
| // Empty string is known to be in the boot image. |
| return ""; |
| } |
| |
| /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.String Main.$noinline$getNonBootImageString() builder (after) |
| /// CHECK: LoadString load_kind:BssEntry |
| |
| /// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() pc_relative_fixups_x86 (before) |
| /// CHECK-NOT: X86ComputeBaseMethodAddress |
| |
| /// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() pc_relative_fixups_x86 (after) |
| /// CHECK-DAG: X86ComputeBaseMethodAddress |
| /// CHECK-DAG: LoadString load_kind:BssEntry |
| |
| public static String $noinline$getNonBootImageString() { |
| // Prevent inlining to avoid the string comparison being optimized away. |
| if (doThrow) { throw new Error(); } |
| // This string is not in the boot image. |
| return "non-boot-image-string"; |
| } |
| |
| /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.Class Main.$noinline$getStringClass() builder (after) |
| /// CHECK: LoadClass load_kind:BootImageRelRo class_name:java.lang.String |
| |
| public static Class<?> $noinline$getStringClass() { |
| // Prevent inlining to avoid the string comparison being optimized away. |
| if (doThrow) { throw new Error(); } |
| // String class is known to be in the boot image. |
| return String.class; |
| } |
| |
| /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.Class Main.$noinline$getOtherClass() builder (after) |
| /// CHECK: LoadClass load_kind:BssEntry class_name:Other |
| |
| /// CHECK-START-X86: java.lang.Class Main.$noinline$getOtherClass() pc_relative_fixups_x86 (before) |
| /// CHECK-NOT: X86ComputeBaseMethodAddress |
| |
| /// CHECK-START-X86: java.lang.Class Main.$noinline$getOtherClass() pc_relative_fixups_x86 (after) |
| /// CHECK-DAG: X86ComputeBaseMethodAddress |
| /// CHECK-DAG: LoadClass load_kind:BssEntry class_name:Other |
| |
| public static Class<?> $noinline$getOtherClass() { |
| // Prevent inlining to avoid the string comparison being optimized away. |
| if (doThrow) { throw new Error(); } |
| // Other class is not in the boot image. |
| return Other.class; |
| } |
| |
| /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.String Main.$noinline$toHexString(int) builder (after) |
| /// CHECK: InvokeStaticOrDirect method_load_kind:BootImageRelRo |
| public static String $noinline$toHexString(int value) { |
| return Integer.toString(value, 16); |
| } |
| |
| /// CHECK-START-{ARM,ARM64,X86,X86_64}: java.lang.String Main.$noinline$toHexStringIndirect(int) builder (after) |
| /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry |
| |
| /// CHECK-START-X86: java.lang.String Main.$noinline$toHexStringIndirect(int) pc_relative_fixups_x86 (before) |
| /// CHECK-NOT: X86ComputeBaseMethodAddress |
| |
| /// CHECK-START-X86: java.lang.String Main.$noinline$toHexStringIndirect(int) pc_relative_fixups_x86 (after) |
| /// CHECK-DAG: X86ComputeBaseMethodAddress |
| /// CHECK-DAG: InvokeStaticOrDirect method_load_kind:BssEntry |
| public static String $noinline$toHexStringIndirect(int value) { |
| return $noinline$toHexString(value); |
| } |
| |
| public static void main(String[] args) { |
| assertIntEquals(1, testSimple(1)); |
| assertIntEquals(1, testDiamond(false, 1)); |
| assertIntEquals(-1, testDiamond(true, 1)); |
| assertIntEquals(3, testLoop(new int[]{ 2 }, 1)); |
| assertIntEquals(8, testLoop(new int[]{ 3, 4 }, 1)); |
| assertIntEquals(1, testLoopWithDiamond(null, false, 1)); |
| assertIntEquals(3, testLoopWithDiamond(new int[]{ 2 }, false, 1)); |
| assertIntEquals(-6, testLoopWithDiamond(new int[]{ 3, 4 }, true, 1)); |
| assertStringEquals("", $noinline$getBootImageString()); |
| assertStringEquals("non-boot-image-string", $noinline$getNonBootImageString()); |
| assertClassEquals(String.class, $noinline$getStringClass()); |
| assertClassEquals(Other.class, $noinline$getOtherClass()); |
| assertStringEquals("12345678", $noinline$toHexString(0x12345678)); |
| assertStringEquals("76543210", $noinline$toHexStringIndirect(0x76543210)); |
| } |
| } |
| |
| class Other { |
| } |
| |
| class MainExtension extends Main { |
| } |