Skip to content

[WIP] [GR-55885] Initialize FileSystemProvider at run time #11205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> ALL_VALUES = Set.of(RUN_TIME_INITIALIZE_JDK_NAME, ALL_NAME, NONE_NAME);

private static String futureDefaultsAllValues() {
Expand All @@ -66,14 +68,15 @@ 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<AccumulatingLocatableMultiOptionValue.Strings> FutureDefaults = new HostedOptionKey<>(
static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> FutureDefaults = new HostedOptionKey<>(
AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());

private static EconomicSet<String> futureDefaults;

@Platforms(Platform.HOSTED_ONLY.class)
public static void parseAndVerifyOptions() {
futureDefaults = EconomicSet.create(ALL_VALUES.size());
futureDefaults.add(RUN_TIME_INITIALIZE_JDK_NAME);
var valuesWithOrigin = FutureDefaults.getValue().getValuesWithOrigins();
valuesWithOrigin.forEach(valueWithOrigin -> {
String value = valueWithOrigin.value();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<FileSystemProvider> installedProviders() {
Expand Down Expand Up @@ -171,7 +171,7 @@ public static List<FileSystemProvider> 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 {

Expand Down Expand Up @@ -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 {
}
Expand Down Expand Up @@ -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 {

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2016, 2017, 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.fs.runtimeinit;

import java.nio.file.FileSystem;
import java.nio.file.spi.FileSystemProvider;

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 = Target_java_io_DefaultFileSystem_RunTime.getFileSystem();// =
}

class DefaultFileSystemAccessor {
@SuppressWarnings("unused")
static Target_java_io_FileSystem_RunTime get() {
return DefaultFileSystemHolder.FS;
}
}

// sun.nio.fs

@TargetClass(className = "sun.nio.fs.DefaultFileSystemProvider", onlyWith = JDKInitializedAtRunTime.class)
final class Target_sun_nio_fs_DefaultFileSystemProvider_RunTime {
@Alias
public 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 = 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;
}

class UnixFileSystemAccessor {
static Target_sun_nio_fs_UnixFileSystem_RunTime get(Target_sun_nio_fs_UnixPath_RunTime that) {
return 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) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,11 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import jdk.graal.compiler.core.common.ContextClassLoaderScope;
import org.graalvm.nativeimage.libgraal.hosted.LibGraalLoader;
import org.graalvm.collections.EconomicSet;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;
import org.graalvm.nativeimage.impl.clinit.ClassInitializationTracking;
import org.graalvm.nativeimage.libgraal.hosted.LibGraalLoader;

import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider;
import com.oracle.graal.pointsto.meta.AnalysisType;
Expand All @@ -65,6 +64,7 @@
import com.oracle.svm.util.LogUtils;
import com.oracle.svm.util.ModuleSupport;

import jdk.graal.compiler.core.common.ContextClassLoaderScope;
import jdk.graal.compiler.java.LambdaUtils;
import jdk.internal.misc.Unsafe;
import jdk.vm.ci.meta.MetaAccessProvider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,40 @@ 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);
// because static Path
// rci.initializeAtRunTime("jdk.internal.jrtfs.SystemImage",
// 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.File",
// 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.initializeAtBuildTime("java.io.File", FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON);
rci.initializeAtBuildTime("sun.nio.fs.UnixPath", 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);

// Contains a static File reference
// rci.initializeAtRunTime("java.lang.ProcessBuilder$Redirect",
// FutureDefaultsOptions.RUN_TIME_INITIALIZE_JDK_REASON);
}

/* XML-related */
if (FutureDefaultsOptions.isJDKInitializedAtRunTime()) {
// GR-50683 should remove this part
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
Loading