From 942234d197fcef61d562377af243166e0a72a1b8 Mon Sep 17 00:00:00 2001 From: liach Date: Sun, 4 May 2025 16:43:59 -0500 Subject: [PATCH 01/11] 8356126: Revisit CaptureCallState --- .../classes/java/lang/foreign/Linker.java | 11 ++- .../internal/foreign/abi/CallingSequence.java | 4 +- .../internal/foreign/abi/CapturableState.java | 90 ++++++++++--------- .../internal/foreign/abi/LinkerOptions.java | 32 +++---- .../foreign/abi/fallback/FallbackLinker.java | 4 +- .../jdk/internal/util/OperatingSystem.java | 12 ++- .../TestCaptureCallState.java | 14 ++- 7 files changed, 86 insertions(+), 81 deletions(-) diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java index 8f1cab22b86e5..9e6adf2bc0656 100644 --- a/src/java.base/share/classes/java/lang/foreign/Linker.java +++ b/src/java.base/share/classes/java/lang/foreign/Linker.java @@ -859,12 +859,11 @@ static Option firstVariadicArg(int index) { * @see #captureStateLayout() */ static Option captureCallState(String... capturedState) { - int set = Stream.of(Objects.requireNonNull(capturedState)) - .map(Objects::requireNonNull) - .map(CapturableState::forName) - .mapToInt(state -> 1 << state.ordinal()) - .sum(); - return new LinkerOptions.CaptureCallState(set); + int mask = 0; + for (var state : capturedState) { + mask |= CapturableState.forName(state).mask; + } + return new LinkerOptions.CaptureCallState(mask); } /** diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java index 4f7a049fd6d1b..c2a74eb0965d5 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java @@ -185,9 +185,7 @@ public boolean hasReturnBindings() { } public int capturedStateMask() { - return linkerOptions.capturedCallState() - .mapToInt(CapturableState::mask) - .reduce(0, (a, b) -> a | b); + return linkerOptions.capturedCallStateMask(); } public boolean needsTransition() { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index d95e713541f59..577f36209d5a5 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,66 +30,70 @@ import java.lang.foreign.MemoryLayout; import java.lang.foreign.StructLayout; import java.lang.foreign.ValueLayout; -import java.util.List; -import java.util.stream.Collectors; +import java.util.ArrayList; +import java.util.Map; import java.util.stream.Stream; import static java.lang.foreign.ValueLayout.JAVA_INT; public enum CapturableState { - GET_LAST_ERROR ("GetLastError", JAVA_INT, 1 << 0, OperatingSystem.isWindows()), - WSA_GET_LAST_ERROR("WSAGetLastError", JAVA_INT, 1 << 1, OperatingSystem.isWindows()), - ERRNO ("errno", JAVA_INT, 1 << 2, true); + GET_LAST_ERROR ("GetLastError", JAVA_INT, 1 << 0), + WSA_GET_LAST_ERROR("WSAGetLastError", JAVA_INT, 1 << 1), + ERRNO ("errno", JAVA_INT, 1 << 2); - public static final StructLayout LAYOUT = MemoryLayout.structLayout( - supportedStates().map(CapturableState::layout).toArray(MemoryLayout[]::new)); - public static final List BY_ORDINAL = List.of(values()); + public static final StructLayout LAYOUT; + public static final Map SUPPORTED; static { - assert (BY_ORDINAL.size() < Integer.SIZE); // Update LinkerOptions.CaptureCallState + var values = values(); + + if (OperatingSystem.isWindows()) { + SUPPORTED = Map.of(GET_LAST_ERROR.stateName, GET_LAST_ERROR, + WSA_GET_LAST_ERROR.stateName, WSA_GET_LAST_ERROR, + ERRNO.stateName, ERRNO); + } else { + SUPPORTED = Map.of(ERRNO.stateName, ERRNO); + } + + MemoryLayout[] stateLayouts = new MemoryLayout[SUPPORTED.size()]; + int i = 0; + for (var supported : SUPPORTED.values()) { + stateLayouts[i++] = supported.layout; + } + LAYOUT = MemoryLayout.structLayout(stateLayouts); } - private final String stateName; - private final ValueLayout layout; - private final int mask; - private final boolean isSupported; + public final String stateName; + public final ValueLayout layout; + public final int mask; - CapturableState(String stateName, ValueLayout layout, int mask, boolean isSupported) { + CapturableState(String stateName, ValueLayout layout, int mask) { this.stateName = stateName; this.layout = layout.withName(stateName); this.mask = mask; - this.isSupported = isSupported; - } - - private static Stream supportedStates() { - return Stream.of(values()).filter(CapturableState::isSupported); } public static CapturableState forName(String name) { - return Stream.of(values()) - .filter(stl -> stl.stateName().equals(name)) - .filter(CapturableState::isSupported) - .findAny() - .orElseThrow(() -> new IllegalArgumentException( - "Unknown name: " + name +", must be one of: " - + supportedStates() - .map(CapturableState::stateName) - .collect(Collectors.joining(", ")))); - } - - public String stateName() { - return stateName; - } - - public ValueLayout layout() { - return layout; - } - - public int mask() { - return mask; + var ret = SUPPORTED.get(name); + if (ret == null) { + throw new IllegalArgumentException( + "Unknown name: " + name +", must be one of: " + + SUPPORTED.keySet()); + } + return ret; } - public boolean isSupported() { - return isSupported; + /** + * Returns a list-like display string for a captured state mask. + * Enclosed with brackets. + */ + public static String displayString(int mask) { + var displayList = new ArrayList<>(); + for (var e : SUPPORTED.values()) { + if ((mask & e.mask) != 0) { + displayList.add(e.stateName); + } + } + return displayList.toString(); } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java b/src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java index 4ada4b2341783..848d6b22b83b1 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,9 +84,9 @@ public boolean hasCapturedCallState() { return getOption(CaptureCallState.class) != null; } - public Stream capturedCallState() { + public int capturedCallStateMask() { CaptureCallState stl = getOption(CaptureCallState.class); - return stl == null ? Stream.empty() : stl.saved().stream(); + return stl == null ? 0 : stl.mask(); } public boolean isVariadicFunction() { @@ -150,35 +150,25 @@ public boolean equals(Object obj) { } } - public record CaptureCallState(int compact) implements LinkerOptionImpl { + public record CaptureCallState(int mask) implements LinkerOptionImpl { @Override public void validateForDowncall(FunctionDescriptor descriptor) { // done during construction } - public Set saved() { - var set = EnumSet.noneOf(CapturableState.class); - int mask = compact; - int i = 0; - while (mask != 0) { - if ((mask & 1) == 1) { - set.add(CapturableState.BY_ORDINAL.get(i)); - } - mask >>= 1; - i++; - } - return set; - } - - @Override public boolean equals(Object obj) { - return obj instanceof CaptureCallState that && compact == that.compact; + return obj instanceof CaptureCallState that && mask == that.mask; } @Override public int hashCode() { - return compact; + return mask; + } + + @Override + public String toString() { + return "CaptureCallState" + CapturableState.displayString(mask); } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java index 9be958e7689f6..7343a23436d95 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java @@ -84,9 +84,7 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe assertNotEmpty(function); MemorySegment cif = makeCif(inferredMethodType, function, options, Arena.ofAuto()); - int capturedStateMask = options.capturedCallState() - .mapToInt(CapturableState::mask) - .reduce(0, (a, b) -> a | b); + int capturedStateMask = options.capturedCallStateMask(); DowncallData invData = new DowncallData(cif, function.returnLayout().orElse(null), function.argumentLayouts(), capturedStateMask, options.allowsHeapAccess()); diff --git a/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java b/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java index 927ab682c3e83..d7101bba3c661 100644 --- a/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java +++ b/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.util.Locale; import jdk.internal.util.PlatformProps; import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; /** * Enumeration of operating system types and testing for the current OS. @@ -84,7 +85,7 @@ public enum OperatingSystem { ; // The current OperatingSystem - private static final OperatingSystem CURRENT_OS = initOS(); + private static @Stable OperatingSystem CURRENT_OS; /** * {@return {@code true} if built for the Linux operating system} @@ -122,7 +123,11 @@ public static boolean isAix() { * {@return the current operating system} */ public static OperatingSystem current() { - return CURRENT_OS; + var current = CURRENT_OS; + if (current == null) { + return CURRENT_OS = initOS(); + } + return current; } /** @@ -131,6 +136,7 @@ public static OperatingSystem current() { * Names not recognized throw ExceptionInInitializerError with IllegalArgumentException. */ private static OperatingSystem initOS() { + // Called lazily, valueOf has overhead return OperatingSystem.valueOf(PlatformProps.CURRENT_OS_STRING.toUpperCase(Locale.ROOT)); } } diff --git a/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java b/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java index 842f36fd08da9..b6b399338af74 100644 --- a/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java +++ b/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java @@ -47,8 +47,7 @@ import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; import static java.lang.foreign.ValueLayout.JAVA_INT; import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.*; public class TestCaptureCallState extends NativeTestHelper { @@ -61,6 +60,17 @@ public class TestCaptureCallState extends NativeTestHelper { } } + // Basic sanity tests around Java API contracts + @Test + public void testApiContracts() { + assertThrows(IllegalArgumentException.class, () -> Linker.Option.captureCallState("Does not exist")); + var duplicateOpt = Linker.Option.captureCallState("errno", "errno"); // duplicates + var noDuplicateOpt = Linker.Option.captureCallState("errno"); + assertEquals(duplicateOpt, noDuplicateOpt, "auto deduplication"); + var display = duplicateOpt.toString(); + assertTrue(display.contains("errno"), "toString should contain state name 'errno': " + display); + } + private record SaveValuesCase(String nativeTarget, FunctionDescriptor nativeDesc, String threadLocalName, Consumer resultCheck, boolean critical) {} From 94fca4b40aa7d14ca260e8e2bbb1acd72b05b885 Mon Sep 17 00:00:00 2001 From: liach Date: Sun, 4 May 2025 17:37:14 -0500 Subject: [PATCH 02/11] Bugid --- test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java b/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java index b6b399338af74..2c69c5691b872 100644 --- a/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java +++ b/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8356126 * @library ../ /test/lib * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestCaptureCallState */ From 106ad2524bf7255861caee23e40c681319ceebf8 Mon Sep 17 00:00:00 2001 From: liach Date: Sun, 4 May 2025 22:09:58 -0500 Subject: [PATCH 03/11] Further revamp, remove unnecessary instances on irrelevant platforms --- .../internal/foreign/abi/CapturableState.java | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index 577f36209d5a5..c751bc7a54b6d 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -31,54 +31,57 @@ import java.lang.foreign.StructLayout; import java.lang.foreign.ValueLayout; import java.util.ArrayList; +import java.util.List; import java.util.Map; -import java.util.stream.Stream; import static java.lang.foreign.ValueLayout.JAVA_INT; -public enum CapturableState { - GET_LAST_ERROR ("GetLastError", JAVA_INT, 1 << 0), - WSA_GET_LAST_ERROR("WSAGetLastError", JAVA_INT, 1 << 1), - ERRNO ("errno", JAVA_INT, 1 << 2); +public final class CapturableState { public static final StructLayout LAYOUT; - public static final Map SUPPORTED; + private static final Map LOOKUP; static { - var values = values(); + List supported; if (OperatingSystem.isWindows()) { - SUPPORTED = Map.of(GET_LAST_ERROR.stateName, GET_LAST_ERROR, - WSA_GET_LAST_ERROR.stateName, WSA_GET_LAST_ERROR, - ERRNO.stateName, ERRNO); + supported = List.of( + new CapturableState("GetLastError", JAVA_INT, 1 << 0), + new CapturableState("WSAGetLastError", JAVA_INT, 1 << 1), + new CapturableState("errno", JAVA_INT, 1 << 2) + ); } else { - SUPPORTED = Map.of(ERRNO.stateName, ERRNO); + supported = List.of(new CapturableState("errno", JAVA_INT, 1 << 2)); } - MemoryLayout[] stateLayouts = new MemoryLayout[SUPPORTED.size()]; + MemoryLayout[] stateLayouts = new MemoryLayout[supported.size()]; + @SuppressWarnings("rawtypes") + Map.Entry[] entries = new Map.Entry[supported.size()]; int i = 0; - for (var supported : SUPPORTED.values()) { - stateLayouts[i++] = supported.layout; + for (var each : supported) { + stateLayouts[i++] = each.layout; + entries[i++] = Map.entry(each.stateName, each); } LAYOUT = MemoryLayout.structLayout(stateLayouts); + LOOKUP = Map.ofEntries(entries); } public final String stateName; public final ValueLayout layout; public final int mask; - CapturableState(String stateName, ValueLayout layout, int mask) { + private CapturableState(String stateName, ValueLayout layout, int mask) { this.stateName = stateName; this.layout = layout.withName(stateName); this.mask = mask; } public static CapturableState forName(String name) { - var ret = SUPPORTED.get(name); + var ret = LOOKUP.get(name); if (ret == null) { throw new IllegalArgumentException( "Unknown name: " + name +", must be one of: " - + SUPPORTED.keySet()); + + LOOKUP.keySet()); } return ret; } @@ -89,11 +92,16 @@ public static CapturableState forName(String name) { */ public static String displayString(int mask) { var displayList = new ArrayList<>(); - for (var e : SUPPORTED.values()) { + for (var e : LOOKUP.values()) { if ((mask & e.mask) != 0) { displayList.add(e.stateName); } } return displayList.toString(); } + + @Override + public String toString() { + return stateName; + } } From fc3e7a807b452242572aca4f8c5662733acd54aa Mon Sep 17 00:00:00 2001 From: liach Date: Sun, 4 May 2025 22:29:31 -0500 Subject: [PATCH 04/11] Unchecked --- .../share/classes/jdk/internal/foreign/abi/CapturableState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index c751bc7a54b6d..70cb44e0591f7 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -55,7 +55,7 @@ public final class CapturableState { } MemoryLayout[] stateLayouts = new MemoryLayout[supported.size()]; - @SuppressWarnings("rawtypes") + @SuppressWarnings({"unchecked", "rawtypes"}) Map.Entry[] entries = new Map.Entry[supported.size()]; int i = 0; for (var each : supported) { From 806d307b2d0b64b1c2092dbe056f12423b9c0dee Mon Sep 17 00:00:00 2001 From: liach Date: Sun, 4 May 2025 23:46:39 -0500 Subject: [PATCH 05/11] No env to test --- .../classes/jdk/internal/foreign/abi/CapturableState.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index 70cb44e0591f7..55ab058f77b19 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -59,8 +59,9 @@ public final class CapturableState { Map.Entry[] entries = new Map.Entry[supported.size()]; int i = 0; for (var each : supported) { - stateLayouts[i++] = each.layout; - entries[i++] = Map.entry(each.stateName, each); + stateLayouts[i] = each.layout; + entries[i] = Map.entry(each.stateName, each); + i++; } LAYOUT = MemoryLayout.structLayout(stateLayouts); LOOKUP = Map.ofEntries(entries); From d1598afa6e0357b7af3318a573cb5225017b05ec Mon Sep 17 00:00:00 2001 From: liach Date: Mon, 5 May 2025 11:40:49 -0500 Subject: [PATCH 06/11] Review remarks --- .../classes/jdk/internal/foreign/abi/CapturableState.java | 2 +- .../share/classes/jdk/internal/util/OperatingSystem.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index 55ab058f77b19..a18260cc38f02 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -92,7 +92,7 @@ public static CapturableState forName(String name) { * Enclosed with brackets. */ public static String displayString(int mask) { - var displayList = new ArrayList<>(); + var displayList = new ArrayList<>(); // unordered for (var e : LOOKUP.values()) { if ((mask & e.mask) != 0) { displayList.add(e.stateName); diff --git a/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java b/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java index d7101bba3c661..21db1232cbd37 100644 --- a/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java +++ b/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java @@ -133,10 +133,10 @@ public static OperatingSystem current() { /** * Returns the OperatingSystem of the build. * Build time names are mapped to respective uppercase enum values. - * Names not recognized throw ExceptionInInitializerError with IllegalArgumentException. + * Names not recognized throw IllegalArgumentException. */ private static OperatingSystem initOS() { - // Called lazily, valueOf has overhead + // Called lazily, valueOf has MH.dropArguments overhead from reflective invocation return OperatingSystem.valueOf(PlatformProps.CURRENT_OS_STRING.toUpperCase(Locale.ROOT)); } } From 41549f828c1feaf17a7c2b4221115cebd9bd83ca Mon Sep 17 00:00:00 2001 From: liach Date: Tue, 6 May 2025 07:46:17 -0500 Subject: [PATCH 07/11] rollback OS --- .../classes/jdk/internal/util/OperatingSystem.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java b/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java index 21db1232cbd37..927ab682c3e83 100644 --- a/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java +++ b/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ import java.util.Locale; import jdk.internal.util.PlatformProps; import jdk.internal.vm.annotation.ForceInline; -import jdk.internal.vm.annotation.Stable; /** * Enumeration of operating system types and testing for the current OS. @@ -85,7 +84,7 @@ public enum OperatingSystem { ; // The current OperatingSystem - private static @Stable OperatingSystem CURRENT_OS; + private static final OperatingSystem CURRENT_OS = initOS(); /** * {@return {@code true} if built for the Linux operating system} @@ -123,20 +122,15 @@ public static boolean isAix() { * {@return the current operating system} */ public static OperatingSystem current() { - var current = CURRENT_OS; - if (current == null) { - return CURRENT_OS = initOS(); - } - return current; + return CURRENT_OS; } /** * Returns the OperatingSystem of the build. * Build time names are mapped to respective uppercase enum values. - * Names not recognized throw IllegalArgumentException. + * Names not recognized throw ExceptionInInitializerError with IllegalArgumentException. */ private static OperatingSystem initOS() { - // Called lazily, valueOf has MH.dropArguments overhead from reflective invocation return OperatingSystem.valueOf(PlatformProps.CURRENT_OS_STRING.toUpperCase(Locale.ROOT)); } } From 450ea11515506938015519931e881f5d2dab049e Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 6 May 2025 10:48:18 -0500 Subject: [PATCH 08/11] Update src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java Co-authored-by: Shaojin Wen --- .../share/classes/jdk/internal/foreign/abi/CapturableState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index a18260cc38f02..9e267b3650e46 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -81,7 +81,7 @@ public static CapturableState forName(String name) { var ret = LOOKUP.get(name); if (ret == null) { throw new IllegalArgumentException( - "Unknown name: " + name +", must be one of: " + "Unknown name: " + name + ", must be one of: " + LOOKUP.keySet()); } return ret; From 0f495539a9787fa7a742a50d7879b54639d35136 Mon Sep 17 00:00:00 2001 From: liach Date: Tue, 6 May 2025 15:03:11 -0500 Subject: [PATCH 09/11] Simplify to utility class --- .../classes/java/lang/foreign/Linker.java | 6 +- .../internal/foreign/abi/CapturableState.java | 71 ++++++++----------- 2 files changed, 30 insertions(+), 47 deletions(-) diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java index 9e6adf2bc0656..cfa0309029949 100644 --- a/src/java.base/share/classes/java/lang/foreign/Linker.java +++ b/src/java.base/share/classes/java/lang/foreign/Linker.java @@ -34,11 +34,7 @@ import java.lang.invoke.MethodHandle; import java.util.Map; -import java.util.Objects; -import java.util.Set; import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * A linker provides access to foreign functions from Java code, and access to Java code @@ -861,7 +857,7 @@ static Option firstVariadicArg(int index) { static Option captureCallState(String... capturedState) { int mask = 0; for (var state : capturedState) { - mask |= CapturableState.forName(state).mask; + mask |= CapturableState.maskFromName(state); } return new LinkerOptions.CaptureCallState(mask); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index 9e267b3650e46..dca6507e2ec61 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -29,80 +29,67 @@ import java.lang.foreign.MemoryLayout; import java.lang.foreign.StructLayout; -import java.lang.foreign.ValueLayout; import java.util.ArrayList; -import java.util.List; import java.util.Map; import static java.lang.foreign.ValueLayout.JAVA_INT; +/** + * Utility class for the call states to capture. + */ public final class CapturableState { public static final StructLayout LAYOUT; - private static final Map LOOKUP; + private static final Map MASKS; static { - List supported; - if (OperatingSystem.isWindows()) { - supported = List.of( - new CapturableState("GetLastError", JAVA_INT, 1 << 0), - new CapturableState("WSAGetLastError", JAVA_INT, 1 << 1), - new CapturableState("errno", JAVA_INT, 1 << 2) + LAYOUT = MemoryLayout.structLayout( + JAVA_INT.withName("GetLastError"), + JAVA_INT.withName("WSAGetLastError"), + JAVA_INT.withName("errno")); + MASKS = Map.of( + "GetLastError", 1 << 0, + "WSAGetLastError", 1 << 1, + "errno", 1 << 2 ); } else { - supported = List.of(new CapturableState("errno", JAVA_INT, 1 << 2)); - } - - MemoryLayout[] stateLayouts = new MemoryLayout[supported.size()]; - @SuppressWarnings({"unchecked", "rawtypes"}) - Map.Entry[] entries = new Map.Entry[supported.size()]; - int i = 0; - for (var each : supported) { - stateLayouts[i] = each.layout; - entries[i] = Map.entry(each.stateName, each); - i++; + LAYOUT = MemoryLayout.structLayout( + JAVA_INT.withName("errno")); + MASKS = Map.of( + "errno", 1 << 2 + ); } - LAYOUT = MemoryLayout.structLayout(stateLayouts); - LOOKUP = Map.ofEntries(entries); } - public final String stateName; - public final ValueLayout layout; - public final int mask; - - private CapturableState(String stateName, ValueLayout layout, int mask) { - this.stateName = stateName; - this.layout = layout.withName(stateName); - this.mask = mask; + private CapturableState() { } - public static CapturableState forName(String name) { - var ret = LOOKUP.get(name); + /** + * Returns the mask for a supported capturable state, or throw an + * IllegalArgumentException if no supported state with this name exists. + */ + public static int maskFromName(String name) { + var ret = MASKS.get(name); if (ret == null) { throw new IllegalArgumentException( "Unknown name: " + name + ", must be one of: " - + LOOKUP.keySet()); + + MASKS.keySet()); } return ret; } /** - * Returns a list-like display string for a captured state mask. + * Returns a collection-like display string for a captured state mask. * Enclosed with brackets. */ public static String displayString(int mask) { var displayList = new ArrayList<>(); // unordered - for (var e : LOOKUP.values()) { - if ((mask & e.mask) != 0) { - displayList.add(e.stateName); + for (var e : MASKS.entrySet()) { + if ((mask & e.getValue()) != 0) { + displayList.add(e.getKey()); } } return displayList.toString(); } - - @Override - public String toString() { - return stateName; - } } From 0700fb053df23a61467deb6f6696cd95b6e467b8 Mon Sep 17 00:00:00 2001 From: liach Date: Tue, 6 May 2025 17:06:43 -0500 Subject: [PATCH 10/11] Keep in sync comments --- src/hotspot/share/prims/downcallLinker.cpp | 2 +- .../share/classes/jdk/internal/foreign/abi/CapturableState.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/prims/downcallLinker.cpp b/src/hotspot/share/prims/downcallLinker.cpp index 6486143981774..5dde825d75f02 100644 --- a/src/hotspot/share/prims/downcallLinker.cpp +++ b/src/hotspot/share/prims/downcallLinker.cpp @@ -32,7 +32,7 @@ // We call this from _thread_in_native, right after a downcall JVM_LEAF(void, DowncallLinker::capture_state(int32_t* value_ptr, int captured_state_mask)) - // keep in synch with jdk.internal.foreign.abi.PreservableValues + // keep in synch with jdk.internal.foreign.abi.CapturableState enum PreservableValues { NONE = 0, GET_LAST_ERROR = 1, diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index dca6507e2ec61..dc1a227cb70cf 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -40,6 +40,7 @@ public final class CapturableState { public static final StructLayout LAYOUT; + // Keep in synch with DowncallLinker::capture_state private static final Map MASKS; static { From 5986dbff798ac56c24282e046253934d1b5c3566 Mon Sep 17 00:00:00 2001 From: liach Date: Tue, 6 May 2025 17:07:53 -0500 Subject: [PATCH 11/11] Indicate source file --- .../share/classes/jdk/internal/foreign/abi/CapturableState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index dc1a227cb70cf..d22c23b03a10b 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -40,7 +40,7 @@ public final class CapturableState { public static final StructLayout LAYOUT; - // Keep in synch with DowncallLinker::capture_state + // Keep in synch with DowncallLinker::capture_state in downcallLinker.cpp private static final Map MASKS; static {