From ea765ed8e8f8442badbad99e39ba98254c7ab526 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 16 Sep 2025 06:35:20 +0200 Subject: [PATCH 1/2] Cleanup image heap partition logic and fix heap walking issue for layered native images. --- .../genscavenge/ChunkedImageHeapLayouter.java | 126 ++++++++------- .../ChunkedImageHeapPartition.java | 49 +++--- .../oracle/svm/core/genscavenge/GCImpl.java | 4 +- .../oracle/svm/core/genscavenge/HeapImpl.java | 18 +-- .../svm/core/genscavenge/ImageHeapInfo.java | 143 ++++++++++-------- .../svm/core/genscavenge/ImageHeapWalker.java | 107 +++++-------- .../core/genscavenge/ObjectHeaderImpl.java | 2 +- .../src/com/oracle/svm/core/MemoryWalker.java | 4 +- ...Target_java_lang_Integer_IntegerCache.java | 37 +++++ .../SubstrateConstantReflectionProvider.java | 11 +- .../svm/hosted/webimage/wasm/gc/WasmHeap.java | 2 +- 11 files changed, 268 insertions(+), 235 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Integer_IntegerCache.java diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java index cb0bf00ad7ad..306bcc06d13b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java @@ -50,40 +50,36 @@ public class ChunkedImageHeapLayouter implements ImageHeapLayouter { /** A partition holding read-only objects. */ - private static final int READ_ONLY_REGULAR = 0; + private static final int ALIGNED_READ_ONLY_REGULAR = 0; /** - * A pseudo-partition used during image building to consolidate objects that contain relocatable - * references. + * A partition holding all read-only objects that contain relocatable references. *

* Collecting the relocations together means the dynamic linker has to operate on less of the * image heap during image startup, and it means that less of the image heap has to be * copied-on-write if the image heap is relocated in a new process. *

- * A relocated reference is read-only once relocated, e.g., at runtime. + * A relocated reference is read-only once relocated, i.e., at runtime. */ - private static final int READ_ONLY_RELOCATABLE = READ_ONLY_REGULAR + 1; + private static final int ALIGNED_READ_ONLY_RELOCATABLE = ALIGNED_READ_ONLY_REGULAR + 1; /** * A partition holding objects which must be patched at execution startup by our initialization * code. This is currently only used within layered images. */ - private static final int WRITABLE_PATCHED = READ_ONLY_RELOCATABLE + 1; + private static final int ALIGNED_WRITABLE_PATCHED = ALIGNED_READ_ONLY_RELOCATABLE + 1; /** A partition holding writable objects. */ - private static final int WRITABLE_REGULAR = WRITABLE_PATCHED + 1; - /** A partition holding very large writable objects with or without references. */ - private static final int WRITABLE_HUGE = WRITABLE_REGULAR + 1; - /** - * A partition holding very large read-only objects with or without references, but never with - * relocatable references. - */ - private static final int READ_ONLY_HUGE = WRITABLE_HUGE + 1; - private static final int PARTITION_COUNT = READ_ONLY_HUGE + 1; + private static final int ALIGNED_WRITABLE_REGULAR = ALIGNED_WRITABLE_PATCHED + 1; + /** A partition holding very large writable objects. */ + private static final int UNALIGNED_WRITABLE = ALIGNED_WRITABLE_REGULAR + 1; + /** A partition holding very large read-only objects, but never with relocatable references. */ + private static final int UNALIGNED_READ_ONLY = UNALIGNED_WRITABLE + 1; + private static final int PARTITION_COUNT = UNALIGNED_READ_ONLY + 1; private static final String ALIGNED_HEAP_CHUNK_OPTION = SubstrateOptionsParser.commandArgument(SerialAndEpsilonGCOptions.AlignedHeapChunkSize, "<2^n>"); private final ChunkedImageHeapPartition[] partitions; private final ImageHeapInfo heapInfo; private final long startOffset; - private final long hugeObjectThreshold; + private final long unalignedObjectSizeThreshold; private ChunkedImageHeapAllocator allocator; /** @param startOffset Offset relative to the heap base. */ @@ -92,19 +88,18 @@ public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset) { assert startOffset % Heap.getHeap().getImageHeapAlignment() == 0 : "the start of each image heap must be aligned"; this.partitions = new ChunkedImageHeapPartition[PARTITION_COUNT]; - this.partitions[READ_ONLY_REGULAR] = new ChunkedImageHeapPartition("readOnly", false, false); - this.partitions[READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("readOnlyRelocatable", false, false); - this.partitions[WRITABLE_PATCHED] = new ChunkedImageHeapPartition("writablePatched", true, false); - this.partitions[WRITABLE_REGULAR] = new ChunkedImageHeapPartition("writable", true, false); - this.partitions[WRITABLE_HUGE] = new ChunkedImageHeapPartition("writableHuge", true, true); - this.partitions[READ_ONLY_HUGE] = new ChunkedImageHeapPartition("readOnlyHuge", false, true); + this.partitions[ALIGNED_READ_ONLY_REGULAR] = new ChunkedImageHeapPartition("alignedReadOnlyRegular", false, false); + this.partitions[ALIGNED_READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("alignedReadOnlyRelocatable", false, false); + this.partitions[ALIGNED_WRITABLE_PATCHED] = new ChunkedImageHeapPartition("alignedWritablePatched", true, false); + this.partitions[ALIGNED_WRITABLE_REGULAR] = new ChunkedImageHeapPartition("alignedWritableRegular", true, false); + this.partitions[UNALIGNED_WRITABLE] = new ChunkedImageHeapPartition("unalignedWritable", true, true); + this.partitions[UNALIGNED_READ_ONLY] = new ChunkedImageHeapPartition("unalignedReadOnly", false, true); this.heapInfo = heapInfo; this.startOffset = startOffset; UnsignedWord alignedHeaderSize = RememberedSet.get().getHeaderSizeOfAlignedChunk(); - UnsignedWord hugeThreshold = HeapParameters.getAlignedHeapChunkSize().subtract(alignedHeaderSize); - this.hugeObjectThreshold = hugeThreshold.rawValue(); + this.unalignedObjectSizeThreshold = HeapParameters.getAlignedHeapChunkSize().subtract(alignedHeaderSize).rawValue(); } @Override @@ -124,35 +119,35 @@ private ChunkedImageHeapPartition choosePartition(ImageHeapObject info, boolean throw VMError.shouldNotReachHere("Object cannot contain both relocatables and patched constants: " + info.getObject()); } if (patched) { - return getWritablePatched(); + return getAlignedWritablePatched(); } else if (immutable) { - if (info.getSize() >= hugeObjectThreshold) { + if (info.getSize() >= unalignedObjectSizeThreshold) { if (hasRelocatables) { if (info.getObjectClass() == DynamicHub.class) { - throw reportHugeObjectError(info, "Class metadata (dynamic hubs) cannot be huge objects: the dynamic hub %s", info.getObject().toString()); + throw reportObjectTooLargeForAlignedChunkError(info, "Class metadata (dynamic hubs) cannot be in unaligned heap chunks: the dynamic hub %s", info.getObject().toString()); } - throw reportHugeObjectError(info, "Objects in image heap with relocatable pointers cannot be huge objects. Detected an object of type %s", + throw reportObjectTooLargeForAlignedChunkError(info, "Objects in image heap with relocatable pointers cannot be in unaligned heap chunks. Detected an object of type %s", info.getObject().getClass().getTypeName()); } - return getReadOnlyHuge(); + return getUnalignedReadOnly(); } if (hasRelocatables) { - return getReadOnlyRelocatable(); + return getAlignedReadOnlyRelocatable(); } else { - return getReadOnlyRegular(); + return getAlignedReadOnlyRegular(); } } else { assert info.getObjectClass() != DynamicHub.class : "Class metadata (dynamic hubs) cannot be writable"; - if (info.getSize() >= hugeObjectThreshold) { - return getWritableHuge(); + if (info.getSize() >= unalignedObjectSizeThreshold) { + return getUnalignedWritable(); } - return getWritableRegular(); + return getAlignedWritableRegular(); } } - private Error reportHugeObjectError(ImageHeapObject info, String objectTypeMsg, String objectText) { + private Error reportObjectTooLargeForAlignedChunkError(ImageHeapObject info, String objectTypeMsg, String objectText) { String msg = String.format(objectTypeMsg + " with size %d B and the limit is %d B. Use '%s' to increase GC chunk size to be larger than the object.", - objectText, info.getSize(), hugeObjectThreshold, ALIGNED_HEAP_CHUNK_OPTION); + objectText, info.getSize(), unalignedObjectSizeThreshold, ALIGNED_HEAP_CHUNK_OPTION); if (ImageInfo.inImageBuildtimeCode()) { throw UserError.abort(msg); } else { @@ -214,20 +209,37 @@ private ImageHeapLayoutInfo populateInfoObjects(int dynamicHubCount, int pageSiz } control.poll(); - heapInfo.initialize(getReadOnlyRegular().firstObject, getReadOnlyRegular().lastObject, getReadOnlyRelocatable().firstObject, getReadOnlyRelocatable().lastObject, - getWritablePatched().firstObject, getWritablePatched().lastObject, - getWritableRegular().firstObject, getWritableRegular().lastObject, getWritableHuge().firstObject, getWritableHuge().lastObject, - getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, offsetOfFirstWritableAlignedChunk, offsetOfFirstWritableUnalignedChunk, offsetOfLastWritableUnalignedChunk, + Object firstAlignedReadOnlyObject = firstNonNullValue(getAlignedReadOnlyRegular().firstObject, getAlignedReadOnlyRelocatable().firstObject); + Object lastAlignedReadOnlyObject = firstNonNullValue(getAlignedReadOnlyRelocatable().lastObject, getAlignedReadOnlyRegular().lastObject); + Object firstAlignedWritableObject = firstNonNullValue(getAlignedWritablePatched().firstObject, getAlignedWritableRegular().firstObject); + Object lastAlignedWritableObject = firstNonNullValue(getAlignedWritableRegular().lastObject, getAlignedWritablePatched().lastObject); + + heapInfo.initialize(firstAlignedReadOnlyObject, lastAlignedReadOnlyObject, + getAlignedReadOnlyRelocatable().firstObject, getAlignedReadOnlyRelocatable().lastObject, + firstAlignedWritableObject, lastAlignedWritableObject, + getAlignedWritablePatched().firstObject, getAlignedWritablePatched().lastObject, + getUnalignedWritable().firstObject, getUnalignedWritable().lastObject, + getUnalignedReadOnly().firstObject, getUnalignedReadOnly().lastObject, + offsetOfFirstWritableAlignedChunk, offsetOfFirstWritableUnalignedChunk, offsetOfLastWritableUnalignedChunk, dynamicHubCount); control.poll(); - long writableEnd = getWritableHuge().getStartOffset() + getWritableHuge().getSize(); + long writableEnd = getUnalignedWritable().getStartOffset() + getUnalignedWritable().getSize(); long writableSize = writableEnd - offsetOfFirstWritableAlignedChunk; - /* Aligning the end to the page size can be required for mapping into memory. */ - long imageHeapEnd = NumUtil.roundUp(getReadOnlyHuge().getStartOffset() + getReadOnlyHuge().getSize(), pageSize); - return new ImageHeapLayoutInfo(startOffset, imageHeapEnd, offsetOfFirstWritableAlignedChunk, writableSize, getReadOnlyRelocatable().getStartOffset(), getReadOnlyRelocatable().getSize(), - getWritablePatched().getStartOffset(), getWritablePatched().getSize()); + long imageHeapEnd = NumUtil.roundUp(getUnalignedReadOnly().getStartOffset() + getUnalignedReadOnly().getSize(), pageSize); + return new ImageHeapLayoutInfo(startOffset, imageHeapEnd, offsetOfFirstWritableAlignedChunk, writableSize, + getAlignedReadOnlyRelocatable().getStartOffset(), getAlignedReadOnlyRelocatable().getSize(), + getAlignedWritablePatched().getStartOffset(), getAlignedWritablePatched().getSize()); + } + + private static Object firstNonNullValue(Object... objects) { + for (Object o : objects) { + if (o != null) { + return o; + } + } + return null; } @Override @@ -266,27 +278,27 @@ private static void writeHeader(ImageHeapChunkWriter writer, Chunk previous, Chu } } - private ChunkedImageHeapPartition getReadOnlyRegular() { - return partitions[READ_ONLY_REGULAR]; + private ChunkedImageHeapPartition getAlignedReadOnlyRegular() { + return partitions[ALIGNED_READ_ONLY_REGULAR]; } - private ChunkedImageHeapPartition getReadOnlyRelocatable() { - return partitions[READ_ONLY_RELOCATABLE]; + private ChunkedImageHeapPartition getAlignedReadOnlyRelocatable() { + return partitions[ALIGNED_READ_ONLY_RELOCATABLE]; } - private ChunkedImageHeapPartition getWritablePatched() { - return partitions[WRITABLE_PATCHED]; + private ChunkedImageHeapPartition getAlignedWritablePatched() { + return partitions[ALIGNED_WRITABLE_PATCHED]; } - private ChunkedImageHeapPartition getWritableRegular() { - return partitions[WRITABLE_REGULAR]; + private ChunkedImageHeapPartition getAlignedWritableRegular() { + return partitions[ALIGNED_WRITABLE_REGULAR]; } - private ChunkedImageHeapPartition getWritableHuge() { - return partitions[WRITABLE_HUGE]; + private ChunkedImageHeapPartition getUnalignedWritable() { + return partitions[UNALIGNED_WRITABLE]; } - private ChunkedImageHeapPartition getReadOnlyHuge() { - return partitions[READ_ONLY_HUGE]; + private ChunkedImageHeapPartition getUnalignedReadOnly() { + return partitions[UNALIGNED_READ_ONLY]; } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java index 19a40562a6fa..80315e57f0c3 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java @@ -45,7 +45,7 @@ public class ChunkedImageHeapPartition implements ImageHeapPartition { private final String name; private final boolean writable; - private final boolean hugeObjects; + private final boolean unalignedChunks; private final int minimumObjectSize; private final List objects = new ArrayList<>(); @@ -55,10 +55,10 @@ public class ChunkedImageHeapPartition implements ImageHeapPartition { long startOffset = -1; long endOffset = -1; - ChunkedImageHeapPartition(String name, boolean writable, boolean hugeObjects) { + ChunkedImageHeapPartition(String name, boolean writable, boolean unalignedChunks) { this.name = name; this.writable = writable; - this.hugeObjects = hugeObjects; + this.unalignedChunks = unalignedChunks; /* Cache to prevent frequent lookups of the object layout from ImageSingletons. */ this.minimumObjectSize = ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize(); @@ -70,25 +70,26 @@ void assign(ImageHeapObject obj) { } void layout(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl control) { - if (hugeObjects) { - layoutInUnalignedChunks(allocator, control); - } else { - layoutInAlignedChunks(allocator, control); - } - } - - private void layoutInUnalignedChunks(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl control) { if (objects.isEmpty()) { /* - * Without objects, don't force finishing the current chunk and therefore committing - * space for the rest of it. Another partition might be able to continue filling it, or, - * if no more objects follow, we don't need to dedicate space in the image at all. + * Without objects, there is no need to start a new chunk, or to force finishing the + * current chunk and therefore committing space for the rest of it. Another partition + * might be able to continue filling it, or, if no more objects follow, we don't need to + * dedicate space in the image at all. */ startOffset = allocator.getPosition(); endOffset = startOffset; return; } + if (unalignedChunks) { + layoutInUnalignedChunks(allocator, control); + } else { + layoutInAlignedChunks(allocator, control); + } + } + + private void layoutInUnalignedChunks(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl control) { allocator.finishAlignedChunk(); startOffset = allocator.getPosition(); @@ -108,7 +109,7 @@ private void layoutInAlignedChunks(ChunkedImageHeapAllocator allocator, ImageHea } private void allocateObjectsInAlignedChunks(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl control) { - NavigableMap> sortedObjects = createSortedObjectsMap(); + TreeMap> sortedObjects = createSortedObjectsMap(); while (!sortedObjects.isEmpty()) { ImageHeapObject info = dequeueBestFit(sortedObjects, allocator.getRemainingBytesInAlignedChunk()); if (info == null) { @@ -120,16 +121,16 @@ private void allocateObjectsInAlignedChunks(ChunkedImageHeapAllocator allocator, } } + /** + * Find a floor entry. We intentionally do not call {@link TreeMap#getFloorEntry} because that + * method allocates a new entry object. Instead, we fetch the floor key and get the value for + * the returned key. + */ private ImageHeapObject dequeueBestFit(NavigableMap> sortedObjects, long nbytes) { if (nbytes < minimumObjectSize) { return null; } - /** - * Find a floor entry. We are purposefully not calling {@link TreeMap#getFloorEntry(Object)} - * as that method allocates a new entry object. Instead, we fetch the floor key and get the - * value for the returned key. - */ Long floorKey = sortedObjects.floorKey(nbytes); if (floorKey == null) { return null; @@ -142,8 +143,8 @@ private ImageHeapObject dequeueBestFit(NavigableMap return obj; } - private NavigableMap> createSortedObjectsMap() { - NavigableMap> map = new TreeMap<>(); + private TreeMap> createSortedObjectsMap() { + TreeMap> map = new TreeMap<>(); for (ImageHeapObject obj : objects) { long objSize = obj.getSize(); assert objSize >= ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize() : Assertions.errorMessage(obj, objSize); @@ -174,8 +175,8 @@ public boolean isWritable() { return writable; } - boolean usesUnalignedObjects() { - return hugeObjects; + boolean usesUnalignedChunks() { + return unalignedChunks; } @Override diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java index b8254deb6f7b..6a7c15776dd8 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java @@ -962,8 +962,8 @@ private void blackenImageHeapRoots(ImageHeapInfo imageHeapInfo) { @AlwaysInline("GC Performance") @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) static void walkImageHeapRoots(ImageHeapInfo imageHeapInfo, ObjectVisitor visitor) { - ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstWritableRegularObject, imageHeapInfo.lastWritableRegularObject, visitor, true); - ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstWritableHugeObject, imageHeapInfo.lastWritableHugeObject, visitor, false); + ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstAlignedWritableObject, imageHeapInfo.lastAlignedWritableObject, visitor, true); + ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstUnalignedWritableObject, imageHeapInfo.lastUnalignedWritableObject, visitor, false); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 55c6f1d9da1a..cd2e07b12d1c 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -385,7 +385,7 @@ private static class ClassListBuilderVisitor implements MemoryWalker.ImageHeapRe @Override public void visitNativeImageHeapRegion(T region, MemoryWalker.NativeImageHeapRegionAccess access) { - if (!access.isWritable(region) && !access.consistsOfHugeObjects(region)) { + if (!access.isWritable(region) && !access.usesUnalignedChunks(region)) { access.visitObjects(region, this); } } @@ -765,22 +765,22 @@ public UnsignedWord getUsedMemoryAfterLastGC() { private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { for (ImageHeapInfo info : HeapImpl.getImageHeapInfos()) { - if (info.isInReadOnlyRegularPartition(ptr)) { + if (info.isInAlignedReadOnly(ptr)) { log.string("points into the image heap (read-only)"); return true; - } else if (info.isInReadOnlyRelocatablePartition(ptr)) { + } else if (info.isInAlignedReadOnlyRelocatable(ptr)) { log.string("points into the image heap (read-only relocatables)"); return true; - } else if (info.isInWritablePatchedPartition(ptr)) { + } else if (info.isInAlignedWritablePatched(ptr)) { log.string("points into the image heap (writable patched)"); return true; - } else if (info.isInWritableRegularPartition(ptr)) { + } else if (info.isInAlignedWritable(ptr)) { log.string("points into the image heap (writable)"); return true; - } else if (info.isInWritableHugePartition(ptr)) { + } else if (info.isInUnalignedWritable(ptr)) { log.string("points into the image heap (writable huge)"); return true; - } else if (info.isInReadOnlyHugePartition(ptr)) { + } else if (info.isInUnalignedReadOnly(ptr)) { log.string("points into the image heap (read-only huge)"); return true; } @@ -933,7 +933,7 @@ public int maxInvocationCount() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { - log.string("Image heap boundaries:").indent(true); + log.string("Image heap:").indent(true); for (ImageHeapInfo info : HeapImpl.getImageHeapInfos()) { info.print(log); } @@ -942,7 +942,7 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev if (AuxiliaryImageHeap.isPresent()) { ImageHeapInfo auxHeapInfo = AuxiliaryImageHeap.singleton().getImageHeapInfo(); if (auxHeapInfo != null) { - log.string("Auxiliary image heap boundaries:").indent(true); + log.string("Auxiliary image heap:").indent(true); auxHeapInfo.print(log); log.indent(false); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java index f33bc4b9f6c4..a1033d06ad3b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java @@ -52,28 +52,41 @@ public final class ImageHeapInfo { /** Indicates no chunk with {@link #initialize} chunk offset parameters. */ public static final long NO_CHUNK = -1; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstReadOnlyRegularObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastReadOnlyRegularObject; + /* All read-only objects that are located in aligned chunks. */ + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstAlignedReadOnlyObject; + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastAlignedReadOnlyObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstReadOnlyRelocatableObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastReadOnlyRelocatableObject; + /* + * The read-only objects that contain relocatable pointers. This is a subset of all the + * read-only objects that are located in aligned chunks. + */ + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstAlignedReadOnlyRelocatableObject; + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastAlignedReadOnlyRelocatableObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstWritablePatchedObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastWritablePatchedObject; + /* All writable objects that are located in aligned chunks. */ + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstAlignedWritableObject; + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastAlignedWritableObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstWritableRegularObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastWritableRegularObject; + /* + * The writable objects that need to be patched. This is a subset of all the writable objects + * that are located in aligned chunks. + */ + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstAlignedWritablePatchedObject; + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastAlignedWritablePatchedObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstWritableHugeObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastWritableHugeObject; + /* All writable objects that are located in unaligned chunks. */ + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstUnalignedWritableObject; + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastUnalignedWritableObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstReadOnlyHugeObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastReadOnlyHugeObject; + /* All read-only objects that are located in unaligned chunks. */ + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstUnalignedReadOnlyObject; + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastUnalignedReadOnlyObject; + /* The first/last object in the image heap. */ @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstObject; @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastObject; - // All offsets are relative to the heap base. + /* All offsets are relative to the heap base. */ @UnknownPrimitiveField(availability = AfterHeapLayout.class) public long offsetOfFirstWritableAlignedChunk; @UnknownPrimitiveField(availability = AfterHeapLayout.class) public long offsetOfFirstWritableUnalignedChunk; @UnknownPrimitiveField(availability = AfterHeapLayout.class) public long offsetOfLastWritableUnalignedChunk; @@ -84,26 +97,29 @@ public ImageHeapInfo() { } @SuppressWarnings("hiding") - public void initialize(Object firstReadOnlyRegularObject, Object lastReadOnlyRegularObject, Object firstReadOnlyRelocatableObject, Object lastReadOnlyRelocatableObject, - Object firstWritablePatchedObject, Object lastWritablePatchedObject, - Object firstWritableRegularObject, Object lastWritableRegularObject, Object firstWritableHugeObject, Object lastWritableHugeObject, - Object firstReadOnlyHugeObject, Object lastReadOnlyHugeObject, long offsetOfFirstWritableAlignedChunk, long offsetOfFirstWritableUnalignedChunk, - long offsetOfLastWritableUnalignedChunk, int dynamicHubCount) { + public void initialize(Object firstAlignedReadOnlyObject, Object lastAlignedReadOnlyObject, + Object firstAlignedReadOnlyRelocatableObject, Object lastAlignedReadOnlyRelocatableObject, + Object firstAlignedWritableObject, Object lastAlignedWritableObject, + Object firstAlignedWritablePatchedObject, Object lastAlignedWritablePatchedObject, + Object firstUnalignedWritableObject, Object lastUnalignedWritableObject, + Object firstUnalignedReadOnlyObject, Object lastUnalignedReadOnlyObject, + long offsetOfFirstWritableAlignedChunk, long offsetOfFirstWritableUnalignedChunk, long offsetOfLastWritableUnalignedChunk, + int dynamicHubCount) { assert offsetOfFirstWritableAlignedChunk == NO_CHUNK || offsetOfFirstWritableAlignedChunk >= 0; assert offsetOfFirstWritableUnalignedChunk == NO_CHUNK || offsetOfFirstWritableUnalignedChunk >= 0; - this.firstReadOnlyRegularObject = firstReadOnlyRegularObject; - this.lastReadOnlyRegularObject = lastReadOnlyRegularObject; - this.firstReadOnlyRelocatableObject = firstReadOnlyRelocatableObject; - this.lastReadOnlyRelocatableObject = lastReadOnlyRelocatableObject; - this.firstWritablePatchedObject = firstWritablePatchedObject; - this.lastWritablePatchedObject = lastWritablePatchedObject; - this.firstWritableRegularObject = firstWritableRegularObject; - this.lastWritableRegularObject = lastWritableRegularObject; - this.firstWritableHugeObject = firstWritableHugeObject; - this.lastWritableHugeObject = lastWritableHugeObject; - this.firstReadOnlyHugeObject = firstReadOnlyHugeObject; - this.lastReadOnlyHugeObject = lastReadOnlyHugeObject; + this.firstAlignedReadOnlyObject = firstAlignedReadOnlyObject; + this.lastAlignedReadOnlyObject = lastAlignedReadOnlyObject; + this.firstAlignedReadOnlyRelocatableObject = firstAlignedReadOnlyRelocatableObject; + this.lastAlignedReadOnlyRelocatableObject = lastAlignedReadOnlyRelocatableObject; + this.firstAlignedWritableObject = firstAlignedWritableObject; + this.lastAlignedWritableObject = lastAlignedWritableObject; + this.firstAlignedWritablePatchedObject = firstAlignedWritablePatchedObject; + this.lastAlignedWritablePatchedObject = lastAlignedWritablePatchedObject; + this.firstUnalignedWritableObject = firstUnalignedWritableObject; + this.lastUnalignedWritableObject = lastUnalignedWritableObject; + this.firstUnalignedReadOnlyObject = firstUnalignedReadOnlyObject; + this.lastUnalignedReadOnlyObject = lastUnalignedReadOnlyObject; this.offsetOfFirstWritableAlignedChunk = offsetOfFirstWritableAlignedChunk; this.offsetOfFirstWritableUnalignedChunk = offsetOfFirstWritableUnalignedChunk; this.offsetOfLastWritableUnalignedChunk = offsetOfLastWritableUnalignedChunk; @@ -114,18 +130,16 @@ public void initialize(Object firstReadOnlyRegularObject, Object lastReadOnlyReg * layout. Empty partitions will have (first == last == null). */ Object[] orderedObjects = { - firstReadOnlyRegularObject, - lastReadOnlyRegularObject, - firstReadOnlyRelocatableObject, - lastReadOnlyRelocatableObject, - firstWritablePatchedObject, - lastWritablePatchedObject, - firstWritableRegularObject, - lastWritableRegularObject, - firstWritableHugeObject, - lastWritableHugeObject, - firstReadOnlyHugeObject, - lastReadOnlyHugeObject + firstAlignedReadOnlyObject, + lastAlignedReadOnlyObject, + firstAlignedReadOnlyRelocatableObject, + lastAlignedReadOnlyRelocatableObject, + firstAlignedWritableObject, + lastAlignedWritableObject, + firstUnalignedWritableObject, + lastUnalignedWritableObject, + firstUnalignedReadOnlyObject, + lastUnalignedReadOnlyObject }; for (Object cur : orderedObjects) { if (cur != null) { @@ -146,39 +160,43 @@ public void initialize(Object firstReadOnlyRegularObject, Object lastReadOnlyReg */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInReadOnlyRegularPartition(Pointer ptr) { + public boolean isInAlignedReadOnly(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstReadOnlyRegularObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastReadOnlyRegularObject)); + return Word.objectToUntrackedPointer(firstAlignedReadOnlyObject).belowOrEqual(ptr) && ptr.belowThan(objEnd(lastAlignedReadOnlyObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInReadOnlyRelocatablePartition(Pointer ptr) { + public boolean isInAlignedReadOnlyRelocatable(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstReadOnlyRelocatableObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastReadOnlyRelocatableObject)); + boolean result = Word.objectToUntrackedPointer(firstAlignedReadOnlyRelocatableObject).belowOrEqual(ptr) && ptr.belowThan(objEnd(lastAlignedReadOnlyRelocatableObject)); + assert !result || isInAlignedReadOnly(ptr); + return result; } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInWritablePatchedPartition(Pointer ptr) { + public boolean isInAlignedWritable(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstWritablePatchedObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastWritablePatchedObject)); + return Word.objectToUntrackedPointer(firstAlignedWritableObject).belowOrEqual(ptr) && ptr.belowThan(objEnd(lastAlignedWritableObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInWritableRegularPartition(Pointer ptr) { + public boolean isInAlignedWritablePatched(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstWritableRegularObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastWritableRegularObject)); + boolean result = Word.objectToUntrackedPointer(firstAlignedWritablePatchedObject).belowOrEqual(ptr) && ptr.belowThan(objEnd(lastAlignedWritablePatchedObject)); + assert !result || isInAlignedWritable(ptr); + return result; } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInWritableHugePartition(Pointer ptr) { + public boolean isInUnalignedWritable(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstWritableHugeObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastWritableHugeObject)); + return Word.objectToUntrackedPointer(firstUnalignedWritableObject).belowOrEqual(ptr) && ptr.belowThan(objEnd(lastUnalignedWritableObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInReadOnlyHugePartition(Pointer ptr) { + public boolean isInUnalignedReadOnly(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstReadOnlyHugeObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastReadOnlyHugeObject)); + return Word.objectToUntrackedPointer(firstUnalignedReadOnlyObject).belowOrEqual(ptr) && ptr.belowThan(objEnd(lastUnalignedReadOnlyObject)); } /** @@ -207,7 +225,7 @@ public UnalignedHeader getLastWritableUnalignedChunk() { } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - private static Pointer getObjectEnd(Object obj) { + private static Pointer objEnd(Object obj) { if (obj == null) { return Word.nullPointer(); } @@ -225,11 +243,14 @@ private static > T asImageHeapChunk(long offsetInI } public void print(Log log) { - log.string("ReadOnly: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyRegularObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyRegularObject)).newline(); - log.string("ReadOnly Relocatables: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyRelocatableObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyRelocatableObject)).newline(); - log.string("Writeable Patched: ").zhex(Word.objectToUntrackedPointer(firstWritablePatchedObject)).string(" - ").zhex(getObjectEnd(lastWritablePatchedObject)).newline(); - log.string("Writable: ").zhex(Word.objectToUntrackedPointer(firstWritableRegularObject)).string(" - ").zhex(getObjectEnd(lastWritableRegularObject)).newline(); - log.string("Writable Huge: ").zhex(Word.objectToUntrackedPointer(firstWritableHugeObject)).string(" - ").zhex(getObjectEnd(lastWritableHugeObject)).newline(); - log.string("ReadOnly Huge: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyHugeObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyHugeObject)).newline(); + log.string("Objects in aligned chunks").indent(true); + log.string("read-only: ").zhex(Word.objectToUntrackedPointer(firstAlignedReadOnlyObject)).string(" - ").zhex(objEnd(lastAlignedReadOnlyObject)).newline(); + log.string("read-only relocatables: ").zhex(Word.objectToUntrackedPointer(firstAlignedReadOnlyRelocatableObject)).string(" - ").zhex(objEnd(lastAlignedReadOnlyRelocatableObject)).newline(); + log.string("writable: ").zhex(Word.objectToUntrackedPointer(firstAlignedWritableObject)).string(" - ").zhex(objEnd(lastAlignedWritableObject)).newline(); + log.string("writeable patched: ").zhex(Word.objectToUntrackedPointer(firstAlignedWritablePatchedObject)).string(" - ").zhex(objEnd(lastAlignedWritablePatchedObject)).indent(false); + + log.string("Objects in unaligned chunks").indent(true); + log.string("writable: ").zhex(Word.objectToUntrackedPointer(firstUnalignedWritableObject)).string(" - ").zhex(objEnd(lastUnalignedWritableObject)).newline(); + log.string("read-only: ").zhex(Word.objectToUntrackedPointer(firstUnalignedReadOnlyObject)).string(" - ").zhex(objEnd(lastUnalignedReadOnlyObject)).indent(false); } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java index a1bf4ba1ad9c..eba2eb72a834 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java @@ -45,29 +45,26 @@ import jdk.graal.compiler.word.Word; public final class ImageHeapWalker { - private static final MemoryWalker.NativeImageHeapRegionAccess READ_ONLY_REGULAR_WALKER = new ReadOnlyRegularMemoryWalkerAccess(); - private static final MemoryWalker.NativeImageHeapRegionAccess READ_ONLY_RELOCATABLE_WALKER = new ReadOnlyRelocatableMemoryWalkerAccess(); - private static final MemoryWalker.NativeImageHeapRegionAccess WRITABLE_REGULAR_WALKER = new WritableRegularMemoryWalkerAccess(); - private static final MemoryWalker.NativeImageHeapRegionAccess WRITABLE_HUGE_WALKER = new WritableHugeMemoryWalkerAccess(); - private static final MemoryWalker.NativeImageHeapRegionAccess READ_ONLY_HUGE_WALKER = new ReadOnlyHugeMemoryWalkerAccess(); + private static final MemoryWalker.NativeImageHeapRegionAccess ALIGNED_READ_ONLY_WALKER = new AlignedReadOnlyMemoryWalkerAccess(); + private static final MemoryWalker.NativeImageHeapRegionAccess ALIGNED_WRITABLE_WALKER = new AlignedWritableMemoryWalkerAccess(); + private static final MemoryWalker.NativeImageHeapRegionAccess UNALIGNED_WRITABLE_WALKER = new UnalignedWritableMemoryWalkerAccess(); + private static final MemoryWalker.NativeImageHeapRegionAccess UNALIGNED_READ_ONLY_WALKER = new UnalignedReadOnlyMemoryWalkerAccess(); private ImageHeapWalker() { } public static void walkRegions(ImageHeapInfo heapInfo, MemoryWalker.ImageHeapRegionVisitor visitor) { - visitor.visitNativeImageHeapRegion(heapInfo, READ_ONLY_REGULAR_WALKER); - visitor.visitNativeImageHeapRegion(heapInfo, READ_ONLY_RELOCATABLE_WALKER); - visitor.visitNativeImageHeapRegion(heapInfo, WRITABLE_REGULAR_WALKER); - visitor.visitNativeImageHeapRegion(heapInfo, WRITABLE_HUGE_WALKER); - visitor.visitNativeImageHeapRegion(heapInfo, READ_ONLY_HUGE_WALKER); + visitor.visitNativeImageHeapRegion(heapInfo, ALIGNED_READ_ONLY_WALKER); + visitor.visitNativeImageHeapRegion(heapInfo, ALIGNED_WRITABLE_WALKER); + visitor.visitNativeImageHeapRegion(heapInfo, UNALIGNED_WRITABLE_WALKER); + visitor.visitNativeImageHeapRegion(heapInfo, UNALIGNED_READ_ONLY_WALKER); } public static void walkImageHeapObjects(ImageHeapInfo heapInfo, ObjectVisitor visitor) { - walkPartition(heapInfo.firstReadOnlyRegularObject, heapInfo.lastReadOnlyRegularObject, visitor, true); - walkPartition(heapInfo.firstReadOnlyRelocatableObject, heapInfo.lastReadOnlyRelocatableObject, visitor, true); - walkPartition(heapInfo.firstWritableRegularObject, heapInfo.lastWritableRegularObject, visitor, true); - walkPartition(heapInfo.firstWritableHugeObject, heapInfo.lastWritableHugeObject, visitor, false); - walkPartition(heapInfo.firstReadOnlyHugeObject, heapInfo.lastReadOnlyHugeObject, visitor, false); + walkPartition(heapInfo.firstAlignedReadOnlyObject, heapInfo.lastAlignedReadOnlyObject, visitor, true); + walkPartition(heapInfo.firstAlignedWritableObject, heapInfo.lastAlignedWritableObject, visitor, true); + walkPartition(heapInfo.firstUnalignedWritableObject, heapInfo.lastUnalignedWritableObject, visitor, false); + walkPartition(heapInfo.firstUnalignedReadOnlyObject, heapInfo.lastUnalignedReadOnlyObject, visitor, false); } public static void walkImageHeapChunks(ImageHeapInfo heapInfo, HeapChunkVisitor visitor) { @@ -79,9 +76,9 @@ public static void walkImageHeapChunks(ImageHeapInfo heapInfo, HeapChunkVisitor } /* Walk all unaligned chunks (can only be at the end of the image heap). */ - Object firstUnalignedObject = heapInfo.firstWritableHugeObject; + Object firstUnalignedObject = heapInfo.firstUnalignedWritableObject; if (firstUnalignedObject == null) { - firstUnalignedObject = heapInfo.firstReadOnlyHugeObject; + firstUnalignedObject = heapInfo.firstUnalignedReadOnlyObject; } if (firstUnalignedObject != null) { HeapChunk.Header unalignedChunks = getImageHeapChunkForObject(firstUnalignedObject, false); @@ -161,15 +158,13 @@ private static HeapChunk.Header getImageHeapChunkForObject(Object object, boo } abstract class MemoryWalkerAccessBase implements MemoryWalker.NativeImageHeapRegionAccess { - private final String regionName; private final boolean isWritable; - private final boolean consistsOfHugeObjects; + private final boolean unalignedChunks; @Platforms(Platform.HOSTED_ONLY.class) - MemoryWalkerAccessBase(String regionName, boolean isWritable, boolean consistsOfHugeObjects) { - this.regionName = regionName; + MemoryWalkerAccessBase(boolean isWritable, boolean unalignedChunks) { this.isWritable = isWritable; - this.consistsOfHugeObjects = consistsOfHugeObjects; + this.unalignedChunks = unalignedChunks; } @Override @@ -182,109 +177,87 @@ public UnsignedWord getSize(ImageHeapInfo info) { return lastEnd.subtract(firstStart); } - @Override - public String getRegionName(ImageHeapInfo region) { - return regionName; - } - @Override public boolean isWritable(ImageHeapInfo region) { return isWritable; } @Override - public boolean consistsOfHugeObjects(ImageHeapInfo region) { - return consistsOfHugeObjects; + public boolean usesUnalignedChunks(ImageHeapInfo region) { + return unalignedChunks; } @Override public final void visitObjects(ImageHeapInfo region, ObjectVisitor visitor) { - boolean alignedChunks = !consistsOfHugeObjects; + boolean alignedChunks = !unalignedChunks; ImageHeapWalker.walkPartition(getFirstObject(region), getLastObject(region), visitor, alignedChunks); } } -final class ReadOnlyRegularMemoryWalkerAccess extends MemoryWalkerAccessBase { - @Platforms(Platform.HOSTED_ONLY.class) - ReadOnlyRegularMemoryWalkerAccess() { - super("read-only", false, false); - } - - @Override - public Object getFirstObject(ImageHeapInfo info) { - return info.firstReadOnlyRegularObject; - } - - @Override - public Object getLastObject(ImageHeapInfo info) { - return info.lastReadOnlyRegularObject; - } -} - -final class ReadOnlyRelocatableMemoryWalkerAccess extends MemoryWalkerAccessBase { +final class AlignedReadOnlyMemoryWalkerAccess extends MemoryWalkerAccessBase { @Platforms(Platform.HOSTED_ONLY.class) - ReadOnlyRelocatableMemoryWalkerAccess() { - super("read-only relocatables", false, false); + AlignedReadOnlyMemoryWalkerAccess() { + super(false, false); } @Override public Object getFirstObject(ImageHeapInfo info) { - return info.firstReadOnlyRelocatableObject; + return info.firstAlignedReadOnlyObject; } @Override public Object getLastObject(ImageHeapInfo info) { - return info.lastReadOnlyRelocatableObject; + return info.lastAlignedReadOnlyObject; } } -final class WritableRegularMemoryWalkerAccess extends MemoryWalkerAccessBase { +final class AlignedWritableMemoryWalkerAccess extends MemoryWalkerAccessBase { @Platforms(Platform.HOSTED_ONLY.class) - WritableRegularMemoryWalkerAccess() { - super("writable", true, false); + AlignedWritableMemoryWalkerAccess() { + super(true, false); } @Override public Object getFirstObject(ImageHeapInfo info) { - return info.firstWritableRegularObject; + return info.firstAlignedWritableObject; } @Override public Object getLastObject(ImageHeapInfo info) { - return info.lastWritableRegularObject; + return info.lastAlignedWritableObject; } } -final class WritableHugeMemoryWalkerAccess extends MemoryWalkerAccessBase { +final class UnalignedWritableMemoryWalkerAccess extends MemoryWalkerAccessBase { @Platforms(Platform.HOSTED_ONLY.class) - WritableHugeMemoryWalkerAccess() { - super("writable huge", true, true); + UnalignedWritableMemoryWalkerAccess() { + super(true, true); } @Override public Object getFirstObject(ImageHeapInfo info) { - return info.firstWritableHugeObject; + return info.firstUnalignedWritableObject; } @Override public Object getLastObject(ImageHeapInfo info) { - return info.lastWritableHugeObject; + return info.lastUnalignedWritableObject; } } -final class ReadOnlyHugeMemoryWalkerAccess extends MemoryWalkerAccessBase { +final class UnalignedReadOnlyMemoryWalkerAccess extends MemoryWalkerAccessBase { @Platforms(Platform.HOSTED_ONLY.class) - ReadOnlyHugeMemoryWalkerAccess() { - super("read-only huge", false, true); + UnalignedReadOnlyMemoryWalkerAccess() { + super(false, true); } @Override public Object getFirstObject(ImageHeapInfo info) { - return info.firstReadOnlyHugeObject; + return info.firstUnalignedReadOnlyObject; } @Override public Object getLastObject(ImageHeapInfo info) { - return info.lastReadOnlyHugeObject; + return info.lastUnalignedReadOnlyObject; } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java index eb2167e7c84c..1639ba8c3c2b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java @@ -337,7 +337,7 @@ public long encodeHubPointerForImageHeap(ImageHeapObject obj, long hubOffsetFrom if (partition.isWritable() && HeapImpl.usesImageHeapCardMarking()) { header |= REMSET_OR_MARKED1_BIT.rawValue(); } - if (partition.usesUnalignedObjects()) { + if (partition.usesUnalignedChunks()) { header |= UNALIGNED_BIT.rawValue(); } if (isIdentityHashFieldOptional()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java index 72a66ac44215..4a84a44c2249 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java @@ -46,11 +46,9 @@ public interface NativeImageHeapRegionAccess { UnsignedWord getSize(T region); - String getRegionName(T region); - boolean isWritable(T region); - boolean consistsOfHugeObjects(T region); + boolean usesUnalignedChunks(T region); void visitObjects(T region, ObjectVisitor visitor); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Integer_IntegerCache.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Integer_IntegerCache.java new file mode 100644 index 000000000000..fc93c5d8fc75 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Integer_IntegerCache.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.jdk; + +import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.None; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.TargetClass; + +@TargetClass(value = Integer.class, innerClass = "IntegerCache") +public final class Target_java_lang_Integer_IntegerCache { + @Alias @RecomputeFieldValue(kind = None, isFinal = true) // + public static int high; +} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateConstantReflectionProvider.java index d4a4224825c0..27d8e3da75e7 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateConstantReflectionProvider.java @@ -29,13 +29,10 @@ import org.graalvm.word.SignedWord; import com.oracle.svm.core.StaticFieldsSupport; -import com.oracle.svm.core.annotate.Alias; -import com.oracle.svm.core.annotate.RecomputeFieldValue; -import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; -import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.graal.meta.SharedConstantReflectionProvider; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.jdk.Target_java_lang_Integer_IntegerCache; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.snippets.KnownIntrinsics; @@ -195,9 +192,3 @@ protected static int getImageHeapOffsetInternal(SubstrateObjectConstant constant } } } - -@TargetClass(className = "java.lang.Integer$IntegerCache") -final class Target_java_lang_Integer_IntegerCache { - @Alias @RecomputeFieldValue(kind = Kind.None, isFinal = true) // - static int high; -} diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/gc/WasmHeap.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/gc/WasmHeap.java index dbec1c3f0c11..bbefa6aa82f7 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/gc/WasmHeap.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/gc/WasmHeap.java @@ -201,7 +201,7 @@ private ClassListBuilderVisitor(List> list) { @Override public void visitNativeImageHeapRegion(T region, MemoryWalker.NativeImageHeapRegionAccess access) { - if (!access.isWritable(region) && !access.consistsOfHugeObjects(region)) { + if (!access.isWritable(region) && !access.usesUnalignedChunks(region)) { access.visitObjects(region, this); } } From 5aba5eddf3b8ec37f85db5c6476e2820b3b0e579 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 6 Nov 2025 09:23:19 +0100 Subject: [PATCH 2/2] Fix HeapImpl.printLocationInfo(...). --- .../oracle/svm/core/genscavenge/HeapImpl.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index cd2e07b12d1c..c4a31f941bbc 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -764,24 +764,25 @@ public UnsignedWord getUsedMemoryAfterLastGC() { } private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { - for (ImageHeapInfo info : HeapImpl.getImageHeapInfos()) { - if (info.isInAlignedReadOnly(ptr)) { - log.string("points into the image heap (read-only)"); + for (ImageHeapInfo imageHeap : HeapImpl.getImageHeapInfos()) { + /* Check from most-specific to least-specific. */ + if (imageHeap.isInAlignedReadOnlyRelocatable(ptr)) { + log.string("points into the image heap (aligned chunk, read-only relocatables)"); return true; - } else if (info.isInAlignedReadOnlyRelocatable(ptr)) { - log.string("points into the image heap (read-only relocatables)"); + } else if (imageHeap.isInAlignedReadOnly(ptr)) { + log.string("points into the image heap (aligned chunk, read-only)"); return true; - } else if (info.isInAlignedWritablePatched(ptr)) { - log.string("points into the image heap (writable patched)"); + } else if (imageHeap.isInAlignedWritablePatched(ptr)) { + log.string("points into the image heap (aligned chunk, writable patched)"); return true; - } else if (info.isInAlignedWritable(ptr)) { - log.string("points into the image heap (writable)"); + } else if (imageHeap.isInAlignedWritable(ptr)) { + log.string("points into the image heap (aligned chunk, writable)"); return true; - } else if (info.isInUnalignedWritable(ptr)) { - log.string("points into the image heap (writable huge)"); + } else if (imageHeap.isInUnalignedWritable(ptr)) { + log.string("points into the image heap (unaligned chunk, writable)"); return true; - } else if (info.isInUnalignedReadOnly(ptr)) { - log.string("points into the image heap (read-only huge)"); + } else if (imageHeap.isInUnalignedReadOnly(ptr)) { + log.string("points into the image heap (unaligned chunk, read-only)"); return true; } }