Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ static AuxiliaryImageHeap singleton() {

void walkObjects(ObjectVisitor visitor);

void walkHeapChunks(HeapChunkVisitor visitor);

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
void walkRegions(MemoryWalker.ImageHeapRegionVisitor visitor);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public static void logChunks(Log log, UnalignedHeapChunk.UnalignedHeader firstCh
}
}

private static void logChunk(Log log, HeapChunk.Header<?> chunk, Pointer bottom, Pointer top, Pointer end, boolean isAligned, String shortSpaceName, boolean isToSpace) {
public static void logChunk(Log log, HeapChunk.Header<?> chunk, Pointer bottom, Pointer top, Pointer end, boolean isAligned, String shortSpaceName, boolean isToSpace) {
log.string("|").zhex(chunk).string("|").zhex(bottom).string(", ").zhex(top).string(", ").zhex(end);
log.string("|");
if (top.isNonNull()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2025, 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.genscavenge;

import static com.oracle.svm.core.heap.RestrictHeapAccess.Access.NO_ALLOCATION;

import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader;
import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader;
import com.oracle.svm.core.heap.RestrictHeapAccess;

public interface HeapChunkVisitor {
@RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate while visiting the heap.")
void visitAlignedChunk(AlignedHeader chunk);

@RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate while visiting the heap.")
void visitUnalignedChunk(UnalignedHeader chunk);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
import com.oracle.svm.core.Uninterruptible;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader;
import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader;
import com.oracle.svm.core.genscavenge.metaspace.MetaspaceImpl;
import com.oracle.svm.core.genscavenge.remset.RememberedSet;
import com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets;
Expand Down Expand Up @@ -104,6 +106,7 @@ public final class HeapImpl extends Heap {
private final GCImpl gcImpl;
private final RuntimeCodeInfoGCSupportImpl runtimeCodeInfoGcSupport;
private final HeapAccounting accounting = new HeapAccounting();
private final ImageHeapChunkLogger imageHeapChunkLogger = new ImageHeapChunkLogger();

/** Head of the linked list of currently pending (ready to be enqueued) {@link Reference}s. */
private Reference<?> refPendingList;
Expand Down Expand Up @@ -284,6 +287,13 @@ void logChunks(Log log, boolean allowUnsafe) {
if (Metaspace.isSupported()) {
MetaspaceImpl.singleton().logChunks(log);
}
imageHeapChunkLogger.initialize(log);
for (ImageHeapInfo info : HeapImpl.getImageHeapInfos()) {
ImageHeapWalker.walkImageHeapChunks(info, imageHeapChunkLogger);
}
if (AuxiliaryImageHeap.isPresent()) {
AuxiliaryImageHeap.singleton().walkHeapChunks(imageHeapChunkLogger);
}
getYoungGeneration().logChunks(log, allowUnsafe);
getOldGeneration().logChunks(log);
getChunkProvider().logFreeChunks(log);
Expand Down Expand Up @@ -955,6 +965,30 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev
log.indent(false);
}
}

private static final class ImageHeapChunkLogger implements HeapChunkVisitor {
private Log log;

@SuppressWarnings("hiding")
void initialize(Log log) {
this.log = log;
}

@Override
public void visitAlignedChunk(AlignedHeader chunk) {
Pointer bottom = AlignedHeapChunk.getObjectsStart(chunk);
Pointer top = HeapChunk.getTopPointer(chunk);
Pointer end = AlignedHeapChunk.getObjectsEnd(chunk);
HeapChunkLogging.logChunk(log, chunk, bottom, top, end, true, "I", false);
}

public void visitUnalignedChunk(UnalignedHeader chunk) {
Pointer bottom = UnalignedHeapChunk.getObjectStart(chunk);
Pointer top = HeapChunk.getTopPointer(chunk);
Pointer end = UnalignedHeapChunk.getObjectEnd(chunk);
HeapChunkLogging.logChunk(log, chunk, bottom, top, end, false, "I", false);
}
}
}

@TargetClass(value = java.lang.Runtime.class, onlyWith = UseSerialOrEpsilonGC.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
*/
package com.oracle.svm.core.genscavenge;

import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;

import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.word.Pointer;
Expand All @@ -33,6 +35,8 @@
import com.oracle.svm.core.MemoryWalker;
import com.oracle.svm.core.NeverInline;
import com.oracle.svm.core.Uninterruptible;
import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader;
import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader;
import com.oracle.svm.core.heap.Heap;
import com.oracle.svm.core.heap.ObjectVisitor;
import com.oracle.svm.core.hub.LayoutEncoding;
Expand Down Expand Up @@ -66,6 +70,38 @@ public static void walkImageHeapObjects(ImageHeapInfo heapInfo, ObjectVisitor vi
walkPartition(heapInfo.firstReadOnlyHugeObject, heapInfo.lastReadOnlyHugeObject, visitor, false);
}

public static void walkImageHeapChunks(ImageHeapInfo heapInfo, HeapChunkVisitor visitor) {
/* Walk all aligned chunks (can only be at the start of the image heap). */
Object firstObject = heapInfo.firstObject;
if (ObjectHeaderImpl.isAlignedObject(firstObject)) {
HeapChunk.Header<?> alignedChunks = getImageHeapChunkForObject(firstObject, true);
walkChunks(alignedChunks, visitor, true);
}

/* Walk all unaligned chunks (can only be at the end of the image heap). */
Object firstUnalignedObject = heapInfo.firstWritableHugeObject;
if (firstUnalignedObject == null) {
firstUnalignedObject = heapInfo.firstReadOnlyHugeObject;
}
if (firstUnalignedObject != null) {
HeapChunk.Header<?> unalignedChunks = getImageHeapChunkForObject(firstUnalignedObject, false);
walkChunks(unalignedChunks, visitor, false);
}
}

@NeverInline("Not performance critical")
private static void walkChunks(HeapChunk.Header<?> firstChunk, HeapChunkVisitor visitor, boolean alignedChunks) {
HeapChunk.Header<?> currentChunk = firstChunk;
while (currentChunk.isNonNull()) {
if (alignedChunks) {
visitor.visitAlignedChunk((AlignedHeader) currentChunk);
} else {
visitor.visitUnalignedChunk((UnalignedHeader) currentChunk);
}
currentChunk = HeapChunk.getNext(currentChunk);
}
}

@NeverInline("Not performance critical")
@Uninterruptible(reason = "Forced inlining (StoredContinuation objects must not move).")
static void walkPartition(Object firstObject, Object lastObject, ObjectVisitor visitor, boolean alignedChunks) {
Expand All @@ -83,16 +119,9 @@ static void walkPartitionInline(Object firstObject, Object lastObject, ObjectVis
Pointer lastPointer = Word.objectToUntrackedPointer(lastObject);
Pointer current = firstPointer;

/* Compute the enclosing chunk without assuming that the image heap is aligned. */
Pointer base = Heap.getHeap().getImageHeapStart();
Pointer offset = current.subtract(base);
UnsignedWord chunkOffset = alignedChunks ? UnsignedUtils.roundDown(offset, HeapParameters.getAlignedHeapChunkAlignment())
: offset.subtract(UnalignedHeapChunk.getOffsetForObject(current));
HeapChunk.Header<?> currentChunk = (HeapChunk.Header<?>) chunkOffset.add(base);

// Assumption: the order of chunks in their linked list is the same order as in memory,
// and objects are laid out as a continuous sequence without any gaps.

// and objects in a chunk are laid out as a continuous sequence without any gaps.
HeapChunk.Header<?> currentChunk = getImageHeapChunkForObject(firstObject, alignedChunks);
do {
Pointer limit = lastPointer;
Pointer chunkTop = HeapChunk.getTopPointer(currentChunk);
Expand All @@ -106,8 +135,8 @@ static void walkPartitionInline(Object firstObject, Object lastObject, ObjectVis
}
if (current.belowThan(lastPointer)) {
currentChunk = HeapChunk.getNext(currentChunk);
current = alignedChunks ? AlignedHeapChunk.getObjectsStart((AlignedHeapChunk.AlignedHeader) currentChunk)
: UnalignedHeapChunk.getObjectStart((UnalignedHeapChunk.UnalignedHeader) currentChunk);
current = alignedChunks ? AlignedHeapChunk.getObjectsStart((AlignedHeader) currentChunk)
: UnalignedHeapChunk.getObjectStart((UnalignedHeader) currentChunk);
// Note: current can be equal to lastPointer now, despite not having visited it yet
}
} while (current.belowOrEqual(lastPointer));
Expand All @@ -118,6 +147,17 @@ static void walkPartitionInline(Object firstObject, Object lastObject, ObjectVis
private static void visitObjectInline(ObjectVisitor visitor, Object currentObject) {
visitor.visitObject(currentObject);
}

/** Computes the enclosing chunk without assuming that the image heap is aligned. */
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
private static HeapChunk.Header<?> getImageHeapChunkForObject(Object object, boolean alignedChunks) {
Pointer objPtr = Word.objectToUntrackedPointer(object);
Pointer base = Heap.getHeap().getImageHeapStart();
Pointer offset = objPtr.subtract(base);
UnsignedWord chunkOffset = alignedChunks ? UnsignedUtils.roundDown(offset, HeapParameters.getAlignedHeapChunkAlignment())
: offset.subtract(UnalignedHeapChunk.getOffsetForObject(objPtr));
return (HeapChunk.Header<?>) chunkOffset.add(base);
}
}

abstract class MemoryWalkerAccessBase implements MemoryWalker.NativeImageHeapRegionAccess<ImageHeapInfo> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
import com.oracle.svm.core.c.CGlobalData;
import com.oracle.svm.core.c.CGlobalDataFactory;
import com.oracle.svm.core.c.function.CEntryPointErrors;
import com.oracle.svm.core.heap.Heap;
import com.oracle.svm.core.os.CommittedMemoryProvider;
import com.oracle.svm.core.util.PointerUtils;
import com.oracle.svm.core.util.TimeUtils;
import com.oracle.svm.core.util.VMError;

Expand Down Expand Up @@ -145,7 +147,17 @@ public static long getIsolateId() {

@Uninterruptible(reason = "Thread state not yet set up.")
public static int checkIsolate(Isolate isolate) {
return isolate.isNull() ? CEntryPointErrors.NULL_ARGUMENT : CEntryPointErrors.NO_ERROR;
if (isolate.isNull()) {
return CEntryPointErrors.NULL_ARGUMENT;
} else if (SubstrateOptions.SpawnIsolates.getValue() && !PointerUtils.isAMultiple(isolate, Word.signed(Heap.getHeap().getHeapBaseAlignment()))) {
/*
* The Isolate pointer is currently the same as the heap base, so we can check if the
* alignment matches the one that is expected for the heap base. This will detect most
* (but not all) invalid isolates.
*/
return CEntryPointErrors.INVALID_ISOLATE_ARGUMENT;
}
return CEntryPointErrors.NO_ERROR;
}

@Uninterruptible(reason = "Thread state not yet set up.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev
}
}
log.string(", stack(").zhex(VMThreads.StackEnd.get(thread)).string(",").zhex(VMThreads.StackBase.get(thread)).string(")");
log.string(", OS thread ").signed(VMThreads.OSThreadIdTL.get(thread)).string(" (").zhex(VMThreads.OSThreadHandleTL.get(thread)).string(")");
log.newline();
printed++;
}
Expand Down Expand Up @@ -876,7 +877,10 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev
log.string("Platform: ").string(platform.getOS()).string("/").string(platform.getArchitecture()).newline();
log.string("Page size: ").unsigned(SubstrateOptions.getPageSize()).newline();
log.string("Supports isolates: ").bool(SubstrateOptions.SpawnIsolates.getValue()).newline();
log.string("Containerized: ").string(String.valueOf(Container.singleton().isContainerized())).newline();
if (RuntimeCompilation.isEnabled()) {
log.string("Supports isolated compilation: ").bool(SubstrateOptions.supportCompileInIsolates()).newline();
}
log.string("Container support: ").bool(Container.isSupported()).newline();
log.string("Object reference size: ").signed(ConfigurationValues.getObjectLayout().getReferenceSize()).newline();
log.string("CPU features used for AOT compiled code: ").string(getBuildTimeCpuFeatures()).newline();
log.indent(false);
Expand All @@ -898,12 +902,18 @@ public int maxInvocationCount() {
@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("Runtime information:").indent(true);
log.string("Isolate id: ").signed(Isolates.getIsolateId()).newline();
log.string("Isolate id: ").signed(Isolates.getIsolateId());
if (RuntimeCompilation.isEnabled() && IsolateArgumentParser.isCompilationIsolate()) {
log.string(" (compilation isolate)");
}
log.newline();

log.string("Heap base: ").zhex(KnownIntrinsics.heapBase()).newline();
if (SubstrateOptions.useRelativeCodePointers()) {
log.string("Code base: ").zhex(KnownIntrinsics.codeBase()).newline();
}
log.string("CGlobalData base: ").zhex(CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS.getPointer()).newline();
log.string("Containerized: ").bool(Container.singleton().isContainerized()).newline();

if (Container.singleton().isContainerized()) {
log.string("CPU cores (container): ");
Expand Down Expand Up @@ -962,6 +972,9 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev
layerNumber++;
} while (info.isNonNull());

if (RuntimeCompilation.isEnabled()) {
log.string("Compile in isolates: ").bool(SubstrateOptions.shouldCompileInIsolates()).newline();
}
log.indent(false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ private CEntryPointErrors() {
@Description("The isolate could not be created because only a single isolate is supported.") //
public static final int SINGLE_ISOLATE_ALREADY_CREATED = 33;

@Description("An invalid isolate was passed as an argument.") //
public static final int INVALID_ISOLATE_ARGUMENT = 34;

public static String getDescription(int code) {
String result = null;
if (code >= 0 && code < DESCRIPTIONS.length) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public static VMThreads singleton() {
* this field after being removed from the linked list.
*/
public static final FastThreadLocalWord<IsolateThread> nextTL = FastThreadLocalFactory.createWord("VMThreads.nextTL");
private static final FastThreadLocalWord<OSThreadId> OSThreadIdTL = FastThreadLocalFactory.createWord("VMThreads.OSThreadIdTL");
public static final FastThreadLocalWord<OSThreadId> OSThreadIdTL = FastThreadLocalFactory.createWord("VMThreads.OSThreadIdTL");
public static final FastThreadLocalWord<OSThreadHandle> OSThreadHandleTL = FastThreadLocalFactory.createWord("VMThreads.OSThreadHandleTL");
public static final FastThreadLocalWord<Isolate> IsolateTL = FastThreadLocalFactory.createWord("VMThreads.IsolateTL");
/** The highest stack address. 0 if not available on this platform. */
Expand Down
Loading