Skip to content

Commit db0006f

Browse files
committed
Make CGlobalDataBasePointer layer aware to ensure the base corresponding to the correct layer is used when accessing CGlobalData
1 parent c588bdc commit db0006f

File tree

5 files changed

+163
-32
lines changed

5 files changed

+163
-32
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core;
26+
27+
import java.util.EnumSet;
28+
29+
import org.graalvm.nativeimage.Platform;
30+
import org.graalvm.nativeimage.Platforms;
31+
32+
import com.oracle.svm.core.c.BoxedRelocatedPointer;
33+
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
34+
import com.oracle.svm.core.graal.code.CGlobalDataBasePointer;
35+
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter;
36+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
37+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonSupport;
38+
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
39+
40+
/**
41+
* This singleton contains the {@link CGlobalDataBasePointer} of the current layer. In layered
42+
* images, there is one {@link com.oracle.svm.core.c.CGlobalData} memory space for each layer, so
43+
* when reading a {@link com.oracle.svm.core.c.CGlobalData}, the corresponding base needs to be
44+
* used.
45+
*/
46+
@AutomaticallyRegisteredImageSingleton
47+
public class CGlobalDataPointerSingleton implements MultiLayeredImageSingleton {
48+
49+
/**
50+
* Image heap object storing the base address of CGlobalData memory using a relocation. Before
51+
* the image heap is set up, CGlobalData must be accessed via relocations in the code instead.
52+
*/
53+
private final BoxedRelocatedPointer cGlobalDataRuntimeBaseAddress = new BoxedRelocatedPointer(CGlobalDataBasePointer.INSTANCE);
54+
55+
@Platforms(Platform.HOSTED_ONLY.class)
56+
public static CGlobalDataPointerSingleton currentLayer() {
57+
return LayeredImageSingletonSupport.singleton().lookup(CGlobalDataPointerSingleton.class, false, true);
58+
}
59+
60+
public static CGlobalDataPointerSingleton[] allLayers() {
61+
return MultiLayeredImageSingleton.getAllLayers(CGlobalDataPointerSingleton.class);
62+
}
63+
64+
public BoxedRelocatedPointer getRuntimeBaseAddress() {
65+
return cGlobalDataRuntimeBaseAddress;
66+
}
67+
68+
@Override
69+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
70+
return LayeredImageSingletonBuilderFlags.ALL_ACCESS;
71+
}
72+
73+
@Override
74+
public PersistFlags preparePersist(ImageSingletonWriter writer) {
75+
return PersistFlags.NOTHING;
76+
}
77+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import com.oracle.svm.core.SubstrateDiagnostics.DumpDeoptStubPointer;
5151
import com.oracle.svm.core.SubstrateDiagnostics.DumpRecentDeoptimizations;
5252
import com.oracle.svm.core.SubstrateDiagnostics.DumpRuntimeCodeInfoMemory;
53+
import com.oracle.svm.core.c.BoxedRelocatedPointer;
5354
import com.oracle.svm.core.c.NonmovableArrays;
5455
import com.oracle.svm.core.code.CodeInfo;
5556
import com.oracle.svm.core.code.CodeInfoAccess;
@@ -67,7 +68,6 @@
6768
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
6869
import com.oracle.svm.core.feature.InternalFeature;
6970
import com.oracle.svm.core.graal.RuntimeCompilation;
70-
import com.oracle.svm.core.graal.code.CGlobalDataInfo;
7171
import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue;
7272
import com.oracle.svm.core.heap.Heap;
7373
import com.oracle.svm.core.heap.RestrictHeapAccess;
@@ -912,7 +912,15 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev
912912
if (SubstrateOptions.useRelativeCodePointers()) {
913913
log.string("Code base: ").zhex(KnownIntrinsics.codeBase()).newline();
914914
}
915-
log.string("CGlobalData base: ").zhex(CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS.getPointer()).newline();
915+
CGlobalDataPointerSingleton[] layeredSingletons = CGlobalDataPointerSingleton.allLayers();
916+
if (ImageLayerBuildingSupport.buildingImageLayer()) {
917+
for (int i = 0; i < layeredSingletons.length; ++i) {
918+
log.string("CGlobalData base for layer ").unsigned(i).string(": ").zhex(layeredSingletons[i].getRuntimeBaseAddress().getPointer()).newline();
919+
}
920+
} else {
921+
BoxedRelocatedPointer baseAddress = layeredSingletons[0].getRuntimeBaseAddress();
922+
log.string("CGlobalData base: ").zhex(baseAddress.getPointer()).newline();
923+
}
916924
log.string("Containerized: ").bool(Container.singleton().isContainerized()).newline();
917925

