Skip to content

Commit e412034

Browse files
[GR-33223] Add protected memory between heap base and image heap.
PullRequest: graal/9590
2 parents 40e93dd + f5d7bd7 commit e412034

File tree

17 files changed

+284
-133
lines changed

17 files changed

+284
-133
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,22 @@
3333
import com.oracle.svm.core.genscavenge.ChunkedImageHeapAllocator.AlignedChunk;
3434
import com.oracle.svm.core.genscavenge.ChunkedImageHeapAllocator.Chunk;
3535
import com.oracle.svm.core.genscavenge.ChunkedImageHeapAllocator.UnalignedChunk;
36+
import com.oracle.svm.core.heap.Heap;
3637
import com.oracle.svm.core.image.ImageHeap;
3738
import com.oracle.svm.core.image.ImageHeapLayoutInfo;
3839

3940
public class ChunkedImageHeapLayouter extends AbstractImageHeapLayouter<ChunkedImageHeapPartition> {
4041
private final ImageHeapInfo heapInfo;
4142
private final long startOffset;
42-
private final boolean compressedNullPadding;
43+
private final int nullRegionSize;
4344
private final long hugeObjectThreshold;
4445
private ChunkedImageHeapAllocator allocator;
4546

46-
public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset, boolean compressedNullPadding) {
47+
public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset, int nullRegionSize) {
48+
assert startOffset == 0 || startOffset >= Heap.getHeap().getImageHeapOffsetInAddressSpace() : "must be relative to the heap base";
4749
this.heapInfo = heapInfo;
4850
this.startOffset = startOffset;
49-
this.compressedNullPadding = compressedNullPadding;
51+
this.nullRegionSize = nullRegionSize;
5052
this.hugeObjectThreshold = HeapPolicy.getLargeArrayThreshold().rawValue();
5153
}
5254

