diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/attach/PosixAttachApiSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/attach/PosixAttachApiSupport.java index 4a967df3cce2..68224beeede3 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/attach/PosixAttachApiSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/attach/PosixAttachApiSupport.java @@ -26,7 +26,7 @@ package com.oracle.svm.core.posix.attach; -import java.nio.file.Paths; +import java.nio.file.FileSystems; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; @@ -181,7 +181,7 @@ private String getSocketFilePath() { if (cachedSocketFilePath == null) { long pid = ProcessHandle.current().pid(); String tempDir = Target_jdk_internal_vm_VMSupport.getVMTemporaryDirectory(); - cachedSocketFilePath = Paths.get(tempDir, ".java_pid" + pid).toString(); + cachedSocketFilePath = tempDir + FileSystems.getDefault().getSeparator() + ".java_pid" + pid; } return cachedSocketFilePath; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FutureDefaultsOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FutureDefaultsOptions.java index e53f70cb9b43..6861a5c02583 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FutureDefaultsOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FutureDefaultsOptions.java @@ -54,6 +54,8 @@ public class FutureDefaultsOptions { private static final String NONE_NAME = "none"; private static final String RUN_TIME_INITIALIZE_JDK_NAME = "run-time-initialized-jdk"; + public static final String RUN_TIME_INITIALIZE_JDK_REASON = "Initialize JDK classes at run time (--" + OPTION_NAME + " includes " + RUN_TIME_INITIALIZE_JDK_NAME + ")"; + private static final Set ALL_VALUES = Set.of(RUN_TIME_INITIALIZE_JDK_NAME, ALL_NAME, NONE_NAME); private static String futureDefaultsAllValues() { @@ -66,7 +68,7 @@ private static String futureDefaultsAllValues() { @APIOption(name = OPTION_NAME, defaultValue = DEFAULT_NAME) // @Option(help = "file:doc-files/FutureDefaultsHelp.txt", type = OptionType.User) // - public static final HostedOptionKey FutureDefaults = new HostedOptionKey<>( + static final HostedOptionKey FutureDefaults = new HostedOptionKey<>( AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); private static EconomicSet futureDefaults; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/FileSystemProviderSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/FileSystemProviderSupport.java index 008d59d433c7..a1ffb6f9d56e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/FileSystemProviderSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/FileSystemProviderSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -142,7 +142,7 @@ public void afterRegistration(AfterRegistrationAccess access) { } } -@TargetClass(java.nio.file.spi.FileSystemProvider.class) +@TargetClass(value = java.nio.file.spi.FileSystemProvider.class, onlyWith = JDKInitializedAtBuildTime.class) final class Target_java_nio_file_spi_FileSystemProvider { @Substitute public static List installedProviders() { @@ -171,7 +171,7 @@ public static List installedProviders() { * c) Allow UnixFileSystem in the image heap and recompute state at run time on first acccess. This * approach is implemented here. */ -@TargetClass(className = "sun.nio.fs.UnixFileSystem") +@TargetClass(className = "sun.nio.fs.UnixFileSystem", onlyWith = JDKInitializedAtBuildTime.class) @Platforms({Platform.LINUX.class, Platform.DARWIN.class}) final class Target_sun_nio_fs_UnixFileSystem { @@ -224,12 +224,12 @@ final class Target_sun_nio_fs_UnixFileSystem { native void originalConstructor(Target_sun_nio_fs_UnixFileSystemProvider p, String dir); } -@TargetClass(className = "sun.nio.fs.UnixFileSystemProvider") +@TargetClass(className = "sun.nio.fs.UnixFileSystemProvider", onlyWith = JDKInitializedAtBuildTime.class) @Platforms({Platform.LINUX.class, Platform.DARWIN.class}) final class Target_sun_nio_fs_UnixFileSystemProvider { } -@TargetClass(className = "sun.nio.fs.UnixPath") +@TargetClass(className = "sun.nio.fs.UnixPath", onlyWith = JDKInitializedAtBuildTime.class) @Platforms({Platform.LINUX.class, Platform.DARWIN.class}) final class Target_sun_nio_fs_UnixPath { } @@ -403,7 +403,7 @@ private static synchronized void reinitialize(Target_sun_nio_fs_WindowsFileSyste } } -@TargetClass(className = "java.io.UnixFileSystem") +@TargetClass(className = "java.io.UnixFileSystem", onlyWith = JDKInitializedAtBuildTime.class) @Platforms({Platform.LINUX.class, Platform.DARWIN.class}) final class Target_java_io_UnixFileSystem { @@ -412,7 +412,7 @@ final class Target_java_io_UnixFileSystem { private String userDir; } -@TargetClass(className = "java.io.FileSystem") +@TargetClass(className = "java.io.FileSystem", onlyWith = JDKInitializedAtBuildTime.class) final class Target_java_io_FileSystem { @Alias diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKInitializedAtBuildTime.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKInitializedAtBuildTime.java new file mode 100644 index 000000000000..5633833cbfcd --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKInitializedAtBuildTime.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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; + +import com.oracle.svm.core.FutureDefaultsOptions; + +public class JDKInitializedAtBuildTime implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return !FutureDefaultsOptions.isJDKInitializedAtRunTime(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKInitializedAtRunTime.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKInitializedAtRunTime.java new file mode 100644 index 000000000000..58cd8f77d6a9 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKInitializedAtRunTime.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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; + +import com.oracle.svm.core.FutureDefaultsOptions; + +public class JDKInitializedAtRunTime implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return FutureDefaultsOptions.isJDKInitializedAtRunTime(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/runtimeinit/FileSystemProviderRuntimeInitSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/runtimeinit/FileSystemProviderRuntimeInitSupport.java new file mode 100644 index 000000000000..42fa21eebd88 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/runtimeinit/FileSystemProviderRuntimeInitSupport.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.runtimeinit; + +import java.nio.file.FileSystem; +import java.nio.file.spi.FileSystemProvider; +import java.util.Objects; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.InjectAccessors; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.jdk.JDKInitializedAtRunTime; + +/** + * This file contains substitutions that are required for initializing {@link FileSystemProvider} at + * image run time. Other related functionality (general and build time initialization) can be found + * in {@link com.oracle.svm.core.jdk.FileSystemProviderSupport}. + * + * @see JDKInitializedAtRunTime + * @see com.oracle.svm.core.jdk.FileSystemProviderSupport + */ +final class FileSystemProviderRuntimeInitSupport { +} + +// java.io + +@TargetClass(className = "java.io.FileSystem", onlyWith = JDKInitializedAtRunTime.class) +final class Target_java_io_FileSystem_RunTime { +} + +@TargetClass(className = "java.io.File", onlyWith = JDKInitializedAtRunTime.class) +@SuppressWarnings("unused") +final class Target_java_io_File_RunTime { + @Alias // + @InjectAccessors(DefaultFileSystemAccessor.class) // + private static Target_java_io_FileSystem_RunTime FS; +} + +@TargetClass(className = "java.io.DefaultFileSystem", onlyWith = JDKInitializedAtRunTime.class) +final class Target_java_io_DefaultFileSystem_RunTime { + @Alias + static native Target_java_io_FileSystem_RunTime getFileSystem(); +} + +/** + * Holds the default java.io file system. Initialized at run time via + * {@code JDKInitializationFeature}. + */ +class DefaultFileSystemHolder { + static final Target_java_io_FileSystem_RunTime FS; + static { + if (SubstrateUtil.HOSTED) { + // unused - layered images might want to initialize during image build + FS = null; + } else { + FS = Target_java_io_DefaultFileSystem_RunTime.getFileSystem(); + } + } +} + +class DefaultFileSystemAccessor { + @SuppressWarnings("unused") + static Target_java_io_FileSystem_RunTime get() { + return Objects.requireNonNull(DefaultFileSystemHolder.FS); + } +} + +// sun.nio.fs + +@TargetClass(className = "sun.nio.fs.DefaultFileSystemProvider", onlyWith = JDKInitializedAtRunTime.class) +final class Target_sun_nio_fs_DefaultFileSystemProvider_RunTime { + @Alias + static native FileSystem theFileSystem(); +} + +/** + * Holds the default sun.nio.fs file system. Initialized at run time via + * {@code JDKInitializationFeature}. + */ +class SunNioFsDefaultFileSystemHolder { + static final FileSystem FS; + + static { + if (SubstrateUtil.HOSTED) { + // unused - layered images might want to initialize during image build + FS = null; + } else { + FS = Target_sun_nio_fs_DefaultFileSystemProvider_RunTime.theFileSystem(); + } + } +} + +@TargetClass(className = "sun.nio.fs.UnixFileSystem", onlyWith = JDKInitializedAtRunTime.class) +@Platforms({Platform.LINUX.class, Platform.DARWIN.class}) +final class Target_sun_nio_fs_UnixFileSystem_RunTime { +} + +@TargetClass(className = "sun.nio.fs.UnixPath", onlyWith = JDKInitializedAtRunTime.class) +@Platforms({Platform.LINUX.class, Platform.DARWIN.class}) +final class Target_sun_nio_fs_UnixPath_RunTime { + @Alias // + @InjectAccessors(UnixFileSystemAccessor.class) // + private Target_sun_nio_fs_UnixFileSystem_RunTime fs; +} + +@SuppressWarnings("unused") +class UnixFileSystemAccessor { + static Target_sun_nio_fs_UnixFileSystem_RunTime get(Target_sun_nio_fs_UnixPath_RunTime that) { + return Objects.requireNonNull(SubstrateUtil.cast(SunNioFsDefaultFileSystemHolder.FS, Target_sun_nio_fs_UnixFileSystem_RunTime.class)); + } + + static void set(Target_sun_nio_fs_UnixPath_RunTime that, Target_sun_nio_fs_UnixFileSystem_RunTime value) { + /* + * `value` should always be DefaultFileSystemProvider.INSTANCE.theFileSystem() but we cannot + * check that here because it would introduce a class initialization cycle. + */ + } +} + +@TargetClass(className = "sun.nio.fs.WindowsFileSystem", onlyWith = JDKInitializedAtRunTime.class) +@Platforms(Platform.WINDOWS.class) +final class Target_sun_nio_fs_WindowsFileSystem_RunTime { +} + +@TargetClass(className = "sun.nio.fs.WindowsPath", onlyWith = JDKInitializedAtRunTime.class) +@Platforms(Platform.WINDOWS.class) +final class Target_sun_nio_fs_WindowsPath_RunTime { + @Alias // + @InjectAccessors(WindowsFileSystemAccessor.class) // + private Target_sun_nio_fs_WindowsFileSystem_RunTime fs; +} + +@SuppressWarnings("unused") +class WindowsFileSystemAccessor { + static Target_sun_nio_fs_WindowsFileSystem_RunTime get(Target_sun_nio_fs_WindowsPath_RunTime that) { + return Objects.requireNonNull(SubstrateUtil.cast(SunNioFsDefaultFileSystemHolder.FS, Target_sun_nio_fs_WindowsFileSystem_RunTime.class)); + } + + static void set(Target_sun_nio_fs_WindowsPath_RunTime that, Target_sun_nio_fs_WindowsFileSystem_RunTime value) { + /* + * `value` should always be DefaultFileSystemProvider.INSTANCE.theFileSystem() but we cannot + * check that here because it would introduce a class initialization cycle. + */ + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java index a6f5fb32c145..b28a424ee1c1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -142,6 +142,34 @@ public void afterRegistration(AfterRegistrationAccess access) { rci.initializeAtBuildTime("java.awt.font.NumericShaper", "Required for sun.text.bidi.BidiBase.NumericShapings"); rci.initializeAtBuildTime("java.awt.font.JavaAWTFontAccessImpl", "Required for sun.text.bidi.BidiBase.NumericShapings"); + /* FileSystemProviders related */ + if (FutureDefaultsOptions.isJDKInitializedAtRunTime()) { + rci.initializeAtRunTime("java.nio.file.spi", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + rci.initializeAtRunTime("sun.nio.fs", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + + rci.initializeAtRunTime("java.nio.file.FileSystems", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + rci.initializeAtRunTime("java.nio.file.FileSystems$DefaultFileSystemHolder", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + + rci.initializeAtRunTime("java.util.zip.ZipFile$Source", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + rci.initializeAtRunTime("java.util.zip.ZipFile$Source", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + + rci.initializeAtRunTime("java.io.FileSystem", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + rci.initializeAtRunTime("java.io.FileSystem$CurrentWorkingDirectoryHolder", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + rci.initializeAtRunTime("java.io.UnixFileSystem", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + rci.initializeAtRunTime("java.io.WindowsFileSystem", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + + rci.initializeAtBuildTime("java.io.File", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + rci.initializeAtBuildTime("sun.nio.fs.UnixPath", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + rci.initializeAtBuildTime("sun.nio.fs.WindowsPath", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + + // holder for the default file system + rci.initializeAtRunTime("com.oracle.svm.core.jdk.fs.runtimeinit.DefaultFileSystemHolder", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + rci.initializeAtRunTime("com.oracle.svm.core.jdk.fs.runtimeinit.SunNioFsDefaultFileSystemHolder", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + + // JrtFS support + rci.initializeAtBuildTime("jdk.internal.jrtfs.SystemImage", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON); + } + /* XML-related */ if (FutureDefaultsOptions.isJDKInitializedAtRunTime()) { // GR-50683 should remove this part diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKRegistrations.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKRegistrations.java index 33289d653864..ee1c46fa7b2c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKRegistrations.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKRegistrations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,7 @@ public void duringSetup(DuringSetupAccess a) { * a `Random` object and the temporary directory in a static final field. */ initializeAtRunTime(a, "sun.nio.ch.UnixDomainSockets"); + initializeAtRunTime(a, "sun.nio.ch.UnixDomainSockets$UnnamedHolder"); initializeAtRunTime(a, "java.util.concurrent.ThreadLocalRandom$ThreadLocalRandomProxy");