Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import java.security.ProtectionDomain;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Set;
import java.util.Vector;
import java.util.WeakHashMap;
Expand All @@ -43,7 +42,6 @@
import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability;
import com.oracle.svm.core.hub.ClassForNameSupport;
import com.oracle.svm.core.hub.PredefinedClassesSupport;
import com.oracle.svm.core.util.VMError;
Expand Down Expand Up @@ -72,13 +70,6 @@ public final class Target_java_lang_ClassLoader {
@Alias @RecomputeFieldValue(kind = Kind.NewInstanceWhenNotNull, declClass = ConcurrentHashMap.class)//
private ConcurrentHashMap<String, Object> parallelLockMap;

/**
* Recompute ClassLoader.packages; See {@link ClassLoaderSupport} for explanation on why this
* information must be reset.
*/
@Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = PackageFieldTransformer.class)//
private ConcurrentHashMap<String, Package> packages;

@Alias //
private static ClassLoader scl;

Expand Down Expand Up @@ -330,31 +321,6 @@ private static Class<?> defineClass0(ClassLoader loader, Class<?> lookup, String
final class Target_java_lang_AssertionStatusDirectives {
}

class PackageFieldTransformer implements FieldValueTransformerWithAvailability {

@Override
public ValueAvailability valueAvailability() {
return ValueAvailability.AfterAnalysis;
}

@Override
public Object transform(Object receiver, Object originalValue) {
assert receiver instanceof ClassLoader;

/* JDK9+ stores packages in a ConcurrentHashMap, while 8 and before use a HashMap. */
boolean useConcurrentHashMap = originalValue instanceof ConcurrentHashMap;

/* Retrieving initial package state for this class loader. */
ConcurrentHashMap<String, Package> packages = ClassLoaderSupport.getRegisteredPackages((ClassLoader) receiver);
if (packages == null) {
/* No package state available - have to create clean state. */
return useConcurrentHashMap ? new ConcurrentHashMap<String, Package>() : new HashMap<String, Package>();
} else {
return useConcurrentHashMap ? packages : new HashMap<>(packages);
}
}
}

@TargetClass(className = "java.lang.ClassLoader", innerClass = "ParallelLoaders")
final class Target_java_lang_ClassLoader_ParallelLoaders {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,20 @@

import java.lang.reflect.Method;

import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.ReflectionUtil;

import jdk.internal.loader.ClassLoaders;

public class BootLoaderSupport {

/**
* Gets the boot loader or {@code null} if it does not exist.
*/
private static ClassLoader bootLoader;

public static ClassLoader getBootLoader() {
Class<?> classLoadersClass;
try {
classLoadersClass = Class.forName("jdk.internal.loader.ClassLoaders");
Method method = ReflectionUtil.lookupMethod(classLoadersClass, "bootLoader");
Object r = method.invoke(null);
return (ClassLoader) r;
} catch (ReflectiveOperationException e) {
throw VMError.shouldNotReachHere("Cannot get access to the boot loader", e);
if (bootLoader != null) {
return bootLoader;
}
Method method = ReflectionUtil.lookupMethod(ClassLoaders.class, "bootLoader");
bootLoader = ReflectionUtil.invokeMethod(method, null);
return bootLoader;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,51 @@
*/
package com.oracle.svm.hosted;

import com.oracle.svm.core.feature.InternalFeature;
import java.util.concurrent.ConcurrentHashMap;

import com.oracle.graal.pointsto.heap.ImageHeapConstant;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
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.imagelayer.CrossLayerConstantRegistry;
import com.oracle.svm.hosted.jdk.HostedClassLoaderPackageManagement;
import com.oracle.svm.util.ReflectionUtil;

import jdk.internal.loader.ClassLoaders;

@AutomaticallyRegisteredFeature
public class ClassLoaderFeature implements InternalFeature {

private static final String APP_KEY_NAME = "ClassLoader#App";
private static final String PLATFORM_KEY_NAME = "ClassLoader#Platform";
private static final String BOOT_KEY_NAME = "ClassLoader#Boot";

private static final NativeImageSystemClassLoader nativeImageSystemClassLoader = NativeImageSystemClassLoader.singleton();

private static final ClassLoader bootClassLoader;
private static final ClassLoader platformClassLoader;

static {
if (ImageLayerBuildingSupport.buildingImageLayer()) {
platformClassLoader = ClassLoaders.platformClassLoader();
bootClassLoader = BootLoaderSupport.getBootLoader();
} else {
platformClassLoader = null;
bootClassLoader = null;
}
}

public static ClassLoader getRuntimeClassLoader(ClassLoader original) {
if (needsReplacement(original)) {
if (replaceWithAppClassLoader(original)) {
return nativeImageSystemClassLoader.defaultSystemClassLoader;
}

return original;
}

private static boolean needsReplacement(ClassLoader loader) {
private static boolean replaceWithAppClassLoader(ClassLoader loader) {
if (loader == nativeImageSystemClassLoader) {
return true;
}
Expand All @@ -50,14 +79,79 @@ private static boolean needsReplacement(ClassLoader loader) {
}

private Object runtimeClassLoaderObjectReplacer(Object replaceCandidate) {
if (replaceCandidate instanceof ClassLoader) {
return getRuntimeClassLoader((ClassLoader) replaceCandidate);
if (replaceCandidate instanceof ClassLoader loader) {
return getRuntimeClassLoader(loader);
}
return replaceCandidate;
}

ImageHeapConstant replaceClassLoadersWithLayerConstant(CrossLayerConstantRegistry registry, Object object) {
if (object instanceof ClassLoader loader) {
if (replaceWithAppClassLoader(loader) || loader == nativeImageSystemClassLoader.defaultSystemClassLoader) {
return registry.getConstant(APP_KEY_NAME);
} else if (loader == platformClassLoader) {
return registry.getConstant(PLATFORM_KEY_NAME);
} else if (loader == bootClassLoader) {
return registry.getConstant(BOOT_KEY_NAME);
} else {
throw VMError.shouldNotReachHere("Currently unhandled class loader seen in extension layer: %s", loader);
}
}

return null;
}

@Override
public void duringSetup(DuringSetupAccess access) {
access.registerObjectReplacer(this::runtimeClassLoaderObjectReplacer);
var packageManager = HostedClassLoaderPackageManagement.singleton();
var registry = CrossLayerConstantRegistry.singletonOrNull();
if (ImageLayerBuildingSupport.buildingImageLayer()) {
packageManager.initialize(nativeImageSystemClassLoader.defaultSystemClassLoader, registry);
}

if (ImageLayerBuildingSupport.firstImageBuild()) {
access.registerObjectReplacer(this::runtimeClassLoaderObjectReplacer);
} else {
var config = (FeatureImpl.DuringSetupAccessImpl) access;
config.registerObjectToConstantReplacer(obj -> replaceClassLoadersWithLayerConstant(registry, obj));
// relink packages defined in the prior layers
config.registerObjectToConstantReplacer(packageManager::replaceWithPriorLayerPackage);
}
}

@Override
public void beforeAnalysis(BeforeAnalysisAccess access) {
var packagesField = ReflectionUtil.lookupField(ClassLoader.class, "packages");
access.registerFieldValueTransformer(packagesField, new FieldValueTransformerWithAvailability() {

@Override
public ValueAvailability valueAvailability() {
return ValueAvailability.AfterAnalysis;
}

@Override
public Object transform(Object receiver, Object originalValue) {
assert receiver instanceof ClassLoader : receiver;
assert originalValue instanceof ConcurrentHashMap : "Underlying representation has changed: " + originalValue;

/* Retrieving initial package state for this class loader. */
ConcurrentHashMap<String, Package> packages = HostedClassLoaderPackageManagement.singleton().getRegisteredPackages((ClassLoader) receiver);
/* If no package state is available then we must create a clean state. */
return packages == null ? new ConcurrentHashMap<>() : packages;
}
});

if (ImageLayerBuildingSupport.buildingInitialLayer()) {
/*
* Note we cannot register these heap constants until the field value transformer has
* been registered. Otherwise there is a race between this feature and
* ObservableImageHeapMapProviderImpl#beforeAnalysis, as during heap scanning all
* fieldValueInterceptors will be computed for the scanned objects.
*/
var registry = CrossLayerConstantRegistry.singletonOrNull();
registry.registerHeapConstant(APP_KEY_NAME, nativeImageSystemClassLoader.defaultSystemClassLoader);
registry.registerHeapConstant(PLATFORM_KEY_NAME, platformClassLoader);
registry.registerHeapConstant(BOOT_KEY_NAME, bootClassLoader);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ public NativeImageSystemClassLoader(ClassLoader defaultSystemClassLoader) {
systemIOWrappers.replaceSystemOutErr();
}

/*
* Note this is not an image singleton; this ClassLoader is installed while starting
* NativeImageGeneratorRunner.
*/
public static NativeImageSystemClassLoader singleton() {
ClassLoader loader = ClassLoader.getSystemClassLoader();
if (loader instanceof NativeImageSystemClassLoader) {
Expand All @@ -87,14 +91,17 @@ public void setNativeImageClassLoader(ClassLoader nativeImageClassLoader) {
this.nativeImageClassLoader = nativeImageClassLoader;
}

private boolean isNativeImageClassLoader(ClassLoader current, ClassLoader c) {
ClassLoader loader = current;
/**
* Checks class loaders match. {@code start} is searched up to the system class loader.
*/
private boolean matchesClassLoaderOrParent(ClassLoader start, ClassLoader candidate) {
ClassLoader current = start;
do {
if (loader == c) {
if (current == candidate) {
return true;
}
loader = loader.getParent();
} while (loader != defaultSystemClassLoader);
current = current.getParent();
} while (current != defaultSystemClassLoader);
return false;
}

Expand All @@ -103,12 +110,12 @@ public boolean isNativeImageClassLoader(ClassLoader c) {
if (loader == null) {
return false;
}
return isNativeImageClassLoader(nativeImageClassLoader, c);
return matchesClassLoaderOrParent(nativeImageClassLoader, c);
}

public boolean isDisallowedClassLoader(ClassLoader c) {
for (ClassLoader disallowedClassLoader : disallowedClassLoaders) {
if (isNativeImageClassLoader(disallowedClassLoader, c)) {
if (matchesClassLoaderOrParent(disallowedClassLoader, c)) {
return true;
}
}
Expand Down
Loading