Skip to content

Commit 2d6e4b5

Browse files
committed
[GR-47064] Enable partitioned loading of compiled code at non-contiguous memory locations.
PullRequest: graal/22222
2 parents bca835c + 7d331a9 commit 2d6e4b5

16 files changed

+447
-255
lines changed

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,8 @@
4646
import jdk.graal.compiler.api.replacements.Fold;
4747
import jdk.graal.compiler.word.Word;
4848

49+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
50+
4951
/**
5052
* Provides functionality to query information about a unit of compiled code from a {@link CodeInfo}
5153
* object. This helper class is necessary to ensure that {@link CodeInfo} objects are used
@@ -184,6 +186,13 @@ public static CodePointer getCodeStart(CodeInfo info) {
184186
return cast(info).getCodeStart();
185187
}
186188

189+
/** @see CodeInfoImpl#setCodeStart */
190+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
191+
public static void setCodeStart(CodeInfo info, CodePointer codeStart) {
192+
CodeInfoImpl impl = cast(info);
193+
impl.setCodeStart(codeStart);
194+
}
195+
187196
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
188197
public static UnsignedWord getCodeEntryPointOffset(CodeInfo info) {
189198
return cast(info).getCodeEntryPointOffset();
@@ -195,6 +204,13 @@ public static UnsignedWord getCodeSize(CodeInfo info) {
195204
return cast(info).getCodeSize();
196205
}
197206

207+
/** @see CodeInfoImpl#setCodeSize */
208+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
209+
public static void setCodeSize(CodeInfo info, UnsignedWord codeSize) {
210+
CodeInfoImpl impl = cast(info);
211+
impl.setCodeSize(codeSize);
212+
}
213+
198214
/** @see CodeInfoImpl#getDataSize */
199215
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
200216
public static UnsignedWord getDataSize(CodeInfo info) {
@@ -245,7 +261,9 @@ public static boolean contains(CodeInfo info, CodePointer ip) {
245261
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
246262
public static long relativeIP(CodeInfo info, CodePointer ip) {
247263
assert contains(info, ip);
248-
return ((UnsignedWord) ip).subtract((UnsignedWord) cast(info).getCodeStart()).rawValue();
264+
CodeInfoImpl impl = cast(info);
265+
UnsignedWord baseOffset = ((UnsignedWord) ip).subtract((UnsignedWord) impl.getCodeStart());
266+
return baseOffset.add(impl.getRelativeIPOffset()).rawValue();
249267
}
250268

251269
public static CodePointer absoluteIP(CodeInfo info, long relativeIP) {
@@ -444,6 +462,15 @@ public static CodeInfo getNextImageCodeInfo(CodeInfo info) {
444462
return cast(info).getNextImageCodeInfo();
445463
}
446464

465+
/** @see CodeInfoImpl#setNextImageCodeInfo */
466+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
467+
public static void setNextImageCodeInfo(CodeInfo info, CodeInfo next) {
468+
assert isAOTImageCode(info);
469+
CodeInfoImpl impl = cast(info);
470+
assert impl.getNextImageCodeInfo().isNull();
471+
impl.setNextImageCodeInfo(next);
472+
}
473+
447474
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
448475
private static CodeInfoImpl cast(UntetheredCodeInfo info) {
449476
assert isValid(info);
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (c) 2015, 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.code;
26+
27+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
28+
import com.oracle.svm.core.feature.InternalFeature;
29+
import com.oracle.svm.core.util.CounterFeature;
30+
import org.graalvm.nativeimage.ImageSingletons;
31+
import org.graalvm.nativeimage.hosted.Feature;
32+
33+
import java.util.Arrays;
34+
import java.util.List;
35+
36+
@AutomaticallyRegisteredFeature
37+
public class CodeInfoFeature implements InternalFeature {
38+
@Override
39+
public List<Class<? extends Feature>> getRequiredFeatures() {
40+
return Arrays.asList(CounterFeature.class);
41+
}
42+
43+
@Override
44+
public void duringSetup(DuringSetupAccess access) {
45+
ImageSingletons.add(CodeInfoTableCounters.class, new CodeInfoTableCounters());
46+
ImageSingletons.add(CodeInfoDecoderCounters.class, new CodeInfoDecoderCounters());
47+
ImageSingletons.add(CodeInfoEncoder.Counters.class, new CodeInfoEncoder.Counters());
48+
49+
ImageSingletons.add(ImageCodeInfo.class, new ImageCodeInfo());
50+
ImageSingletons.add(RuntimeCodeInfoHistory.class, new RuntimeCodeInfoHistory());
51+
ImageSingletons.add(RuntimeCodeCache.class, new RuntimeCodeCache());
52+
ImageSingletons.add(RuntimeCodeInfoMemory.class, new RuntimeCodeInfoMemory());
53+
}
54+
55+
@Override
56+
public void afterCompilation(AfterCompilationAccess config) {
57+
ImageCodeInfo imageInfo = CodeInfoTable.getCurrentLayerImageCodeCache();
58+
imageInfo.registerAsImmutable(config);
59+
}
60+
61+
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,16 @@ interface CodeInfoImpl extends CodeInfo {
169169
@RawField
170170
void setCodeAndDataMemorySize(UnsignedWord codeAndDataMemorySize);
171171

172+
@RawField
173+
void setRelativeIPOffset(UnsignedWord offset);
174+
175+
/**
176+
* An offset that enables us to store code in different memory regions while keeping the code
177+
* info encoding as if it were part of a single continuous memory region.
178+
*/
179+
@RawField
180+
UnsignedWord getRelativeIPOffset();
181+
172182
@RawField
173183
NonmovableArray<Byte> getCodeInfoIndex();
174184

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

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,16 @@
2626

2727
import static com.oracle.svm.core.deopt.Deoptimizer.Options.LazyDeoptimization;
2828

29-
import java.util.Arrays;
30-
import java.util.List;
31-
3229
import org.graalvm.nativeimage.ImageSingletons;
3330
import org.graalvm.nativeimage.Platform;
3431
import org.graalvm.nativeimage.Platforms;
3532
import org.graalvm.nativeimage.c.function.CodePointer;
36-
import org.graalvm.nativeimage.hosted.Feature;
3733
import org.graalvm.word.Pointer;
3834

3935
import com.oracle.svm.core.Uninterruptible;
4036
import com.oracle.svm.core.c.NonmovableArray;
4137
import com.oracle.svm.core.c.NonmovableArrays;
4238
import com.oracle.svm.core.deopt.SubstrateInstalledCode;
43-
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
44-
import com.oracle.svm.core.feature.InternalFeature;
4539
import com.oracle.svm.core.heap.CodeReferenceMapDecoder;
4640
import com.oracle.svm.core.heap.ObjectReferenceVisitor;
4741
import com.oracle.svm.core.heap.ReferenceMapIndex;
@@ -56,7 +50,6 @@
5650
import com.oracle.svm.core.thread.JavaVMOperation;
5751
import com.oracle.svm.core.thread.VMOperation;
5852
import com.oracle.svm.core.util.Counter;
59-
import com.oracle.svm.core.util.CounterFeature;
6053
import com.oracle.svm.core.util.VMError;
6154

6255
import jdk.graal.compiler.api.replacements.Fold;
@@ -112,7 +105,7 @@ public static CodeInfo getFirstImageCodeInfo() {
112105

113106
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
114107
public static CodeInfo getFirstImageCodeInfo(int layerNumber) {
115-
return MultiLayeredImageSingleton.getForLayer(ImageCodeInfoStorage.class, layerNumber).getData();
108+
return MultiLayeredImageSingleton.getForLayer(ImageCodeInfoStorage.class, layerNumber).getCodeInfo();
116109
}
117110

118111
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
@@ -318,37 +311,3 @@ final class CodeInfoTableCounters {
318311
final Counter lookupInstalledCodeCount = new Counter(counters, "lookupInstalledCode", "");
319312
final Counter invalidateInstalledCodeCount = new Counter(counters, "invalidateInstalledCode", "");
320313
}
321-
322-
@AutomaticallyRegisteredFeature
323-
class CodeInfoFeature implements InternalFeature {
324-
@Override
325-
public List<Class<? extends Feature>> getRequiredFeatures() {
326-
return Arrays.asList(CounterFeature.class);
327-
}
328-
329-
@Override
330-
public void duringSetup(DuringSetupAccess access) {
331-
ImageSingletons.add(CodeInfoTableCounters.class, new CodeInfoTableCounters());
332-
ImageSingletons.add(CodeInfoDecoderCounters.class, new CodeInfoDecoderCounters());
333-
ImageSingletons.add(CodeInfoEncoder.Counters.class, new CodeInfoEncoder.Counters());
334-
ImageSingletons.add(ImageCodeInfo.class, new ImageCodeInfo());
335-
ImageSingletons.add(RuntimeCodeInfoHistory.class, new RuntimeCodeInfoHistory());
336-
ImageSingletons.add(RuntimeCodeCache.class, new RuntimeCodeCache());
337-
ImageSingletons.add(RuntimeCodeInfoMemory.class, new RuntimeCodeInfoMemory());
338-
}
339-
340-
@Override
341-
public void afterCompilation(AfterCompilationAccess config) {
342-
ImageCodeInfo imageInfo = CodeInfoTable.getCurrentLayerImageCodeCache();
343-
config.registerAsImmutable(imageInfo);
344-
config.registerAsImmutable(imageInfo.codeInfoIndex);
345-
config.registerAsImmutable(imageInfo.codeInfoEncodings);
346-
config.registerAsImmutable(imageInfo.referenceMapEncoding);
347-
config.registerAsImmutable(imageInfo.frameInfoEncodings);
348-
config.registerAsImmutable(imageInfo.objectConstants);
349-
config.registerAsImmutable(imageInfo.classes);
350-
config.registerAsImmutable(imageInfo.memberNames);
351-
config.registerAsImmutable(imageInfo.otherStrings);
352-
config.registerAsImmutable(imageInfo.methodTable);
353-
}
354-
}

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

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.graalvm.nativeimage.Platform;
3131
import org.graalvm.nativeimage.Platforms;
3232
import org.graalvm.nativeimage.c.function.CodePointer;
33+
import org.graalvm.nativeimage.hosted.Feature;
3334
import org.graalvm.word.ComparableWord;
3435
import org.graalvm.word.UnsignedWord;
3536

@@ -60,6 +61,7 @@ public class ImageCodeInfo implements MultiLayeredImageSingleton, UnsavedSinglet
6061
@UnknownPrimitiveField(availability = AfterCompilation.class) private UnsignedWord dataOffset;
6162
@UnknownPrimitiveField(availability = AfterCompilation.class) private UnsignedWord dataSize;
6263
@UnknownPrimitiveField(availability = AfterCompilation.class) private UnsignedWord codeAndDataMemorySize;
64+
@UnknownPrimitiveField(availability = AfterCompilation.class) private UnsignedWord relativeIPOffset;
6365
@UnknownPrimitiveField(availability = AfterCompilation.class) private int methodTableFirstId;
6466

6567
private final Object[] objectFields;
@@ -74,7 +76,7 @@ public class ImageCodeInfo implements MultiLayeredImageSingleton, UnsavedSinglet
7476
@UnknownObjectField(availability = AfterCompilation.class) byte[] methodTable;
7577

7678
@Platforms(Platform.HOSTED_ONLY.class)
77-
ImageCodeInfo() {
79+
protected ImageCodeInfo() {
7880
NonmovableObjectArray<Object> objfields = NonmovableArrays.createObjectArray(Object[].class, CodeInfoImpl.OBJFIELDS_COUNT, NmtCategory.Code);
7981
NonmovableArrays.setObject(objfields, CodeInfoImpl.NAME_OBJFIELD, CODE_INFO_NAME);
8082
// The image code info is never invalidated, so we consider it as always tethered.
@@ -90,24 +92,24 @@ static CodeInfo prepareCodeInfo() {
9092
int size = imageCodeInfos.length;
9193
for (int i = 0; i < size; i++) {
9294
ImageCodeInfo imageCodeInfo = imageCodeInfos[i];
93-
CodeInfoImpl codeInfoImpl = runtimeCodeInfos[i].getData();
94-
CodeInfoImpl nextCodeInfoImpl = i + 1 < size ? runtimeCodeInfos[i + 1].getData() : Word.nullPointer();
95+
CodeInfoImpl codeInfoImpl = runtimeCodeInfos[i].getCodeInfo();
96+
CodeInfoImpl nextCodeInfoImpl = i + 1 < size ? runtimeCodeInfos[i + 1].getCodeInfo() : Word.nullPointer();
9597

9698
ImageCodeInfo.prepareCodeInfo0(imageCodeInfo, codeInfoImpl, nextCodeInfoImpl);
9799
}
98-
return runtimeCodeInfos[0].getData();
100+
return runtimeCodeInfos[0].getCodeInfo();
99101
}
100102

101103
@Uninterruptible(reason = "Executes during isolate creation.")
102-
private static void prepareCodeInfo0(ImageCodeInfo imageCodeInfo, CodeInfoImpl infoImpl, CodeInfo next) {
104+
protected static void prepareCodeInfo0(ImageCodeInfo imageCodeInfo, CodeInfoImpl infoImpl, CodeInfo next) {
103105
assert infoImpl.getCodeStart().isNull() : "already initialized";
104-
105106
infoImpl.setObjectFields(NonmovableArrays.fromImageHeap(imageCodeInfo.objectFields));
106107
infoImpl.setCodeStart(imageCodeInfo.codeStart);
107108
infoImpl.setCodeSize(imageCodeInfo.codeSize);
108109
infoImpl.setDataOffset(imageCodeInfo.dataOffset);
109110
infoImpl.setDataSize(imageCodeInfo.dataSize);
110111
infoImpl.setCodeAndDataMemorySize(imageCodeInfo.codeAndDataMemorySize);
112+
infoImpl.setRelativeIPOffset(imageCodeInfo.relativeIPOffset);
111113
infoImpl.setCodeInfoIndex(NonmovableArrays.fromImageHeap(imageCodeInfo.codeInfoIndex));
112114
infoImpl.setCodeInfoEncodings(NonmovableArrays.fromImageHeap(imageCodeInfo.codeInfoEncodings));
113115
infoImpl.setStackReferenceMapEncoding(NonmovableArrays.fromImageHeap(imageCodeInfo.referenceMapEncoding));
@@ -122,6 +124,20 @@ private static void prepareCodeInfo0(ImageCodeInfo imageCodeInfo, CodeInfoImpl i
122124
infoImpl.setNextImageCodeInfo(next);
123125
}
124126

127+
@Platforms(Platform.HOSTED_ONLY.class)
128+
public void registerAsImmutable(Feature.AfterCompilationAccess config) {
129+
config.registerAsImmutable(this);
130+
config.registerAsImmutable(codeInfoIndex);
131+
config.registerAsImmutable(codeInfoEncodings);
132+
config.registerAsImmutable(referenceMapEncoding);
133+
config.registerAsImmutable(frameInfoEncodings);
134+
config.registerAsImmutable(objectConstants);
135+
config.registerAsImmutable(classes);
136+
config.registerAsImmutable(memberNames);
137+
config.registerAsImmutable(otherStrings);
138+
config.registerAsImmutable(methodTable);
139+
}
140+
125141
/**
126142
* Use {@link CodeInfoTable#getImageCodeInfo} and {@link CodeInfoAccess#getCodeStart} instead.
127143
* This method is intended only for VM-internal usage.
@@ -216,6 +232,16 @@ public void setCodeAndDataMemorySize(UnsignedWord value) {
216232
codeAndDataMemorySize = value;
217233
}
218234

235+
@Override
236+
public void setRelativeIPOffset(UnsignedWord offset) {
237+
relativeIPOffset = offset;
238+
}
239+
240+
@Override
241+
public UnsignedWord getRelativeIPOffset() {
242+
return relativeIPOffset;
243+
}
244+
219245
@Override
220246
public NonmovableArray<Byte> getCodeInfoIndex() {
221247
return NonmovableArrays.fromImageHeap(codeInfoIndex);

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

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.graalvm.nativeimage.ImageSingletons;
3030
import org.graalvm.nativeimage.c.struct.SizeOf;
3131
import org.graalvm.word.Pointer;
32-
import org.graalvm.word.UnsignedWord;
3332

3433
import com.oracle.svm.core.Uninterruptible;
3534
import com.oracle.svm.core.c.CIsolateData;
@@ -59,28 +58,23 @@ public class ImageCodeInfoStorage implements MultiLayeredImageSingleton, Unsaved
5958
*/
6059
static final int ALIGNMENT = Long.BYTES;
6160

62-
ImageCodeInfoStorage(int dataSize) {
61+
protected ImageCodeInfoStorage() {
62+
long size = SizeOf.get(CodeInfoImpl.class);
63+
int arrayBaseOffset = ConfigurationValues.getObjectLayout().getArrayBaseOffset(JavaKind.Byte);
64+
int alignedOffset = getAlignedOffsetInArray();
65+
int addend = alignedOffset - arrayBaseOffset;
66+
int dataSize = NumUtil.safeToInt(size + addend);
6367
data = new byte[dataSize];
6468
}
6569

66-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
67-
static CodeInfoImpl get() {
68-
return ImageSingletons.lookup(ImageCodeInfoStorage.class).getData();
69-
}
70-
7170
@Fold
72-
protected static UnsignedWord offset() {
73-
return Word.unsigned(calculateOffset());
74-
}
75-
76-
static int calculateOffset() {
71+
static int getAlignedOffsetInArray() {
7772
return NumUtil.roundUp(ConfigurationValues.getObjectLayout().getArrayBaseOffset(JavaKind.Byte), ALIGNMENT);
7873
}
7974

8075
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
81-
CodeInfoImpl getData() {
82-
Pointer base = Word.objectToUntrackedPointer(data).add(offset());
83-
76+
public CodeInfoImpl getCodeInfo() {
77+
Pointer base = Word.objectToUntrackedPointer(data).add(Word.unsigned(getAlignedOffsetInArray()));
8478
return (CodeInfoImpl) base;
8579
}
8680

@@ -92,14 +86,8 @@ public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
9286

9387
@AutomaticallyRegisteredFeature
9488
class ImageCodeInfoStorageFeature implements InternalFeature, UnsavedSingleton, FeatureSingleton {
95-
9689
@Override
9790
public void duringSetup(DuringSetupAccess access) {
98-
long size = SizeOf.get(CodeInfoImpl.class);
99-
int arrayBaseOffset = ConfigurationValues.getObjectLayout().getArrayBaseOffset(JavaKind.Byte);
100-
int actualOffset = ImageCodeInfoStorage.calculateOffset();
101-
int addend = actualOffset - arrayBaseOffset;
102-
103-
ImageSingletons.add(ImageCodeInfoStorage.class, new ImageCodeInfoStorage(NumUtil.safeToInt(size + addend)));
91+
ImageSingletons.add(ImageCodeInfoStorage.class, new ImageCodeInfoStorage());
10492
}
10593
}

0 commit comments

Comments
 (0)