diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 04a2f12412de..7b6244c1ab3c 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -183,9 +183,6 @@ "sdk:GRAAL_SDK", "compiler:GRAAL", ], - "requires" : [ - "java.instrument", - ], "requiresConcealed" : { "java.base" : ["jdk.internal.module"], }, @@ -244,13 +241,9 @@ ], "requires" : [ "java.compiler", - "java.logging", - "java.scripting", - "jdk.httpserver", "jdk.jfr", "jdk.management", "jdk.management.jfr", - "jdk.unsupported", ], "requiresConcealed" : { "java.base" : [ @@ -293,9 +286,6 @@ "jdk.management.agent": [ "jdk.internal.agent", ], - "jdk.httpserver@19+": [ - "sun.net.httpserver.simpleserver", - ], "jdk.jfr": [ "jdk.jfr.events", "jdk.jfr.internal", @@ -536,9 +526,6 @@ "dependencies": [ "com.oracle.graal.pointsto", ], - "requires" : [ - "jdk.unsupported" # sun.misc.Unsafe - ], "requiresConcealed" : { "java.base" : [ "jdk.internal.misc" @@ -613,13 +600,8 @@ "com.oracle.graal.reachability" ], "requires" : [ - "java.instrument", - "java.security.sasl", - "java.smartcardio", - "java.xml.crypto", "jdk.jfr", "jdk.management", - "jdk.unsupported", ], "requiresConcealed" : { "java.base" : [ @@ -647,9 +629,6 @@ "com.sun.jmx.mbeanserver", # Needed for javadoc links (MXBeanIntrospector,DefaultMXBeanMappingFactory, MXBeanProxy) "sun.management", # Needed for javadoc links (MappedMXBeanType) ], - "java.rmi": [ - "sun.rmi.server", # Needed for javadoc links (UnicastRef, UnicastRef2) - ], "jdk.internal.vm.ci" : [ "jdk.vm.ci.meta", "jdk.vm.ci.code", @@ -664,11 +643,6 @@ "jdk.jfr.internal", "jdk.jfr.internal.jfc", ], - "java.management.rmi": [ - "com.sun.jmx.remote.internal.rmi", # Needed for javadoc links (ProxyRef) - "com.sun.jmx.remote.protocol.rmi", # Needed for javadoc links (ClientProvider, ServerProvider) - "javax.management.remote.rmi", # Needed for javadoc links (RMIServer, RMIServerImpl_Stub, RMIConnection, RMIConnectionImpl_Stub) - ], }, "javaCompliance" : "17+", "checkstyleVersion": "10.7.0", @@ -997,10 +971,7 @@ "subDir": "src", "sourceDirs": ["src"], "dependencies": [ - "com.oracle.svm.core", - ], - "requires" : [ - "jdk.unsupported", + "com.oracle.svm.util", ], "checkstyle": "com.oracle.svm.core", "javaCompliance" : "17+", @@ -1281,9 +1252,6 @@ "dependencies": [ "com.oracle.svm.hosted", ], - "requires" : [ - "jdk.unsupported", - ], "requiresConcealed": { "jdk.internal.vm.ci": [ "jdk.vm.ci.meta", @@ -1359,12 +1327,6 @@ "requires": [ "java.management", "jdk.management", - "java.xml.crypto", - "java.security.sasl", - "java.smartcardio", - "java.net.http", - "jdk.sctp", - "jdk.scripting.nashorn@11..14", "jdk.management.agent", "jdk.management.jfr", ], @@ -1416,9 +1378,6 @@ "java.management": [ "sun.management", ], - "java.xml.crypto": [ - "org.jcp.xml.dsig.internal.dom", - ], }, }, "noMavenJavadoc": True, diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SunMiscSubstitutions.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SunMiscSubstitutions.java index 87d49bc7ed6d..6317561f9f50 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SunMiscSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SunMiscSubstitutions.java @@ -80,14 +80,14 @@ private static void raise0(int signalNumber) { } /** - * Called by the VM to execute Java signal handlers. Except that in sun.misc.Signal, this method - * is private. + * Called by the VM to execute Java signal handlers. Except that in jdk.internal.misc.Signal, + * this method is private. */ @Alias static native void dispatch(int number); } -/** Support for Target_sun_misc_Signal. */ +/** Support for Target_jdk_internal_misc_Signal. */ final class Util_jdk_internal_misc_Signal { /** A thread to dispatch signals as they are raised. */ @@ -105,7 +105,7 @@ private Util_jdk_internal_misc_Signal() { /* All-static class. */ } - /** Constants for the longs from sun.misc.Signal. */ + /** Constants for the longs from jdk.internal.misc.Signal. */ private static final long sunMiscSignalDefaultHandler = 0; private static final long sunMiscSignalIgnoreHandler = 1; private static final long sunMiscSignalDispatchHandler = 2; @@ -182,9 +182,9 @@ private static void ensureInitialized() throws IllegalArgumentException { throw new IllegalArgumentException("C signal handling mechanism is in use."); } /* Report other failure. */ - Log.log().string("Util_sun_misc_Signal.ensureInitialized: CSunMiscSignal.create() failed.") + Log.log().string("Util_jdk_internal_misc_Signal.ensureInitialized: CSunMiscSignal.create() failed.") .string(" errno: ").signed(openErrno).string(" ").string(Errno.strerror(openErrno)).newline(); - throw VMError.shouldNotReachHere("Util_sun_misc_Signal.ensureInitialized: CSunMiscSignal.open() failed."); + throw VMError.shouldNotReachHere("Util_jdk_internal_misc_Signal.ensureInitialized: CSunMiscSignal.open() failed."); } /* Initialize the table of signal states. */ @@ -240,7 +240,7 @@ protected static int numberFromName(String javaSignalName) { return entry.getNumber(); } } - /* {@link sun.misc.Signal#findSignal(String)} expects a -1 on failure. */ + /* {@link jdk.internal.misc.Signal#findSignal(String)} expects a -1 on failure. */ return -1; } @@ -377,12 +377,12 @@ protected void setDispatcher(Signal.SignalDispatcher value) { protected static void await() { final int awaitResult = CSunMiscSignal.await(); - PosixUtils.checkStatusIs0(awaitResult, "Util_sun_misc_Signal.SignalState.await(): CSunMiscSignal.await() failed."); + PosixUtils.checkStatusIs0(awaitResult, "Util_jdk_internal_misc_Signal.SignalState.await(): CSunMiscSignal.await() failed."); } protected static void wakeUp() { final int awaitResult = CSunMiscSignal.post(); - PosixUtils.checkStatusIs0(awaitResult, "Util_sun_misc_Signal.SignalState.post(): CSunMiscSignal.post() failed."); + PosixUtils.checkStatusIs0(awaitResult, "Util_jdk_internal_misc_Signal.SignalState.post(): CSunMiscSignal.post() failed."); } /* diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpHeapOnSignalFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpHeapOnSignalFeature.java index 30d293c3704c..212ae60d9c14 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpHeapOnSignalFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpHeapOnSignalFeature.java @@ -38,8 +38,7 @@ import com.oracle.svm.core.jdk.RuntimeSupport; import com.oracle.svm.core.log.Log; -import sun.misc.Signal; -import sun.misc.SignalHandler; +import jdk.internal.misc.Signal; @AutomaticallyRegisteredFeature public class DumpHeapOnSignalFeature implements InternalFeature { @@ -64,7 +63,7 @@ public void execute(boolean isFirstIsolate) { } } -class DumpHeapReport implements SignalHandler { +class DumpHeapReport implements Signal.Handler { private static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("UTC"); static void install() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpRuntimeCompilationOnSignalFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpRuntimeCompilationOnSignalFeature.java index 6f480f4f10b8..981fd5380bdd 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpRuntimeCompilationOnSignalFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpRuntimeCompilationOnSignalFeature.java @@ -27,16 +27,15 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platform.WINDOWS; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.RuntimeCompilation; import com.oracle.svm.core.heap.VMOperationInfos; import com.oracle.svm.core.jdk.RuntimeSupport; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.thread.JavaVMOperation; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import sun.misc.Signal; -import sun.misc.SignalHandler; +import jdk.internal.misc.Signal; @AutomaticallyRegisteredFeature public class DumpRuntimeCompilationOnSignalFeature implements InternalFeature { @@ -61,7 +60,7 @@ public void execute(boolean isFirstIsolate) { } } -class DumpRuntimeCompilation implements SignalHandler { +class DumpRuntimeCompilation implements Signal.Handler { static void install() { Signal.handle(new Signal("USR2"), new DumpRuntimeCompilation()); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpThreadStacksOnSignalFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpThreadStacksOnSignalFeature.java index c687f82162d1..0fb26bbe6f5f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpThreadStacksOnSignalFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpThreadStacksOnSignalFeature.java @@ -29,6 +29,7 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platform.WINDOWS; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.heap.VMOperationInfos; import com.oracle.svm.core.jdk.RuntimeSupport; @@ -39,10 +40,8 @@ import com.oracle.svm.core.thread.JavaVMOperation; import com.oracle.svm.core.thread.PlatformThreads; import com.oracle.svm.core.thread.VMThreads; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import sun.misc.Signal; -import sun.misc.SignalHandler; +import jdk.internal.misc.Signal; @AutomaticallyRegisteredFeature public class DumpThreadStacksOnSignalFeature implements InternalFeature { @@ -67,7 +66,7 @@ public void execute(boolean isFirstIsolate) { } } -class DumpAllStacks implements SignalHandler { +class DumpAllStacks implements Signal.Handler { static void install() { Signal.handle(Platform.includedIn(WINDOWS.class) ? new Signal("BREAK") : new Signal("QUIT"), new DumpAllStacks()); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index d1f7ca97a9ab..39b395f48dee 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -676,6 +676,9 @@ private static void validateUseOldDebugInfo(HostedOptionKey optionKey) @Option(help = "Directory under which to create source file cache for Application or GraalVM classes")// public static final HostedOptionKey DebugInfoSourceCacheRoot = new HostedOptionKey<>("sources"); + @Option(help = "Temporary option to disable checking of image builder module dependencies or increasing its verbosity", type = OptionType.Debug)// + public static final HostedOptionKey CheckBootModuleDependencies = new HostedOptionKey<>(ModuleSupport.modulePathBuild ? 1 : 0); + public static Path getDebugInfoSourceCacheRoot() { try { return Paths.get(Path.getValue()).resolve(DebugInfoSourceCacheRoot.getValue()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index 328b05cf49b9..f3b3e7cc1b00 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -74,7 +74,6 @@ import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.SuppressFBWarnings; -import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -1932,20 +1931,20 @@ final class Target_java_lang_Class_Atomic { static boolean casReflectionData(DynamicHub clazz, SoftReference> oldData, SoftReference> newData) { - return GraalUnsafeAccess.getUnsafe().compareAndSwapObject(clazz.getCompanion(), reflectionDataOffset, oldData, newData); + return Unsafe.getUnsafe().compareAndSetReference(clazz.getCompanion(), reflectionDataOffset, oldData, newData); } @Substitute static boolean casAnnotationType(DynamicHub clazz, AnnotationType oldType, AnnotationType newType) { - return GraalUnsafeAccess.getUnsafe().compareAndSwapObject(clazz.getCompanion(), annotationTypeOffset, oldType, newType); + return Unsafe.getUnsafe().compareAndSetReference(clazz.getCompanion(), annotationTypeOffset, oldType, newType); } @Substitute static boolean casAnnotationData(DynamicHub clazz, Target_java_lang_Class_AnnotationData oldData, Target_java_lang_Class_AnnotationData newData) { - return GraalUnsafeAccess.getUnsafe().compareAndSwapObject(clazz.getCompanion(), annotationDataOffset, oldData, newData); + return Unsafe.getUnsafe().compareAndSetReference(clazz.getCompanion(), annotationDataOffset, oldData, newData); } } 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 ff3b1e047625..9dde925b45cc 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 @@ -84,7 +84,8 @@ protected static Optional> optionalClazz(FeatureAccess access, String c } protected static Optional optionalMethod(FeatureAccess access, String className, String methodName, Class... parameterTypes) { - return Optional.ofNullable(ReflectionUtil.lookupMethod(true, clazz(access, className), methodName, parameterTypes)); + return optionalClazz(access, className) + .flatMap(clazz -> Optional.ofNullable(ReflectionUtil.lookupMethod(true, clazz, methodName, parameterTypes))); } protected static Method method(FeatureAccess access, String className, String methodName, Class... parameterTypes) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaNetHttpFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaNetHttpFeature.java index e3a61efcbb6a..b5b7a83fa1d1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaNetHttpFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaNetHttpFeature.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.jdk; +import java.util.Optional; + import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.RuntimeReflection; @@ -31,12 +33,26 @@ import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport; import com.oracle.svm.core.configure.ResourcesRegistry; -import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; @AutomaticallyRegisteredFeature public class JavaNetHttpFeature extends JNIRegistrationUtil implements InternalFeature { + private static Optional requiredModule() { + return ModuleLayer.boot().findModule("java.net.http"); + } + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return requiredModule().isPresent(); + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + JavaNetHttpFeature.class.getModule().addReads(requiredModule().get()); + } + @Override public void duringSetup(DuringSetupAccess access) { RuntimeClassInitializationSupport rci = ImageSingletons.lookup(RuntimeClassInitializationSupport.class); @@ -59,13 +75,19 @@ private static void registerInitFiltersAccess(DuringAnalysisAccess a) { @AutomaticallyRegisteredFeature class SimpleWebServerFeature implements InternalFeature { + private static Optional requiredModule() { + return ModuleLayer.boot().findModule("jdk.httpserver"); + } + @Override public boolean isInConfiguration(IsInConfigurationAccess access) { - return JavaVersionUtil.JAVA_SPEC >= 19; + return JavaVersionUtil.JAVA_SPEC >= 19 && requiredModule().isPresent(); } @Override public void afterRegistration(AfterRegistrationAccess access) { + SimpleWebServerFeature.class.getModule().addReads(requiredModule().get()); + RuntimeClassInitializationSupport rci = ImageSingletons.lookup(RuntimeClassInitializationSupport.class); rci.initializeAtRunTime("sun.net.httpserver.simpleserver.SimpleFileServerImpl", "Allocates InetAddress in class initializer"); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/NashornSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/NashornSupport.java deleted file mode 100644 index 6d6850da6fd7..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/NashornSupport.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021, 2021, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.svm.core.jdk; - -import java.util.function.BooleanSupplier; - -public final class NashornSupport { - - // Determine if the jdk.scripting.nashorn module (or jar) is available. If it's not, - // the boolean supplier should return false. - static class NashornAvailable implements BooleanSupplier { - - private static final String CLASSFILTER_NAME = "jdk.nashorn.api.scripting.ClassFilter"; - - @Override - public boolean getAsBoolean() { - try { - Class.forName(CLASSFILTER_NAME); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java index 335f89f1f051..f587cd7aad17 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java @@ -234,9 +234,9 @@ final class Target_java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpda } /** - * The atomic field updaters access fields using {@link sun.misc.Unsafe}. The static analysis needs - * to know about all these fields, so we need to find the original field (the updater only stores - * the field offset) and mark it as unsafe accessed. + * The atomic field updaters access fields using {@code Unsafe}. The static analysis needs to know + * about all these fields, so we need to find the original field (the updater only stores the field + * offset) and mark it as unsafe accessed. */ @AutomaticallyRegisteredFeature class AtomicFieldUpdaterFeature implements InternalFeature { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_misc_Unsafe.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_misc_Unsafe.java index 4e566fff6d52..199f66daae43 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_misc_Unsafe.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_misc_Unsafe.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.jdk; +import java.util.function.BooleanSupplier; + import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; @@ -34,7 +36,7 @@ * of the corresponding (recomputed) fields of {@link jdk.internal.misc.Unsafe}. But copying a * recomputed value during image building does not recompute the value. See GR-12640. */ -@TargetClass(value = sun.misc.Unsafe.class) +@TargetClass(className = "sun.misc.Unsafe", onlyWith = JdkUnsupportedIsEnabled.class) final class Target_sun_misc_Unsafe { /* { Checkstyle: stop */ @@ -94,5 +96,11 @@ final class Target_sun_misc_Unsafe { private static int ARRAY_OBJECT_INDEX_SCALE; /* } Checkstyle: resume */ +} +class JdkUnsupportedIsEnabled implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return ModuleLayer.boot().findModule("jdk.unsupported").isPresent(); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/MissingReflectionRegistrationUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/MissingReflectionRegistrationUtils.java index 79fc40515374..03a4e364d29e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/MissingReflectionRegistrationUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/MissingReflectionRegistrationUtils.java @@ -215,7 +215,7 @@ private static void printLine(StringBuilder sb, Object object) { Constructor.class.getTypeName(), Set.of("newInstance"), "java.lang.reflect.ReflectAccess", Set.of("newInstance"), "jdk.internal.access.JavaLangAccess", Set.of("getDeclaredPublicMethods"), - sun.misc.Unsafe.class.getName(), Set.of("allocateInstance"), + "sun.misc.Unsafe", Set.of("allocateInstance"), /* For jdk.internal.misc.Unsafe.allocateInstance(), which is intrinsified */ SubstrateAllocationSnippets.class.getName(), Set.of("instanceHubErrorStub")); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LoggingFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LoggingFeature.java index 0386d4aef530..e78b7bcbdcac 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LoggingFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LoggingFeature.java @@ -25,25 +25,32 @@ package com.oracle.svm.hosted; import java.lang.reflect.Field; -import java.util.logging.LogManager; +import java.util.Optional; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionType; import org.graalvm.nativeimage.hosted.RuntimeReflection; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.option.HostedOptionKey; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.option.SubstrateOptionsParser; +import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; +import com.oracle.svm.util.ReflectionUtil; @AutomaticallyRegisteredFeature public class LoggingFeature implements InternalFeature { + private static Optional requiredModule() { + return ModuleLayer.boot().findModule("java.logging"); + } + public static class Options { @Option(help = "Enable the feature that provides support for logging.")// - public static final HostedOptionKey EnableLoggingFeature = new HostedOptionKey<>(true); + public static final HostedOptionKey EnableLoggingFeature = new HostedOptionKey<>(requiredModule().isPresent()); @Option(help = "When enabled, logging feature details are printed.", type = OptionType.Debug) // public static final HostedOptionKey TraceLoggingFeature = new HostedOptionKey<>(false); @@ -57,13 +64,23 @@ public static class Options { @Override public boolean isInConfiguration(IsInConfigurationAccess access) { - return LoggingFeature.Options.EnableLoggingFeature.getValue(); + Boolean loggingEnabled = Options.EnableLoggingFeature.getValue(); + if (loggingEnabled && requiredModule().isEmpty()) { + throw UserError.abort("Option %s requires JDK module java.logging to be available", + SubstrateOptionsParser.commandArgument(Options.EnableLoggingFeature, "+")); + } + return loggingEnabled; } @Override public void duringSetup(DuringSetupAccess access) { - /* Ensure that the log manager is initialized and the initial configuration is read. */ - LogManager.getLogManager(); + LoggingFeature.class.getModule().addReads(requiredModule().get()); + try { + /* Ensure that the log manager is initialized and the initial configuration is read. */ + ReflectionUtil.lookupMethod(access.findClassByName("java.util.logging.LogManager"), "getLogManager").invoke(null); + } catch (ReflectiveOperationException e) { + throw VMError.shouldNotReachHere("Reflective LogManager initialization failed", e); + } loggersField = ((DuringSetupAccessImpl) access).findField("sun.util.logging.PlatformLogger", "loggers"); } @@ -73,9 +90,9 @@ public void duringAnalysis(DuringAnalysisAccess a) { access.rescanRoot(loggersField); - if (!reflectionConfigured && access.getMetaAccess().optionalLookupJavaType(java.util.logging.Logger.class).isPresent()) { - registerForReflection(java.util.logging.ConsoleHandler.class); - registerForReflection(java.util.logging.SimpleFormatter.class); + if (!reflectionConfigured && access.getMetaAccess().optionalLookupJavaType(a.findClassByName("java.util.logging.Logger")).isPresent()) { + registerForReflection(a.findClassByName("java.util.logging.ConsoleHandler")); + registerForReflection(a.findClassByName("java.util.logging.SimpleFormatter")); reflectionConfigured = true; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 0b97148c23c5..2d764621f02c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -1377,6 +1377,7 @@ public T getInjectedArgument(Class type) { assert pluginsMetaAccess != null; SubstrateGraphBuilderPlugins.registerInvocationPlugins(annotationSubstitutionProcessor, + loader, pluginsMetaAccess, hostedSnippetReflection, plugins.getInvocationPlugins(), diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index 43196cc0c245..cb11c46b468d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -33,10 +33,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.ServiceLoader; +import java.util.Set; import java.util.TimerTask; import java.util.concurrent.ForkJoinPool; import java.util.function.Consumer; @@ -131,6 +133,11 @@ public void run() { if (!remainingArguments.isEmpty()) { throw UserError.abort("Unknown options: %s", String.join(" ", remainingArguments)); } + + Integer checkDependencies = SubstrateOptions.CheckBootModuleDependencies.getValue(imageClassLoader.classLoaderSupport.getParsedHostedOptions()); + if (checkDependencies > 0) { + checkBootModuleDependencies(checkDependencies > 1); + } exitStatus = build(imageClassLoader); } catch (UserException e) { reportUserError(e.getMessage()); @@ -157,6 +164,84 @@ public void run() { System.exit(exitStatus); } + private static void checkBootModuleDependencies(boolean verbose) { + Set allModules = ModuleLayer.boot().modules(); + List builderModules = allModules.stream().filter(m -> m.isNamed() && m.getName().startsWith("org.graalvm.nativeimage.")).toList(); + Set transitiveBuilderModules = new LinkedHashSet<>(); + for (Module svmModule : builderModules) { + transitiveReaders(svmModule, allModules, transitiveBuilderModules); + } + if (verbose) { + System.out.println(transitiveBuilderModules.stream() + .map(Module::getName) + .collect(Collectors.joining("\n", "All builder modules: \n", "\n"))); + } + + Set modulesBuilderDependsOn = new LinkedHashSet<>(); + for (Module builderModule : transitiveBuilderModules) { + transitiveRequires(verbose, builderModule, allModules, modulesBuilderDependsOn); + } + modulesBuilderDependsOn.removeAll(transitiveBuilderModules); + if (verbose) { + System.out.println(modulesBuilderDependsOn.stream() + .map(Module::getName) + .collect(Collectors.joining("\n", "All modules the builder modules depend on: \n", "\n"))); + } + + Set expectedBuilderDependencies = Set.of( + "java.base", + "java.management", + "jdk.management", + "jdk.management.agent", // READ-BY org.graalvm.nativeimage.builder + "java.management.rmi", // READ-BY jdk.management.agent + "java.rmi", + "java.logging", // READ-BY java.rmi READ-BY java.management.rmi + "java.naming", + "java.security.sasl", // READ-BY java.naming READ-BY java.management.rmi + "java.compiler", + "jdk.management.jfr", + "jdk.jfr"); + + Set unexpectedBuilderDependencies = modulesBuilderDependsOn.stream().map(Module::getName).collect(Collectors.toSet()); + unexpectedBuilderDependencies.removeAll(expectedBuilderDependencies); + if (!unexpectedBuilderDependencies.isEmpty()) { + throw VMError.shouldNotReachHere("Unexpected image builder module-dependencies: " + String.join(", ", unexpectedBuilderDependencies)); + } + } + + private static void transitiveReaders(Module readModule, Set potentialReaders, Set actualReaders) { + for (Module potentialReader : potentialReaders) { + if (potentialReader.canRead(readModule)) { + if (actualReaders.add(potentialReader)) { + transitiveReaders(potentialReader, potentialReaders, actualReaders); + } + } + } + } + + private static void transitiveRequires(boolean verbose, Module requiringModule, Set potentialNeededModules, Set actualNeededModules) { + for (Module potentialNeedModule : potentialNeededModules) { + if (requiringModule.canRead(potentialNeedModule)) { + /* Filter out GraalVM modules */ + if (potentialNeedModule.getName().startsWith("jdk.internal.vm.c") || /* JVMCI */ + /* graal */ + potentialNeedModule.getName().startsWith("org.graalvm.") || + /* enterprise graal */ + potentialNeedModule.getName().startsWith("com.oracle.graal.") || + /* llvm-backend optional dependencies */ + potentialNeedModule.getName().startsWith("com.oracle.svm.shadowed.")) { + continue; + } + if (actualNeededModules.add(potentialNeedModule)) { + if (verbose) { + System.out.println(requiringModule + " reads " + potentialNeedModule); + } + transitiveRequires(verbose, potentialNeedModule, potentialNeededModules, actualNeededModules); + } + } + } + } + public static void uninstallNativeImageClassLoader() { ClassLoader loader = ClassLoader.getSystemClassLoader(); if (loader instanceof NativeImageSystemClassLoader) { @@ -574,8 +659,7 @@ public static void reportUserError(Throwable e, OptionValues parsedHostedOptions } private static void reportUserException(Throwable e, OptionValues parsedHostedOptions, Consumer report) { - if (e instanceof UserException) { - UserException ue = (UserException) e; + if (e instanceof UserException ue) { for (String message : ue.getMessages()) { report.accept(message); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java index 3b0b0cad9061..3a0491679f8e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java @@ -35,7 +35,6 @@ import java.util.List; import java.util.Set; import java.util.WeakHashMap; -import java.util.jar.JarFile; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; @@ -277,7 +276,7 @@ private List getActiveClassLoaders() { /** * This method is necessary for all custom system class loaders. It allows for the load of the * agent during startup. See - * {@link java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch(JarFile)} } + * {@code java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch(JarFile)} } * * @param classPathEntry the classpath entry that will be added to the class path */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java index 0cf9914daa74..6b4ada7eeac5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java @@ -56,10 +56,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -77,14 +79,6 @@ import javax.net.ssl.TrustManagerFactory; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.Configuration; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslClientFactory; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; -import javax.smartcardio.TerminalFactory; -import javax.xml.crypto.dsig.TransformService; -import javax.xml.crypto.dsig.XMLSignatureFactory; -import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; @@ -158,13 +152,31 @@ public static class Options { private static final String[] emptyStringArray = new String[0]; /** The list of known service classes defined by the JCA. */ - private static final Class[] knownServices = {AlgorithmParameterGenerator.class, AlgorithmParameters.class, - CertPathBuilder.class, CertPathValidator.class, CertStore.class, CertificateFactory.class, - Cipher.class, Configuration.class, KeyAgreement.class, KeyFactory.class, - KeyGenerator.class, KeyInfoFactory.class, KeyManagerFactory.class, KeyPairGenerator.class, - KeyStore.class, Mac.class, MessageDigest.class, Policy.class, SSLContext.class, - SaslClientFactory.class, SaslServerFactory.class, SecretKeyFactory.class, SecureRandom.class, Signature.class, - TerminalFactory.class, TransformService.class, TrustManagerFactory.class, XMLSignatureFactory.class}; + private static final List> knownServices; + + static { + List> classList = new ArrayList<>(List.of( + AlgorithmParameterGenerator.class, AlgorithmParameters.class, + CertPathBuilder.class, CertPathValidator.class, CertStore.class, CertificateFactory.class, + Cipher.class, Configuration.class, KeyAgreement.class, KeyFactory.class, + KeyGenerator.class, KeyManagerFactory.class, KeyPairGenerator.class, + KeyStore.class, Mac.class, MessageDigest.class, Policy.class, SSLContext.class, + SecretKeyFactory.class, SecureRandom.class, Signature.class, TrustManagerFactory.class)); + + if (ModuleLayer.boot().findModule("java.security.sasl").isPresent()) { + classList.add(ReflectionUtil.lookupClass(false, "javax.security.sasl.SaslClientFactory")); + classList.add(ReflectionUtil.lookupClass(false, "javax.security.sasl.SaslServerFactory")); + } + if (ModuleLayer.boot().findModule("java.xml.crypto").isPresent()) { + classList.add(ReflectionUtil.lookupClass(false, "javax.xml.crypto.dsig.TransformService")); + classList.add(ReflectionUtil.lookupClass(false, "javax.xml.crypto.dsig.XMLSignatureFactory")); + classList.add(ReflectionUtil.lookupClass(false, "javax.xml.crypto.dsig.keyinfo.KeyInfoFactory")); + } + if (ModuleLayer.boot().findModule("java.smartcardio").isPresent()) { + classList.add(ReflectionUtil.lookupClass(false, "javax.smartcardio.TerminalFactory")); + } + knownServices = Collections.unmodifiableList(classList); + } private ImageClassLoader loader; /** Given a service type will return its constructor parameters, if any. */ @@ -257,7 +269,7 @@ public void duringSetup(DuringSetupAccess a) { */ rci.rerunInitialization(clazz(access, "sun.security.jca.JCAUtil$CachedSecureRandomHolder"), "for substitutions"); rci.rerunInitialization(clazz(access, "com.sun.crypto.provider.SunJCE$SecureRandomHolder"), "for substitutions"); - rci.rerunInitialization(clazz(access, "sun.security.krb5.Confounder"), "for substitutions"); + optionalClazz(access, "sun.security.krb5.Confounder").ifPresent(clazz -> rci.rerunInitialization(clazz, "for substitutions")); rci.rerunInitialization(clazz(access, "sun.security.jca.JCAUtil"), "JCAUtil.def holds a SecureRandom."); @@ -318,9 +330,12 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { } if (isPosix()) { - access.registerReachabilityHandler(SecurityServicesFeature::linkJaas, method(access, "com.sun.security.auth.module.UnixSystem", "getUnixInfo")); - /* Resolve calls to com_sun_security_auth_module_UnixSystem* as builtIn. */ - PlatformNativeLibrarySupport.singleton().addBuiltinPkgNativePrefix("com_sun_security_auth_module_UnixSystem"); + Optional optMethodGetUnixInfo = optionalMethod(access, "com.sun.security.auth.module.UnixSystem", "getUnixInfo"); + optMethodGetUnixInfo.ifPresent(m -> { + access.registerReachabilityHandler(SecurityServicesFeature::linkJaas, m); + /* Resolve calls to com_sun_security_auth_module_UnixSystem* as builtIn. */ + PlatformNativeLibrarySupport.singleton().addBuiltinPkgNativePrefix("com_sun_security_auth_module_UnixSystem"); + }); } if (isWindows()) { @@ -449,7 +464,7 @@ private static void linkJaas(DuringAnalysisAccess a) { } private static Set> computeKnownServices(BeforeAnalysisAccess access) { - Set> allKnownServices = new HashSet<>(Arrays.asList(knownServices)); + Set> allKnownServices = new HashSet<>(knownServices); for (String value : Options.AdditionalSecurityServiceTypes.getValue().values()) { for (String serviceClazzName : value.split(",")) { Class serviceClazz = access.findClassByName(serviceClazzName); @@ -460,7 +475,10 @@ private static Set> computeKnownServices(BeforeAnalysisAccess access) { return allKnownServices; } - private void registerSpecialReachabilityHandlers(BeforeAnalysisAccess access) { + private Class classSaslClient; + private Class classSaslServer; + + private void registerSASLReachabilityHandlers(BeforeAnalysisAccess access) { /* * Sasl does not conform to the JCA - the service has no getInstance method. We instead use * the Sasl facade class for our reachability handlers. @@ -475,10 +493,14 @@ private void registerSpecialReachabilityHandlers(BeforeAnalysisAccess access) { } Class saslClass = saslClassLookup.getOrFail(); + + classSaslClient = ReflectionUtil.lookupClass(false, "javax.security.sasl.SaslClient"); + classSaslServer = ReflectionUtil.lookupClass(false, "javax.security.sasl.SaslServer"); + Method createSaslClient = ReflectionUtil.lookupMethod(saslClass, "createSaslClient", String[].class, String.class, String.class, String.class, Map.class, CallbackHandler.class); - access.registerReachabilityHandler(a -> registerServices(a, createSaslClient, SaslClient.class), createSaslClient); + access.registerReachabilityHandler(a -> registerServices(a, createSaslClient, classSaslClient), createSaslClient); Method createSaslServer = ReflectionUtil.lookupMethod(saslClass, "createSaslServer", String.class, String.class, String.class, Map.class, CallbackHandler.class); - access.registerReachabilityHandler(a -> registerServices(a, createSaslServer, SaslServer.class), createSaslServer); + access.registerReachabilityHandler(a -> registerServices(a, createSaslServer, classSaslServer), createSaslServer); } catch (ReflectionUtil.ReflectionUtilError e) { trace(saslRegistrationFailureMessage, e); } @@ -516,7 +538,9 @@ private void registerServiceReachabilityHandlers(BeforeAnalysisAccess access) { } } - registerSpecialReachabilityHandlers(access); + if (ModuleLayer.boot().findModule("java.security.sasl").isPresent()) { + registerSASLReachabilityHandlers(access); + } /* * On Oracle JDK the SecureRandom service implementations are not automatically discovered @@ -544,9 +568,10 @@ private void registerServices(DuringAnalysisAccess access, Object trigger, Class registerServices(access, trigger, serviceType); } - private static String getServiceType(Class serviceClass) { + private String getServiceType(Class serviceClass) { + Objects.requireNonNull(serviceClass); // Checkstyle: allow Class.getSimpleName - if (serviceClass == SaslClient.class || serviceClass == SaslServer.class) { + if (serviceClass == classSaslClient || serviceClass == classSaslServer) { return serviceClass.getSimpleName() + "Factory"; } return serviceClass.getSimpleName(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/DashboardDumpFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/DashboardDumpFeature.java index a4a10dbbcde7..00a6abd25285 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/DashboardDumpFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/DashboardDumpFeature.java @@ -27,21 +27,20 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; +import java.lang.System.Logger.Level; import java.nio.channels.Channels; import java.nio.file.Path; import java.util.Collection; import java.util.Collections; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; import org.graalvm.graphio.GraphOutput; import org.graalvm.graphio.GraphStructure; import com.oracle.graal.pointsto.reports.ReportUtils; import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.hosted.FeatureImpl.AfterCompilationAccessImpl; import com.oracle.svm.hosted.FeatureImpl.AfterHeapLayoutAccessImpl; import com.oracle.svm.hosted.FeatureImpl.OnAnalysisExitAccessImpl; @@ -100,7 +99,7 @@ public DashboardDumpFeature() { try { GraphOutput.newBuilder(VoidGraphStructure.INSTANCE).build(Channels.newChannel(os)).close(); } catch (IOException ex) { - Logger.getLogger(DashboardDumpFeature.class.getName()).log(Level.SEVERE, null, ex); + System.getLogger(DashboardDumpFeature.class.getName()).log(Level.ERROR, "IOException during Dashboard BGV dump header", ex); } }); } 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 1b03adf858d5..f7d4073a47f0 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 @@ -27,6 +27,7 @@ import java.net.InetAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; +import java.util.Optional; import java.util.function.Consumer; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; @@ -46,6 +47,10 @@ @AutomaticallyRegisteredFeature public class JNIRegistrationJavaNio extends JNIRegistrationUtil implements InternalFeature { + private static Optional jdkSctpModule() { + return ModuleLayer.boot().findModule("jdk.sctp"); + } + @Override public void duringSetup(DuringSetupAccess a) { rerunClassInit(a, "sun.nio.ch.IOUtil", "sun.nio.ch.ServerSocketChannelImpl", "sun.nio.ch.DatagramChannelImpl", "sun.nio.ch.FileChannelImpl", "sun.nio.ch.FileKey"); @@ -59,7 +64,7 @@ public void duringSetup(DuringSetupAccess a) { rerunClassInit(a, "sun.nio.ch.SimpleAsynchronousFileChannelImpl", "sun.nio.ch.SimpleAsynchronousFileChannelImpl$DefaultExecutorHolder", "sun.nio.ch.SinkChannelImpl", "sun.nio.ch.SourceChannelImpl"); rerunClassInit(a, "sun.nio.fs.UnixNativeDispatcher", "sun.nio.ch.UnixAsynchronousServerSocketChannelImpl"); - if (isLinux()) { + if (isLinux() && jdkSctpModule().isPresent()) { rerunClassInit(a, "sun.nio.ch.sctp.SctpChannelImpl"); } } else if (isWindows()) { @@ -88,7 +93,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { if (isPosix()) { a.registerReachabilityHandler(JNIRegistrationJavaNio::registerUnixNativeDispatcherInit, method(a, "sun.nio.fs.UnixNativeDispatcher", "init")); - if (isLinux()) { + if (isLinux() && jdkSctpModule().isPresent()) { a.registerReachabilityHandler(JNIRegistrationJavaNio::registerSctpChannelImplInitIDs, method(a, "sun.nio.ch.sctp.SctpChannelImpl", "initIDs")); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationPrefs.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationPrefs.java index d0bca3c0b761..9283d4b389b0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationPrefs.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationPrefs.java @@ -25,6 +25,7 @@ package com.oracle.svm.hosted.jdk; import java.util.ArrayList; +import java.util.Optional; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.RuntimeJNIAccess; @@ -33,6 +34,7 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.jdk.JNIRegistrationUtil; +import com.oracle.svm.core.jdk.JavaNetHttpFeature; import com.oracle.svm.core.jdk.NativeLibrarySupport; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl; @@ -42,6 +44,20 @@ @AutomaticallyRegisteredFeature public class JNIRegistrationPrefs extends JNIRegistrationUtil implements InternalFeature { + private static Optional requiredModule() { + return ModuleLayer.boot().findModule("java.prefs"); + } + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return requiredModule().isPresent(); + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + JavaNetHttpFeature.class.getModule().addReads(requiredModule().get()); + } + @Override public void beforeAnalysis(BeforeAnalysisAccess access) { /* diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxClientFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxClientFeature.java index 1f37719af52f..585a9ff10ea2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxClientFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxClientFeature.java @@ -35,10 +35,6 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; -import javax.management.remote.JMXServiceURL; -import java.io.ObjectOutput; -import java.util.Map; - @AutomaticallyRegisteredFeature public class JmxClientFeature extends JNIRegistrationUtil implements InternalFeature { @Override @@ -64,13 +60,13 @@ private static void configureJNI() { /** * This method configures reflection metadata only required by a JMX client. *
    - *
  • Register {@link com.sun.jmx.remote.protocol.rmi.ClientProvider} which can be reflectively + *
  • Register {@code com.sun.jmx.remote.protocol.rmi.ClientProvider} which can be reflectively * looked up on a code path starting from - * {@link javax.management.remote.JMXConnectorFactory#newJMXConnector(JMXServiceURL, Map)}
  • - *
  • Register {@link sun.rmi.server.UnicastRef2}, which can be reflectively accessed with - * {@link sun.rmi.server.UnicastRef2#getRefClass(ObjectOutput)}.
  • - *
  • Register {@link sun.rmi.server.UnicastRef}, which can be reflectively accessed with - * {@link sun.rmi.server.UnicastRef#getRefClass(ObjectOutput)}.
  • + * {@code javax.management.remote.JMXConnectorFactory#newJMXConnector(JMXServiceURL, Map)} + *
  • Register {@code sun.rmi.server.UnicastRef2}, which can be reflectively accessed with + * {@code sun.rmi.server.UnicastRef2#getRefClass(ObjectOutput)}.
  • + *
  • Register {@code sun.rmi.server.UnicastRef}, which can be reflectively accessed with + * {@code sun.rmi.server.UnicastRef#getRefClass(ObjectOutput)}.
  • *
*/ private static void configureReflection(BeforeAnalysisAccess access) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxCommonFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxCommonFeature.java index 11f2221d93e4..870e2e67b2c0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxCommonFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxCommonFeature.java @@ -26,8 +26,6 @@ package com.oracle.svm.hosted.jdk; -import java.lang.reflect.Method; -import java.rmi.Remote; import java.util.Arrays; import org.graalvm.nativeimage.ImageSingletons; @@ -148,11 +146,11 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { * Proxy registration also registers the methods of these MXBeans for reflection. This is * important because they are accessed in many places in the JMX infrastructure. For example: *
    - *
  • {@link com.sun.jmx.remote.internal.rmi.ProxyRef#invoke(Remote, Method, Object[], long)} + *
  • {@code com.sun.jmx.remote.internal.rmi.ProxyRef#invoke(Remote, Method, Object[], long)} *
  • *
  • {@code com.sun.jmx.mbeanserver.MXBeanIntrospector}
  • - *
  • {@link com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory}
  • - *
  • {@link com.sun.jmx.mbeanserver.MXBeanProxy}
  • + *
  • {@code com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory}
  • + *
  • {@code com.sun.jmx.mbeanserver.MXBeanProxy}
  • *
  • {@code javax.management.MBeanServerInvocationHandler#isLocal(Object, Method)}
  • *
*

@@ -194,7 +192,7 @@ private static void configureJNI() { *
  • {@link javax.management.openmbean.CompositeData}
  • *
  • {@link javax.management.openmbean.ArrayType}
  • These * {@link javax.management.openmbean.OpenType}s are reflectively accessed at multiple points in - * the remote JMX infrastructure (See {@link sun.management.MappedMXBeanType}, + * the remote JMX infrastructure (See {@code sun.management.MappedMXBeanType}, * {@code com.sun.jmx.mbeanserver.MXBeanMapping#makeOpenClass(Type, javax.management.openmbean.OpenType)}) */ private static void configureSerialization(BeforeAnalysisAccess access) { @@ -256,11 +254,11 @@ private static void configureSerialization(BeforeAnalysisAccess access) { * This method configures reflection metadata shared between both JMX client and server. *
      *
    • All *Skel and *Stub classes must be registered for reflection along with - * their constructors. See {@link sun.rmi.server.Util} for an example.
    • + * their constructors. See {@code sun.rmi.server.Util} for an example. * *
    • All methods of *Info classes with static from methods must be registered * for reflection. For example see: - * {@link com.sun.management.GcInfo#from(javax.management.openmbean.CompositeData)} and + * {@code com.sun.management.GcInfo#from(javax.management.openmbean.CompositeData)} and * {@link java.lang.management.MemoryUsage#from(javax.management.openmbean.CompositeData)}. This * is because these classes have their methods reflectively accessed from their static * from methods. Remote JMX infrastructure uses the following pattern: the *Info @@ -268,11 +266,11 @@ private static void configureSerialization(BeforeAnalysisAccess access) { * static frommethod. (ie. SomeInfo would correspond to SomeInfoCompositeData extends * LazyCompositeData ).
    • * - *
    • {@link javax.management.remote.rmi.RMIServer} requires registration of all its methods as - * they are used from {@link javax.management.remote.rmi.RMIServerImpl_Stub}.
    • - *
    • {@link javax.management.remote.rmi.RMIConnection} requires registration of all its + *
    • {@code javax.management.remote.rmi.RMIServer} requires registration of all its methods as + * they are used from {@code javax.management.remote.rmi.RMIServerImpl_Stub}.
    • + *
    • {@code javax.management.remote.rmi.RMIConnection} requires registration of all its * methods as they are used from - * {@link javax.management.remote.rmi.RMIConnectionImpl_Stub}.
    • + * {@code javax.management.remote.rmi.RMIConnectionImpl_Stub}. *
    */ private static void configureReflection(BeforeAnalysisAccess access) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxServerFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxServerFeature.java index 3026e72d4bdb..ba9315d8dd8b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxServerFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxServerFeature.java @@ -26,29 +26,28 @@ package com.oracle.svm.hosted.jdk; -import com.oracle.svm.core.feature.InternalFeature; - import java.lang.management.PlatformManagedObject; - import java.util.Map; import java.util.Set; -import com.oracle.svm.core.jdk.NativeLibrarySupport; -import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; -import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport; -import org.graalvm.nativeimage.impl.ConfigurationCondition; +import javax.management.MBeanServer; +import javax.management.remote.JMXServiceURL; + import org.graalvm.nativeimage.ImageSingletons; -import com.oracle.svm.core.configure.ResourcesRegistry; -import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry; import org.graalvm.nativeimage.hosted.RuntimeReflection; +import org.graalvm.nativeimage.impl.ConfigurationCondition; + +import com.oracle.svm.core.VMInspectionOptions; +import com.oracle.svm.core.configure.ResourcesRegistry; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.jdk.NativeLibrarySupport; +import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport; import com.oracle.svm.core.jdk.RuntimeSupport; import com.oracle.svm.core.jdk.management.ManagementAgentStartupHook; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.VMInspectionOptions; import com.oracle.svm.core.jdk.management.ManagementSupport; - -import javax.management.MBeanServer; -import javax.management.remote.JMXServiceURL; +import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry; +import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; @AutomaticallyRegisteredFeature public class JmxServerFeature implements InternalFeature { @@ -101,7 +100,7 @@ private static void configureProxy(BeforeAnalysisAccess access) { *
      *
    • Here we register all the custom MXBeans of Substrate VM. They will not be accounted for * by the native image tracing agent so a user may not know they need to register them.
    • - *
    • We also register {@link com.sun.jmx.remote.protocol.rmi.ServerProvider} which can be + *
    • We also register {@code com.sun.jmx.remote.protocol.rmi.ServerProvider} which can be * reflectively looked up on a code path starting from * {@link javax.management.remote.JMXConnectorServerFactory#newJMXConnectorServer(JMXServiceURL, Map, MBeanServer)} *
    • diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index b52aa2dfb5c7..cb8fcd9c29be 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -155,6 +155,7 @@ import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FallbackFeature; +import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.ReachabilityRegistrationNode; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMetaAccess; @@ -172,7 +173,6 @@ import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -import sun.reflect.ReflectionFactory; public class SubstrateGraphBuilderPlugins { @@ -183,6 +183,7 @@ public static class Options { } public static void registerInvocationPlugins(AnnotationSubstitutionProcessor annotationSubstitutions, + ImageClassLoader loader, MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, @@ -196,7 +197,7 @@ public static void registerInvocationPlugins(AnnotationSubstitutionProcessor ann registerReflectionPlugins(plugins, replacements); registerImageInfoPlugins(metaAccess, plugins); registerProxyPlugins(snippetReflection, annotationSubstitutions, plugins, parsingReason); - registerSerializationPlugins(snippetReflection, plugins, parsingReason); + registerSerializationPlugins(loader, snippetReflection, plugins, parsingReason); registerAtomicUpdaterPlugins(metaAccess, snippetReflection, plugins, parsingReason); registerObjectPlugins(plugins); registerUnsafePlugins(metaAccess, plugins, snippetReflection, parsingReason); @@ -215,7 +216,7 @@ public static void registerInvocationPlugins(AnnotationSubstitutionProcessor ann } } - private static void registerSerializationPlugins(SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, ParsingReason reason) { + private static void registerSerializationPlugins(ImageClassLoader loader, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, ParsingReason reason) { if (reason.duringAnalysis() && reason != ParsingReason.JITCompilation) { Registration serializationFilter = new Registration(plugins, ObjectInputFilter.Config.class); serializationFilter.register(new RequiredInvocationPlugin("createFilter", String.class) { @@ -235,40 +236,42 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } }); - Registration customConstructor = new Registration(plugins, ReflectionFactory.class); - customConstructor.register(new RequiredInvocationPlugin("newConstructorForSerialization", Receiver.class, Class.class) { - @Override - public boolean isDecorator() { - return true; - } - - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode clazz) { - if (nonNullJavaConstants(receiver.get(), clazz)) { - b.add(ReachabilityRegistrationNode.create(() -> RuntimeSerialization.register(snippetReflection.asObject(Class.class, clazz.asJavaConstant())), reason)); + if (ModuleLayer.boot().findModule("jdk.unsupported").isPresent()) { + Registration customConstructor = new Registration(plugins, loader.findClassOrFail("sun.reflect.ReflectionFactory")); + customConstructor.register(new RequiredInvocationPlugin("newConstructorForSerialization", Receiver.class, Class.class) { + @Override + public boolean isDecorator() { return true; } - return false; - } - }); - customConstructor.register(new RequiredInvocationPlugin("newConstructorForSerialization", Receiver.class, Class.class, Constructor.class) { - @Override - public boolean isDecorator() { - return true; - } + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode clazz) { + if (nonNullJavaConstants(receiver.get(), clazz)) { + b.add(ReachabilityRegistrationNode.create(() -> RuntimeSerialization.register(snippetReflection.asObject(Class.class, clazz.asJavaConstant())), reason)); + return true; + } + return false; + } + }); - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode clazz, ValueNode constructor) { - if (nonNullJavaConstants(receiver.get(), clazz, constructor)) { - var constructorDeclaringClass = snippetReflection.asObject(Constructor.class, constructor.asJavaConstant()).getDeclaringClass(); - b.add(ReachabilityRegistrationNode.create(() -> RuntimeSerialization.registerWithTargetConstructorClass(snippetReflection.asObject(Class.class, clazz.asJavaConstant()), - constructorDeclaringClass), reason)); + customConstructor.register(new RequiredInvocationPlugin("newConstructorForSerialization", Receiver.class, Class.class, Constructor.class) { + @Override + public boolean isDecorator() { return true; } - return false; - } - }); + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode clazz, ValueNode constructor) { + if (nonNullJavaConstants(receiver.get(), clazz, constructor)) { + var constructorDeclaringClass = snippetReflection.asObject(Constructor.class, constructor.asJavaConstant()).getDeclaringClass(); + b.add(ReachabilityRegistrationNode.create(() -> RuntimeSerialization.registerWithTargetConstructorClass(snippetReflection.asObject(Class.class, clazz.asJavaConstant()), + constructorDeclaringClass), reason)); + return true; + } + return false; + } + }); + } } } diff --git a/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs_SignalImpl.h b/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs_SignalImpl.h index e93637e0ee0a..e87735f037cc 100644 --- a/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs_SignalImpl.h +++ b/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs_SignalImpl.h @@ -96,7 +96,7 @@ static void os__signal_notify(int sig) { sig_sem__signal(); } -// sun.misc.Signal +// jdk.internal.misc.Signal // NOTE that this is a workaround for an apparent kernel bug where if // a signal handler for SIGBREAK is installed then that signal handler // takes priority over the console control handler for CTRL_CLOSE_EVENT. diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/cSunMiscSignal.c b/substratevm/src/com.oracle.svm.native.libchelper/src/cSunMiscSignal.c index e7a9300ae2f8..1922389ab7e0 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/src/cSunMiscSignal.c +++ b/substratevm/src/com.oracle.svm.native.libchelper/src/cSunMiscSignal.c @@ -49,7 +49,7 @@ * notifying of increments to the values of the counters. * * The other public functions here are operations on the data allocated here, for the convenience of - * the code in Target_sun_misc_Signal. + * the code in Target_jdk_internal_misc_Signal. * * The state for handling signals is global to a process, and has no knowledge of isolates. That * imposes the restriction that only one isolate at a time may register to receive signals. diff --git a/substratevm/src/com.oracle.svm.thirdparty/src/com/oracle/svm/thirdparty/gson/GsonFeature.java b/substratevm/src/com.oracle.svm.thirdparty/src/com/oracle/svm/thirdparty/gson/GsonFeature.java index 65f559b183b0..c1b071018956 100644 --- a/substratevm/src/com.oracle.svm.thirdparty/src/com/oracle/svm/thirdparty/gson/GsonFeature.java +++ b/substratevm/src/com.oracle.svm.thirdparty/src/com/oracle/svm/thirdparty/gson/GsonFeature.java @@ -24,10 +24,12 @@ */ package com.oracle.svm.thirdparty.gson; +import java.util.Optional; + import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeReflection; -import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.ReflectionUtil; /** * Support for the Gson library on SubstrateVM. @@ -36,25 +38,33 @@ * to be registered manually by the user using the {@link RuntimeReflection runtime reflection * support} of Substrate VM. It is not feasible to automatically detect all necessary classes. *

      - * This feature registers parts of {@link sun.misc.Unsafe} as reflectively accessible. Gson uses it + * This feature registers parts of {@code sun.misc.Unsafe} as reflectively accessible. Gson uses it * internally to instantiate classes that do not have a no-argument constructor. */ public final class GsonFeature implements Feature { + private static Optional requiredModule() { + return ModuleLayer.boot().findModule("jdk.unsupported"); + } + @Override public boolean isInConfiguration(IsInConfigurationAccess access) { - return access.findClassByName("com.google.gson.Gson") != null; + /* `sun.misc.Unsafe` is in `jdk.unsupported` */ + return requiredModule().isPresent(); } @Override public void beforeAnalysis(BeforeAnalysisAccess access) { - try { - /* Reflection usage in com.google.gson.internal.UnsafeAllocator.create(). */ - RuntimeReflection.register(sun.misc.Unsafe.class); - RuntimeReflection.register(sun.misc.Unsafe.class.getDeclaredField("theUnsafe")); - RuntimeReflection.register(sun.misc.Unsafe.class.getDeclaredMethod("allocateInstance", Class.class)); - } catch (NoSuchFieldException | NoSuchMethodException ex) { - throw VMError.shouldNotReachHere(ex); + Class gsonClass = access.findClassByName("com.google.gson.Gson"); + if (gsonClass != null) { + access.registerReachabilityHandler(GsonFeature::makeUnsafeReflectivelyAccessible, gsonClass); } } + + private static void makeUnsafeReflectivelyAccessible(DuringAnalysisAccess a) { + Class unsafeClass = a.findClassByName("sun.misc.Unsafe"); + RuntimeReflection.register(unsafeClass); + RuntimeReflection.register(ReflectionUtil.lookupField(unsafeClass, "theUnsafe")); + RuntimeReflection.register(ReflectionUtil.lookupMethod(unsafeClass, "allocateInstance", Class.class)); + } } diff --git a/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java b/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java index 43439a065689..c75e6603ee4b 100644 --- a/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java +++ b/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java @@ -88,7 +88,6 @@ import jdk.vm.ci.meta.ModifiersProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -import sun.misc.Unsafe; /** * A Truffle TCK {@code Feature} detecting privileged calls done by Truffle language. The @@ -171,6 +170,8 @@ public boolean getAsBoolean() { private InlinedUnsafeMethodNode inlinedUnsafeCall; + private Class sunMiscUnsafe; + @Override public String getDescription() { return "Detects privileged calls in Truffle languages"; @@ -187,6 +188,10 @@ public void duringSetup(DuringSetupAccess access) { } reportFilePath = Paths.get(reportFile); + if (ModuleLayer.boot().findModule("jdk.unsupported").isPresent()) { + sunMiscUnsafe = access.findClassByName("sun.misc.Unsafe"); + } + FeatureImpl.DuringSetupAccessImpl accessImpl = (FeatureImpl.DuringSetupAccessImpl) access; accessImpl.getHostVM().keepAnalysisGraphs(); } @@ -203,7 +208,9 @@ public void afterAnalysis(AfterAnalysisAccess access) { DebugContext debugContext = accessImpl.getDebugContext(); try (DebugContext.Scope s = debugContext.scope(ClassUtil.getUnqualifiedName(getClass()))) { BigBang bb = accessImpl.getBigBang(); - inlinedUnsafeCall = new InlinedUnsafeMethodNode(bb); + if (sunMiscUnsafe != null) { + inlinedUnsafeCall = new InlinedUnsafeMethodNode(bb.getMetaAccess().lookupJavaType(sunMiscUnsafe)); + } WhiteListParser parser = new WhiteListParser(accessImpl.getImageClassLoader(), bb); ConfigurationParserUtils.parseAndRegisterConfigurations(parser, accessImpl.getImageClassLoader(), @@ -216,7 +223,9 @@ public void afterAnalysis(AfterAnalysisAccess access) { whiteList = parser.getLoadedWhiteList(); Set deniedMethods = new HashSet<>(); deniedMethods.addAll(findMethods(bb, SecurityManager.class, (m) -> m.getName().startsWith("check"))); - deniedMethods.addAll(findMethods(bb, sun.misc.Unsafe.class, ModifiersProvider::isPublic)); + if (sunMiscUnsafe != null) { + deniedMethods.addAll(findMethods(bb, sunMiscUnsafe, ModifiersProvider::isPublic)); + } // The type of the host Java NIO FileSystem. // The FileSystem obtained from the FileSystem.newDefaultFileSystem() is in the Truffle // package but @@ -225,7 +234,9 @@ public void afterAnalysis(AfterAnalysisAccess access) { // JDK 19 introduced BigInteger.parallelMultiply that uses the ForkJoinPool. // We deny this method but explicitly allow non-parallel multiply (cf. jre.json). deniedMethods.addAll(findMethods(bb, BigInteger.class, (m) -> m.getName().startsWith("parallel"))); - deniedMethods.add(inlinedUnsafeCall); + if (inlinedUnsafeCall != null) { + deniedMethods.add(inlinedUnsafeCall); + } Map> cg = callGraph(bb, deniedMethods, debugContext, (SVMHost) bb.getHostVM()); List> report = new ArrayList<>(); Set contextFilters = new HashSet<>(); @@ -307,7 +318,9 @@ private boolean callGraphImpl( StructuredGraph mGraph = hostVM.getAnalysisGraph(m); if (mGraph.hasUnsafeAccess() && !(isSystemClass(mNode) || isCompilerClass(mNode))) { debugContext.log(DebugContext.VERY_DETAILED_LEVEL, "Method: %s has unsafe access.", mName); - visited.computeIfAbsent(inlinedUnsafeCall, (e) -> new HashSet<>()).add(mNode); + if (inlinedUnsafeCall != null) { + visited.computeIfAbsent(inlinedUnsafeCall, (e) -> new HashSet<>()).add(mNode); + } } try { boolean callPathContainsTarget = false; @@ -829,8 +842,8 @@ private static final class InlinedUnsafeMethodNode extends BaseMethodNode { private final AnalysisType unsafe; - InlinedUnsafeMethodNode(BigBang bigBang) { - this.unsafe = bigBang.getMetaAccess().lookupJavaType(Unsafe.class); + InlinedUnsafeMethodNode(AnalysisType unsafe) { + this.unsafe = unsafe; } @Override