Skip to content

Commit

Permalink
Make NativeImageSystemClassLoader able to handle having module classl…
Browse files Browse the repository at this point in the history
…oader with a parent ClassPathClassLoader
  • Loading branch information
olpaw committed Jun 2, 2022
1 parent 1152923 commit fc95742
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,19 @@ public class NativeImageClassLoaderSupport {
public final ModuleLayer moduleLayerForImageBuild;
public final ModuleFinder modulepathModuleFinder;

static final class ClassPathClassLoader extends URLClassLoader {
ClassPathClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
}

protected NativeImageClassLoaderSupport(ClassLoader defaultSystemClassLoader, String[] classpath, String[] modulePath) {

classes = EconomicMap.create();
packages = EconomicMap.create();
emptySet = EconomicSet.create();

classPathClassLoader = new URLClassLoader(Util.verifyClassPathAndConvertToURLs(classpath), defaultSystemClassLoader);
classPathClassLoader = new ClassPathClassLoader(Util.verifyClassPathAndConvertToURLs(classpath), defaultSystemClassLoader);

imagecp = Arrays.stream(classPathClassLoader.getURLs())
.map(Util::urlToPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
package com.oracle.svm.hosted;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.security.SecureClassLoader;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.jar.JarFile;
Expand Down Expand Up @@ -135,34 +137,56 @@ public boolean isDisallowedClassLoader(ClassLoader c) {
private static final Method defineClass = ReflectionUtil.lookupMethod(ClassLoader.class, "defineClass",
String.class, byte[].class, int.class, int.class);

static Class<?> loadClass(ClassLoader classLoader, String name, boolean resolve) throws ClassNotFoundException {
Class<?> loadedClass = null;
private static final Constructor<Enumeration<?>> compoundEnumerationConstructor;
static {
/* Reuse utility class defined as package-private class in java.lang.ClassLoader.java */
String className = "java.lang.CompoundEnumeration";
try {
/* invoke the "loadClass" method on the current class loader */
loadedClass = ((Class<?>) loadClass.invoke(classLoader, name, resolve));
} catch (Exception e) {
if (e.getCause() instanceof ClassNotFoundException) {
throw ((ClassNotFoundException) e.getCause());
@SuppressWarnings("unchecked")
Class<Enumeration<?>> compoundEnumerationClass = (Class<Enumeration<?>>) Class.forName(className);
compoundEnumerationConstructor = ReflectionUtil.lookupConstructor(compoundEnumerationClass, Enumeration[].class);
} catch (ClassNotFoundException | ReflectionUtil.ReflectionUtilError e) {
throw VMError.shouldNotReachHere("Unable to get access to class " + className, e);
}
}

private static Class<?> loadClass(List<ClassLoader> activeClassLoaders, String name, boolean resolve) throws ClassNotFoundException {
ClassNotFoundException classNotFoundException = null;
for (ClassLoader loader : activeClassLoaders) {
try {
/* invoke the "loadClass" method on the current class loader */
return ((Class<?>) loadClass.invoke(loader, name, resolve));
} catch (Exception e) {
if (e.getCause() instanceof ClassNotFoundException) {
classNotFoundException = ((ClassNotFoundException) e.getCause());
} else {
String message = String.format("Can not load class: %s, with class loader: %s", name, loader);
VMError.shouldNotReachHere(message, e);
}
}
String message = String.format("Can not load class: %s, with class loader: %s", name, classLoader);
VMError.shouldNotReachHere(message, e);
}
return loadedClass;
VMError.guarantee(classNotFoundException != null);
throw classNotFoundException;
}

static URL findResource(ClassLoader classLoader, String name) {
try {
// invoke the "findResource" method on the current class loader
return (URL) findResource.invoke(classLoader, name);
} catch (ReflectiveOperationException e) {
String message = String.format("Can not find resource: %s using class loader: %s", name, classLoader);
VMError.shouldNotReachHere(message, e);
private static URL findResource(List<ClassLoader> activeClassLoaders, String name) {
for (ClassLoader loader : activeClassLoaders) {
try {
// invoke the "findResource" method on the current class loader
Object url = findResource.invoke(loader, name);
if (url != null) {
return (URL) url;
}
} catch (ReflectiveOperationException | ClassCastException e) {
String message = String.format("Can not find resource: %s using class loader: %s", name, loader);
VMError.shouldNotReachHere(message, e);
}
}
return null;
}

@SuppressWarnings("unchecked")
static Enumeration<URL> findResources(ClassLoader classLoader, String name) {
private static Enumeration<URL> findResources(ClassLoader classLoader, String name) {
try {
// invoke the "findResources" method on the current class loader
return (Enumeration<URL>) findResources.invoke(classLoader, name);
Expand All @@ -186,22 +210,38 @@ static Class<?> defineClass(ClassLoader classLoader, String name, byte[] b, int

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
return loadClass(getActiveClassLoader(), name, resolve);
return loadClass(getActiveClassLoaders(), name, resolve);
}

@Override
protected URL findResource(String name) {
return findResource(getActiveClassLoader(), name);
return findResource(getActiveClassLoaders(), name);
}

@Override
protected Enumeration<URL> findResources(String name) throws IOException {
return findResources(getActiveClassLoader(), name);
List<ClassLoader> activeClassLoaders = getActiveClassLoaders();
assert !activeClassLoaders.isEmpty() & activeClassLoaders.size() <= 2;
ClassLoader activeClassLoader = activeClassLoaders.get(0);
ClassLoader activeClassLoaderParent = activeClassLoaders.size() > 1 ? activeClassLoaders.get(1) : null;
if (activeClassLoaderParent != null) {
return newCompoundEnumeration(findResources(activeClassLoaderParent, name), findResources(activeClassLoader, name));
}
return findResources(activeClassLoader, name);
}

@SuppressWarnings("unchecked")
private static <T> Enumeration<T> newCompoundEnumeration(Enumeration<?>... enums) {
try {
return (Enumeration<T>) compoundEnumerationConstructor.newInstance((Object) enums);
} catch (ReflectiveOperationException e) {
throw VMError.shouldNotReachHere("Cannot instantiate CompoundEnumeration", e);
}
}

public Class<?> forNameOrNull(String name, boolean initialize) {
try {
return Class.forName(name, initialize, getActiveClassLoader());
return Class.forName(name, initialize, getActiveClassLoaders().get(0));
} catch (LinkageError | ClassNotFoundException ignored) {
return null;
}
Expand All @@ -212,7 +252,7 @@ public Class<?> predefineClass(String name, byte[] array, int offset, int length
if (forNameOrNull(name, false) != null) {
throw VMError.shouldNotReachHere("The class loader hierarchy already provides a class with the same name as the class submitted for predefinition: " + name);
}
return defineClass(getActiveClassLoader(), name, array, offset, length);
return defineClass(getActiveClassLoaders().get(0), name, array, offset, length);
}

@Override
Expand All @@ -224,11 +264,18 @@ public String toString() {
'}';
}

private ClassLoader getActiveClassLoader() {
ClassLoader delegate = nativeImageClassLoader;
return delegate != null
? delegate
: defaultSystemClassLoader;
private List<ClassLoader> getActiveClassLoaders() {
ClassLoader activeClassLoader = nativeImageClassLoader;
if (activeClassLoader != null) {
ClassLoader activeClassLoaderParent = activeClassLoader.getParent();
if (activeClassLoaderParent instanceof NativeImageClassLoaderSupport.ClassPathClassLoader) {
return List.of(activeClassLoader, activeClassLoaderParent);
} else {
return List.of(activeClassLoader);
}
} else {
return List.of(defaultSystemClassLoader);
}
}

/**
Expand Down

0 comments on commit fc95742

Please sign in to comment.