Skip to content

Commit bc85dc3

Browse files
committed
[GR-40561] [GR-40562] Improve native image Windows support on JDK 19
PullRequest: graal/12497
2 parents d9f5d62 + aa89cb7 commit bc85dc3

File tree

6 files changed

+97
-67
lines changed

6 files changed

+97
-67
lines changed

substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsNativeLibrarySupport.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import java.io.FileDescriptor;
2828

29+
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
2930
import org.graalvm.nativeimage.Platform;
3031
import org.graalvm.nativeimage.Platforms;
3132
import org.graalvm.nativeimage.c.type.CCharPointer;
@@ -37,17 +38,30 @@
3738
import com.oracle.svm.core.Isolates;
3839
import com.oracle.svm.core.annotate.Alias;
3940
import com.oracle.svm.core.annotate.TargetClass;
41+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
42+
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
43+
import com.oracle.svm.core.feature.InternalFeature;
4044
import com.oracle.svm.core.jdk.JNIPlatformNativeLibrarySupport;
4145
import com.oracle.svm.core.jdk.Jvm;
4246
import com.oracle.svm.core.jdk.NativeLibrarySupport;
4347
import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport;
4448
import com.oracle.svm.core.log.Log;
45-
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
4649
import com.oracle.svm.core.windows.headers.FileAPI;
4750
import com.oracle.svm.core.windows.headers.LibLoaderAPI;
4851
import com.oracle.svm.core.windows.headers.WinBase.HMODULE;
4952
import com.oracle.svm.core.windows.headers.WinSock;
5053

54+
@AutomaticallyRegisteredFeature
55+
@Platforms(Platform.WINDOWS.class)
56+
class WindowsNativeLibraryFeature implements InternalFeature {
57+
@Override
58+
public void duringSetup(DuringSetupAccess access) {
59+
if (JavaVersionUtil.JAVA_SPEC >= 19) {
60+
NativeLibrarySupport.singleton().preregisterUninitializedBuiltinLibrary("extnet");
61+
}
62+
}
63+
}
64+
5165
@AutomaticallyRegisteredImageSingleton(PlatformNativeLibrarySupport.class)
5266
class WindowsNativeLibrarySupport extends JNIPlatformNativeLibrarySupport {
5367

@@ -86,6 +100,10 @@ private static void loadNetLibrary() {
86100
} else {
87101
NativeLibrarySupport.singleton().registerInitializedBuiltinLibrary("net");
88102
}
103+
if (JavaVersionUtil.JAVA_SPEC >= 19) {
104+
NativeLibrarySupport.singleton().registerInitializedBuiltinLibrary("extnet");
105+
System.loadLibrary("extnet");
106+
}
89107
}
90108

