Skip to content

Commit

Permalink
8308452: Extend internal Architecture enum with byte order and addres…
Browse files Browse the repository at this point in the history
…s size

8310982: jdk/internal/util/ArchTest.java fails after JDK-8308452 failed with Method isARM()

Backport-of: d6dd0dc3e06d42f108fe80920e1102d47a5aa583
  • Loading branch information
shipilev committed Sep 13, 2023
1 parent 0294541 commit 88633d9
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 70 deletions.
4 changes: 1 addition & 3 deletions make/modules/java.base/gensrc/GensrcMisc.gmk
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
111 changes: 84 additions & 27 deletions src/java.base/share/classes/jdk/internal/util/Architecture.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
package jdk.internal.util;

import jdk.internal.vm.annotation.ForceInline;

import java.nio.ByteOrder;
import java.util.Locale;

/**
Expand All @@ -35,19 +37,81 @@
* 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);

/**
Expand Down Expand Up @@ -91,14 +155,21 @@ public static boolean isS390() {
}

/**
* {@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}
*/
Expand Down Expand Up @@ -153,18 +224,4 @@ public static boolean is64bit() {
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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,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";
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ public static Platform parsePlatform(String platformString) {
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));

Expand Down
98 changes: 59 additions & 39 deletions test/jdk/jdk/internal/util/ArchTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -44,67 +46,85 @@
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 8310982
* @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.isARM()),
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().
*/
@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 + ")");
Expand Down

1 comment on commit 88633d9

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.