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
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ private void addKnownClass(String name, ConditionalRuntimeValue<Object> cond) {

private void addKnownClass(String name, Consumer<EconomicMap<String, ConditionalRuntimeValue<Object>>> callback, ConditionalRuntimeValue<Object> cond) {
Boolean previousLayerData = previousLayerClasses.get(name);
/* GR-66387: The runtime condition should be combined across layers. */
if (previousLayerData == null || (!previousLayerData && cond.getValueUnconditionally() != NEGATIVE_QUERY)) {
callback.accept(knownClasses);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ private void updateTimeStamp() {

private void addResource(ModuleResourceKey key, ConditionalRuntimeValue<ResourceStorageEntryBase> entry) {
Boolean previousLayerData = ImageLayerBuildingSupport.buildingImageLayer() ? previousLayerResources.get(key.toString()) : null;
/* GR-66387: The runtime condition should be combined across layers. */
if (previousLayerData == null || (!previousLayerData && entry.getValueUnconditionally() != NEGATIVE_QUERY_MARKER)) {
resources.put(key, entry);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) {
* enabled. Until a clear SVM core separation is created and included in the base layer,
* those types should be manually registered as instantiated before the analysis.
*/
if (HostedImageLayerBuildingSupport.buildingSharedLayer()) {
if (HostedImageLayerBuildingSupport.buildingImageLayer()) {
String reason = "Included in the base image";
access.getMetaAccess().lookupJavaType(ReflectionUtil.lookupClass(false, "com.oracle.svm.core.jdk.resources.CompressedGlobTrie.LiteralNode")).registerAsInstantiated(reason);
access.getMetaAccess().lookupJavaType(ReflectionUtil.lookupClass(false, "com.oracle.svm.core.jdk.resources.CompressedGlobTrie.DoubleStarNode")).registerAsInstantiated(reason);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand All @@ -66,6 +68,7 @@
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.graalvm.nativeimage.ImageSingletons;
Expand All @@ -85,8 +88,15 @@
import com.oracle.svm.core.MissingRegistrationUtils;
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.hub.ClassForNameSupport;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.imagelayer.BuildingImageLayerPredicate;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader;
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter;
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton;
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
import com.oracle.svm.core.reflect.SubstrateAccessor;
import com.oracle.svm.core.reflect.target.ReflectionSubstitutionSupport;
import com.oracle.svm.core.util.VMError;
Expand All @@ -112,6 +122,7 @@ public class ReflectionDataBuilder extends ConditionalConfigurationRegistry impl
private final SubstrateAnnotationExtractor annotationExtractor;
private BeforeAnalysisAccessImpl analysisAccess;
private final ClassForNameSupport classForNameSupport;
private LayeredReflectionDataBuilder layeredReflectionDataBuilder;

private boolean sealed;

Expand Down Expand Up @@ -174,6 +185,9 @@ public void duringSetup(AnalysisMetaAccess analysisMetaAccess, AnalysisUniverse
registerConditionalConfiguration(conditionalTask.condition, (cnd) -> universe.getBigbang().postTask(debug -> conditionalTask.task.accept(cnd)));
}
pendingConditionalTasks.clear();
if (ImageLayerBuildingSupport.buildingImageLayer()) {
layeredReflectionDataBuilder = LayeredReflectionDataBuilder.singleton();
}
}

public void beforeAnalysis(BeforeAnalysisAccessImpl beforeAnalysisAccess) {
Expand Down Expand Up @@ -444,6 +458,12 @@ private void registerMethod(ConfigurationCondition cnd, boolean queriedOnly, Exe

AnalysisMethod analysisMethod = metaAccess.lookupJavaMethod(reflectExecutable);
AnalysisType declaringType = analysisMethod.getDeclaringClass();

if (layeredReflectionDataBuilder != null && layeredReflectionDataBuilder.isMethodRegistered(analysisMethod)) {
/* GR-66387: The runtime condition should be combined across layers. */
return;
}

var classMethods = registeredMethods.computeIfAbsent(declaringType, t -> new ConcurrentHashMap<>());
var shouldRegisterReachabilityHandler = classMethods.isEmpty();

Expand Down Expand Up @@ -606,6 +626,11 @@ private void registerField(ConfigurationCondition cnd, boolean queriedOnly, Fiel
AnalysisField analysisField = metaAccess.lookupJavaField(reflectField);
AnalysisType declaringClass = analysisField.getDeclaringClass();

if (layeredReflectionDataBuilder != null && layeredReflectionDataBuilder.isFieldRegistered(analysisField)) {
/* GR-66387: The runtime condition should be combined across layers. */
return;
}

var classFields = registeredFields.computeIfAbsent(declaringClass, t -> new ConcurrentHashMap<>());
boolean exists = classFields.containsKey(analysisField);
boolean shouldRegisterReachabilityHandler = classFields.isEmpty();
Expand Down Expand Up @@ -1391,4 +1416,98 @@ public static void registerField(ReflectionDataBuilder reflectionDataBuilder, bo
reflectionDataBuilder.runConditionalInAnalysisTask(ConfigurationCondition.alwaysTrue(), (cnd) -> reflectionDataBuilder.registerField(cnd, queriedOnly, field));
}
}

@AutomaticallyRegisteredImageSingleton(onlyWith = BuildingImageLayerPredicate.class)
public static class LayeredReflectionDataBuilder implements LayeredImageSingleton {
public static final String METHODS = "methods";
public static final String FIELDS = "fields";
public static final String REFLECTION_DATA_BUILDER = "reflection data builder";
public static final String REFLECTION_DATA_BUILDER_CLASSES = REFLECTION_DATA_BUILDER + " classes";
/**
* The methods registered for reflection in the previous layers. The key of the map is the
* id of the declaring type and the set contains the method ids.
*/
private final Map<Integer, Set<Integer>> previousLayerRegisteredMethods;
/**
* The fields registered for reflection in the previous layers. The key of the map is the id
* of the declaring type and the set contains the field ids.
*/
private final Map<Integer, Set<Integer>> previousLayerRegisteredFields;

public LayeredReflectionDataBuilder() {
this(Map.of(), Map.of());
}

private LayeredReflectionDataBuilder(Map<Integer, Set<Integer>> previousLayerRegisteredMethods, Map<Integer, Set<Integer>> previousLayerRegisteredFields) {
this.previousLayerRegisteredMethods = previousLayerRegisteredMethods;
this.previousLayerRegisteredFields = previousLayerRegisteredFields;
}

public static LayeredReflectionDataBuilder singleton() {
return ImageSingletons.lookup(LayeredReflectionDataBuilder.class);
}

public boolean isMethodRegistered(AnalysisMethod analysisMethod) {
return isElementRegistered(previousLayerRegisteredMethods, analysisMethod.getDeclaringClass(), analysisMethod.getId());
}

public boolean isFieldRegistered(AnalysisField analysisField) {
return isElementRegistered(previousLayerRegisteredFields, analysisField.getDeclaringClass(), analysisField.getId());
}

private static boolean isElementRegistered(Map<Integer, Set<Integer>> previousLayerRegisteredElements, AnalysisType declaringClass, int elementId) {
Set<Integer> previousLayerRegisteredElementIds = previousLayerRegisteredElements.get(declaringClass.getId());
if (declaringClass.isInBaseLayer() && previousLayerRegisteredElementIds != null) {
return previousLayerRegisteredElementIds.contains(elementId);
}
return false;
}

@Override
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY;
}

@Override
public PersistFlags preparePersist(ImageSingletonWriter writer) {
ReflectionDataBuilder reflectionDataBuilder = (ReflectionDataBuilder) ImageSingletons.lookup(RuntimeReflectionSupport.class);
persistRegisteredElements(writer, reflectionDataBuilder.registeredMethods, AnalysisMethod::getId, METHODS);
persistRegisteredElements(writer, reflectionDataBuilder.registeredFields, AnalysisField::getId, FIELDS);
return PersistFlags.CREATE;
}

private static <T, U> void persistRegisteredElements(ImageSingletonWriter writer, Map<AnalysisType, Map<T, U>> registeredElements, Function<T, Integer> getId, String element) {
List<Integer> classes = new ArrayList<>();
for (var entry : registeredElements.entrySet()) {
classes.add(entry.getKey().getId());
writer.writeIntList(getElementKeyName(element, entry.getKey().getId()), entry.getValue().keySet().stream().map(getId).toList());
}
writer.writeIntList(getClassesKeyName(element), classes);
}

@SuppressWarnings("unused")
public static Object createFromLoader(ImageSingletonLoader loader) {
var previousLayerRegisteredMethods = loadRegisteredElements(loader, METHODS);
var previousLayerRegisteredFields = loadRegisteredElements(loader, FIELDS);
return new LayeredReflectionDataBuilder(previousLayerRegisteredMethods, previousLayerRegisteredFields);
}

private static Map<Integer, Set<Integer>> loadRegisteredElements(ImageSingletonLoader loader, String element) {
Map<Integer, Set<Integer>> previousLayerRegisteredElements = new HashMap<>();
var classes = loader.readIntList(getClassesKeyName(element));
for (int key : classes) {
var elements = loader.readIntList(getElementKeyName(element, key)).stream().collect(Collectors.toUnmodifiableSet());
previousLayerRegisteredElements.put(key, elements);
}
return Collections.unmodifiableMap(previousLayerRegisteredElements);
}

private static String getClassesKeyName(String element) {
return REFLECTION_DATA_BUILDER_CLASSES + " " + element;
}

private static String getElementKeyName(String element, int typeId) {
return REFLECTION_DATA_BUILDER + " " + element + " " + typeId;
}
}
}
Loading