From d6dd0dc3e06d42f108fe80920e1102d47a5aa583 Mon Sep 17 00:00:00 2001 From: Roger Riggs <rriggs@openjdk.org> Date: Tue, 27 Jun 2023 17:49:09 +0000 Subject: [PATCH] 8308452: Extend internal Architecture enum with byte order and address size Reviewed-by: mdoerr, jpai, mchung, amitkumar --- make/modules/java.base/gensrc/GensrcMisc.gmk | 4 +- .../jdk/internal/util/Architecture.java | 111 +++++++++++++----- .../internal/util/PlatformProps.java.template | 1 + .../jdk/tools/jlink/internal/Platform.java | 1 - test/jdk/jdk/internal/util/ArchTest.java | 98 ++++++++++------ 5 files changed, 145 insertions(+), 70 deletions(-) diff --git a/make/modules/java.base/gensrc/GensrcMisc.gmk b/make/modules/java.base/gensrc/GensrcMisc.gmk index e37aa50d41c..578adce4e9d 100644 --- a/make/modules/java.base/gensrc/GensrcMisc.gmk +++ b/make/modules/java.base/gensrc/GensrcMisc.gmk @@ -52,9 +52,7 @@ $(eval $(call SetupTextFileProcessing, BUILD_VERSION_JAVA, \ # Normalize OPENJDK_TARGET_CPU name to match jdk.internal.util.Architecture enum -ifneq ($(filter $(OPENJDK_TARGET_CPU), ppc64le), ) - OPENJDK_TARGET_ARCH_CANONICAL = ppc64 -else ifneq ($(filter $(OPENJDK_TARGET_CPU), s390x), ) +ifneq ($(filter $(OPENJDK_TARGET_CPU), s390x), ) OPENJDK_TARGET_ARCH_CANONICAL = s390 else ifneq ($(filter $(OPENJDK_TARGET_CPU), x86_64 amd64), ) OPENJDK_TARGET_ARCH_CANONICAL = x64 diff --git a/src/java.base/share/classes/jdk/internal/util/Architecture.java b/src/java.base/share/classes/jdk/internal/util/Architecture.java index 3d68426ce3d..2c7d1f05f66 100644 --- a/src/java.base/share/classes/jdk/internal/util/Architecture.java +++ b/src/java.base/share/classes/jdk/internal/util/Architecture.java @@ -23,6 +23,8 @@ package jdk.internal.util; import jdk.internal.vm.annotation.ForceInline; + +import java.nio.ByteOrder; import java.util.Locale; /** @@ -33,19 +35,81 @@ import java.util.Locale; * architecture values. */ public enum Architecture { - OTHER, // An unknown architecture not specifically named - X64, // Represents AMD64 and X86_64 - X86, - AARCH64, - ARM, - RISCV64, - LOONGARCH64, - S390, - PPC64, - MIPSEL, - MIPS64EL + /* + * An unknown architecture not specifically named. + * The addrSize and ByteOrder values are those of the current architecture. + */ + OTHER(is64bit() ? 64 : 32, ByteOrder.nativeOrder()), + X64(64, ByteOrder.LITTLE_ENDIAN), // Represents AMD64 and X86_64 + X86(32, ByteOrder.LITTLE_ENDIAN), + AARCH64(64, ByteOrder.LITTLE_ENDIAN), + ARM(32, ByteOrder.LITTLE_ENDIAN), + RISCV64(64, ByteOrder.LITTLE_ENDIAN), + LOONGARCH64(64, ByteOrder.LITTLE_ENDIAN), + S390(64, ByteOrder.BIG_ENDIAN), + PPC64(64, ByteOrder.BIG_ENDIAN), + PPC64LE(64, ByteOrder.LITTLE_ENDIAN), + MIPSEL(32, ByteOrder.LITTLE_ENDIAN), + MIPS64EL(64, ByteOrder.LITTLE_ENDIAN) ; + private final int addrSize; + private final ByteOrder byteOrder; + + /** + * Construct an Architecture with number of address bits and byte order. + * @param addrSize number of address bits, typically 64 or 32 + * @param byteOrder the byte order, big-endian or little-endian + */ + Architecture(int addrSize, ByteOrder byteOrder) { + this.addrSize = addrSize; + this.byteOrder = byteOrder; + } + + /** + * {@return the number of address bits, typically 64 or 32} + */ + public int addressSize() { + return addrSize; + } + + /** + * {@return the byte order, {@link ByteOrder#BIG_ENDIAN} or {@link ByteOrder#LITTLE_ENDIAN}} + */ + public ByteOrder byteOrder() { + return byteOrder; + } + + /** + * {@return the Architecture by name or an alias for the architecture} + * The names are mapped to upper case before mapping to an Architecture. + * @param archName an Architecture name or alias for the architecture. + * @throws IllegalArgumentException if the name is not an alias or an Architecture name + */ + public static Architecture lookupByName(String archName) { + archName = archName.toUpperCase(Locale.ROOT); // normalize to uppercase + return switch (archName) { + case "X86_64", "AMD64" -> X64; + case "I386" -> X86; + case "S390X" -> S390; + default -> Architecture.valueOf(archName); + }; + } + + /** + * Returns the Architecture of the built architecture. + * Build time names are mapped to respective uppercase enum values. + * Names not recognized are mapped to Architecture.OTHER. + */ + private static Architecture initArch(String archName) { + try { + return lookupByName(archName); + } catch (IllegalArgumentException ile) { + return Architecture.OTHER; + } + } + + // Initialize the architecture by mapping aliases and names to the enum values. private static Architecture CURRENT_ARCH = initArch(PlatformProps.CURRENT_ARCH_STRING); /** @@ -89,14 +153,21 @@ public enum Architecture { } /** - * {@return {@code true} if the current architecture is PPC64} - * Use {@link #isLittleEndian()} to determine big or little endian. + * {@return {@code true} if the current architecture is PPC64, big-endian} */ @ForceInline public static boolean isPPC64() { return PlatformProps.TARGET_ARCH_IS_PPC64; } + /** + * {@return {@code true} if the current architecture is PPC64, little-endian} + */ + @ForceInline + public static boolean isPPC64LE() { + return PlatformProps.TARGET_ARCH_IS_PPC64LE; + } + /** * {@return {@code true} if the current architecture is ARM} */ @@ -151,18 +222,4 @@ public enum Architecture { public static boolean isLittleEndian() { return PlatformProps.TARGET_ARCH_LITTLE_ENDIAN; } - - - /** - * Returns the Architecture of the built architecture. - * Build time names are mapped to respective uppercase enum values. - * Names not recognized are mapped to Architecture.OTHER. - */ - private static Architecture initArch(String archName) { - try { - return Architecture.valueOf(archName.toUpperCase(Locale.ROOT)); - } catch (IllegalArgumentException ile) { - return Architecture.OTHER; - } - } } diff --git a/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template b/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template index cd615e600dd..fc3bccc6b28 100644 --- a/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template +++ b/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template @@ -58,6 +58,7 @@ class PlatformProps { static final boolean TARGET_ARCH_IS_LOONGARCH64 = "@@OPENJDK_TARGET_CPU@@" == "loongarch64"; static final boolean TARGET_ARCH_IS_S390 = "@@OPENJDK_TARGET_CPU@@" == "s390"; static final boolean TARGET_ARCH_IS_PPC64 = "@@OPENJDK_TARGET_CPU@@" == "ppc64"; + static final boolean TARGET_ARCH_IS_PPC64LE = "@@OPENJDK_TARGET_CPU@@" == "ppc64le"; static final boolean TARGET_ARCH_IS_MIPSEL = "@@OPENJDK_TARGET_CPU@@" == "mipsel"; static final boolean TARGET_ARCH_IS_MIPS64EL= "@@OPENJDK_TARGET_CPU@@" == "mips64el"; } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java index cf9b9c324da..79744ba1621 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java @@ -52,7 +52,6 @@ public record Platform(OperatingSystem os, Architecture arch) { archName = platformString.substring(index + 1); // Alias architecture names, if needed archName = archName.replace("amd64", "X64"); - archName = archName.replace("ppc64le", "PPC64"); archName = archName.replace("s390x", "S390"); Architecture arch = Architecture.valueOf(archName.toUpperCase(Locale.ROOT)); diff --git a/test/jdk/jdk/internal/util/ArchTest.java b/test/jdk/jdk/internal/util/ArchTest.java index 1ffc91f77a5..4505a086027 100644 --- a/test/jdk/jdk/internal/util/ArchTest.java +++ b/test/jdk/jdk/internal/util/ArchTest.java @@ -20,16 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +import java.nio.ByteOrder; +import java.util.List; import java.util.Locale; import java.util.stream.Stream; import jdk.internal.util.Architecture; import jdk.internal.misc.Unsafe; -import static jdk.internal.util.Architecture.OTHER; import static jdk.internal.util.Architecture.AARCH64; import static jdk.internal.util.Architecture.ARM; import static jdk.internal.util.Architecture.PPC64; +import static jdk.internal.util.Architecture.PPC64LE; import static jdk.internal.util.Architecture.RISCV64; import static jdk.internal.util.Architecture.LOONGARCH64; import static jdk.internal.util.Architecture.S390; @@ -44,20 +46,51 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; /** * @test - * @bug 8304915 + * @bug 8304915 8308452 * @summary Verify Architecture enum maps to system property os.arch * @modules java.base/jdk.internal.util * @modules java.base/jdk.internal.misc * @run junit ArchTest */ public class ArchTest { - private static boolean IS_BIG_ENDIAN = Unsafe.getUnsafe().isBigEndian(); + private static final boolean IS_BIG_ENDIAN = Unsafe.getUnsafe().isBigEndian(); + + private static final boolean IS_64BIT_ADDRESS = Unsafe.getUnsafe().addressSize() == 8; + + /** + * Test data for Architecture name vs Arch enums, address bits, endian-ness and boolean isXXX() methods.. + * Each Argument contains: + * - the common os.arch name, + * - the Architecture Enum, + * - address bits 32/64, + * - the byte-order (little or big), + * - the result of invoking the architecture specific static method + * @return a stream of arguments for parameterized tests + */ + private static Stream<Arguments> archParams() { + // In alphabetical order + return Stream.of( + Arguments.of("aarch64", AARCH64, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isAARCH64()), + Arguments.of("amd64", X64, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isX64()), + Arguments.of("arm", ARM, 32, ByteOrder.LITTLE_ENDIAN, Architecture.isAARCH64()), + Arguments.of("i386", X86, 32, ByteOrder.LITTLE_ENDIAN, Architecture.isX86()), + Arguments.of("loongarch64", LOONGARCH64, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isLOONGARCH64()), + Arguments.of("mips64el", MIPS64EL, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isMIPS64EL()), + Arguments.of("mipsel", MIPSEL, 32, ByteOrder.LITTLE_ENDIAN, Architecture.isMIPSEL()), + Arguments.of("ppc64", PPC64, 64, ByteOrder.BIG_ENDIAN, Architecture.isPPC64()), + Arguments.of("ppc64le", PPC64LE, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isPPC64LE()), + Arguments.of("riscv64", RISCV64, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isRISCV64()), + Arguments.of("s390", S390, 64, ByteOrder.BIG_ENDIAN, Architecture.isS390()), + Arguments.of("s390x", S390, 64, ByteOrder.BIG_ENDIAN, Architecture.isS390()), + Arguments.of("x64", X64, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isX64()), + Arguments.of("x86", X86, 32, ByteOrder.LITTLE_ENDIAN, Architecture.isX86()), + Arguments.of("x86_64", X64, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isX64()) + ); + } - private static boolean IS_64BIT_ADDRESS = Unsafe.getUnsafe().addressSize() == 8; /** * Test consistency of System property "os.arch" with Architecture.current(). @@ -65,46 +98,33 @@ public class ArchTest { @Test public void nameVsCurrent() { String osArch = System.getProperty("os.arch").toLowerCase(Locale.ROOT); - System.out.printf("System property os.arch: \"%s\", Architecture.current(): \"%s\"%n", + System.err.printf("System property os.arch: \"%s\", Architecture.current(): \"%s\"%n", osArch, Architecture.current()); - Architecture arch = switch (osArch) { - case "x86_64", "amd64" -> X64; - case "x86", "i386" -> X86; - case "aarch64" -> AARCH64; - case "arm" -> ARM; - case "riscv64" -> RISCV64; - case "loongarch64" -> LOONGARCH64; - case "s390x", "s390" -> S390; - case "ppc64", "ppc64le" -> PPC64; - case "mipsel" -> MIPSEL; - case "mips64el" -> MIPS64EL; - default -> OTHER; - }; - assertEquals(Architecture.current(), arch, "mismatch in Architecture.current vs " + osArch); - } - /** - * Test various Architecture enum values vs boolean isXXX() methods. - * @return a stream of arguments for parameterized test - */ - private static Stream<Arguments> archParams() { - return Stream.of( - Arguments.of(X64, Architecture.isX64()), - Arguments.of(X86, Architecture.isX86()), - Arguments.of(AARCH64, Architecture.isAARCH64()), - Arguments.of(ARM, Architecture.isARM()), - Arguments.of(RISCV64, Architecture.isRISCV64()), - Arguments.of(LOONGARCH64, Architecture.isLOONGARCH64()), - Arguments.of(S390, Architecture.isS390()), - Arguments.of(MIPSEL, Architecture.isMIPSEL()), - Arguments.of(MIPS64EL, Architecture.isMIPS64EL()), - Arguments.of(PPC64, Architecture.isPPC64()) - ); + // Map os.arch system property to expected Architecture + List<Architecture> argList = archParams() + .filter(p -> p.get()[0].equals(osArch)) + .map(a -> (Architecture)a.get()[1]) + .toList(); + assertEquals(1, argList.size(), osArch + " too few or too many matching system property os.arch cases: " + argList); + assertEquals(Architecture.current(), argList.get(0), "mismatch in Architecture.current vs " + osArch); } @ParameterizedTest @MethodSource("archParams") - public void isArch(Architecture arch, boolean isArch) { + public void checkParams(String archName, Architecture arch, int addrSize, ByteOrder byteOrder, boolean isArch) { + Architecture actual = Architecture.lookupByName(archName); + assertEquals(actual, arch, "Wrong Architecture from lookupByName"); + + actual = Architecture.lookupByName(archName.toUpperCase(Locale.ROOT)); + assertEquals(actual, arch, "Wrong Architecture from lookupByName (upper-case)"); + + actual = Architecture.lookupByName(archName.toLowerCase(Locale.ROOT)); + assertEquals(actual, arch, "Wrong Architecture from lookupByName (lower-case)"); + + assertEquals(addrSize, actual.addressSize(), "Wrong address size"); + assertEquals(byteOrder, actual.byteOrder(), "Wrong byteOrder"); + Architecture current = Architecture.current(); assertEquals(arch == current, isArch, "Method is" + arch + "(): returned " + isArch + ", should be (" + arch + " == " + current + ")");