From 091c9f4156659252e34c53bc3c30f1953858d87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksandar=20Pejovi=C4=87?= Date: Sat, 30 Nov 2019 14:36:20 +0100 Subject: [PATCH 1/8] Clean up JNIRegistrationJavaNet.duringSetup --- .../hosted/jdk/JNIRegistrationJavaNet.java | 61 ++++++++++--------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java index 91eda3698bde..2e12445e158e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java @@ -48,28 +48,37 @@ class JNIRegistrationJavaNet extends JNIRegistrationUtil implements Feature { @Override public void duringSetup(DuringSetupAccess a) { - rerunClassInit(a, "java.net.NetworkInterface", "java.net.DefaultInterface", - "java.net.InetAddress", "java.net.Inet4AddressImpl", "java.net.Inet6AddressImpl", - "java.net.SocketInputStream", "java.net.SocketOutputStream", - "java.net.DatagramPacket", - "java.net.AbstractPlainSocketImpl", "java.net.AbstractPlainDatagramSocketImpl"); - if (isPosix()) { - rerunClassInit(a, "java.net.PlainSocketImpl", "java.net.PlainDatagramSocketImpl"); - if (JavaVersionUtil.JAVA_SPEC <= 8) { - rerunClassInit(a, "sun.net.ExtendedOptionsImpl"); - } - } + rerunClassInit(a, "java.net.DatagramPacket", "java.net.InetAddress", "java.net.NetworkInterface", + "java.net.SocketInputStream", "java.net.SocketOutputStream"); if (isWindows()) { rerunClassInit(a, "java.net.DualStackPlainDatagramSocketImpl", "java.net.TwoStacksPlainDatagramSocketImpl"); - if (JavaVersionUtil.JAVA_SPEC >= 11) { + if (JavaVersionUtil.JAVA_SPEC < 11) { + rerunClassInit(a, "java.net.DualStackPlainSocketImpl", "java.net.TwoStacksPlainSocketImpl"); + } else { + /* The other implementations are merged into PlainSocketImpl. */ rerunClassInit(a, "java.net.PlainSocketImpl"); + } + } else { + assert isPosix(); + rerunClassInit(a, "java.net.PlainDatagramSocketImpl", "java.net.PlainSocketImpl"); + if (JavaVersionUtil.JAVA_SPEC < 9) { + rerunClassInit(a, "sun.net.ExtendedOptionsImpl"); } else { - rerunClassInit(a, "java.net.DualStackPlainSocketImpl", "java.net.TwoStacksPlainSocketImpl"); + /* These two classes cache whether SO_REUSEPORT, added in Java 9, is supported. */ + rerunClassInit(a, "java.net.AbstractPlainDatagramSocketImpl", "java.net.AbstractPlainSocketImpl"); + } + if (JavaVersionUtil.JAVA_SPEC >= 11) { + /* + * The libextnet was actually introduced in Java 9, but the support for Linux and + * Darwin was added later in Java 10 and Java 11 respectively. + */ + rerunClassInit(a, "jdk.net.ExtendedSocketOptions", "sun.net.ext.ExtendedSocketOptions", + "jdk.net.ExtendedSocketOptions$PlatformSocketOptions"); + } + if (isDarwin()) { + /* Caches the default interface. */ + rerunClassInit(a, "java.net.DefaultInterface"); } - } - - if (JavaVersionUtil.JAVA_SPEC >= 11) { - rerunClassInit(a, "jdk.net.ExtendedSocketOptions", "sun.net.ext.ExtendedSocketOptions", "jdk.net.ExtendedSocketOptions$PlatformSocketOptions"); } } @@ -126,10 +135,15 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplInitProto, method(a, "java.net.PlainSocketImpl", "initProto")); - if (JavaVersionUtil.JAVA_SPEC <= 8) { + if (JavaVersionUtil.JAVA_SPEC < 9) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerExtendedOptionsImplInit, method(a, "sun.net.ExtendedOptionsImpl", "init")); } + if (JavaVersionUtil.JAVA_SPEC >= 11) { + /* Support for the libextnet. */ + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlatformSocketOptionsCreate, + method(a, "jdk.net.ExtendedSocketOptions$PlatformSocketOptions", "create")); + } } if (isWindows()) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainDatagramSocketImplInit, @@ -140,11 +154,6 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplInitProto, method(a, "java.net." + plainSocketImpl, "initIDs")); } - - if (JavaVersionUtil.JAVA_SPEC >= 11) { - a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlatformSocketOptionsCreate, - method(a, "jdk.net.ExtendedSocketOptions$PlatformSocketOptions", "create")); - } } private static void registerInitInetAddressIDs(DuringAnalysisAccess a) { @@ -249,12 +258,6 @@ private static void registerPlatformSocketOptionsCreate(DuringAnalysisAccess a) implClassName = "jdk.net.LinuxSocketOptions"; } else if (isDarwin()) { implClassName = "jdk.net.MacOSXSocketOptions"; - } else if (isWindows()) { - /* - * Windows uses PlatformSocketOptions directly, without any subclass and without any - * reflective instantiation. - */ - return; } else { throw VMError.shouldNotReachHere("Unexpected platform"); } From 7e5272cde15051a90dcaf38a580b6500e7c46df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksandar=20Pejovi=C4=87?= Date: Sat, 30 Nov 2019 18:51:46 +0100 Subject: [PATCH 2/8] Clean up JNIRegistrationJavaNet.registerInitInetAddressIDs --- .../hosted/jdk/JNIRegistrationJavaNet.java | 56 ++++++++++--------- .../hosted/jdk/JNIRegistrationJavaNio.java | 7 +++ 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java index 2e12445e158e..e73e64c7aaa5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java @@ -25,7 +25,7 @@ package com.oracle.svm.hosted.jdk; import java.net.DatagramPacket; -import java.net.InetAddress; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; @@ -93,20 +93,20 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { "java.net.ProtocolException", "java.net.NoRouteToHostException", "java.net.SocketTimeoutException", "java.net.PortUnreachableException", "sun.net.ConnectionResetException"); - /* Reuse same lambda for registerInitInetAddressIDs to ensure it only gets called once */ - Consumer registerInitInetAddressIDs = JNIRegistrationJavaNet::registerInitInetAddressIDs; /* * InetAddress, Inet4Address, and Inet6Address are registered from many places in the JDK, * so it does not make sense to separate them. */ + Consumer registerInitInetAddressIDs = JNIRegistrationJavaNet::registerInitInetAddressIDs; a.registerReachabilityHandler(registerInitInetAddressIDs, method(a, "java.net.InetAddress", "init"), - method(a, "java.net.Inet4Address", "init"), - method(a, "java.net.Inet6Address", "init"), + /* The following methods call initInetAddressIDs directly. */ method(a, "java.net.NetworkInterface", "init"), - method(a, "sun.nio.ch.IOUtil", "initIDs"), - clazz(a, "java.net.Inet4AddressImpl"), - clazz(a, "java.net.Inet6AddressImpl")); + method(a, "java.net.Inet4AddressImpl", "lookupAllHostAddr", String.class), + method(a, "java.net.Inet6AddressImpl", "lookupAllHostAddr", String.class)); + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerInetAddressLoadImpl, + method(a, "java.net.InetAddress", "loadImpl", String.class)); + if (isPosix()) { a.registerReachabilityHandler(registerInitInetAddressIDs, method(a, "java.net.PlainSocketImpl", "initProto"), @@ -156,36 +156,42 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { } } - private static void registerInitInetAddressIDs(DuringAnalysisAccess a) { - JNIRuntimeAccess.register(method(a, "java.net.InetAddress", "anyLocalAddress")); - JNIRuntimeAccess.register(fields(a, "java.net.InetAddress", "holder", "preferIPv6Address")); - - RuntimeReflection.register(clazz(a, "java.net.InetAddressImpl")); - RuntimeReflection.register(clazz(a, "java.net.Inet4AddressImpl")); - RuntimeReflection.register(constructor(a, "java.net.Inet4AddressImpl")); - RuntimeReflection.register(clazz(a, "java.net.Inet6AddressImpl")); - RuntimeReflection.register(constructor(a, "java.net.Inet6AddressImpl")); + @Override + public void cleanup() { + /* Reset the static state. */ + initInetAddressIDs.set(false); + } - JNIRuntimeAccess.register(fields(a, "java.net.InetAddress$InetAddressHolder", "address", "family", "hostName", "originalHostName")); + private static AtomicBoolean initInetAddressIDs = new AtomicBoolean(); - JNIRuntimeAccess.register(fields(a, "java.net.InetAddressContainer", "addr")); + static void registerInitInetAddressIDs(DuringAnalysisAccess a) { + if (!initInetAddressIDs.compareAndSet(false, true)) { + return; /* Already registered. */ + } - JNIRuntimeAccess.register(constructor(a, "java.net.InetSocketAddress", InetAddress.class, int.class)); + /* Java_java_net_InetAddress_init */ + JNIRuntimeAccess.register(fields(a, "java.net.InetAddress", "holder", "preferIPv6Address")); + JNIRuntimeAccess.register(fields(a, "java.net.InetAddress$InetAddressHolder", "address", "family", "hostName", "originalHostName")); - JNIRuntimeAccess.register(clazz(a, "java.net.Inet4Address")); + /* Java_java_net_Inet4Address_init */ JNIRuntimeAccess.register(constructor(a, "java.net.Inet4Address")); - JNIRuntimeAccess.register(clazz(a, "java.net.Inet6Address")); + /* Java_java_net_Inet6Address_init */ JNIRuntimeAccess.register(constructor(a, "java.net.Inet6Address")); JNIRuntimeAccess.register(fields(a, "java.net.Inet6Address", "holder6")); - if (JavaVersionUtil.JAVA_SPEC <= 11) { + if (JavaVersionUtil.JAVA_SPEC < 13) { JNIRuntimeAccess.register(fields(a, "java.net.Inet6Address", "cached_scope_id")); } - - JNIRuntimeAccess.register(clazz(a, "java.net.Inet6Address$Inet6AddressHolder")); JNIRuntimeAccess.register(fields(a, "java.net.Inet6Address$Inet6AddressHolder", "ipaddress", "scope_id", "scope_id_set", "scope_ifname")); } + private static void registerInetAddressLoadImpl(DuringAnalysisAccess a) { + RuntimeReflection.register(clazz(a, "java.net.Inet4AddressImpl")); + RuntimeReflection.register(constructor(a, "java.net.Inet4AddressImpl")); + RuntimeReflection.register(clazz(a, "java.net.Inet6AddressImpl")); + RuntimeReflection.register(constructor(a, "java.net.Inet6AddressImpl")); + } + private static void registerNetworkInterfaceInit(DuringAnalysisAccess a) { JNIRuntimeAccess.register(constructor(a, "java.net.NetworkInterface")); JNIRuntimeAccess.register(fields(a, "java.net.NetworkInterface", "name", "displayName", "index", "addrs", "bindings", "childs")); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java index 07b98b85efbe..8b95bceb7bf0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java @@ -100,6 +100,13 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { } a.registerReachabilityHandler(JNIRegistrationJavaNio::registerConnectionCreateInetSocketAddress, method(a, "com.sun.jndi.ldap.Connection", "createInetSocketAddress", String.class, int.class)); + + Consumer registerInitInetAddressIDs = JNIRegistrationJavaNet::registerInitInetAddressIDs; + if (JavaVersionUtil.JAVA_SPEC < 9) { + a.registerReachabilityHandler(registerInitInetAddressIDs, method(a, "sun.nio.ch.IOUtil", "initIDs")); + } else { + a.registerReachabilityHandler(registerInitInetAddressIDs, method(a, "sun.nio.ch.Net", "initIDs")); + } } private static void registerServerSocketChannelImplInitIDs(DuringAnalysisAccess a) { From 7d8aef84b03bf82b6327129c3a359c00e448f6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksandar=20Pejovi=C4=87?= Date: Sat, 30 Nov 2019 19:03:09 +0100 Subject: [PATCH 3/8] Clean up JNIRegistrationJavaNet.registerNetworkInterfaceInit --- .../svm/hosted/jdk/JNIRegistrationJavaNet.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java index e73e64c7aaa5..c2236f284b7c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java @@ -100,8 +100,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { Consumer registerInitInetAddressIDs = JNIRegistrationJavaNet::registerInitInetAddressIDs; a.registerReachabilityHandler(registerInitInetAddressIDs, method(a, "java.net.InetAddress", "init"), - /* The following methods call initInetAddressIDs directly. */ - method(a, "java.net.NetworkInterface", "init"), + /* The next two methods call initInetAddressIDs directly. */ method(a, "java.net.Inet4AddressImpl", "lookupAllHostAddr", String.class), method(a, "java.net.Inet6AddressImpl", "lookupAllHostAddr", String.class)); a.registerReachabilityHandler(JNIRegistrationJavaNet::registerInetAddressLoadImpl, @@ -119,7 +118,6 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); } - /* Reuse same lambda for registerNetworkInterfaceInit to ensure it only gets called once */ Consumer registerNetworkInterfaceInit = JNIRegistrationJavaNet::registerNetworkInterfaceInit; a.registerReachabilityHandler(registerNetworkInterfaceInit, method(a, "java.net.NetworkInterface", "init")); @@ -160,6 +158,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { public void cleanup() { /* Reset the static state. */ initInetAddressIDs.set(false); + networkInterfaceInit.set(false); } private static AtomicBoolean initInetAddressIDs = new AtomicBoolean(); @@ -192,18 +191,23 @@ private static void registerInetAddressLoadImpl(DuringAnalysisAccess a) { RuntimeReflection.register(constructor(a, "java.net.Inet6AddressImpl")); } + private static AtomicBoolean networkInterfaceInit = new AtomicBoolean(); + private static void registerNetworkInterfaceInit(DuringAnalysisAccess a) { + if (!networkInterfaceInit.compareAndSet(false, true)) { + return; /* Already registered. */ + } + JNIRuntimeAccess.register(constructor(a, "java.net.NetworkInterface")); JNIRuntimeAccess.register(fields(a, "java.net.NetworkInterface", "name", "displayName", "index", "addrs", "bindings", "childs")); - RuntimeReflection.register(clazz(a, "[Ljava.net.NetworkInterface;")); - if (isPosix()) { JNIRuntimeAccess.register(fields(a, "java.net.NetworkInterface", "virtual", "parent", "defaultIndex")); } JNIRuntimeAccess.register(constructor(a, "java.net.InterfaceAddress")); JNIRuntimeAccess.register(fields(a, "java.net.InterfaceAddress", "address", "broadcast", "maskLength")); - RuntimeReflection.register(clazz(a, "[Ljava.net.InterfaceAddress;")); + + registerInitInetAddressIDs(a); } private static void registerDatagramPacketInit(DuringAnalysisAccess a) { From 96406ef7f6f3eb6d43be31afd97ce869ce607dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksandar=20Pejovi=C4=87?= Date: Sun, 1 Dec 2019 20:00:52 +0100 Subject: [PATCH 4/8] Clean up JNIRegistrationJavaNet.beforeAnalysis --- .../hosted/jdk/JNIRegistrationJavaNet.java | 72 +++++++++---------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java index c2236f284b7c..a956d13da58a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java @@ -89,9 +89,10 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { * unconditional registration is cheap because the exception classes have no dependency on * the actual network implementation. Therefore, we register them unconditionally. */ - registerForThrowNew(a, "java.net.SocketException", "java.net.ConnectException", "java.net.BindException", "java.net.UnknownHostException", - "java.net.ProtocolException", "java.net.NoRouteToHostException", - "java.net.SocketTimeoutException", "java.net.PortUnreachableException", "sun.net.ConnectionResetException"); + registerForThrowNew(a, "java.net.BindException", "java.net.ConnectException", + "java.net.NoRouteToHostException", "java.net.PortUnreachableException", + "java.net.ProtocolException", "java.net.SocketException", "java.net.SocketTimeoutException", + "java.net.UnknownHostException", "sun.net.ConnectionResetException"); /* * InetAddress, Inet4Address, and Inet6Address are registered from many places in the JDK, @@ -106,18 +107,6 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerInetAddressLoadImpl, method(a, "java.net.InetAddress", "loadImpl", String.class)); - if (isPosix()) { - a.registerReachabilityHandler(registerInitInetAddressIDs, - method(a, "java.net.PlainSocketImpl", "initProto"), - method(a, "java.net.PlainDatagramSocketImpl", "init")); - } - if (isWindows()) { - String plainSocketImpl = JavaVersionUtil.JAVA_SPEC >= 11 ? "PlainSocketImpl" : "DualStackPlainSocketImpl"; - a.registerReachabilityHandler(registerInitInetAddressIDs, - method(a, "java.net." + plainSocketImpl, "initIDs"), - method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); - } - Consumer registerNetworkInterfaceInit = JNIRegistrationJavaNet::registerNetworkInterfaceInit; a.registerReachabilityHandler(registerNetworkInterfaceInit, method(a, "java.net.NetworkInterface", "init")); @@ -125,7 +114,25 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDatagramPacketInit, method(a, "java.net.DatagramPacket", "init")); - if (isPosix()) { + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDatagramSocketCheckOldImpl, + method(a, "java.net.DatagramSocket", "checkOldImpl")); + + if (isWindows()) { + String plainSocketImpl = JavaVersionUtil.JAVA_SPEC >= 11 ? "PlainSocketImpl" : "DualStackPlainSocketImpl"; + a.registerReachabilityHandler(registerInitInetAddressIDs, + method(a, "java.net." + plainSocketImpl, "initIDs"), + method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainDatagramSocketImplInit, + method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); + a.registerReachabilityHandler(registerNetworkInterfaceInit, + method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplInitProto, + method(a, "java.net." + plainSocketImpl, "initIDs")); + } else { + assert isPosix(); + a.registerReachabilityHandler(registerInitInetAddressIDs, + method(a, "java.net.PlainSocketImpl", "initProto"), + method(a, "java.net.PlainDatagramSocketImpl", "init")); a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainDatagramSocketImplInit, method(a, "java.net.PlainDatagramSocketImpl", "init")); a.registerReachabilityHandler(registerNetworkInterfaceInit, @@ -143,15 +150,6 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { method(a, "jdk.net.ExtendedSocketOptions$PlatformSocketOptions", "create")); } } - if (isWindows()) { - a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainDatagramSocketImplInit, - method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); - a.registerReachabilityHandler(registerNetworkInterfaceInit, - method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); - String plainSocketImpl = JavaVersionUtil.JAVA_SPEC >= 11 ? "PlainSocketImpl" : "DualStackPlainSocketImpl"; - a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplInitProto, - method(a, "java.net." + plainSocketImpl, "initIDs")); - } } @Override @@ -212,33 +210,27 @@ private static void registerNetworkInterfaceInit(DuringAnalysisAccess a) { private static void registerDatagramPacketInit(DuringAnalysisAccess a) { JNIRuntimeAccess.register(fields(a, "java.net.DatagramPacket", "address", "port", "buf", "offset", "length", "bufLength")); + } + private static void registerDatagramSocketCheckOldImpl(DuringAnalysisAccess a) { + a.registerSubtypeReachabilityHandler((access, clazz) -> { + // Checkstyle: stop + if (!java.lang.reflect.Modifier.isAbstract(clazz.getModifiers())) { + // Checkstyle: resume + RuntimeReflection.register(method(access, clazz.getName(), "peekData", DatagramPacket.class)); + } + }, clazz(a, "java.net.DatagramSocketImpl")); } private static void registerPlainDatagramSocketImplInit(DuringAnalysisAccess a) { - /* See java.net.DatagramSocket.checkOldImpl */ - a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDatagramSocketImplPeekData, - method(a, "java.net.DatagramSocket", "checkOldImpl")); - JNIRuntimeAccess.register(fields(a, "java.net.AbstractPlainDatagramSocketImpl", "timeout", "trafficClass", "connected", "connectedAddress", "connectedPort")); JNIRuntimeAccess.register(fields(a, "java.net.DatagramSocketImpl", "fd", "localPort")); - if (isWindows()) { JNIRuntimeAccess.register(clazz(a, "java.net.DualStackPlainDatagramSocketImpl")); JNIRuntimeAccess.register(fields(a, "java.net.TwoStacksPlainDatagramSocketImpl", "fd1", "fduse", "lastfd")); } } - private static void registerDatagramSocketImplPeekData(DuringAnalysisAccess a) { - a.registerSubtypeReachabilityHandler((access, clazz) -> { - // Checkstyle: stop - if (!java.lang.reflect.Modifier.isAbstract(clazz.getModifiers())) { - // Checkstyle: resume - RuntimeReflection.register(method(access, clazz.getName(), "peekData", DatagramPacket.class)); - } - }, clazz(a, "java.net.DatagramSocketImpl")); - } - private static void registerPlainSocketImplInitProto(DuringAnalysisAccess a) { JNIRuntimeAccess.register(fields(a, "java.net.SocketImpl", "fd", "address", "port", "localport", "serverSocket")); JNIRuntimeAccess.register(fields(a, "java.net.AbstractPlainSocketImpl", "timeout", "trafficClass")); From 4de6304ee630ee4f7c872e112625841e956e2d3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksandar=20Pejovi=C4=87?= Date: Sun, 1 Dec 2019 22:34:58 +0100 Subject: [PATCH 5/8] Fix JNI registration of DatagramSocket implementations on Windows --- .../hosted/jdk/JNIRegistrationJavaNet.java | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java index a956d13da58a..908a4cf24fce 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java @@ -49,7 +49,9 @@ class JNIRegistrationJavaNet extends JNIRegistrationUtil implements Feature { @Override public void duringSetup(DuringSetupAccess a) { rerunClassInit(a, "java.net.DatagramPacket", "java.net.InetAddress", "java.net.NetworkInterface", - "java.net.SocketInputStream", "java.net.SocketOutputStream"); + "java.net.SocketInputStream", "java.net.SocketOutputStream", + /* Caches networking properties. */ + "java.net.DefaultDatagramSocketImplFactory"); if (isWindows()) { rerunClassInit(a, "java.net.DualStackPlainDatagramSocketImpl", "java.net.TwoStacksPlainDatagramSocketImpl"); if (JavaVersionUtil.JAVA_SPEC < 11) { @@ -107,8 +109,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerInetAddressLoadImpl, method(a, "java.net.InetAddress", "loadImpl", String.class)); - Consumer registerNetworkInterfaceInit = JNIRegistrationJavaNet::registerNetworkInterfaceInit; - a.registerReachabilityHandler(registerNetworkInterfaceInit, + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerNetworkInterfaceInit, method(a, "java.net.NetworkInterface", "init")); a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDatagramPacketInit, @@ -117,27 +118,24 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDatagramSocketCheckOldImpl, method(a, "java.net.DatagramSocket", "checkOldImpl")); + String plainDatagramSocketImpl = isWindows() ? "TwoStacksPlainDatagramSocketImpl" : "PlainDatagramSocketImpl"; + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainDatagramSocketImplInit, + method(a, "java.net." + plainDatagramSocketImpl, "init")); + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainDatagramSocketImplSocketGetOption, + method(a, "java.net." + plainDatagramSocketImpl, "socketGetOption", int.class)); + if (isWindows()) { + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDualStackPlainDatagramSocketImplInitIDs, + method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); String plainSocketImpl = JavaVersionUtil.JAVA_SPEC >= 11 ? "PlainSocketImpl" : "DualStackPlainSocketImpl"; a.registerReachabilityHandler(registerInitInetAddressIDs, - method(a, "java.net." + plainSocketImpl, "initIDs"), - method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); - a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainDatagramSocketImplInit, - method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); - a.registerReachabilityHandler(registerNetworkInterfaceInit, - method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); + method(a, "java.net." + plainSocketImpl, "initIDs")); a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplInitProto, method(a, "java.net." + plainSocketImpl, "initIDs")); } else { assert isPosix(); a.registerReachabilityHandler(registerInitInetAddressIDs, - method(a, "java.net.PlainSocketImpl", "initProto"), - method(a, "java.net.PlainDatagramSocketImpl", "init")); - a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainDatagramSocketImplInit, - method(a, "java.net.PlainDatagramSocketImpl", "init")); - a.registerReachabilityHandler(registerNetworkInterfaceInit, - method(a, "java.net.PlainDatagramSocketImpl", "init")); - + method(a, "java.net.PlainSocketImpl", "initProto")); a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplInitProto, method(a, "java.net.PlainSocketImpl", "initProto")); if (JavaVersionUtil.JAVA_SPEC < 9) { @@ -223,14 +221,27 @@ private static void registerDatagramSocketCheckOldImpl(DuringAnalysisAccess a) { } private static void registerPlainDatagramSocketImplInit(DuringAnalysisAccess a) { - JNIRuntimeAccess.register(fields(a, "java.net.AbstractPlainDatagramSocketImpl", "timeout", "trafficClass", "connected", "connectedAddress", "connectedPort")); JNIRuntimeAccess.register(fields(a, "java.net.DatagramSocketImpl", "fd", "localPort")); + JNIRuntimeAccess.register(fields(a, "java.net.AbstractPlainDatagramSocketImpl", "timeout", "trafficClass", "connected")); if (isWindows()) { - JNIRuntimeAccess.register(clazz(a, "java.net.DualStackPlainDatagramSocketImpl")); JNIRuntimeAccess.register(fields(a, "java.net.TwoStacksPlainDatagramSocketImpl", "fd1", "fduse", "lastfd")); + registerInitInetAddressIDs(a); + } else { + JNIRuntimeAccess.register(fields(a, "java.net.AbstractPlainDatagramSocketImpl", "connectedAddress", "connectedPort")); + registerNetworkInterfaceInit(a); } } + private static void registerPlainDatagramSocketImplSocketGetOption(DuringAnalysisAccess a) { + JNIRuntimeAccess.register(method(a, "java.net.InetAddress", "anyLocalAddress")); + RuntimeReflection.register(clazz(a, "[Ljava.net.Inet4Address;")); /* Created via JNI. */ + } + + private static void registerDualStackPlainDatagramSocketImplInitIDs(DuringAnalysisAccess a) { + JNIRuntimeAccess.register(fields(a, "java.net.DatagramSocketImpl", "fd")); + registerInitInetAddressIDs(a); + } + private static void registerPlainSocketImplInitProto(DuringAnalysisAccess a) { JNIRuntimeAccess.register(fields(a, "java.net.SocketImpl", "fd", "address", "port", "localport", "serverSocket")); JNIRuntimeAccess.register(fields(a, "java.net.AbstractPlainSocketImpl", "timeout", "trafficClass")); From 9795eca47eac1bf20a233cb922c448d6c34d1dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksandar=20Pejovi=C4=87?= Date: Fri, 6 Dec 2019 12:22:13 +0100 Subject: [PATCH 6/8] Fix JNI registration of Socket implementations on Windows --- .../hosted/jdk/JNIRegistrationJavaNet.java | 52 ++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java index 908a4cf24fce..ba704c3beeb9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java @@ -25,8 +25,8 @@ package com.oracle.svm.hosted.jdk; import java.net.DatagramPacket; +import java.net.InetAddress; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.Platforms; @@ -55,7 +55,9 @@ public void duringSetup(DuringSetupAccess a) { if (isWindows()) { rerunClassInit(a, "java.net.DualStackPlainDatagramSocketImpl", "java.net.TwoStacksPlainDatagramSocketImpl"); if (JavaVersionUtil.JAVA_SPEC < 11) { - rerunClassInit(a, "java.net.DualStackPlainSocketImpl", "java.net.TwoStacksPlainSocketImpl"); + rerunClassInit(a, "java.net.DualStackPlainSocketImpl", "java.net.TwoStacksPlainSocketImpl", + /* Caches networking properties. */ + "java.net.PlainSocketImpl"); } else { /* The other implementations are merged into PlainSocketImpl. */ rerunClassInit(a, "java.net.PlainSocketImpl"); @@ -100,8 +102,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { * InetAddress, Inet4Address, and Inet6Address are registered from many places in the JDK, * so it does not make sense to separate them. */ - Consumer registerInitInetAddressIDs = JNIRegistrationJavaNet::registerInitInetAddressIDs; - a.registerReachabilityHandler(registerInitInetAddressIDs, + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerInitInetAddressIDs, method(a, "java.net.InetAddress", "init"), /* The next two methods call initInetAddressIDs directly. */ method(a, "java.net.Inet4AddressImpl", "lookupAllHostAddr", String.class), @@ -124,20 +125,24 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainDatagramSocketImplSocketGetOption, method(a, "java.net." + plainDatagramSocketImpl, "socketGetOption", int.class)); + if (JavaVersionUtil.JAVA_SPEC < 11 || isPosix()) { + String plainSocketImpl = isWindows() ? "TwoStacksPlainSocketImpl" : "PlainSocketImpl"; + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplInitProto, + method(a, "java.net." + plainSocketImpl, "initProto")); + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplSocketGetOption, + method(a, "java.net." + plainSocketImpl, "socketGetOption", int.class, Object.class)); + } if (isWindows()) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDualStackPlainDatagramSocketImplInitIDs, method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); - String plainSocketImpl = JavaVersionUtil.JAVA_SPEC >= 11 ? "PlainSocketImpl" : "DualStackPlainSocketImpl"; - a.registerReachabilityHandler(registerInitInetAddressIDs, - method(a, "java.net." + plainSocketImpl, "initIDs")); - a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplInitProto, - method(a, "java.net." + plainSocketImpl, "initIDs")); + + String dualStackPlainSocketImpl = JavaVersionUtil.JAVA_SPEC < 11 ? "DualStackPlainSocketImpl" : "PlainSocketImpl"; + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDualStackPlainSocketImplInitIDs, + method(a, "java.net." + dualStackPlainSocketImpl, "initIDs")); + a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDualStackPlainSocketImplLocalAddress, + method(a, "java.net." + dualStackPlainSocketImpl, "localAddress", int.class, clazz(a, "java.net.InetAddressContainer"))); } else { assert isPosix(); - a.registerReachabilityHandler(registerInitInetAddressIDs, - method(a, "java.net.PlainSocketImpl", "initProto")); - a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplInitProto, - method(a, "java.net.PlainSocketImpl", "initProto")); if (JavaVersionUtil.JAVA_SPEC < 9) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerExtendedOptionsImplInit, method(a, "sun.net.ExtendedOptionsImpl", "init")); @@ -245,14 +250,25 @@ private static void registerDualStackPlainDatagramSocketImplInitIDs(DuringAnalys private static void registerPlainSocketImplInitProto(DuringAnalysisAccess a) { JNIRuntimeAccess.register(fields(a, "java.net.SocketImpl", "fd", "address", "port", "localport", "serverSocket")); JNIRuntimeAccess.register(fields(a, "java.net.AbstractPlainSocketImpl", "timeout", "trafficClass")); - if (isPosix()) { - JNIRuntimeAccess.register(fields(a, "java.net.AbstractPlainSocketImpl", "fdLock", "closePending")); - } if (isWindows()) { JNIRuntimeAccess.register(fields(a, "java.net.TwoStacksPlainSocketImpl", "fd1", "lastfd")); + } else { + JNIRuntimeAccess.register(fields(a, "java.net.AbstractPlainSocketImpl", "fdLock", "closePending")); + registerInitInetAddressIDs(a); } - JNIRuntimeAccess.register(clazz(a, "java.net.SocketInputStream")); - JNIRuntimeAccess.register(clazz(a, "java.net.SocketOutputStream")); + } + + private static void registerPlainSocketImplSocketGetOption(DuringAnalysisAccess a) { + JNIRuntimeAccess.register(fields(a, "java.net.InetAddressContainer", "addr")); + } + + private static void registerDualStackPlainSocketImplInitIDs(DuringAnalysisAccess a) { + JNIRuntimeAccess.register(constructor(a, "java.net.InetSocketAddress", InetAddress.class, int.class)); + registerInitInetAddressIDs(a); + } + + private static void registerDualStackPlainSocketImplLocalAddress(DuringAnalysisAccess a) { + JNIRuntimeAccess.register(fields(a, "java.net.InetAddressContainer", "addr")); } private static void registerExtendedOptionsImplInit(DuringAnalysisAccess a) { From 5c872d343f0566d378f5bc03564edd4e7a4ff6c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksandar=20Pejovi=C4=87?= Date: Thu, 12 Dec 2019 13:03:54 +0100 Subject: [PATCH 7/8] Add support for running callbacks once --- .../svm/core/jdk/JNIRegistrationUtil.java | 19 ++++++++++++++++++- .../hosted/jdk/JNIRegistrationJavaNet.java | 16 ++-------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JNIRegistrationUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JNIRegistrationUtil.java index fba8fa927170..b070ca563a1a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JNIRegistrationUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JNIRegistrationUtil.java @@ -25,17 +25,23 @@ package com.oracle.svm.core.jdk; /* Checkstyle: allow reflection */ + import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Set; +import java.util.function.Consumer; -import com.oracle.svm.core.util.VMError; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess; import org.graalvm.nativeimage.hosted.Feature.FeatureAccess; import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport; import com.oracle.svm.core.jni.JNIRuntimeAccess; +import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; /** @@ -95,4 +101,15 @@ protected static void registerForThrowNew(FeatureAccess access, String... except JNIRuntimeAccess.register(constructor(access, exceptionClassName, String.class)); } } + + private static Set> runOnceCallbacks = Collections.newSetFromMap(new IdentityHashMap<>()); + + /** Intended to be used from within a callback to ensure that it is run only once. */ + protected static boolean isRunOnce(Consumer callback) { + return !runOnceCallbacks.add(callback); + } + + public void cleanup() { + runOnceCallbacks.clear(); + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java index ba704c3beeb9..7915eb31ad02 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java @@ -26,7 +26,6 @@ import java.net.DatagramPacket; import java.net.InetAddress; -import java.util.concurrent.atomic.AtomicBoolean; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.Platforms; @@ -155,17 +154,8 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { } } - @Override - public void cleanup() { - /* Reset the static state. */ - initInetAddressIDs.set(false); - networkInterfaceInit.set(false); - } - - private static AtomicBoolean initInetAddressIDs = new AtomicBoolean(); - static void registerInitInetAddressIDs(DuringAnalysisAccess a) { - if (!initInetAddressIDs.compareAndSet(false, true)) { + if (isRunOnce(JNIRegistrationJavaNet::registerInitInetAddressIDs)) { return; /* Already registered. */ } @@ -192,10 +182,8 @@ private static void registerInetAddressLoadImpl(DuringAnalysisAccess a) { RuntimeReflection.register(constructor(a, "java.net.Inet6AddressImpl")); } - private static AtomicBoolean networkInterfaceInit = new AtomicBoolean(); - private static void registerNetworkInterfaceInit(DuringAnalysisAccess a) { - if (!networkInterfaceInit.compareAndSet(false, true)) { + if (isRunOnce(JNIRegistrationJavaNet::registerNetworkInterfaceInit)) { return; /* Already registered. */ } From fd45f6582f6596e76387390ed9202a58b5102e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksandar=20Pejovi=C4=87?= Date: Fri, 13 Dec 2019 00:30:53 +0100 Subject: [PATCH 8/8] Make array types automatically accessible via JNI when possible --- .../src/com/oracle/svm/jni/access/JNIAccessFeature.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java index 2a1acd61cb6d..ca19d5f5f13b 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java @@ -299,6 +299,13 @@ private static void addField(Field reflField, boolean writable, DuringAnalysisAc field.registerAsRead(null); if (writable) { field.registerAsWritten(null); + AnalysisType fieldType = field.getType(); + if (fieldType.isArray() && !access.isReachable(fieldType)) { + // For convenience, make the array type reachable if its elemental type becomes + // such, allowing the array creation via JNI without an explicit reflection config. + access.registerReachabilityHandler(a -> fieldType.registerAsAllocated(null), + ((AnalysisType) fieldType.getElementalType()).getJavaClass()); + } } else if (field.isStatic() && field.isFinal()) { MaterializedConstantFields.singleton().register(field); }