Commit Graph

85916 Commits

Author SHA1 Message Date
Fabio Niephaus a4af3090d8 [GR-52996] Improve VS detection and related error messages.
PullRequest: graal/17427
2024-11-08 14:51:48 +00:00
Allan Gregersen d7f4612086 [GR-59465] Fix disabling debugger stepping too aggressively.
PullRequest: graal/19238
2024-11-08 09:13:07 +00:00
Gilles Duboscq 2c9935c913 [GR-59566] Avoid requiring sun/nio/ch/NativeThread.current0.
PullRequest: graal/19211
2024-11-08 09:06:07 +00:00
Paul Wögerer accd13dd24 [GR-57627] Allow LibGraalFeature class to be loaded by HostedLibGraalClassLoader.
PullRequest: graal/18691
2024-11-08 07:54:08 +00:00
Yudi Zheng 4d4b61da33 [GR-59678] Update SyncPort info.
PullRequest: graal/19261
2024-11-08 04:43:57 +00:00
Christian Humer c9539d8ed8 [GR-59640] Add IOException checked exception to InternalResource.versionHash(Env).
PullRequest: graal/19237
2024-11-08 02:24:37 +00:00
Sacha Coppey 806c89ae9b [GR-58468] Load lambda types in the application layer
PullRequest: graal/18883
2024-11-08 00:25:21 +00:00
Yudi Zheng e002c8aeb6 [GR-58215] Adapt JDK-8329254: optimize integral reverse operations on x86 GFNI target.
PullRequest: graal/19258
2024-11-08 00:25:05 +00:00
Olya Gupalo 3bf288d174 [GR-59533] Test and refresh Include Reachability Metadata Native Image guides.
PullRequest: graal/19219
2024-11-07 21:27:43 +00:00
Vojin Jovanovic f3d5274aca [GR-59651] Link the troubleshooting guide in the GitHub issue template.
PullRequest: graal/19242
2024-11-07 19:52:49 +00:00
Paul Wögerer 45253c7be4 Refactor LibGraalClassLoader to be usable as customLoader
diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py
index 6fa9c61e2f5..7c4d8918601 100644
--- a/compiler/mx.compiler/suite.py
+++ b/compiler/mx.compiler/suite.py
@@ -465,6 +465,22 @@ suite = {
       "workingSets" : "Graal,Test",
       "graalCompilerSourceEdition": "ignore",
     },
