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 |