918926
if (Container.singleton().isContainerized()) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/CGlobalDataInfo.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232

3333
import com.oracle.svm.core.BuildPhaseProvider.AfterHeapLayout;
3434
import com.oracle.svm.core.BuildPhaseProvider.AfterHostedUniverse;
35-
import com.oracle.svm.core.c.BoxedRelocatedPointer;
3635
import com.oracle.svm.core.c.CGlobalDataImpl;
3736
import com.oracle.svm.core.heap.UnknownPrimitiveField;
3837
import com.oracle.svm.core.util.VMError;
@@ -43,12 +42,6 @@
4342
* {@link CGlobalDataImpl} within static fields.
4443
*/
4544
public final class CGlobalDataInfo {
46-
/**
47-
* Image heap object storing the base address of CGlobalData memory using a relocation. Before
48-
* the image heap is set up, CGlobalData must be accessed via relocations in the code instead.
49-
*/
50-
public static final BoxedRelocatedPointer CGLOBALDATA_RUNTIME_BASE_ADDRESS = new BoxedRelocatedPointer(CGlobalDataBasePointer.INSTANCE);
51-
5245
private final CGlobalDataImpl<?> data;
5346
private final boolean isSymbolReference;
5447

@@ -68,13 +61,16 @@ public final class CGlobalDataInfo {
6861
/** Cache until writing the image in case the {@link Supplier} is costly or has side-effects. */
6962
@Platforms(HOSTED_ONLY.class) private byte[] bytes;
7063

64+
private final int layerNum;
65+
7166
@Platforms(Platform.HOSTED_ONLY.class)
72-
public CGlobalDataInfo(CGlobalDataImpl<?> data, boolean definedAsGlobalInPriorLayer) {
67+
public CGlobalDataInfo(CGlobalDataImpl<?> data, boolean definedAsGlobalInPriorLayer, int layerNum) {
7368
assert data != null;
7469
this.data = data;
7570
this.isSymbolReference = data.isSymbolReference();
7671
assert !this.isSymbolReference || data.symbolName != null;
7772
this.definedAsGlobalInPriorLayer = definedAsGlobalInPriorLayer;
73+
this.layerNum = layerNum;
7874
}
7975

8076
public CGlobalDataImpl<?> getData() {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.graalvm.nativeimage.ImageSingletons;
4141

4242
import com.oracle.graal.pointsto.meta.AnalysisType;
43+
import com.oracle.svm.core.CGlobalDataPointerSingleton;
4344
import com.oracle.svm.core.ParsingReason;
4445
import com.oracle.svm.core.c.BoxedRelocatedPointer;
4546
import com.oracle.svm.core.c.CGlobalData;
@@ -50,14 +51,17 @@
5051
import com.oracle.svm.core.feature.InternalFeature;
5152
import com.oracle.svm.core.graal.code.CGlobalDataInfo;
5253
import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode;
54+
import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo;
5355
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
5456
import com.oracle.svm.core.traits.BuiltinTraits.BuildtimeAccessOnly;
5557
import com.oracle.svm.core.traits.BuiltinTraits.NoLayeredCallbacks;
5658
import com.oracle.svm.core.traits.SingletonLayeredInstallationKind.Independent;
5759
import com.oracle.svm.core.traits.SingletonTraits;
5860
import com.oracle.svm.core.util.VMError;
61+
import com.oracle.svm.hosted.FeatureImpl;
5962
import com.oracle.svm.hosted.image.RelocatableBuffer;
6063
import com.oracle.svm.hosted.imagelayer.CodeLocation;
64+
import com.oracle.svm.hosted.imagelayer.LoadImageSingletonFeature;
6165
import com.oracle.svm.hosted.meta.HostedSnippetReflectionProvider;
6266
import com.oracle.svm.util.ReflectionUtil;
6367

@@ -90,10 +94,12 @@
9094
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.RequiredInvocationPlugin;
9195
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
9296
import jdk.graal.compiler.nodes.java.LoadFieldNode;
97+
import jdk.graal.compiler.nodes.java.LoadIndexedNode;
9398
import jdk.graal.compiler.nodes.memory.ReadNode;
9499
import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode;
95100
import jdk.graal.compiler.phases.util.Providers;
96101
import jdk.vm.ci.meta.JavaConstant;
102+
import jdk.vm.ci.meta.JavaKind;
97103
import jdk.vm.ci.meta.ResolvedJavaField;
98104
import jdk.vm.ci.meta.ResolvedJavaMethod;
99105
import jdk.vm.ci.meta.ResolvedJavaType;
@@ -103,6 +109,8 @@
103109
public class CGlobalDataFeature implements InternalFeature {
104110

105111
private final Method getCGlobalDataInfoMethod = ReflectionUtil.lookupMethod(CGlobalDataNonConstantRegistry.class, "getCGlobalDataInfo", CGlobalDataImpl.class);
112+
private final Field layerNumField = ReflectionUtil.lookupField(CGlobalDataInfo.class, "layerNum");
113+
private final Field cGlobalDataRuntimeBaseAddressField = ReflectionUtil.lookupField(CGlobalDataPointerSingleton.class, "cGlobalDataRuntimeBaseAddress");
106114
private final Field offsetField = ReflectionUtil.lookupField(CGlobalDataInfo.class, "offset");
107115
private final Field isSymbolReferenceField = ReflectionUtil.lookupField(CGlobalDataInfo.class, "isSymbolReference");
108116
private final Field baseHolderPointerField = ReflectionUtil.lookupField(BoxedRelocatedPointer.class, "pointer");
@@ -132,6 +140,17 @@ public void duringSetup(DuringSetupAccess a) {
132140
a.registerObjectReplacer(this::replaceObject);
133141
}
134142

143+
@Override
144+
public void beforeAnalysis(BeforeAnalysisAccess access) {
145+
if (ImageLayerBuildingSupport.buildingImageLayer()) {
146+
/*
147+
* The non-constant registry needs to be rescanned in layered images to make sure it is
148+
* always reachable in every layer and that all the data is properly tracked.
149+
*/
150+
((FeatureImpl.BeforeAnalysisAccessImpl) access).rescanObject(nonConstantRegistry);
151+
}
152+
}
153+
135154
@Override
136155
public void afterHeapLayout(AfterHeapLayoutAccess access) {
137156
layout();
@@ -180,8 +199,39 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
180199
}
181200
}
182201

183-
JavaConstant baseHolderConstant = providers.getSnippetReflection().forObject(CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS);
184-
ConstantNode baseHolder = ConstantNode.forConstant(baseHolderConstant, b.getMetaAccess(), b.getGraph());
202+
ValueNode baseHolder;
203+
if (ImageLayerBuildingSupport.buildingImageLayer()) {
204+
/*
205+
* When building layered images, each layer has its own CGlobalData base
206+
* pointer, meaning the one associated with this specific CGlobalDataInfo
207+
* needs to be used.
208+
*/
209+
JavaConstant cGlobalDataPointerSingletonClass = providers.getSnippetReflection().forObject(CGlobalDataPointerSingleton.class);
210+
ConstantNode classConstant = ConstantNode.forConstant(cGlobalDataPointerSingletonClass, b.getMetaAccess(), b.getGraph());
211+
212+
/* Load the array containing all the singletons. */
213+
ValueNode layers = b.add(ImageSingletons.lookup(LoadImageSingletonFeature.class).loadMultiLayeredImageSingleton(b, classConstant));
214+
215+
/*
216+
* Get the layer number of the CGlobalDataInfo to get the index to use in
217+
* the singleton array.
218+
*/
219+
ValueNode layerNum = b.add(LoadFieldNode.create(b.getAssumptions(), info, b.getMetaAccess().lookupJavaField(layerNumField)));
220+
221+
/* Use the layer number to get the corresponding singleton. */
222+
ValueNode singleton = b.add(LoadIndexedNode.create(b.getAssumptions(), layers, layerNum, null, JavaKind.Object, b.getMetaAccess(), b.getConstantReflection()));
223+
224+
/* Get the CGlobalData base pointer from the singleton. */
225+
baseHolder = b.add(LoadFieldNode.create(b.getAssumptions(), singleton, b.getMetaAccess().lookupJavaField(cGlobalDataRuntimeBaseAddressField)));
226+
} else {
227+
/*
228+
* In standalone image, there is only one CGlobalData base pointer, so there
229+
* is no need to have a custom access.
230+
*/
231+
JavaConstant baseHolderConstant = providers.getSnippetReflection().forObject(CGlobalDataPointerSingleton.currentLayer().getRuntimeBaseAddress());
232+
baseHolder = ConstantNode.forConstant(baseHolderConstant, b.getMetaAccess(), b.getGraph());
233+
}
234+
185235
ResolvedJavaField holderPointerField = providers.getMetaAccess().lookupJavaField(baseHolderPointerField);
186236
StampPair pointerStamp = StampPair.createSingle(providers.getWordTypes().getWordStamp((ResolvedJavaType) holderPointerField.getType()));
187237
LoadFieldNode baseAddress = b.add(LoadFieldNode.createOverrideStamp(pointerStamp, baseHolder, holderPointerField));
@@ -270,7 +320,7 @@ CGlobalDataInfo createCGlobalDataInfo(CGlobalDataImpl<?> data, boolean definedAs
270320
"We currently do not allow CGlobalData code locations to be in a hidden class. Please adapt the code accordingly. Location: %s",
271321
data.codeLocation);
272322
}
273-
CGlobalDataInfo cGlobalDataInfo = new CGlobalDataInfo(data, definedAsGlobalInPriorLayer);
323+
CGlobalDataInfo cGlobalDataInfo = new CGlobalDataInfo(data, definedAsGlobalInPriorLayer, DynamicImageLayerInfo.getCurrentLayerNumber());
274324
if (data.nonConstant) {
275325
nonConstantRegistry.registerNonConstantSymbol(cGlobalDataInfo);
276326
}

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

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import java.util.Objects;
3838
import java.util.concurrent.ConcurrentHashMap;
3939
import java.util.function.BiConsumer;
40-
import java.util.function.BiFunction;
4140
import java.util.function.Consumer;
4241

4342
import org.graalvm.nativeimage.AnnotationAccess;
@@ -128,29 +127,13 @@ public boolean isInConfiguration(IsInConfigurationAccess access) {
128127

129128
@Override
130129
public void registerInvocationPlugins(Providers providers, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) {
131-
BiFunction<GraphBuilderContext, ValueNode, ValueNode> loadMultiLayeredImageSingleton = (b, classNode) -> {
132-
Class<?> key = b.getSnippetReflection().asObject(Class.class, classNode.asJavaConstant());
133-
134-
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
135-
/*
136-
* Load reference to the proper slot within the cross-layer singleton table.
137-
*/
138-
return LoadImageSingletonFactory.loadLayeredImageSingleton(key, b.getMetaAccess());
139-
} else {
140-
/*
141-
* Can directly load the array of all objects
142-
*/
143-
JavaConstant multiLayerArray = getMultiLayerConstant(key, b.getMetaAccess(), b.getSnippetReflection());
144-
return ConstantNode.forConstant(multiLayerArray, 1, true, b.getMetaAccess());
145-
}
146-
};
147130

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

151134
@Override
152135
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode) {
153-
b.addPush(JavaKind.Object, loadMultiLayeredImageSingleton.apply(b, classNode));
136+
b.addPush(JavaKind.Object, loadMultiLayeredImageSingleton(b, classNode));
154137
return true;
155138
}
156139
});
@@ -159,7 +142,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
159142
@Override
160143
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode, ValueNode indexNode) {
161144
try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) {
162-
ValueNode layerArray = b.add(loadMultiLayeredImageSingleton.apply(b, classNode));
145+
ValueNode layerArray = b.add(loadMultiLayeredImageSingleton(b, classNode));
163146

164147
helper.intrinsicArrayRangeCheck(layerArray, indexNode, ConstantNode.forInt(1));
165148
var arrayElem = LoadIndexedNode.create(null, layerArray, indexNode, null, JavaKind.Object, b.getMetaAccess(), b.getConstantReflection());
@@ -181,6 +164,23 @@ static void checkAllowNullEntries(Class<?> key) {
181164
"This MultiLayeredSingleton requires an entry to be installed in every layer. Please see the javadoc within MultiLayeredAllowNullEntries for more details.");
182165
}
183166

167+
public ValueNode loadMultiLayeredImageSingleton(GraphBuilderContext b, ValueNode classNode) {
168+
Class<?> key = b.getSnippetReflection().asObject(Class.class, classNode.asJavaConstant());
169+
170+
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
171+
/*
172+
* Load reference to the proper slot within the cross-layer singleton table.
173+
*/
174+
return LoadImageSingletonFactory.loadLayeredImageSingleton(key, b.getMetaAccess());
175+
} else {
176+
/*
177+
* Can directly load the array of all objects
178+
*/
179+
JavaConstant multiLayerArray = getMultiLayerConstant(key, b.getMetaAccess(), b.getSnippetReflection());
180+
return ConstantNode.forConstant(multiLayerArray, 1, true, b.getMetaAccess());
181+
}
182+
}
183+
184184
/**
185185
* This method needs to be called after all image singletons are registered. Currently, some
186186
* singletons are registered in

0 commit comments

Comments
 (0)