+
+    "jdk.graal.compiler.libgraal" : {
+      "subDir" : "src",
+      "sourceDirs" : ["src"],
+      "workingSets" : "Graal",
+      "javaCompliance" : "21+",
+      "dependencies" : [
+        "jdk.graal.compiler",
+      ],
+      "requiresConcealed" : {
+        "java.base" : [
+          "jdk.internal.module",
+          "jdk.internal.jimage",
+        ],
+      },
+    },
   },

   "distributions" : {
@@ -581,6 +597,7 @@ suite = {
         "GRAAL_VERSION",
       ],
       "distDependencies" : [
+        "sdk:NATIVEIMAGE",
         "sdk:COLLECTIONS",
         "sdk:WORD",
         "sdk:NATIVEIMAGE",
@@ -691,6 +708,17 @@ suite = {
       "graalCompilerSourceEdition": "ignore",
     },

+    "GRAAL_LIBGRAAL" : {
+      "subDir": "src",
+      "dependencies" : [
+        "jdk.graal.compiler.libgraal",
+      ],
+      "distDependencies" : [
+        "GRAAL",
+      ],
+      "maven": False,
+    },
+
     "GRAAL_PROFDIFF_TEST" : {
       "subDir" : "src",
       "dependencies" : [
diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalClassLoader.java b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/hotspot/libgraal/LibGraalClassLoader.java
similarity index 70%
rename from substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalClassLoader.java
rename to compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/hotspot/libgraal/LibGraalClassLoader.java
index aaa171c742a..2c1e53e6850 100644
--- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalClassLoader.java
+++ b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/hotspot/libgraal/LibGraalClassLoader.java
@@ -22,7 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.svm.graal.hotspot.libgraal;
+package jdk.graal.compiler.hotspot.libgraal;

 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -38,7 +38,6 @@ import java.nio.ByteBuffer;
 import java.nio.file.Path;
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
@@ -47,50 +46,49 @@ import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Set;

-import com.oracle.svm.core.SubstrateUtil;
-import com.oracle.svm.core.util.VMError;
+import org.graalvm.nativeimage.Platform;
+import org.graalvm.nativeimage.Platforms;
+import org.graalvm.nativeimage.hosted.Feature;

-import com.oracle.svm.util.ModuleSupport;
+import jdk.graal.compiler.debug.GraalError;
 import jdk.internal.jimage.BasicImageReader;
 import jdk.internal.jimage.ImageLocation;
-import org.graalvm.nativeimage.Platform;
-import org.graalvm.nativeimage.Platforms;
+import jdk.internal.module.Modules;

 /**
  * A classloader, that reads class files and resources from a jimage file at image build time.
  */
-public class LibGraalClassLoader extends ClassLoader {
+@Platforms(Platform.HOSTED_ONLY.class)
+final class HostedLibGraalClassLoader extends ClassLoader {
+
+    private static final String JAVA_HOME_PROPERTY_KEY = "libgraal.javahome";
+    private static final String JAVA_HOME_PROPERTY_VALUE = System.getProperty(JAVA_HOME_PROPERTY_KEY, System.getProperty("java.home"));

     /**
      * Reader for the image.
      */
-    @Platforms(Platform.HOSTED_ONLY.class) //
     private final BasicImageReader imageReader;

     /**
      * Map from the name of a resource (without module qualifier) to its path in the image.
      */
-    @Platforms(Platform.HOSTED_ONLY.class) //
     private final Map<String, String> resources = new HashMap<>();

     /**
      * Map from the {@linkplain Class#forName(String) name} of a class to the image path of its
      * class file.
      */
-    @Platforms(Platform.HOSTED_ONLY.class) //
     private final Map<String, String> classes = new HashMap<>();

     /**
      * Map from a service name to a list of providers.
      */
-    @Platforms(Platform.HOSTED_ONLY.class) //
     private final Map<String, List<String>> services = new HashMap<>();

     /**
      * Map from the {@linkplain Class#forName(String) name} of a class to the name of its enclosing
      * module.
      */
-    @Platforms(Platform.HOSTED_ONLY.class) //
     private final Map<String, String> modules;

     /**
@@ -109,17 +107,22 @@ public class LibGraalClassLoader extends ClassLoader {
         ClassLoader.registerAsParallelCapable();
     }

-    /**
-     * @param imagePath path to the runtime image of a Java installation
-     */
-    @Platforms(Platform.HOSTED_ONLY.class)
-    LibGraalClassLoader(Path imagePath) {
-        super("LibGraalClassLoader", null);
+    public final Path libGraalJavaHome;
+
+    public HostedLibGraalClassLoader() {
+        super(LibGraalClassLoader.LOADER_NAME, Feature.class.getClassLoader());
+        libGraalJavaHome = Path.of(JAVA_HOME_PROPERTY_VALUE);
+
         Map<String, String> modulesMap = new HashMap<>();
         try {
-            // Need access to jdk.internal.jimage
-            ModuleSupport.accessPackagesToClass(ModuleSupport.Access.EXPORT, getClass(), false,
-                            "java.base", "jdk.internal.jimage");
+            /*
+             * Access to jdk.internal.jimage classes is needed by this Classloader implementation.
+             */
+            Modules.addExports(Object.class.getModule(), "jdk.internal.jimage", HostedLibGraalClassLoader.class.getModule());
+
+            Modules.addExports(Object.class.getModule(), "jdk.internal.misc", HostedLibGraalClassLoader.class.getModule());
+
+            Path imagePath = libGraalJavaHome.resolve(Path.of("lib", "modules"));
             this.imageReader = BasicImageReader.open(imagePath);
             for (var entry : imageReader.getEntryNames()) {
                 int secondSlash = entry.indexOf('/', 1);
@@ -152,15 +155,28 @@ public class LibGraalClassLoader extends ClassLoader {

     /**
      * Gets an unmodifiable map from the {@linkplain Class#forName(String) name} of a class to the
-     * name of its enclosing module.
+     * name of its enclosing module. Reflectively accessed by
+     * {@code LibGraalFeature.OptionCollector#afterAnalysis(AfterAnalysisAccess)}.
      */
+    @SuppressWarnings("unused")
     public Map<String, String> getModules() {
         return modules;
     }

+    @SuppressWarnings("unused")
+    public List<Class<?>> getSystemClasses() {
+        Class<?> clazz = null;
+        try {
+            clazz = loadClass("jdk.graal.compiler.hotspot.libgraal.NewLibGraalEntryPoints");
+        } catch (ClassNotFoundException e) {
+            throw GraalError.shouldNotReachHere("FIXME");
+        }
+        return List.of(clazz);
+    }
+
     @Override
     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
-        if (!SubstrateUtil.HOSTED || !classes.containsKey(name)) {
+        if (!classes.containsKey(name)) {
             return super.loadClass(name, resolve);
         }
         synchronized (getClassLoadingLock(name)) {
@@ -172,40 +188,18 @@ public class LibGraalClassLoader extends ClassLoader {
         }
     }

-    @Platforms(Platform.HOSTED_ONLY.class)
-    public Class<?> loadClassOrFail(Class<?> c) {
-        if (c.getClassLoader() == this) {
-            return c;
-        }
-        if (c.isArray()) {
-            return loadClassOrFail(c.getComponentType()).arrayType();
-        }
-        return loadClassOrFail(c.getName());
-    }
-
-    @Platforms(Platform.HOSTED_ONLY.class)
-    public Class<?> loadClassOrFail(String name) {
-        try {
-            return loadClass(name);
-        } catch (ClassNotFoundException e) {
-            throw VMError.shouldNotReachHere("%s unable to load class '%s'", getName(), name);
-        }
-    }
-
     @Override
     protected Class<?> findClass(final String name)
                     throws ClassNotFoundException {
-        if (SubstrateUtil.HOSTED) {
-            String path = name.replace('.', '/').concat(".class");
-
-            String pathInImage = resources.get(path);
-            if (pathInImage != null) {
-                ImageLocation location = imageReader.findLocation(pathInImage);
-                if (location != null) {
-                    ByteBuffer bb = Objects.requireNonNull(imageReader.getResourceBuffer(location));
-                    ProtectionDomain pd = null;
-                    return super.defineClass(name, bb, pd);
-                }
+        String path = name.replace('.', '/').concat(".class");
+
+        String pathInImage = resources.get(path);
+        if (pathInImage != null) {
+            ImageLocation location = imageReader.findLocation(pathInImage);
+            if (location != null) {
+                ByteBuffer bb = Objects.requireNonNull(imageReader.getResourceBuffer(location));
+                ProtectionDomain pd = null;
+                return super.defineClass(name, bb, pd);
             }
         }
         throw new ClassNotFoundException(name);
@@ -222,35 +216,32 @@ public class LibGraalClassLoader extends ClassLoader {
      */
     private static final String RESOURCE_PROTOCOL = "resource";

-    @Platforms(Platform.HOSTED_ONLY.class) //
     private URLStreamHandler serviceHandler;

     @Override
     protected URL findResource(String name) {
-        if (SubstrateUtil.HOSTED) {
-            URLStreamHandler handler = this.serviceHandler;
-            if (handler == null) {
-                this.serviceHandler = handler = new ImageURLStreamHandler();
-            }
-            if (name.startsWith("META-INF/services/")) {
-                String service = name.substring("META-INF/services/".length());
-                if (services.containsKey(service)) {
-                    try {
-                        var uri = new URI(SERVICE_PROTOCOL, service, null);
-                        return URL.of(uri, handler);
-                    } catch (URISyntaxException | MalformedURLException e) {
-                        return null;
-                    }
+        URLStreamHandler handler = this.serviceHandler;
+        if (handler == null) {
+            this.serviceHandler = handler = new ImageURLStreamHandler();
+        }
+        if (name.startsWith("META-INF/services/")) {
+            String service = name.substring("META-INF/services/".length());
+            if (services.containsKey(service)) {
+                try {
+                    var uri = new URI(SERVICE_PROTOCOL, service, null);
+                    return URL.of(uri, handler);
+                } catch (URISyntaxException | MalformedURLException e) {
+                    return null;
                 }
-            } else {
-                String path = resources.get(name);
-                if (path != null) {
-                    try {
-                        var uri = new URI(RESOURCE_PROTOCOL, name, null);
-                        return URL.of(uri, handler);
-                    } catch (URISyntaxException | MalformedURLException e) {
-                        return null;
-                    }
+            }
+        } else {
+            String path = resources.get(name);
+            if (path != null) {
+                try {
+                    var uri = new URI(RESOURCE_PROTOCOL, name, null);
+                    return URL.of(uri, handler);
+                } catch (URISyntaxException | MalformedURLException e) {
+                    return null;
                 }
             }
         }
@@ -259,9 +250,6 @@ public class LibGraalClassLoader extends ClassLoader {

     @Override
     protected Enumeration<URL> findResources(String name) throws IOException {
-        if (!SubstrateUtil.HOSTED) {
-            return Collections.emptyEnumeration();
-        }
         return new Enumeration<>() {
             private URL next = findResource(name);

@@ -284,9 +272,8 @@ public class LibGraalClassLoader extends ClassLoader {

     /**
      * A {@link URLStreamHandler} for use with URLs returned by
-     * {@link LibGraalClassLoader#findResource(java.lang.String)}.
+     * {@link HostedLibGraalClassLoader#findResource(java.lang.String)}.
      */
-    @Platforms(Platform.HOSTED_ONLY.class)
     private class ImageURLStreamHandler extends URLStreamHandler {
         @Override
         public URLConnection openConnection(URL u) {
@@ -307,7 +294,6 @@ public class LibGraalClassLoader extends ClassLoader {
         }
     }

-    @Platforms(Platform.HOSTED_ONLY.class)
     private static class ImageURLConnection extends URLConnection {
         private final byte[] bytes;
         private InputStream in;
@@ -341,4 +327,23 @@ public class LibGraalClassLoader extends ClassLoader {
             return "application/octet-stream";
         }
     }
+
+    /**
+     * @return instance of ClassLoader that should be seen at image-runtime if a class was loaded at
+     *         image-buildtime by this classloader.
+     */
+    @SuppressWarnings("unused")
+    public static ClassLoader getRuntimeClassLoader() {
+        return LibGraalClassLoader.singleton;
+    }
+}
+
+public final class LibGraalClassLoader extends ClassLoader {
+
+    static final String LOADER_NAME = "LibGraalClassLoader";
+    static final LibGraalClassLoader singleton = new LibGraalClassLoader();
+
+    private LibGraalClassLoader() {
+        super(LOADER_NAME, null);
+    }
 }
diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/NewLibGraalEntryPoints.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/NewLibGraalEntryPoints.java
new file mode 100644
index 00000000000..e5a5ab499ef
--- /dev/null
+++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/NewLibGraalEntryPoints.java
@@ -0,0 +1,36 @@
+package jdk.graal.compiler.hotspot.libgraal;
+
+import java.util.function.BooleanSupplier;
+
+import org.graalvm.nativeimage.IsolateThread;
+import org.graalvm.nativeimage.c.function.CEntryPoint;
+
+import jdk.graal.compiler.core.phases.EconomyLowTier;
+
+public class NewLibGraalEntryPoints {
+
+    private static class LoadedByLibGraalClassLoader implements BooleanSupplier {
+        @Override
+        public boolean getAsBoolean() {
+            ClassLoader loader = NewLibGraalEntryPoints.class.getClassLoader();
+            return loader != null && "LibGraalClassLoader".equals(loader.getName());
+        }
+    }
+
+    @CEntryPoint(name = "runMain", include = LoadedByLibGraalClassLoader.class)
+    public static int runMain(@SuppressWarnings("unused") IsolateThread thread) {
+        System.out.println("Hello from jdk.graal.compiler.hotspot.libgraal.NewLibGraalEntryPoints.runMain");
+        System.out.println("EconomyLowTier.class.getClassLoader() = " + EconomyLowTier.class.getClassLoader());
+        try {
+            CompilerConfig.main(new String[]{"CompilerConfig.out"});
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return 0;
+    }
+
+    @CEntryPoint(name = "java_check_heap", include = LoadedByLibGraalClassLoader.class)
+    protected static int checkHeap(@SuppressWarnings("unused") IsolateThread thread) {
+        return 0;
+    }
+}
\ No newline at end of file
diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/NewLibGraalFeature.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/NewLibGraalFeature.java
new file mode 100644
index 00000000000..0fbc82d734d
--- /dev/null
+++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/NewLibGraalFeature.java
@@ -0,0 +1,27 @@
+package jdk.graal.compiler.hotspot.libgraal;
+
+import java.io.PrintStream;
+
+import org.graalvm.nativeimage.hosted.Feature;
+
+import jdk.graal.compiler.core.phases.CommunityCompilerConfiguration;
+import jdk.graal.compiler.debug.GraalError;
+
+public class NewLibGraalFeature implements Feature {
+    @Override
+    public void afterRegistration(AfterRegistrationAccess access) {
+        System.out.println("access.getApplicationClassLoader() = " + access.getApplicationClassLoader());
+        ClassLoader loader = NewLibGraalFeature.class.getClassLoader();
+        System.out.println("CommunityCompilerConfiguration.class.getClassLoader() = " + CommunityCompilerConfiguration.class.getClassLoader());
+        if (loader == null || !"HostedLibGraalClassLoader".equals(loader.getClass().getSimpleName())) {
+            throw GraalError.shouldNotReachHere("NewLibGraalFeature was not loaded by HostedLibGraalClassLoader");
+        }
+    }
+
+    @Override
+    public void beforeAnalysis(BeforeAnalysisAccess access) {
+        access.registerSubtypeReachabilityHandler((duringAnalysisAccess, aClass) -> {
+            System.out.println(aClass.getName() + " reachable");
+        }, PrintStream.class);
+    }
+}
diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py
index e685f649bc8..d930dbb8220 100644
--- a/substratevm/mx.substratevm/mx_substratevm.py
+++ b/substratevm/mx.substratevm/mx_substratevm.py
@@ -1468,6 +1468,7 @@ mx_sdk_vm.register_graalvm_component(mx_sdk_vm.GraalVMSvmMacro(
 libgraal_jar_distributions = [
     'sdk:NATIVEBRIDGE',
     'sdk:JNIUTILS',
+    'compiler:GRAAL_LIBGRAAL',
     'substratevm:LIBGRAAL_LIBRARY']

 def allow_build_path_in_libgraal():
diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py
index 12feca34223..58b4a8b610d 100644
--- a/substratevm/mx.substratevm/suite.py
+++ b/substratevm/mx.substratevm/suite.py
@@ -298,6 +298,7 @@ suite = {
                     "sun.util.resources",
                     "jdk.internal.access",
                     "jdk.internal.event",
+                    "jdk.internal.jimage",
                     "jdk.internal.loader",
                     "jdk.internal.logger",
                     "jdk.internal.misc",
@@ -1386,7 +1387,6 @@ suite = {
             ],
             "requiresConcealed" : {
                 "java.base" : [
-                    "jdk.internal.jimage",
                     "jdk.internal.misc",
                 ],
                 "jdk.internal.vm.ci" : [
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java
index 7420631d361..120fe5a356e 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java
@@ -32,12 +32,12 @@ import java.util.Objects;
 import org.graalvm.collections.EconomicMap;
 import org.graalvm.nativeimage.ImageSingletons;
 import org.graalvm.nativeimage.Platform;
+import org.graalvm.nativeimage.Platform.HOSTED_ONLY;
 import org.graalvm.nativeimage.Platforms;
 import org.graalvm.nativeimage.impl.ConfigurationCondition;

 import com.oracle.svm.core.configure.ConditionalRuntimeValue;
 import com.oracle.svm.core.configure.RuntimeConditionSet;
-import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
 import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
 import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
 import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
@@ -45,9 +45,18 @@ import com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils;
 import com.oracle.svm.core.util.ImageHeapMap;
 import com.oracle.svm.core.util.VMError;

-@AutomaticallyRegisteredImageSingleton
 public final class ClassForNameSupport implements MultiLayeredImageSingleton, UnsavedSingleton {

+    private ClassLoader customLoader;
+
+    public ClassForNameSupport(ClassLoader customLoader) {
+        setCustomLoader(customLoader);
+    }
+
+    public void setCustomLoader(ClassLoader customLoader) {
+        this.customLoader = customLoader;
+    }
+
     public static ClassForNameSupport singleton() {
         return ImageSingletons.lookup(ClassForNameSupport.class);
     }
@@ -115,12 +124,9 @@ public final class ClassForNameSupport implements MultiLayeredImageSingleton, Un
         }
     }

-    private static boolean isLibGraalClass(Class<?> clazz) {
-        var loader = clazz.getClassLoader();
-        if (loader == null) {
-            return false;
-        }
-        return "LibGraalClassLoader".equals(loader.getName());
+    @Platforms(HOSTED_ONLY.class)
+    private boolean isLibGraalClass(Class<?> clazz) {
+        return customLoader != null && clazz.getClassLoader() == customLoader;
     }

     public static ConditionalRuntimeValue<Object> updateConditionalValue(ConditionalRuntimeValue<Object> existingConditionalValue, Object newValue,
diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java
index 0c341c9ca9b..bb3d3bcd51f 100644
--- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java
+++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java
@@ -58,22 +58,23 @@ import com.oracle.graal.pointsto.meta.AnalysisType;
 import com.oracle.graal.pointsto.meta.ObjectReachableCallback;
 import com.oracle.graal.pointsto.reports.CallTreePrinter;
 import com.oracle.svm.core.SubstrateTargetDescription;
-import com.oracle.svm.core.option.HostedOptionKey;
+import com.oracle.svm.core.hub.ClassForNameSupport;
 import com.oracle.svm.core.util.VMError;
 import com.oracle.svm.graal.hotspot.GetCompilerConfig;
 import com.oracle.svm.graal.hotspot.GetJNIConfig;
+import com.oracle.svm.hosted.ClassLoaderFeature;
 import com.oracle.svm.hosted.FeatureImpl.AfterAnalysisAccessImpl;
 import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl;
 import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl;
 import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl;
 import com.oracle.svm.util.ModuleSupport;
+import com.oracle.svm.util.ModuleSupport.Access;
 import com.oracle.svm.util.ReflectionUtil;

 import jdk.graal.compiler.debug.DebugContext;
 import jdk.graal.compiler.hotspot.CompilerConfigurationFactory;
 import jdk.graal.compiler.hotspot.libgraal.BuildTime;
 import jdk.graal.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin;
-import jdk.graal.compiler.options.Option;
 import jdk.graal.compiler.options.OptionDescriptor;
 import jdk.graal.compiler.options.OptionKey;
 import jdk.graal.compiler.serviceprovider.LibGraalService;
@@ -87,7 +88,7 @@ import jdk.vm.ci.code.TargetDescription;
  * <p>
  * This feature is composed of these key classes:
  * <ul>
- * <li>{@link LibGraalClassLoader}</li>
+ * <li>{@code HostedLibGraalClassLoader}</li>
  * <li>{@link LibGraalEntryPoints}</li>
  * <li>{@link LibGraalSubstitutions}</li>
  * </ul>
@@ -95,14 +96,6 @@ import jdk.vm.ci.code.TargetDescription;
 @Platforms(Platform.HOSTED_ONLY.class)
 public final class LibGraalFeature implements Feature {

-    static class Options {
-        @Option(help = "The value of the java.home system property reported by the Java " +
-                        "installation that includes the Graal classes in its runtime image " +
-                        "from which libgraal will be built. If not provided, the java.home " +
-                        "of the Java installation running native-image will be used.") //
-        public static final HostedOptionKey<Path> LibGraalJavaHome = new HostedOptionKey<>(Path.of(System.getProperty("java.home")));
-    }
-
     public static final class IsEnabled implements BooleanSupplier {
         @Override
         public boolean getAsBoolean() {
@@ -120,7 +113,7 @@ public final class LibGraalFeature implements Feature {
     /**
      * Loader used for loading classes from the guest GraalVM.
      */
-    LibGraalClassLoader loader;
+    ClassLoader loader;

     /**
      * Handle to {@link BuildTime} in the guest.
@@ -143,14 +136,32 @@ public final class LibGraalFeature implements Feature {

     MethodHandle handleGlobalAtomicLongGetInitialValue;

-    public LibGraalClassLoader getLoader() {
+    public ClassLoader getLoader() {
         return loader;
     }

+    public Class<?> loadClassOrFail(Class<?> c) {
+        if (c.getClassLoader() == loader) {
+            return c;
+        }
+        if (c.isArray()) {
+            return loadClassOrFail(c.getComponentType()).arrayType();
+        }
+        return loadClassOrFail(c.getName());
+    }
+
+    public Class<?> loadClassOrFail(String name) {
+        try {
+            return loader.loadClass(name);
+        } catch (ClassNotFoundException e) {
+            throw new AssertionError("%s unable to load class '%s'".formatted(loader.getName(), name));
+        }
+    }
+
     /**
      * Performs tasks once this feature is registered.
      * <ul>
-     * <li>Create the {@link LibGraalClassLoader} instance.</li>
+     * <li>Create the {@code HostedLibGraalClassLoader} instance.</li>
      * <li>Get a handle to the {@link BuildTime} class in the guest.</li>
      * <li>Initializes the options in the guest.</li>
      * <li>Initializes some state needed by {@link LibGraalSubstitutions}.</li>
@@ -173,9 +184,10 @@ public final class LibGraalFeature implements Feature {
         // org.graalvm.nativeimage.impl.IsolateSupport
         accessModulesToClass(ModuleSupport.Access.EXPORT, LibGraalFeature.class, "org.graalvm.nativeimage");

-        loader = new LibGraalClassLoader(Options.LibGraalJavaHome.getValue().resolve(Path.of("lib", "modules")));
+        loader = createHostedLibGraalClassLoader(access);
+        ImageSingletons.lookup(ClassForNameSupport.class).setCustomLoader(loader);

-        buildTimeClass = loader.loadClassOrFail("jdk.graal.compiler.hotspot.libgraal.BuildTime");
+        buildTimeClass = loadClassOrFail("jdk.graal.compiler.hotspot.libgraal.BuildTime");

         // Guest JVMCI and Graal need access to some JDK internal packages
         String[] basePackages = {"jdk.internal.misc", "jdk.internal.util", "jdk.internal.vm"};
@@ -186,7 +198,7 @@ public final class LibGraalFeature implements Feature {
              * Get GlobalAtomicLong.getInitialValue() method from LibGraalClassLoader for
              * LibGraalGraalSubstitutions.GlobalAtomicLongAddressProvider FieldValueTransformer
              */
-            handleGlobalAtomicLongGetInitialValue = mhl.findVirtual(loader.loadClassOrFail("jdk.graal.compiler.serviceprovider.GlobalAtomicLong"),
+            handleGlobalAtomicLongGetInitialValue = mhl.findVirtual(loadClassOrFail("jdk.graal.compiler.serviceprovider.GlobalAtomicLong"),
                             "getInitialValue", methodType(long.class));

         } catch (Throwable e) {
@@ -194,6 +206,13 @@ public final class LibGraalFeature implements Feature {
         }
     }

+    @SuppressWarnings("unchecked")
+    private static ClassLoader createHostedLibGraalClassLoader(AfterRegistrationAccess access) {
+        var hostedLibGraalClassLoaderClass = access.findClassByName("jdk.graal.compiler.hotspot.libgraal.HostedLibGraalClassLoader");
+        ModuleSupport.accessPackagesToClass(Access.EXPORT, hostedLibGraalClassLoaderClass, false, "java.base", "jdk.internal.module");
+        return ReflectionUtil.newInstance((Class<ClassLoader>) hostedLibGraalClassLoaderClass);
+    }
+
     private static void accessModulesToClass(ModuleSupport.Access access, Class<?> accessingClass, String... moduleNames) {
         for (String moduleName : moduleNames) {
             var module = getBootModule(moduleName);
@@ -208,17 +227,25 @@ public final class LibGraalFeature implements Feature {

     @Override
     public void duringSetup(DuringSetupAccess access) {
+
+        /*
+         * HostedLibGraalClassLoader provides runtime-replacement loader instance. Make sure
+         * HostedLibGraalClassLoader gets replaced by customRuntimeLoader instance in image.
+         */
+        ClassLoader customRuntimeLoader = ClassLoaderFeature.getCustomRuntimeClassLoader(loader);
+        access.registerObjectReplacer(obj -> obj == loader ? customRuntimeLoader : obj);
+
         try {
-            var basePhaseStatisticsClass = loader.loadClassOrFail("jdk.graal.compiler.phases.BasePhase$BasePhaseStatistics");
-            var lirPhaseStatisticsClass = loader.loadClassOrFail("jdk.graal.compiler.lir.phases.LIRPhase$LIRPhaseStatistics");
+            var basePhaseStatisticsClass = loadClassOrFail("jdk.graal.compiler.phases.BasePhase$BasePhaseStatistics");
+            var lirPhaseStatisticsClass = loadClassOrFail("jdk.graal.compiler.lir.phases.LIRPhase$LIRPhaseStatistics");
             MethodType statisticsCTorType = methodType(void.class, Class.class);
             var basePhaseStatisticsCTor = mhl.findConstructor(basePhaseStatisticsClass, statisticsCTorType);
             var lirPhaseStatisticsCTor = mhl.findConstructor(lirPhaseStatisticsClass, statisticsCTorType);
             newBasePhaseStatistics = new StatisticsCreator(basePhaseStatisticsCTor)::create;
             newLIRPhaseStatistics = new StatisticsCreator(lirPhaseStatisticsCTor)::create;

-            basePhaseClass = loader.loadClassOrFail("jdk.graal.compiler.phases.BasePhase");
-            lirPhaseClass = loader.loadClassOrFail("jdk.graal.compiler.lir.phases.LIRPhase");
+            basePhaseClass = loadClassOrFail("jdk.graal.compiler.phases.BasePhase");
+            lirPhaseClass = loadClassOrFail("jdk.graal.compiler.lir.phases.LIRPhase");

             ImageSingletons.add(LibGraalCompilerSupport.class, new LibGraalCompilerSupport());
         } catch (Throwable e) {
@@ -229,7 +256,7 @@ public final class LibGraalFeature implements Feature {
         accessImpl.registerClassReachabilityListener(this::registerPhaseStatistics);
         optionCollector = new OptionCollector(LibGraalEntryPoints.vmOptionDescriptors);
         accessImpl.registerObjectReachableCallback(OptionKey.class, optionCollector::doCallback);
-        accessImpl.registerObjectReachableCallback(loader.loadClassOrFail(OptionKey.class.getName()), optionCollector::doCallback);
+        accessImpl.registerObjectReachableCallback(loadClassOrFail(OptionKey.class.getName()), optionCollector::doCallback);
         GetJNIConfig.register(loader);
     }

@@ -240,7 +267,7 @@ public final class LibGraalFeature implements Feature {
      * {@link OptionKey} instances reached by the static analysis. The VM options are instances of
      * {@link OptionKey} loaded by the {@link com.oracle.svm.hosted.NativeImageClassLoader} and
      * compiler options are instances of {@link OptionKey} loaded by the
-     * {@link LibGraalClassLoader}.
+     * {@code HostedLibGraalClassLoader}.
      */
     private class OptionCollector implements ObjectReachableCallback<Object> {
         private final Set<Object> options = Collections.newSetFromMap(new ConcurrentHashMap<>());
@@ -298,7 +325,7 @@ public final class LibGraalFeature implements Feature {
             try {
                 MethodType mt = methodType(Iterable.class, List.class, Object.class, Map.class);
                 MethodHandle mh = mhl.findStatic(buildTimeClass, "finalizeLibgraalOptions", mt);
-                Map<String, String> modules = loader.getModules();
+                Map<String, String> modules = ReflectionUtil.invokeMethod(ReflectionUtil.lookupMethod(loader.getClass(), "getModules"), loader);
                 Iterable<Object> values = (Iterable<Object>) mh.invoke(compilerOptions, compilerOptionsInfo, modules);
                 for (Object descriptor : values) {
                     VMError.guarantee(access.isReachable(descriptor.getClass()), "%s", descriptor.getClass());
@@ -347,11 +374,11 @@ public final class LibGraalFeature implements Feature {
         var bb = impl.getBigBang();

         /* Contains static fields that depend on HotSpotJVMCIRuntime */
-        RuntimeClassInitialization.initializeAtRunTime(loader.loadClassOrFail("jdk.vm.ci.hotspot.HotSpotModifiers"));
-        RuntimeClassInitialization.initializeAtRunTime(loader.loadClassOrFail("jdk.vm.ci.hotspot.HotSpotCompiledCodeStream"));
-        RuntimeClassInitialization.initializeAtRunTime(loader.loadClassOrFail("jdk.vm.ci.hotspot.HotSpotCompiledCodeStream$Tag"));
+        RuntimeClassInitialization.initializeAtRunTime(loadClassOrFail("jdk.vm.ci.hotspot.HotSpotModifiers"));
+        RuntimeClassInitialization.initializeAtRunTime(loadClassOrFail("jdk.vm.ci.hotspot.HotSpotCompiledCodeStream"));
+        RuntimeClassInitialization.initializeAtRunTime(loadClassOrFail("jdk.vm.ci.hotspot.HotSpotCompiledCodeStream$Tag"));
         /* ThreadLocal in static field jdk.graal.compiler.debug.DebugContext.activated */
-        RuntimeClassInitialization.initializeAtRunTime(loader.loadClassOrFail("jdk.graal.compiler.debug.DebugContext"));
+        RuntimeClassInitialization.initializeAtRunTime(loadClassOrFail("jdk.graal.compiler.debug.DebugContext"));

         /* Needed for runtime calls to BoxingSnippets.Templates.getCacheClass(JavaKind) */
         RuntimeReflection.registerAllDeclaredClasses(Character.class);
@@ -377,7 +404,7 @@ public final class LibGraalFeature implements Feature {

             List<Class<?>> guestServiceClasses = new ArrayList<>();
             List<Class<?>> serviceClasses = impl.getImageClassLoader().findAnnotatedClasses(LibGraalService.class, false);
-            serviceClasses.stream().map(c -> loader.loadClassOrFail(c.getName())).forEach(guestServiceClasses::add);
+            serviceClasses.stream().map(c -> loadClassOrFail(c.getName())).forEach(guestServiceClasses::add);

             // Transfer libgraal qualifier (e.g. "PGO optimized") from host to guest.
             String nativeImageLocationQualifier = CompilerConfigurationFactory.getNativeImageLocationQualifier();
@@ -392,13 +419,16 @@ public final class LibGraalFeature implements Feature {
                                             String.class, // nativeImageLocationQualifier
                                             byte[].class // encodedGuestObjects
                             ));
-            GetCompilerConfig.Result configResult = GetCompilerConfig.from(Options.LibGraalJavaHome.getValue(), bb.getOptions());
+            Path libGraalJavaHome = ReflectionUtil.readField(loader.getClass(), "libGraalJavaHome", loader);
+            GetCompilerConfig.Result configResult = GetCompilerConfig.from(libGraalJavaHome, bb.getOptions());
             for (var e : configResult.opens().entrySet()) {
                 for (String source : e.getValue()) {
                     ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, buildTimeClass, false, e.getKey(), source);
                 }
             }

+            ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, buildTimeClass, false, "org.graalvm.word", "org.graalvm.word.impl");
+
             configureGraalForLibGraal.invoke(arch,
                             guestServiceClasses,
                             registerAsInHeap,
@@ -420,7 +450,7 @@ public final class LibGraalFeature implements Feature {

     @SuppressWarnings("unchecked")
     private void initializeTruffle() throws Throwable {
-        Class<?> truffleBuildTimeClass = loader.loadClassOrFail("jdk.graal.compiler.hotspot.libgraal.truffle.BuildTime");
+        Class<?> truffleBuildTimeClass = loadClassOrFail("jdk.graal.compiler.hotspot.libgraal.truffle.BuildTime");
         MethodHandle getLookup = mhl.findStatic(truffleBuildTimeClass, "initializeLookup", methodType(Map.Entry.class, Lookup.class, Class.class, Class.class));
         Map.Entry<Lookup, Class<?>> truffleLibGraal = (Map.Entry<Lookup, Class<?>>) getLookup.invoke(mhl, TruffleFromLibGraalStartPoints.class, NativeImageHostEntryPoints.class);
         ImageSingletons.add(LibGraalTruffleToLibGraalEntryPoints.class, new LibGraalTruffleToLibGraalEntryPoints(truffleLibGraal.getKey(), truffleLibGraal.getValue()));
diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFieldsOffsetsFeature.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFieldsOffsetsFeature.java
index cf55ea2b1f8..13810ffb231 100644
--- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFieldsOffsetsFeature.java
+++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFieldsOffsetsFeature.java
@@ -62,7 +62,7 @@ import jdk.internal.misc.Unsafe;
 public final class LibGraalFieldsOffsetsFeature implements InternalFeature {

     private final MethodHandles.Lookup mhl = MethodHandles.lookup();
-    private LibGraalClassLoader loader;
+    private LibGraalFeature libGraalFeature;

     private Class<?> fieldsClass;
     private Class<?> edgesClass;
@@ -119,20 +119,20 @@ public final class LibGraalFieldsOffsetsFeature implements InternalFeature {
     @Override
     public void duringSetup(DuringSetupAccess a) {
         DuringSetupAccessImpl access = (DuringSetupAccessImpl) a;
-        loader = ImageSingletons.lookup(LibGraalFeature.class).loader;
-
-        fieldsClass = loader.loadClassOrFail("jdk.graal.compiler.core.common.Fields");
-        edgesClass = loader.loadClassOrFail("jdk.graal.compiler.graph.Edges");
-        edgesTypeClass = loader.loadClassOrFail("jdk.graal.compiler.graph.Edges$Type");
-        nodeClass = loader.loadClassOrFail("jdk.graal.compiler.graph.Node");
-        nodeClassClass = loader.loadClassOrFail("jdk.graal.compiler.graph.NodeClass");
-        lirInstructionClass = loader.loadClassOrFail("jdk.graal.compiler.lir.LIRInstruction");
-        lirInstructionClassClass = loader.loadClassOrFail("jdk.graal.compiler.lir.LIRInstructionClass");
-        compositeValueClass = loader.loadClassOrFail("jdk.graal.compiler.lir.CompositeValue");
-        compositeValueClassClass = loader.loadClassOrFail("jdk.graal.compiler.lir.CompositeValueClass");
-        fieldIntrospectionClass = loader.loadClassOrFail("jdk.graal.compiler.core.common.FieldIntrospection");
-        inputEdgesClass = loader.loadClassOrFail("jdk.graal.compiler.graph.InputEdges");
-        successorEdgesClass = loader.loadClassOrFail("jdk.graal.compiler.graph.SuccessorEdges");
+        libGraalFeature = ImageSingletons.lookup(LibGraalFeature.class);
+
+        fieldsClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.core.common.Fields");
+        edgesClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.graph.Edges");
+        edgesTypeClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.graph.Edges$Type");
+        nodeClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.graph.Node");
+        nodeClassClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.graph.NodeClass");
+        lirInstructionClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.lir.LIRInstruction");
+        lirInstructionClassClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.lir.LIRInstructionClass");
+        compositeValueClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.lir.CompositeValue");
+        compositeValueClassClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.lir.CompositeValueClass");
+        fieldIntrospectionClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.core.common.FieldIntrospection");
+        inputEdgesClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.graph.InputEdges");
+        successorEdgesClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.graph.SuccessorEdges");

         try {
             fieldsClassGetOffsetsMethod = mhl.findVirtual(fieldsClass, "getOffsets", MethodType.methodType(long[].class));
@@ -171,7 +171,7 @@ public final class LibGraalFieldsOffsetsFeature implements InternalFeature {
     public void beforeAnalysis(BeforeAnalysisAccess access) {
         MethodHandle getInputEdgesOffsets;
         MethodHandle getSuccessorEdgesOffsets;
-        var buildTimeClass = loader.loadClassOrFail("jdk.graal.compiler.hotspot.libgraal.BuildTime");
+        var buildTimeClass = libGraalFeature.loadClassOrFail("jdk.graal.compiler.hotspot.libgraal.BuildTime");
         try {
             MethodType offsetAccessorSignature = MethodType.methodType(long[].class, Object.class);
             getInputEdgesOffsets = mhl.findStatic(buildTimeClass, "getInputEdgesOffsets", offsetAccessorSignature);
diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java
index 2c2fb99e2fb..c885d19b899 100644
--- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java
+++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java
@@ -30,11 +30,6 @@ import java.lang.ref.ReferenceQueue;
 import java.util.Map;
 import java.util.function.Supplier;

-import com.oracle.svm.core.heap.GCCause;
-import com.oracle.svm.core.heap.Heap;
-import com.oracle.svm.core.jdk.JDKLatest;
-import com.oracle.svm.core.log.FunctionPointerLogHandler;
-import com.oracle.svm.graal.hotspot.LibGraalJNIMethodScope;
 import org.graalvm.jniutils.JNI;
 import org.graalvm.jniutils.JNIExceptionWrapper;
 import org.graalvm.jniutils.JNIMethodScope;
@@ -61,7 +56,12 @@ import com.oracle.svm.core.annotate.TargetClass;
 import com.oracle.svm.core.annotate.TargetElement;
 import com.oracle.svm.core.c.CGlobalData;
 import com.oracle.svm.core.c.CGlobalDataFactory;
+import com.oracle.svm.core.heap.GCCause;
+import com.oracle.svm.core.heap.Heap;
+import com.oracle.svm.core.jdk.JDKLatest;
+import com.oracle.svm.core.log.FunctionPointerLogHandler;
 import com.oracle.svm.core.util.VMError;
+import com.oracle.svm.graal.hotspot.LibGraalJNIMethodScope;

 class LibGraalJVMCISubstitutions {

@@ -461,7 +461,7 @@ public class LibGraalSubstitutions {
 class LibGraalClassLoaderSupplier implements Supplier<ClassLoader> {
     @Override
     public ClassLoader get() {
-        LibGraalClassLoader loader = ImageSingletons.lookup(LibGraalFeature.class).loader;
+        ClassLoader loader = ImageSingletons.lookup(LibGraalFeature.class).loader;
         VMError.guarantee(loader != null);
         return loader;
     }
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassForNameSupportFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassForNameSupportFeature.java
new file mode 100644
index 00000000000..521e2fe4265
--- /dev/null
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassForNameSupportFeature.java
@@ -0,0 +1,23 @@
+package com.oracle.svm.hosted;
+
+import org.graalvm.nativeimage.ImageSingletons;
+
+import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
+import com.oracle.svm.core.feature.InternalFeature;
+import com.oracle.svm.core.hub.ClassForNameSupport;
+import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton;
+import com.oracle.svm.core.layeredimagesingleton.LoadedLayeredImageSingletonInfo;
+import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
+import com.oracle.svm.hosted.FeatureImpl.AfterRegistrationAccessImpl;
+
+@AutomaticallyRegisteredFeature
+public final class ClassForNameSupportFeature implements InternalFeature, FeatureSingleton, UnsavedSingleton {
+    @Override
+    public void afterRegistration(AfterRegistrationAccess access) {
+        if (ImageSingletons.lookup(LoadedLayeredImageSingletonInfo.class).handledDuringLoading(ClassForNameSupport.class)) {
+            return;
+        }
+        ClassLoader customLoader = ((AfterRegistrationAccessImpl) access).getImageClassLoader().classLoaderSupport.getCustomLoader();
+        ImageSingletons.add(ClassForNameSupport.class, new ClassForNameSupport(customLoader));
+    }
+}
\ No newline at end of file
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java
index 6685997b488..085c67d7273 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java
@@ -24,6 +24,7 @@
  */
 package com.oracle.svm.hosted;

+import java.lang.reflect.Method;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;

@@ -34,6 +35,7 @@ import com.oracle.svm.core.feature.InternalFeature;
 import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability;
 import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
 import com.oracle.svm.core.util.VMError;
+import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl;
 import com.oracle.svm.hosted.imagelayer.CrossLayerConstantRegistry;
 import com.oracle.svm.hosted.imagelayer.ObjectToConstantFieldValueTransformer;
 import com.oracle.svm.hosted.jdk.HostedClassLoaderPackageManagement;
@@ -118,6 +120,17 @@ public class ClassLoaderFeature implements InternalFeature {

         var config = (FeatureImpl.DuringSetupAccessImpl) access;
         if (ImageLayerBuildingSupport.firstImageBuild()) {
+            ClassLoader customLoader = ((DuringSetupAccessImpl) access).imageClassLoader.classLoaderSupport.getCustomLoader();
+            if (customLoader != null) {
+                ClassLoader customRuntimeLoader = getCustomRuntimeClassLoader(customLoader);
+                if (customRuntimeLoader != null) {
+                    /*
+                     * CustomLoader provides runtime-replacement ClassLoader instance. Make sure
+                     * customLoader gets replaced by customRuntimeLoader instance in image.
+                     */
+                    access.registerObjectReplacer(obj -> obj == customLoader ? customRuntimeLoader : obj);
+                }
+            }
             access.registerObjectReplacer(this::runtimeClassLoaderObjectReplacer);
             if (ImageLayerBuildingSupport.buildingInitialLayer()) {
                 config.registerObjectReachableCallback(ClassLoader.class, (a1, classLoader, reason) -> {
@@ -133,6 +146,12 @@ public class ClassLoaderFeature implements InternalFeature {
         }
     }

+    public static ClassLoader getCustomRuntimeClassLoader(ClassLoader customLoader) {
+        Class<? extends ClassLoader> customLoaderClass = customLoader.getClass();
+        Method getRuntimeClassLoaderMethod = ReflectionUtil.lookupMethod(true, customLoaderClass, "getRuntimeClassLoader");
+        return getRuntimeClassLoaderMethod != null ? ReflectionUtil.invokeMethod(getRuntimeClassLoaderMethod, null) : null;
+    }
+
     @Override
     public void beforeAnalysis(BeforeAnalysisAccess access) {
         var packagesField = ReflectionUtil.lookupField(ClassLoader.class, "packages");
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureHandler.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureHandler.java
index 418e0d584e2..250f5abf07f 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureHandler.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureHandler.java
@@ -48,8 +48,8 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
 import com.oracle.svm.core.feature.AutomaticallyRegisteredFeatureServiceRegistration;
 import com.oracle.svm.core.feature.InternalFeature;
 import com.oracle.svm.core.option.APIOption;
-import com.oracle.svm.core.option.HostedOptionKey;
 import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue;
+import com.oracle.svm.core.option.HostedOptionKey;
 import com.oracle.svm.core.option.SubstrateOptionsParser;
 import com.oracle.svm.core.util.InterruptImageBuilding;
 import com.oracle.svm.core.util.UserError;
@@ -183,11 +183,24 @@ public class FeatureHandler {
         }

         for (String featureName : Options.userEnabledFeatures()) {
-            Class<?> featureClass;
-            try {
-                featureClass = Class.forName(featureName, true, loader.getClassLoader());
-            } catch (ClassNotFoundException e) {
-                throw UserError.abort("Feature %s class not found on the classpath. Ensure that the name is correct and that the class is on the classpath.", featureName);
+            ClassLoader customLoader = loader.classLoaderSupport.getCustomLoader();
+            List<ClassLoader> featureClassLoaders;
+            if (customLoader != null) {
+                featureClassLoaders = List.of(customLoader, loader.getClassLoader());
+            } else {
+                featureClassLoaders = List.of(loader.getClassLoader());
+            }
+            Class<?> featureClass = null;
+            for (ClassLoader featureClassLoader : featureClassLoaders) {
+                try {
+                    featureClass = Class.forName(featureName, true, featureClassLoader);
+                    break;
+                } catch (ClassNotFoundException e) {
+                    /* Ignore */
+                }
+            }
+            if (featureClass == null) {
+                throw UserError.abort("User-enabled Feature %s class not found. Ensure that the name is correct and that the class is on the class- or module-path.", featureName);
             }
             registerFeature(featureClass, specificClassProvider, access);
         }
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java
index c55efe36d59..fc87c58847d 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java
@@ -99,7 +99,7 @@ public final class ImageClassLoader {
         classLoaderSupport.reportBuilderClassesInApplication();
     }

-    private void findSystemElements(Class<?> systemClass) {
+    void findSystemElements(Class<?> systemClass) {
         Method[] declaredMethods = null;
         try {
             declaredMethods = systemClass.getDeclaredMethods();
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java
index e243c31a216..9611c625370 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java
@@ -118,6 +118,7 @@ public class NativeImageClassLoaderSupport {
     private final ConcurrentHashMap<String, LinkedHashSet<String>> serviceProviders;

     private final NativeImageClassLoader classLoader;
+    private final ClassLoader customLoader;

     public final ModuleFinder upgradeAndSystemModuleFinder;
     public final ModuleLayer moduleLayerForImageBuild;
@@ -187,6 +188,23 @@ public class NativeImageClassLoaderSupport {

         classLoader = new NativeImageClassLoader(imagecp, configuration, defaultSystemClassLoader);

+        String customLoaderPropertyKey = "org.graalvm.nativeimage.experimental.loader";
+        String customLoaderPropertyValue = System.getProperty(customLoaderPropertyKey);
+        if (customLoaderPropertyValue != null) {
+            try {
+                Class<?> customLoaderClass = Class.forName(customLoaderPropertyValue, true, classLoader);
+                customLoader = (ClassLoader) ReflectionUtil.newInstance(customLoaderClass);
+            } catch (ClassNotFoundException e) {
+                throw VMError.shouldNotReachHere("Custom ClassLoader " + customLoaderPropertyValue +
+                                " set via system property " + customLoaderPropertyKey + " could not be found.", e);
+            } catch (ClassCastException e) {
+                throw VMError.shouldNotReachHere("Custom ClassLoader " + customLoaderPropertyValue +
+                                " set via system property " + customLoaderPropertyKey + " does not extend class ClassLoader.", e);
+            }
+        } else {
+            customLoader = null;
+        }
+
         ModuleLayer moduleLayer = ModuleLayer.defineModules(configuration, List.of(ModuleLayer.boot()), ignored -> classLoader).layer();
         adjustBootLayerQualifiedExports(moduleLayer);
         moduleLayerForImageBuild = moduleLayer;
@@ -219,6 +237,10 @@ public class NativeImageClassLoaderSupport {
         return classLoader;
     }

+    public ClassLoader getCustomLoader() {
+        return customLoader;
+    }
+
     private static Path stringToPath(String path) {
         return Path.of(Path.of(path).toAbsolutePath().toUri().normalize());
     }
@@ -246,6 +268,16 @@ public class NativeImageClassLoaderSupport {
         includeAllFromClassPath = IncludeAllFromClassPath.getValue(parsedHostedOptions);

         new LoadClassHandler(executor, imageClassLoader).run();
+        if (customLoader != null) {
+            Class<? extends ClassLoader> customLoaderClass = customLoader.getClass();
+            Method getSystemClassesMethod = ReflectionUtil.lookupMethod(true, customLoaderClass, "getSystemClasses");
+            if (getSystemClassesMethod != null) {
+                List<Class<?>> customSystemClasses = ReflectionUtil.invokeMethod(getSystemClassesMethod, customLoader);
+                for (Class<?> systemClass : customSystemClasses) {
+                    imageClassLoader.findSystemElements(systemClass);
+                }
+            }
+        }
     }

     private static void missingFromSetOfEntriesError(Object entry, Collection<?> allEntries, String typeOfEntry,
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java
index 5d80ffe544e..bcbf1ccb606 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java
@@ -63,7 +63,6 @@ import com.oracle.svm.core.feature.InternalFeature;
 import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability;
 import com.oracle.svm.core.graal.meta.KnownOffsets;
 import com.oracle.svm.core.hub.ClassForNameSupport;
-import com.oracle.svm.core.hub.ClassForNameSupportFeature;
 import com.oracle.svm.core.hub.DynamicHub;
 import com.oracle.svm.core.meta.MethodPointer;
 import com.oracle.svm.core.meta.SharedMethod;
@@ -73,6 +72,7 @@ import com.oracle.svm.core.reflect.SubstrateConstructorAccessor;
 import com.oracle.svm.core.reflect.SubstrateMethodAccessor;
 import com.oracle.svm.core.reflect.target.ReflectionSubstitutionSupport;
 import com.oracle.svm.core.util.VMError;
+import com.oracle.svm.hosted.ClassForNameSupportFeature;
 import com.oracle.svm.hosted.FallbackFeature;
 import com.oracle.svm.hosted.FeatureImpl;
 import com.oracle.svm.hosted.FeatureImpl.BeforeCompilationAccessImpl;
2024-11-07 17:44:49 +01:00
Yudi Zheng 0cfd1139ea Update SyncPort info. 2024-11-07 16:57:17 +01:00
Carlo Refice 249c30e24b [GR-59638] Only run file-size benchmark when building libgraal
PullRequest: graal/19236
2024-11-07 15:50:29 +00:00
Sacha Coppey 039ff639e2 Load lambda types in the application layer by reusing lambda serialization code 2024-11-07 16:42:44 +01:00
Yudi Zheng 60c3bce4ff Adapt JDK-8329254: optimize integral reverse operations on x86 GFNI target. 2024-11-07 15:29:45 +01:00
Olya Gupalo 509a73e1bf Review and update include-reachability-metadata-gradle.md guide to the latest NBT 2024-11-07 16:19:09 +02:00
Fabio Niephaus cb73caae5b
Improve error messages for VS detection. 2024-11-07 13:49:51 +01:00
Fabio Niephaus 215f5f367c
Detect BuildTools via `vswhere.exe`. 2024-11-07 13:47:24 +01:00
Fabio Niephaus e260ae24a0
Avoid NPE in `findVCVarsallWithVSWhere()`. 2024-11-07 13:47:24 +01:00
Vojin Jovanovic e99ccc3fc2 Link the troubleshooting guide in GH-issue template 2024-11-07 10:18:24 +01:00
ol-automation_ww 14139776f9 [GR-59526] Update labsjdk to 24+22-jvmci-b01
PullRequest: graal/19194
2024-11-07 09:01:09 +00:00
Josef Eisl 994143a090 compiler: add SHA3.implCompress0 onto the toBeInvestigated list [JDK-8341527] 2024-11-07 09:48:06 +01:00
Allan Gregersen fecac30024 fix disabling debugger stepping too aggressively 2024-11-07 07:20:49 +01:00
ol-automation_ww fe8d1f52d8 [GR-55132] Periodic update of the language imports.
PullRequest: graal/19241
2024-11-06 23:05:04 +00:00
Jirka Marsik 17c1daf960 [GR-53634] Handle static frame slots in BytecodeOSRMetadata#restoreParentFrame.
PullRequest: graal/19094
2024-11-06 22:03:08 +00:00
ol-automation_ww a323cb8251 Update language imports 2024-11-06 18:07:40 +00:00
Tomáš Zezula 47a7322b39 [GR-46292] [GR-46293] Remove deprecated TruffleInstrument.Provider and TruffleLanguage.Provider.
PullRequest: graal/19190
2024-11-06 15:03:18 +00:00
Danilo Ansaloni a10bbcc1f0 [GR-59591] Generate javadoc in a single directory.
PullRequest: graal/19226
2024-11-06 15:03:08 +00:00
Christian Humer 5da3ef9065 Add IOException checked exception to InternalResource.versionHash(Env). 2024-11-06 15:22:32 +01:00
Carlo Refice e10688ce83 Only run file-size benchmark when building libgraal 2024-11-06 14:32:23 +01:00
Jirka Marsik 92b2c37756 Handle static slots in restoreParentFrame 2024-11-06 10:59:38 +01:00
Olya Gupalo b8dd73b432 [GR-55575] Fix tabs include order in the Embedding guide.
PullRequest: graal/19228
2024-11-06 09:08:10 +00:00
Olya Gupalo 95748b6529 Fix tabs include order 2024-11-06 11:07:12 +02:00
Tomas Zezula 24a5f1a4ce [GR-46292] Remove deprecated TruffleInstrument.Provider and TruffleLanguage.Provider. 2024-11-06 09:39:40 +01:00
Carlo Refice 4356cb0575 [GR-59103] Fix indentation in option help text spanning multiple lines in util.args
PullRequest: graal/19209
2024-11-06 04:10:04 +00:00
David Leopoldseder 48a61fe1a5 [GR-59539] Ensure arrays have sufficient sizes.
PullRequest: graal/19204
2024-11-06 02:31:14 +00:00
Yudi Zheng 44e3a85102 [JDK-8343584] Array types are considered non-abstract.
PullRequest: graal/19224
2024-11-06 02:31:07 +00:00
David Leopoldseder 5e91993b15 [GR-59003] [GR-59366] Safepoint refactorings.
PullRequest: graal/19100
2024-11-06 00:52:47 +00:00
Allan Gregersen c8d41818db [GR-59538] Fix JDWP valid class loader check.
PullRequest: graal/19214
2024-11-05 19:42:49 +00:00
Danilo Ansaloni 71d3ff4f37 Add missing package dependencies of 'jdk.graal.compiler'. 2024-11-05 18:15:54 +01:00
Patrick Ziegler edbfec0c7d [GR-55172] Deprecate BuildOutputBreakdowns option
PullRequest: graal/18444
2024-11-05 17:13:43 +00:00
Allan Gregersen ee9658ccf7 [GR-47672] Use generic types as targets in Espresso interop.
PullRequest: graal/15357
2024-11-05 14:07:59 +00:00
Josef Eisl b8e78534dc svm: Always use SubstrateConstructorAccessor for serialization (adopt removal of SerializationConstructorAccessorGenerator in JDK-8327624) [GR-59282] 2024-11-05 14:38:48 +01:00
Yudi Zheng 901a4b0e3a Array types are considered non-abstract. 2024-11-05 13:57:45 +01:00
Carlo Refice 6623ca0817 [GR-59329] Add option to outline SerialGC post-write barrier snippets
PullRequest: graal/19148
2024-11-05 12:26:11 +00:00
Carlo Refice 7d8c121a22 [GR-59466] Measure and upload libgraal image size when building libgraal for benchmarks
PullRequest: graal/19205
2024-11-05 10:31:26 +00:00
Olya Gupalo 8d3c7691c1 Review and update include-reachability-metadata-maven.md guide to the latest NBT 2024-11-05 12:10:42 +02:00
Patrick Ziegler 45dba624f4
Allow for subclasses of HeapBreakdownProvider
Registration of the HeapBreakdownProvider singleton has to be moved to
duringSetup because HostedConfiguration is not available before that.
2024-11-05 10:31:50 +01:00
Josef Haider 1546bc5bd8 [GR-59497] TRegex: fix OracleDB flavor incorrectly parsing escaped surrogate pairs.
PullRequest: graal/19184
2024-11-05 09:12:42 +00:00
David Leopoldseder c0405ac1a5 safepoint elimination: refactorings 2024-11-05 08:53:55 +01:00