91109
@Override

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/JNILibraryInitializer.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
import org.graalvm.collections.EconomicMap;
3333
import org.graalvm.collections.Equivalence;
34+
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
35+
import org.graalvm.nativeimage.Platform;
3436
import org.graalvm.nativeimage.c.function.CFunctionPointer;
3537
import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer;
3638
import org.graalvm.nativeimage.c.type.VoidPointer;
@@ -85,6 +87,10 @@ public boolean fillCGlobalDataMap(Collection<String> staticLibNames) {
8587
// TODO: This check should be removed when all static libs will have JNI_OnLoad function
8688
ArrayList<String> localStaticLibNames = new ArrayList<>(staticLibNames);
8789
localStaticLibNames.retainAll(libsWithOnLoad);
90+
if (JavaVersionUtil.JAVA_SPEC >= 19 && Platform.includedIn(Platform.WINDOWS.class)) {
91+
/* libextnet on Windows (introduced in Java 19) does not contain an OnLoad method. */
92+
localStaticLibNames.remove("extnet");
93+
}
8894
boolean mapIsChanged = false;
8995
for (String libName : localStaticLibNames) {
9096
if (!onLoadCGlobalDataMap.containsKey(libName)) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_LambdaForm.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,24 @@
2424
*/
2525
package com.oracle.svm.core.methodhandles;
2626

27+
import org.graalvm.nativeimage.hosted.FieldValueTransformer;
28+
2729
import com.oracle.svm.core.annotate.Alias;
2830
import com.oracle.svm.core.annotate.RecomputeFieldValue;
2931
import com.oracle.svm.core.annotate.Substitute;
3032
import com.oracle.svm.core.annotate.TargetClass;
3133
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
34+
import com.oracle.svm.util.ReflectionUtil;
3235

3336
@TargetClass(className = "java.lang.invoke.LambdaForm")
3437
public final class Target_java_lang_invoke_LambdaForm {
3538

3639
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)//
3740
Target_java_lang_invoke_MemberName vmentry;
3841

42+
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = LambdaFormCacheTransformer.class)//
43+
volatile Object transformCache;
44+
3945
@Alias
4046
native String lambdaName();
4147

@@ -64,6 +70,19 @@ private boolean forceInterpretation() {
6470
native Object interpretWithArguments(Object... argumentValues) throws Throwable;
6571
}
6672

73+
final class LambdaFormCacheTransformer implements FieldValueTransformer {
74+
75+
@Override
76+
public Object transform(Object receiver, Object originalValue) {
77+
Class<?> lambdaFormClass = ReflectionUtil.lookupClass(false, "java.lang.invoke.LambdaForm");
78+
if (lambdaFormClass.isInstance(originalValue)) {
79+
// Stores the original LambdaForm for a customized one.
80+
return originalValue;
81+
}
82+
return null;
83+
}
84+
}
85+
6786
@TargetClass(className = "java.lang.invoke.LambdaForm", innerClass = "NamedFunction")
6887
final class Target_java_lang_invoke_LambdaForm_NamedFunction {
6988
@Alias

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_internal_vm_Continuation.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ final class Target_jdk_internal_vm_Continuation__WithoutLoom {
5555
static boolean yield(Target_jdk_internal_vm_ContinuationScope scope) {
5656
throw VMError.shouldNotReachHere();
5757
}
58+
59+
@Substitute
60+
static void pin() {
61+
throw VMError.shouldNotReachHere();
62+
}
63+
64+
@Substitute
65+
static void unpin() {
66+
throw VMError.shouldNotReachHere();
67+
}
5868
}
5969

6070
@TargetClass(className = "Continuation", classNameProvider = Package_jdk_internal_vm_helper.class, onlyWith = LoomJDK.class)

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,13 @@ private static void registerSunMSCAPIConfig(BeforeAnalysisAccess a) {
462462
"java.security.KeyException", "java.security.KeyStoreException", "java.security.ProviderException",
463463
"java.security.SignatureException", "java.lang.OutOfMemoryError");
464464

465-
a.registerReachabilityHandler(SecurityServicesFeature::registerLoadKeysOrCertificateChains,
466-
method(a, "sun.security.mscapi.CKeyStore", "loadKeysOrCertificateChains", String.class));
465+
if (JavaVersionUtil.JAVA_SPEC >= 19) {
466+
a.registerReachabilityHandler(SecurityServicesFeature::registerLoadKeysOrCertificateChains,
467+
method(a, "sun.security.mscapi.CKeyStore", "loadKeysOrCertificateChains", String.class, int.class));
468+
} else {
469+
a.registerReachabilityHandler(SecurityServicesFeature::registerLoadKeysOrCertificateChains,
470+
method(a, "sun.security.mscapi.CKeyStore", "loadKeysOrCertificateChains", String.class));
471+
}
467472
a.registerReachabilityHandler(SecurityServicesFeature::registerGenerateCKeyPair,
468473
method(a, "sun.security.mscapi.CKeyPairGenerator$RSA", "generateCKeyPair", String.class, int.class, String.class));
469474
a.registerReachabilityHandler(SecurityServicesFeature::registerCPrivateKeyOf,
@@ -612,12 +617,23 @@ private static Map<String, Set<Service>> computeAvailableServices() {
612617
Map<String, Set<Service>> availableServices = new HashMap<>();
613618
for (Provider provider : Security.getProviders()) {
614619
for (Service s : provider.getServices()) {
615-
availableServices.computeIfAbsent(s.getType(), t -> new HashSet<>()).add(s);
620+
if (isValid(s)) {
621+
availableServices.computeIfAbsent(s.getType(), t -> new HashSet<>()).add(s);
622+
}
616623
}
617624
}
618625
return availableServices;
619626
}
620627

628+
/**
629+
* Check is service is valid. See {@code java.security.Provider.Service#isValid()}.
630+
*
631+
* Presumably, this is only needed due to an upstream bug introduced in JDK 19 [GR-40544].
632+
*/
633+
private static boolean isValid(Service s) {
634+
return (s.getType() != null) && (s.getAlgorithm() != null) && (s.getClassName() != null);
635+
}
636+
621637
/**
622638
* Return a Function which given the serviceType as a String will return the corresponding
623639
* constructor parameter Class, or null.

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java

Lines changed: 24 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -50,66 +50,40 @@
5050
@Platforms({InternalPlatform.PLATFORM_JNI.class})
5151
@AutomaticallyRegisteredFeature
5252
class JNIRegistrationJavaNet extends JNIRegistrationUtil implements InternalFeature {
53-
54-
private boolean hasExtendedOptionsImpl;
5553
private boolean hasPlatformSocketOptions;
5654

5755
@Override
5856
public void duringSetup(DuringSetupAccess a) {
59-
hasExtendedOptionsImpl = a.findClassByName("sun.net.ExtendedOptionsImpl") != null;
60-
hasPlatformSocketOptions = a.findClassByName("jdk.net.ExtendedSocketOptions$PlatformSocketOptions") != null;
61-
57+
/* jdk.net.ExtendedSocketOptions is only available if the jdk.net module is loaded. */
58+
this.hasPlatformSocketOptions = a.findClassByName("jdk.net.ExtendedSocketOptions$PlatformSocketOptions") != null;
6259
rerunClassInit(a, "java.net.DatagramPacket", "java.net.InetAddress", "java.net.NetworkInterface",
6360
/* Stores a default SSLContext in a static field. */
6461
"javax.net.ssl.SSLContext");
65-
if (JavaVersionUtil.JAVA_SPEC <= 17) {
62+
if (JavaVersionUtil.JAVA_SPEC < 19) {
6663
/* Removed by https://bugs.openjdk.java.net/browse/JDK-8253119 */
6764
rerunClassInit(a, "java.net.SocketInputStream", "java.net.SocketOutputStream",
6865
/* Caches networking properties. */
6966
"java.net.DefaultDatagramSocketImplFactory");
70-
}
71-
if (isWindows()) {
72-
rerunClassInit(a, "java.net.DualStackPlainDatagramSocketImpl", "java.net.TwoStacksPlainDatagramSocketImpl");
73-
if (JavaVersionUtil.JAVA_SPEC <= 17) {
74-
/* Removed by https://bugs.openjdk.java.net/browse/JDK-8253119 */
67+
if (isWindows()) {
7568
/* Caches networking properties. */
76-
rerunClassInit(a, "java.net.PlainSocketImpl");
77-
}
78-
} else {
79-
assert isPosix();
80-
if (JavaVersionUtil.JAVA_SPEC <= 17) {
81-
/* Removed by https://bugs.openjdk.java.net/browse/JDK-8253119 */
69+
rerunClassInit(a, "java.net.PlainSocketImpl", "java.net.DualStackPlainDatagramSocketImpl", "java.net.TwoStacksPlainDatagramSocketImpl");
70+
} else {
71+
assert isPosix();
8272
rerunClassInit(a, "java.net.PlainDatagramSocketImpl", "java.net.PlainSocketImpl");
83-
}
84-
if (hasExtendedOptionsImpl) {
85-
rerunClassInit(a, "sun.net.ExtendedOptionsImpl");
86-
}
87-
88-
if (JavaVersionUtil.JAVA_SPEC <= 17) {
89-
/* Removed by https://bugs.openjdk.java.net/browse/JDK-8253119 */
9073
rerunClassInit(a, "java.net.AbstractPlainDatagramSocketImpl", "java.net.AbstractPlainSocketImpl");
9174
}
75+
}
9276

93-
if (hasPlatformSocketOptions) {
94-
/*
95-
* The libextnet was actually introduced in Java 9, but the support for Linux and
96-
* Darwin was added later in Java 10 and Java 11 respectively.
97-
*/
98-
rerunClassInit(a, "jdk.net.ExtendedSocketOptions", "jdk.net.ExtendedSocketOptions$PlatformSocketOptions");
99-
/*
100-
* Different JDK versions are not consistent about the "ext" in the package name. We
101-
* need to support both variants.
102-
*/
103-
if (a.findClassByName("sun.net.ext.ExtendedSocketOptions") != null) {
104-
rerunClassInit(a, "sun.net.ext.ExtendedSocketOptions");
105-
} else {
106-
rerunClassInit(a, "sun.net.ExtendedSocketOptions");
107-
}
108-
}
109-
if (isDarwin()) {
110-
/* Caches the default interface. */
111-
rerunClassInit(a, "java.net.DefaultInterface");
112-
}
77+
if (this.hasPlatformSocketOptions && (isPosix() || JavaVersionUtil.JAVA_SPEC >= 19)) {
78+
/*
79+
* The libextnet was actually introduced in Java 9, but the support for Linux, Darwin
80+
* and Windows was added later in Java 10, Java 11 and Java 19 respectively.
81+
*/
82+
rerunClassInit(a, "jdk.net.ExtendedSocketOptions", "jdk.net.ExtendedSocketOptions$PlatformSocketOptions", "sun.net.ext.ExtendedSocketOptions");
83+
}
84+
if (isDarwin()) {
85+
/* Caches the default interface. */
86+
rerunClassInit(a, "java.net.DefaultInterface");
11387
}
11488
}
11589

@@ -184,16 +158,10 @@ public void beforeAnalysis(BeforeAnalysisAccess a) {
184158
method(a, "java.net.PlainSocketImpl", "localAddress", int.class, clazz(a, "java.net.InetAddressContainer")));
185159
}
186160
}
187-
if (isPosix()) {
188-
if (hasExtendedOptionsImpl) {
189-
a.registerReachabilityHandler(JNIRegistrationJavaNet::registerExtendedOptionsImplInit,
190-
method(a, "sun.net.ExtendedOptionsImpl", "init"));
191-
}
192-
if (hasPlatformSocketOptions) {
193-
/* Support for the libextnet. */
194-
a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlatformSocketOptionsCreate,
195-
method(a, "jdk.net.ExtendedSocketOptions$PlatformSocketOptions", "create"));
196-
}
161+
if (this.hasPlatformSocketOptions && (isPosix() || JavaVersionUtil.JAVA_SPEC >= 19)) {
162+
/* Support for the libextnet. */
163+
a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlatformSocketOptionsCreate,
164+
method(a, "jdk.net.ExtendedSocketOptions$PlatformSocketOptions", "create"));
197165
}
198166

199167
a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDefaultProxySelectorInit, method(a, "sun.net.spi.DefaultProxySelector", "init"));
@@ -310,22 +278,15 @@ private static void registerDualStackPlainSocketImplLocalAddress(DuringAnalysisA
310278
RuntimeJNIAccess.register(fields(a, "java.net.InetAddressContainer", "addr"));
311279
}
312280

