Skip to content

Commit 9db0e9e

Browse files
committed
[GR-57390] Enable constant folding on getAllLayers calls.
PullRequest: graal/18735
2 parents 6339bcd + 69fc7db commit 9db0e9e

File tree

8 files changed

+96
-54
lines changed

8 files changed

+96
-54
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import com.oracle.svm.core.heap.RestrictHeapAccess;
4646
import com.oracle.svm.core.heap.RestrictHeapAccess.Access;
4747
import com.oracle.svm.core.heap.VMOperationInfos;
48-
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
4948
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
5049
import com.oracle.svm.core.log.Log;
5150
import com.oracle.svm.core.meta.SharedMethod;
@@ -103,13 +102,7 @@ public static CodeInfo getFirstImageCodeInfo() {
103102

104103
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
105104
public static CodeInfo getFirstImageCodeInfo(int layerNumber) {
106-
if (ImageLayerBuildingSupport.buildingImageLayer()) {
107-
ImageCodeInfoStorage[] runtimeCodeInfos = MultiLayeredImageSingleton.getAllLayers(ImageCodeInfoStorage.class);
108-
return runtimeCodeInfos[layerNumber].getData();
109-
} else {
110-
assert layerNumber == 0;
111-
return imageCodeInfo;
112-
}
105+
return MultiLayeredImageSingleton.getForLayer(ImageCodeInfoStorage.class, layerNumber).getData();
113106
}
114107

115108
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataDecoderImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public class RuntimeMetadataDecoderImpl implements RuntimeMetadataDecoder {
9696
public static final int CLASS_ACCESS_FLAGS_MASK = 0x1FFF;
9797

9898
static byte[] getEncoding(DynamicHub hub) {
99-
return MultiLayeredImageSingleton.getAllLayers(RuntimeMetadataEncoding.class)[hub.getLayerId()].getEncoding();
99+
return MultiLayeredImageSingleton.getForLayer(RuntimeMetadataEncoding.class, hub.getLayerId()).getEncoding();
100100
}
101101

102102
static List<byte[]> getEncodings() {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubSupport.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
3939
import com.oracle.svm.core.heap.UnknownObjectField;
4040
import com.oracle.svm.core.heap.UnknownPrimitiveField;
41-
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
4241
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
4342
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
4443
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
@@ -57,11 +56,7 @@ public static DynamicHubSupport singleton() {
5756
@AlwaysInline("Performance")
5857
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
5958
public static DynamicHubSupport forLayer(int layerIndex) {
60-
if (!ImageLayerBuildingSupport.buildingImageLayer()) {
61-
return ImageSingletons.lookup(DynamicHubSupport.class);
62-
}
63-
DynamicHubSupport[] supports = MultiLayeredImageSingleton.getAllLayers(DynamicHubSupport.class);
64-
return supports[layerIndex];
59+
return MultiLayeredImageSingleton.getForLayer(DynamicHubSupport.class, layerIndex);
6560
}
6661

6762
@Platforms(Platform.HOSTED_ONLY.class)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StringInternSupport.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -152,20 +152,13 @@ String intern(String str) {
152152

153153
private String doIntern(String str) {
154154
String result = str;
155-
if (ImageLayerBuildingSupport.buildingImageLayer()) {
156-
StringInternSupport[] layers = MultiLayeredImageSingleton.getAllLayers(StringInternSupport.class);
157-
for (StringInternSupport layer : layers) {
158-
String[] layerImageInternedStrings = layer.imageInternedStrings;
159-
int imageIdx = Arrays.binarySearch(layerImageInternedStrings, str);
160-
if (imageIdx >= 0) {
161-
result = layerImageInternedStrings[imageIdx];
162-
break;
163-
}
164-
}
165-
} else {
166-
int imageIdx = Arrays.binarySearch(imageInternedStrings, str);
155+
StringInternSupport[] layers = MultiLayeredImageSingleton.getAllLayers(StringInternSupport.class);
156+
for (StringInternSupport layer : layers) {
157+
String[] layerImageInternedStrings = layer.imageInternedStrings;
158+
int imageIdx = Arrays.binarySearch(layerImageInternedStrings, str);
167159
if (imageIdx >= 0) {
168-
result = imageInternedStrings[imageIdx];
160+
result = layerImageInternedStrings[imageIdx];
161+
break;
169162
}
170163
}
171164
String oldValue = internedStrings.putIfAbsent(result, result);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/MultiLayeredImageSingleton.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ static <T extends MultiLayeredImageSingleton> T[] getAllLayers(Class<T> key) {
4040
throw VMError.shouldNotReachHere("This can only be called during runtime");
4141
}
4242

43+
/**
44+
* Retrieve a specific layer from a MultiLayeredImageSingleton. Note if a
45+
* MultiLayeredImageSingleton is not installed in all layers, then the singletons index will not
46+
* match the layer number it was installed in.
47+
*/
48+
@SuppressWarnings("unused")
49+
static <T extends MultiLayeredImageSingleton> T getForLayer(Class<T> key, int index) {
50+
throw VMError.shouldNotReachHere("This can only be called during runtime");
51+
}
52+
4353
default <T extends MultiLayeredImageSingleton, U> U getSingletonData(T singleton, T[] singletons, Function<T, U> getSingletonDataFunction) {
4454
if (ImageLayerBuildingSupport.buildingImageLayer()) {
4555
for (var layerSingleton : singletons) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/NonLayeredImageSingletonFeature.java

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@
2424
*/
2525
package com.oracle.svm.core.layeredimagesingleton;
2626

27+
import static jdk.graal.compiler.core.common.calc.Condition.NE;
28+
2729
import java.lang.reflect.Array;
2830
import java.util.concurrent.ConcurrentHashMap;
31+
import java.util.function.Function;
2932

3033
import org.graalvm.nativeimage.hosted.Feature;
3134

3235
import com.oracle.svm.core.ParsingReason;
36+
import com.oracle.svm.core.SubstrateUtil;
3337
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3438
import com.oracle.svm.core.feature.InternalFeature;
3539
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
@@ -42,11 +46,13 @@
4246
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
4347
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins;
4448
import jdk.graal.compiler.phases.util.Providers;
49+
import jdk.graal.compiler.replacements.InvocationPluginHelper;
4550
import jdk.vm.ci.meta.JavaKind;
4651
import jdk.vm.ci.meta.ResolvedJavaMethod;
4752

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

6167
@Override
6268
public void registerInvocationPlugins(Providers providers, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) {
69+
Function<Class<?>, Object> lookupMultiLayeredImageSingleton = (key) -> {
70+
Object singleton = LayeredImageSingletonSupport.singleton().runtimeLookup(key);
71+
boolean conditions = singleton.getClass().equals(key) &&
72+
singleton instanceof MultiLayeredImageSingleton multiLayerSingleton &&
73+
multiLayerSingleton.getImageBuilderFlags().contains(LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS);
74+
VMError.guarantee(conditions, "Illegal singleton %s", singleton);
75+
76+
return singleton;
77+
};
78+
6379
InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins.getInvocationPlugins(), MultiLayeredImageSingleton.class);
6480
r.register(new InvocationPlugin.RequiredInvocationPlugin("getAllLayers", Class.class) {
6581

6682
@Override
6783
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode) {
6884
Class<?> key = b.getSnippetReflection().asObject(Class.class, classNode.asJavaConstant());
69-
70-
Object singleton = LayeredImageSingletonSupport.singleton().runtimeLookup(key);
71-
boolean conditions = singleton.getClass().equals(key) &&
72-
singleton instanceof MultiLayeredImageSingleton multiLayerSingleton &&
73-
multiLayerSingleton.getImageBuilderFlags().contains(LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS);
74-
VMError.guarantee(conditions, "Illegal singleton %s", singleton);
85+
Object singleton = lookupMultiLayeredImageSingleton.apply(key);
7586

7687
var multiLayeredArray = multiLayeredArrays.computeIfAbsent(key, k -> {
7788
var result = Array.newInstance(k, 1);
@@ -83,5 +94,26 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
8394
return true;
8495
}
8596
});
97+
98+
r.register(new InvocationPlugin.RequiredInvocationPlugin("getForLayer", Class.class, int.class) {
99+
@Override
100+
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode, ValueNode indexNode) {
101+
try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) {
102+
Class<?> key = b.getSnippetReflection().asObject(Class.class, classNode.asJavaConstant());
103+
Object singleton = lookupMultiLayeredImageSingleton.apply(key);
104+
105+
/*
106+
* We know this index has to be zero. For performance reasons we validate this
107+
* only when assertions are enabled.
108+
*/
109+
if (SubstrateUtil.assertionsEnabled()) {
110+
helper.intrinsicRangeCheck(indexNode, NE, ConstantNode.forInt(0));
111+
}
112+
113+
helper.emitFinalReturn(JavaKind.Object, ConstantNode.forConstant(b.getSnippetReflection().forObject(singleton), b.getMetaAccess(), b.getGraph()));
114+
return true;
115+
}
116+
}
117+
});
86118
}
87119
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,9 @@ public void finish(DebugContext debug) {
396396
parseAll();
397397
}
398398

399-
if (!ImageLayerBuildingSupport.buildingImageLayer() && !PointstoOptions.UseExperimentalReachabilityAnalysis.getValue(universe.hostVM().options())) {
399+
// GR-59742 re-enable for open type world and layered images
400+
if (SubstrateOptions.useClosedTypeWorld() && !ImageLayerBuildingSupport.buildingImageLayer() &&
401+
!PointstoOptions.UseExperimentalReachabilityAnalysis.getValue(universe.hostVM().options())) {
400402
/*
401403
* Reachability Analysis creates call graphs with more edges compared to the
402404
* Points-to Analysis, therefore the annotations would have to be added to a lot

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.util.Map;
3636
import java.util.Objects;
3737
import java.util.concurrent.ConcurrentHashMap;
38+
import java.util.function.BiFunction;
3839
import java.util.function.Consumer;
3940
import java.util.stream.Stream;
4041

@@ -53,7 +54,6 @@
5354
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
5455
import com.oracle.svm.core.feature.InternalFeature;
5556
import com.oracle.svm.core.graal.code.CGlobalDataInfo;
56-
import com.oracle.svm.core.graal.nodes.LoadImageSingletonNode;
5757
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
5858
import com.oracle.svm.core.imagelayer.LoadImageSingletonFactory;
5959
import com.oracle.svm.core.layeredimagesingleton.ApplicationLayerOnlyImageSingleton;
@@ -81,7 +81,9 @@
8181
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
8282
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
8383
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins;
84+
import jdk.graal.compiler.nodes.java.LoadIndexedNode;
8485
import jdk.graal.compiler.phases.util.Providers;
86+
import jdk.graal.compiler.replacements.InvocationPluginHelper;
8587
import jdk.vm.ci.code.BytecodeFrame;
8688
import jdk.vm.ci.code.BytecodePosition;
8789
import jdk.vm.ci.meta.JavaConstant;
@@ -101,7 +103,8 @@ private static CrossLayerSingletonMappingInfo getCrossLayerSingletonMappingInfo(
101103
}
102104

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

117120
@Override
118121
public void registerInvocationPlugins(Providers providers, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) {
122+
BiFunction<GraphBuilderContext, ValueNode, ValueNode> loadMultiLayeredImageSingleton = (b, classNode) -> {
123+
Class<?> key = b.getSnippetReflection().asObject(Class.class, classNode.asJavaConstant());
124+
125+
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
126+
/*
127+
* Load reference to the proper slot within the cross-layer singleton table.
128+
*/
129+
return LoadImageSingletonFactory.loadLayeredImageSingleton(key, b.getMetaAccess());
130+
} else {
131+
/*
132+
* Can directly load the array of all objects
133+
*/
134+
JavaConstant multiLayerArray = keyToMultiLayerConstantMap.computeIfAbsent(key,
135+
k -> createMultiLayerArray(key, (AnalysisType) b.getMetaAccess().lookupJavaType(k.arrayType()), b.getSnippetReflection()));
136+
return ConstantNode.forConstant(multiLayerArray, 1, true, b.getMetaAccess());
137+
}
138+
};
139+
119140
InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins.getInvocationPlugins(), MultiLayeredImageSingleton.class);
120141
r.register(new InvocationPlugin.RequiredInvocationPlugin("getAllLayers", Class.class) {
121142

122143
@Override
123144
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode) {
145+
b.addPush(JavaKind.Object, loadMultiLayeredImageSingleton.apply(b, classNode));
146+
return true;
147+
}
148+
});
124149

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

127-
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
128-
/*
129-
* Load reference to the proper slot within the cross-layer singleton table.
130-
*/
131-
LoadImageSingletonNode layeredSingleton = LoadImageSingletonFactory.loadLayeredImageSingleton(key, b.getMetaAccess());
132-
b.addPush(JavaKind.Object, layeredSingleton);
133-
return true;
134-
} else {
135-
/*
136-
* Can directly load the array of all objects
137-
*/
138-
JavaConstant multiLayerArray = keyToMultiLayerConstantMap.computeIfAbsent(key,
139-
k -> createMultiLayerArray(key, (AnalysisType) b.getMetaAccess().lookupJavaType(k.arrayType()), b.getSnippetReflection()));
140-
var node = ConstantNode.forConstant(multiLayerArray, b.getMetaAccess());
141-
b.addPush(JavaKind.Object, node);
156+
helper.intrinsicArrayRangeCheck(layerArray, indexNode, ConstantNode.forInt(1));
157+
var arrayElem = LoadIndexedNode.create(null, layerArray, indexNode, null, JavaKind.Object, b.getMetaAccess(), b.getConstantReflection());
158+
helper.emitFinalReturn(JavaKind.Object, arrayElem);
142159
return true;
143160
}
144161
}

0 commit comments

Comments
 (0)