@@ -67,8 +69,8 @@ protected long getHugeObjectThreshold() {
6769

6870
@Override
6971
protected ImageHeapLayoutInfo doLayout(ImageHeap imageHeap) {
70-
assert !compressedNullPadding || AlignedHeapChunk.getObjectsStartOffset().aboveThan(0) : "Expecting header to pad start so object offsets are strictly greater than 0";
71-
allocator = new ChunkedImageHeapAllocator(imageHeap, startOffset);
72+
long position = startOffset + nullRegionSize;
73+
allocator = new ChunkedImageHeapAllocator(imageHeap, position);
7274
for (ChunkedImageHeapPartition partition : getPartitions()) {
7375
partition.layout(allocator);
7476
}
@@ -78,28 +80,43 @@ protected ImageHeapLayoutInfo doLayout(ImageHeap imageHeap) {
7880
private ImageHeapLayoutInfo populateInfoObjects(int dynamicHubCount) {
7981
// Determine writable start boundary from chunks: a chunk that contains writable objects
8082
// must also have a writable card table
81-
long writableBegin = getWritablePrimitive().getStartOffset();
83+
long offsetOfFirstWritableAlignedChunk = getWritablePrimitive().getStartOffset();
8284
for (AlignedChunk chunk : allocator.getAlignedChunks()) {
83-
if (chunk.isWritable() && chunk.getBegin() < writableBegin) {
84-
assert writableBegin <= chunk.getEnd();
85-
writableBegin = chunk.getBegin();
85+
if (chunk.isWritable() && chunk.getBegin() < offsetOfFirstWritableAlignedChunk) {
86+
assert offsetOfFirstWritableAlignedChunk <= chunk.getEnd();
87+
offsetOfFirstWritableAlignedChunk = chunk.getBegin();
8688
break; // (chunks are in ascending memory order)
8789
}
8890
}
89-
long firstWritableUnalignedChunk = -1;
91+
long offsetOfFirstWritableUnalignedChunk = -1;
9092
for (UnalignedChunk chunk : allocator.getUnalignedChunks()) {
9193
if (chunk.isWritable()) {
92-
firstWritableUnalignedChunk = chunk.getBegin();
94+
offsetOfFirstWritableUnalignedChunk = chunk.getBegin();
9395
}
9496
break;
9597
}
9698

99+
initializeHeapInfo(dynamicHubCount, offsetOfFirstWritableAlignedChunk, offsetOfFirstWritableUnalignedChunk);
100+
return createLayoutInfo(startOffset, offsetOfFirstWritableAlignedChunk);
101+
}
102+
103+
private void initializeHeapInfo(int dynamicHubCount, long offsetOfFirstWritableAlignedChunk, long offsetOfFirstWritableUnalignedChunk) {
104+
long writableAligned = offsetOfFirstWritableAlignedChunk;
105+
long writableUnaligned = offsetOfFirstWritableUnalignedChunk;
106+
107+
if (startOffset == 0) {
108+
// Adjust all offsets by the offset of the image heap in the address space.
109+
int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace();
110+
writableAligned += imageHeapOffsetInAddressSpace;
111+
if (writableUnaligned >= 0) {
112+
writableUnaligned += imageHeapOffsetInAddressSpace;
113+
}
114+
}
115+
97116
heapInfo.initialize(getReadOnlyPrimitive().firstObject, getReadOnlyPrimitive().lastObject, getReadOnlyReference().firstObject, getReadOnlyReference().lastObject,
98117
getReadOnlyRelocatable().firstObject, getReadOnlyRelocatable().lastObject, getWritablePrimitive().firstObject, getWritablePrimitive().lastObject,
99118
getWritableReference().firstObject, getWritableReference().lastObject, getWritableHuge().firstObject, getWritableHuge().lastObject,
100-
getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, writableBegin, firstWritableUnalignedChunk, dynamicHubCount);
101-
102-
return createLayoutInfo(startOffset, writableBegin);
119+
getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, writableAligned, writableUnaligned, dynamicHubCount);
103120
}
104121

105122
@Override

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.List;
3030

3131
import org.graalvm.compiler.api.replacements.Fold;
32+
import org.graalvm.compiler.core.common.NumUtil;
3233
import org.graalvm.compiler.core.common.SuppressFBWarnings;
3334
import org.graalvm.compiler.nodes.gc.BarrierSet;
3435
import org.graalvm.compiler.word.Word;
@@ -87,6 +88,8 @@ public final class HeapImpl extends Heap {
8788
private static final VMMutex REF_MUTEX = new VMMutex("referencePendingList");
8889
private static final VMCondition REF_CONDITION = new VMCondition(REF_MUTEX);
8990

91+
private final int pageSize;
92+
9093
// Singleton instances, created during image generation.
9194
private final YoungGeneration youngGeneration = new YoungGeneration("YoungGeneration");
9295
private final OldGeneration oldGeneration = new OldGeneration("OldGeneration");
@@ -111,7 +114,8 @@ public final class HeapImpl extends Heap {
111114
private List<Class<?>> classList;
112115

113116
@Platforms(Platform.HOSTED_ONLY.class)
114-
public HeapImpl(FeatureAccess access) {
117+
public HeapImpl(FeatureAccess access, int pageSize) {
118+
this.pageSize = pageSize;
115119
this.gcImpl = new GCImpl(access);
116120
this.runtimeCodeInfoGcSupport = new RuntimeCodeInfoGCSupportImpl();
117121
this.heapPolicy = new HeapPolicy();
@@ -421,15 +425,34 @@ public static boolean usesImageHeapCardMarking() {
421425
@Fold
422426
@Override
423427
public int getPreferredAddressSpaceAlignment() {
424-
if (usesImageHeapChunks()) {
425-
return UnsignedUtils.safeToInt(HeapPolicy.getAlignedHeapChunkAlignment());
426-
}
427-
return ConfigurationValues.getObjectLayout().getAlignment();
428+
return UnsignedUtils.safeToInt(HeapPolicy.getAlignedHeapChunkAlignment());
428429
}
429430

430431
@Fold
431432
@Override
432433
public int getImageHeapOffsetInAddressSpace() {
434+
if (SubstrateOptions.SpawnIsolates.getValue() && SubstrateOptions.UseNullRegion.getValue() && CommittedMemoryProvider.get().guaranteesHeapPreferredAddressSpaceAlignment()) {
435+
/*
436+
* The image heap will be mapped in a way that there is a memory protected gap between
437+
* the heap base and the start of the image heap. The gap won't need any memory in the
438+
* native image file.
439+
*/
440+
return NumUtil.safeToInt(HeapPolicyOptions.AlignedHeapChunkSize.getValue());
441+
}
442+
return 0;
443+
}
444+
445+
@Fold
446+
@Override
447+
public int getImageHeapNullRegionSize() {
448+
if (SubstrateOptions.SpawnIsolates.getValue() && SubstrateOptions.UseNullRegion.getValue() && !CommittedMemoryProvider.get().guaranteesHeapPreferredAddressSpaceAlignment()) {
449+
/*
450+
* Prepend a single null page to the image heap so that there is a memory protected gap
451+
* between the heap base and the start of the image heap. The null page is placed
452+
* directly into the native image file, so it makes the file slightly larger.
453+
*/
454+
return pageSize;
455+
}
433456
return 0;
434457
}
435458

@@ -605,9 +628,15 @@ public Reference<?> getAndClearReferencePendingList() {
605628

606629
@Override
607630
public boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaHeapAccess) {
608-
if (SubstrateOptions.SpawnIsolates.getValue() && value.equal(KnownIntrinsics.heapBase())) {
609-
log.string("is the heap base");
610-
return true;
631+
if (SubstrateOptions.SpawnIsolates.getValue()) {
632+
Pointer heapBase = KnownIntrinsics.heapBase();
633+
if (value.equal(heapBase)) {
634+
log.string("is the heap base");
635+
return true;
636+
} else if (value.aboveThan(heapBase) && value.belowThan(getImageHeapStart())) {
637+
log.string("points into the protected memory between the heap base and the image heap");
638+
return true;
639+
}
611640
}
612641

613642
Pointer ptr = (Pointer) value;
@@ -623,6 +652,16 @@ public boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaH
623652
return false;
624653
}
625654

655+
static Pointer getImageHeapStart() {
656+
int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace();
657+
if (imageHeapOffsetInAddressSpace > 0) {
658+
return KnownIntrinsics.heapBase().add(imageHeapOffsetInAddressSpace);
659+
} else {
660+
int nullRegionSize = Heap.getHeap().getImageHeapNullRegionSize();
661+
return KnownIntrinsics.heapBase().add(nullRegionSize);
662+
}
663+
}
664+
626665
private boolean printLocationInfo(Log log, Pointer ptr) {
627666
if (imageHeapInfo.isInReadOnlyPrimitivePartition(ptr)) {
628667
log.string("points into the image heap (read-only primitives)");

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public final class ImageHeapInfo {
7070
@UnknownObjectField(types = Object.class) public Object firstObject;
7171
@UnknownObjectField(types = Object.class) public Object lastObject;
7272

73+
// All offsets are relative to the heap base.
7374
@UnknownPrimitiveField public long offsetOfFirstWritableAlignedChunk;
7475
@UnknownPrimitiveField public long offsetOfFirstWritableUnalignedChunk;
7576

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,12 @@
2525
package com.oracle.svm.core.genscavenge;
2626

2727
import org.graalvm.compiler.word.Word;
28-
import org.graalvm.nativeimage.CurrentIsolate;
2928
import org.graalvm.nativeimage.Platform;
3029
import org.graalvm.nativeimage.Platforms;
3130
import org.graalvm.word.Pointer;
3231
import org.graalvm.word.UnsignedWord;
3332
import org.graalvm.word.WordFactory;
3433

35-
import com.oracle.svm.core.Isolates;
3634
import com.oracle.svm.core.MemoryWalker;
3735
import com.oracle.svm.core.annotate.AlwaysInline;
3836
import com.oracle.svm.core.heap.ObjectVisitor;
@@ -94,7 +92,7 @@ private static boolean walkPartitionInline(Object firstObject, Object lastObject
9492
if (HeapImpl.usesImageHeapChunks()) {
9593
Pointer base = WordFactory.zero();
9694
if (!CommittedMemoryProvider.get().guaranteesHeapPreferredAddressSpaceAlignment()) {
97-
base = (Pointer) Isolates.getHeapBase(CurrentIsolate.getIsolate());
95+
base = HeapImpl.getImageHeapStart();
9896
}
9997
Pointer offset = current.subtract(base);
10098
UnsignedWord chunkOffset = alignedChunks ? UnsignedUtils.roundDown(offset, HeapPolicy.getAlignedHeapChunkAlignment())

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapLayouter.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,22 @@
2525
package com.oracle.svm.core.genscavenge;
2626

2727
import com.oracle.svm.core.config.ConfigurationValues;
28+
import com.oracle.svm.core.heap.Heap;
2829
import com.oracle.svm.core.image.ImageHeap;
2930
import com.oracle.svm.core.image.ImageHeapLayoutInfo;
3031

3132
public class LinearImageHeapLayouter extends AbstractImageHeapLayouter<LinearImageHeapPartition> {
3233
private final ImageHeapInfo heapInfo;
3334
private final long startOffset;
34-
private final boolean compressedNullPadding;
35+
private final int nullRegionSize;
3536

36-
public LinearImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset, boolean compressedNullPadding) {
37+
public LinearImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset, int nullRegionSize) {
38+
assert startOffset >= 0;
39+
assert startOffset == 0 || startOffset >= Heap.getHeap().getImageHeapOffsetInAddressSpace() : "must be relative to the heap base";
40+
assert nullRegionSize >= 0;
3741
this.heapInfo = heapInfo;
3842
this.startOffset = startOffset;
39-
this.compressedNullPadding = compressedNullPadding;
43+
this.nullRegionSize = nullRegionSize;
4044
}
4145

4246
@Override
@@ -51,14 +55,8 @@ protected LinearImageHeapPartition createPartition(String name, boolean contains
5155

5256
@Override
5357
protected ImageHeapLayoutInfo doLayout(ImageHeap imageHeap) {
54-
long beginOffset = startOffset;
55-
if (compressedNullPadding) {
56-
/*
57-
* Zero designates null, so adding some explicit padding at the beginning of the native
58-
* image heap is the easiest approach to make object offsets strictly greater than 0.
59-
*/
60-
beginOffset += ConfigurationValues.getObjectLayout().getAlignment();
61-
}
58+
long beginOffset = startOffset + spaceReservedForNull();
59+
assert beginOffset >= ConfigurationValues.getObjectLayout().getAlignment() : "Zero designates null";
6260
LinearImageHeapAllocator allocator = new LinearImageHeapAllocator(beginOffset);
6361
for (LinearImageHeapPartition partition : getPartitions()) {
6462
partition.allocateObjects(allocator);
@@ -67,6 +65,13 @@ protected ImageHeapLayoutInfo doLayout(ImageHeap imageHeap) {
6765
return createLayoutInfo(startOffset, getWritablePrimitive().getStartOffset());
6866
}
6967

68+
private long spaceReservedForNull() {
69+
if (startOffset == 0 && nullRegionSize == 0) {
70+
return ConfigurationValues.getObjectLayout().getAlignment();
71+
}
72+
return nullRegionSize;
73+
}
74+
7075
/**
7176
* Store which objects are at the boundaries of the image heap partitions. Here, we also merge
7277
* the read-only reference partition with the read-only relocatable partition.

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/HeapFeature.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public List<Class<? extends Feature>> getRequiredFeatures() {
7474

7575
@Override
7676
public void afterRegistration(AfterRegistrationAccess access) {
77-
HeapImpl heap = new HeapImpl(access);
77+
HeapImpl heap = new HeapImpl(access, SubstrateOptions.getPageSize());
7878
ImageSingletons.add(Heap.class, heap);
7979
ImageSingletons.add(SubstrateAllocationSnippets.class, new GenScavengeAllocationSnippets());
8080
ImageSingletons.add(RememberedSet.class, createRememberedSet());
@@ -106,10 +106,11 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
106106
@Override
107107
public void afterAnalysis(AfterAnalysisAccess access) {
108108
ImageHeapLayouter heapLayouter;
109+
int imageHeapNullRegionSize = Heap.getHeap().getImageHeapNullRegionSize();
109110
if (HeapImpl.usesImageHeapChunks()) { // needs CommittedMemoryProvider: registered late
110-
heapLayouter = new ChunkedImageHeapLayouter(HeapImpl.getImageHeapInfo(), 0, true);
111+
heapLayouter = new ChunkedImageHeapLayouter(HeapImpl.getImageHeapInfo(), 0, imageHeapNullRegionSize);
111112
} else {
112-
heapLayouter = new LinearImageHeapLayouter(HeapImpl.getImageHeapInfo(), 0, true);
113+
heapLayouter = new LinearImageHeapLayouter(HeapImpl.getImageHeapInfo(), 0, imageHeapNullRegionSize);
113114
}
114115
ImageSingletons.add(ImageHeapLayouter.class, heapLayouter);
115116
}

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ protected void printSignalInfo(Log log, PointerBase signalInfo) {
8585
if (sigInfo.si_errno() != 0) {
8686
log.string(", si_errno: ").signed(sigInfo.si_errno());
8787
}
88-
log.string(", si_addr: ").signed(sigInfo.si_addr());
88+
log.string(", si_addr: ").zhex(sigInfo.si_addr());
8989
log.newline();
9090
}
9191
}

0 commit comments

Comments
 (0)