313-
private static void registerExtendedOptionsImplInit(DuringAnalysisAccess a) {
314-
RuntimeJNIAccess.register(clazz(a, "jdk.net.SocketFlow"));
315-
RuntimeJNIAccess.register(fields(a, "jdk.net.SocketFlow", "status", "priority", "bandwidth"));
316-
317-
RuntimeJNIAccess.register(clazz(a, "jdk.net.SocketFlow$Status"));
318-
RuntimeJNIAccess.register(fields(a, "jdk.net.SocketFlow$Status", "NO_STATUS", "OK", "NO_PERMISSION", "NOT_CONNECTED", "NOT_SUPPORTED", "ALREADY_CREATED", "IN_PROGRESS", "OTHER"));
319-
}
320-
321281
private static void registerPlatformSocketOptionsCreate(DuringAnalysisAccess a) {
322282
String implClassName;
323283
if (isLinux()) {
324284
implClassName = "jdk.net.LinuxSocketOptions";
325285
} else if (isDarwin()) {
326286
implClassName = "jdk.net.MacOSXSocketOptions";
327287
} else {
328-
throw VMError.shouldNotReachHere("Unexpected platform");
288+
VMError.guarantee(isWindows(), "Unexpected platform");
289+
implClassName = "jdk.net.WindowsSocketOptions";
329290
}
330291
RuntimeReflection.register(clazz(a, implClassName));
331292
RuntimeReflection.register(constructor(a, implClassName));

0 commit comments

Comments
 (0)