Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-57390] Enable constant folding on getAllLayers calls. #10090

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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 @@ -45,7 +45,6 @@
import com.oracle.svm.core.heap.RestrictHeapAccess;
import com.oracle.svm.core.heap.RestrictHeapAccess.Access;
import com.oracle.svm.core.heap.VMOperationInfos;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
import com.oracle.svm.core.log.Log;
import com.oracle.svm.core.meta.SharedMethod;
Expand Down Expand Up @@ -103,13 +102,7 @@ public static CodeInfo getFirstImageCodeInfo() {

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static CodeInfo getFirstImageCodeInfo(int layerNumber) {
if (ImageLayerBuildingSupport.buildingImageLayer()) {
ImageCodeInfoStorage[] runtimeCodeInfos = MultiLayeredImageSingleton.getAllLayers(ImageCodeInfoStorage.class);
return runtimeCodeInfos[layerNumber].getData();
} else {
assert layerNumber == 0;
return imageCodeInfo;
}
return MultiLayeredImageSingleton.getForLayer(ImageCodeInfoStorage.class, layerNumber).getData();
}

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public class RuntimeMetadataDecoderImpl implements RuntimeMetadataDecoder {
public static final int CLASS_ACCESS_FLAGS_MASK = 0x1FFF;

static byte[] getEncoding(DynamicHub hub) {
return MultiLayeredImageSingleton.getAllLayers(RuntimeMetadataEncoding.class)[hub.getLayerId()].getEncoding();
return MultiLayeredImageSingleton.getForLayer(RuntimeMetadataEncoding.class, hub.getLayerId()).getEncoding();
}

static List<byte[]> getEncodings() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
import com.oracle.svm.core.heap.UnknownObjectField;
import com.oracle.svm.core.heap.UnknownPrimitiveField;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
Expand All @@ -57,11 +56,7 @@ public static DynamicHubSupport singleton() {
@AlwaysInline("Performance")
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static DynamicHubSupport forLayer(int layerIndex) {
if (!ImageLayerBuildingSupport.buildingImageLayer()) {
return ImageSingletons.lookup(DynamicHubSupport.class);
}
DynamicHubSupport[] supports = MultiLayeredImageSingleton.getAllLayers(DynamicHubSupport.class);
return supports[layerIndex];
return MultiLayeredImageSingleton.getForLayer(DynamicHubSupport.class, layerIndex);
}

@Platforms(Platform.HOSTED_ONLY.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,20 +152,13 @@ String intern(String str) {

private String doIntern(String str) {
String result = str;
if (ImageLayerBuildingSupport.buildingImageLayer()) {
StringInternSupport[] layers = MultiLayeredImageSingleton.getAllLayers(StringInternSupport.class);
for (StringInternSupport layer : layers) {
String[] layerImageInternedStrings = layer.imageInternedStrings;
int imageIdx = Arrays.binarySearch(layerImageInternedStrings, str);
if (imageIdx >= 0) {
result = layerImageInternedStrings[imageIdx];
break;
}
}
} else {
int imageIdx = Arrays.binarySearch(imageInternedStrings, str);
StringInternSupport[] layers = MultiLayeredImageSingleton.getAllLayers(StringInternSupport.class);
for (StringInternSupport layer : layers) {
String[] layerImageInternedStrings = layer.imageInternedStrings;
int imageIdx = Arrays.binarySearch(layerImageInternedStrings, str);
if (imageIdx >= 0) {
result = imageInternedStrings[imageIdx];
result = layerImageInternedStrings[imageIdx];
break;
}
}
String oldValue = internedStrings.putIfAbsent(result, result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ static <T extends MultiLayeredImageSingleton> T[] getAllLayers(Class<T> key) {
throw VMError.shouldNotReachHere("This can only be called during runtime");
}

/**
* Retrieve a specific layer from a MultiLayeredImageSingleton. Note if a
* MultiLayeredImageSingleton is not installed in all layers, then the singletons index will not
* match the layer number it was installed in.
*/
@SuppressWarnings("unused")
static <T extends MultiLayeredImageSingleton> T getForLayer(Class<T> key, int index) {
throw VMError.shouldNotReachHere("This can only be called during runtime");
}

default <T extends MultiLayeredImageSingleton, U> U getSingletonData(T singleton, T[] singletons, Function<T, U> getSingletonDataFunction) {
if (ImageLayerBuildingSupport.buildingImageLayer()) {
for (var layerSingleton : singletons) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@
*/
package com.oracle.svm.core.layeredimagesingleton;

import static jdk.graal.compiler.core.common.calc.Condition.NE;

import java.lang.reflect.Array;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

import org.graalvm.nativeimage.hosted.Feature;

import com.oracle.svm.core.ParsingReason;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
Expand All @@ -42,11 +46,13 @@
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins;
import jdk.graal.compiler.phases.util.Providers;
import jdk.graal.compiler.replacements.InvocationPluginHelper;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;

/**
* Adds support for layered image singleton features within traditional builds.
* Adds support for layered image singleton features within traditional builds. We know traditional
* builds have at most exactly one singleton, so we can optimize these calls accordingly.
*/
@AutomaticallyRegisteredFeature
public class NonLayeredImageSingletonFeature implements InternalFeature, FeatureSingleton {
Expand All @@ -60,18 +66,23 @@ public boolean isInConfiguration(Feature.IsInConfigurationAccess access) {

@Override
public void registerInvocationPlugins(Providers providers, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) {
Function<Class<?>, Object> lookupMultiLayeredImageSingleton = (key) -> {
Object singleton = LayeredImageSingletonSupport.singleton().runtimeLookup(key);
boolean conditions = singleton.getClass().equals(key) &&
singleton instanceof MultiLayeredImageSingleton multiLayerSingleton &&
multiLayerSingleton.getImageBuilderFlags().contains(LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS);
VMError.guarantee(conditions, "Illegal singleton %s", singleton);

return singleton;
};

InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins.getInvocationPlugins(), MultiLayeredImageSingleton.class);
r.register(new InvocationPlugin.RequiredInvocationPlugin("getAllLayers", Class.class) {

@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode) {
Class<?> key = b.getSnippetReflection().asObject(Class.class, classNode.asJavaConstant());

Object singleton = LayeredImageSingletonSupport.singleton().runtimeLookup(key);
boolean conditions = singleton.getClass().equals(key) &&
singleton instanceof MultiLayeredImageSingleton multiLayerSingleton &&
multiLayerSingleton.getImageBuilderFlags().contains(LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS);
VMError.guarantee(conditions, "Illegal singleton %s", singleton);
Object singleton = lookupMultiLayeredImageSingleton.apply(key);

var multiLayeredArray = multiLayeredArrays.computeIfAbsent(key, k -> {
var result = Array.newInstance(k, 1);
Expand All @@ -83,5 +94,26 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
return true;
}
});

r.register(new InvocationPlugin.RequiredInvocationPlugin("getForLayer", Class.class, int.class) {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode, ValueNode indexNode) {
try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) {
Class<?> key = b.getSnippetReflection().asObject(Class.class, classNode.asJavaConstant());
Object singleton = lookupMultiLayeredImageSingleton.apply(key);

/*
* We know this index has to be zero. For performance reasons we validate this
* only when assertions are enabled.
*/
if (SubstrateUtil.assertionsEnabled()) {
helper.intrinsicRangeCheck(indexNode, NE, ConstantNode.forInt(0));
}

helper.emitFinalReturn(JavaKind.Object, ConstantNode.forConstant(b.getSnippetReflection().forObject(singleton), b.getMetaAccess(), b.getGraph()));
return true;
}
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,9 @@ public void finish(DebugContext debug) {
parseAll();
}

if (!ImageLayerBuildingSupport.buildingImageLayer() && !PointstoOptions.UseExperimentalReachabilityAnalysis.getValue(universe.hostVM().options())) {
// GR-59742 re-enable for open type world and layered images
if (SubstrateOptions.useClosedTypeWorld() && !ImageLayerBuildingSupport.buildingImageLayer() &&
!PointstoOptions.UseExperimentalReachabilityAnalysis.getValue(universe.hostVM().options())) {
/*
* Reachability Analysis creates call graphs with more edges compared to the
* Points-to Analysis, therefore the annotations would have to be added to a lot
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.stream.Stream;

Expand All @@ -53,7 +54,6 @@
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.graal.code.CGlobalDataInfo;
import com.oracle.svm.core.graal.nodes.LoadImageSingletonNode;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.core.imagelayer.LoadImageSingletonFactory;
import com.oracle.svm.core.layeredimagesingleton.ApplicationLayerOnlyImageSingleton;
Expand Down Expand Up @@ -81,7 +81,9 @@
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins;
import jdk.graal.compiler.nodes.java.LoadIndexedNode;
import jdk.graal.compiler.phases.util.Providers;
import jdk.graal.compiler.replacements.InvocationPluginHelper;
import jdk.vm.ci.code.BytecodeFrame;
import jdk.vm.ci.code.BytecodePosition;
import jdk.vm.ci.meta.JavaConstant;
Expand All @@ -101,7 +103,8 @@ private static CrossLayerSingletonMappingInfo getCrossLayerSingletonMappingInfo(
}

/*
* Cache for objects created by the calls to getAllLayers within the application layer.
* Cache for objects created by the calls to getAllLayers. This cache is only used in the
* application layer.
*/
private final Map<Class<?>, JavaConstant> keyToMultiLayerConstantMap = new ConcurrentHashMap<>();
/*
Expand All @@ -116,29 +119,43 @@ public boolean isInConfiguration(IsInConfigurationAccess access) {

@Override
public void registerInvocationPlugins(Providers providers, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) {
BiFunction<GraphBuilderContext, ValueNode, ValueNode> loadMultiLayeredImageSingleton = (b, classNode) -> {
Class<?> key = b.getSnippetReflection().asObject(Class.class, classNode.asJavaConstant());

if (ImageLayerBuildingSupport.buildingSharedLayer()) {
/*
* Load reference to the proper slot within the cross-layer singleton table.
*/
return LoadImageSingletonFactory.loadLayeredImageSingleton(key, b.getMetaAccess());
} else {
/*
* Can directly load the array of all objects
*/
JavaConstant multiLayerArray = keyToMultiLayerConstantMap.computeIfAbsent(key,
k -> createMultiLayerArray(key, (AnalysisType) b.getMetaAccess().lookupJavaType(k.arrayType()), b.getSnippetReflection()));
return ConstantNode.forConstant(multiLayerArray, 1, true, b.getMetaAccess());
}
};

InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins.getInvocationPlugins(), MultiLayeredImageSingleton.class);
r.register(new InvocationPlugin.RequiredInvocationPlugin("getAllLayers", Class.class) {

@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode) {
b.addPush(JavaKind.Object, loadMultiLayeredImageSingleton.apply(b, classNode));
return true;
}
});

Class<?> key = b.getSnippetReflection().asObject(Class.class, classNode.asJavaConstant());
r.register(new InvocationPlugin.RequiredInvocationPlugin("getForLayer", Class.class, int.class) {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode, ValueNode indexNode) {
try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) {
ValueNode layerArray = b.add(loadMultiLayeredImageSingleton.apply(b, classNode));

if (ImageLayerBuildingSupport.buildingSharedLayer()) {
/*
* Load reference to the proper slot within the cross-layer singleton table.
*/
LoadImageSingletonNode layeredSingleton = LoadImageSingletonFactory.loadLayeredImageSingleton(key, b.getMetaAccess());
b.addPush(JavaKind.Object, layeredSingleton);
return true;
} else {
/*
* Can directly load the array of all objects
*/
JavaConstant multiLayerArray = keyToMultiLayerConstantMap.computeIfAbsent(key,
k -> createMultiLayerArray(key, (AnalysisType) b.getMetaAccess().lookupJavaType(k.arrayType()), b.getSnippetReflection()));
var node = ConstantNode.forConstant(multiLayerArray, b.getMetaAccess());
b.addPush(JavaKind.Object, node);
helper.intrinsicArrayRangeCheck(layerArray, indexNode, ConstantNode.forInt(1));
var arrayElem = LoadIndexedNode.create(null, layerArray, indexNode, null, JavaKind.Object, b.getMetaAccess(), b.getConstantReflection());
helper.emitFinalReturn(JavaKind.Object, arrayElem);
return true;
}
}
Expand Down