Skip to content

Commit c784c6d

Browse files
[GR-69708] Improve crash log.
PullRequest: graal/22161
2 parents 1dcc9f5 + ac7a14d commit c784c6d

File tree

9 files changed

+159
-16
lines changed

9 files changed

+159
-16
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ static AuxiliaryImageHeap singleton() {
4949

5050
void walkObjects(ObjectVisitor visitor);
5151

52+
void walkHeapChunks(HeapChunkVisitor visitor);
53+
5254
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
5355
void walkRegions(MemoryWalker.ImageHeapRegionVisitor visitor);
5456

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public static void logChunks(Log log, UnalignedHeapChunk.UnalignedHeader firstCh
7272
}
7373
}
7474

75-
private static void logChunk(Log log, HeapChunk.Header<?> chunk, Pointer bottom, Pointer top, Pointer end, boolean isAligned, String shortSpaceName, boolean isToSpace) {
75+
public static void logChunk(Log log, HeapChunk.Header<?> chunk, Pointer bottom, Pointer top, Pointer end, boolean isAligned, String shortSpaceName, boolean isToSpace) {
7676
log.string("|").zhex(chunk).string("|").zhex(bottom).string(", ").zhex(top).string(", ").zhex(end);
7777
log.string("|");
7878
if (top.isNonNull()) {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core.genscavenge;
26+
27+
import static com.oracle.svm.core.heap.RestrictHeapAccess.Access.NO_ALLOCATION;
28+
29+
import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader;
30+
import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader;
31+
import com.oracle.svm.core.heap.RestrictHeapAccess;
32+
33+
public interface HeapChunkVisitor {
34+
@RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate while visiting the heap.")
35+
void visitAlignedChunk(AlignedHeader chunk);
36+
37+
@RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate while visiting the heap.")
38+
void visitUnalignedChunk(UnalignedHeader chunk);
39+
}

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import com.oracle.svm.core.Uninterruptible;
5050
import com.oracle.svm.core.annotate.Substitute;
5151
import com.oracle.svm.core.annotate.TargetClass;
52+
import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader;
53+
import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader;
5254
import com.oracle.svm.core.genscavenge.metaspace.MetaspaceImpl;
5355
import com.oracle.svm.core.genscavenge.remset.RememberedSet;
5456
import com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets;
@@ -104,6 +106,7 @@ public final class HeapImpl extends Heap {
104106
private final GCImpl gcImpl;
105107
private final RuntimeCodeInfoGCSupportImpl runtimeCodeInfoGcSupport;
106108
private final HeapAccounting accounting = new HeapAccounting();
109+
private final ImageHeapChunkLogger imageHeapChunkLogger = new ImageHeapChunkLogger();
107110

108111
/** Head of the linked list of currently pending (ready to be enqueued) {@link Reference}s. */
109112
private Reference<?> refPendingList;
@@ -284,6 +287,13 @@ void logChunks(Log log, boolean allowUnsafe) {
284287
if (Metaspace.isSupported()) {
285288
MetaspaceImpl.singleton().logChunks(log);
286289
}
290+
imageHeapChunkLogger.initialize(log);
291+
for (ImageHeapInfo info : HeapImpl.getImageHeapInfos()) {
292+
ImageHeapWalker.walkImageHeapChunks(info, imageHeapChunkLogger);
293+
}
294+
if (AuxiliaryImageHeap.isPresent()) {
295+
AuxiliaryImageHeap.singleton().walkHeapChunks(imageHeapChunkLogger);
296+
}
287297
getYoungGeneration().logChunks(log, allowUnsafe);
288298
getOldGeneration().logChunks(log);
289299
getChunkProvider().logFreeChunks(log);
@@ -955,6 +965,30 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev
955965
log.indent(false);
956966
}
957967
}
968+
969+
private static final class ImageHeapChunkLogger implements HeapChunkVisitor {
970+
private Log log;
971+
972+
@SuppressWarnings("hiding")
973+
void initialize(Log log) {
974+
this.log = log;
975+
}
976+
977+
@Override
978+
public void visitAlignedChunk(AlignedHeader chunk) {
979+
Pointer bottom = AlignedHeapChunk.getObjectsStart(chunk);
980+
Pointer top = HeapChunk.getTopPointer(chunk);
981+
Pointer end = AlignedHeapChunk.getObjectsEnd(chunk);
982+
HeapChunkLogging.logChunk(log, chunk, bottom, top, end, true, "I", false);
983+
}
984+
985+
public void visitUnalignedChunk(UnalignedHeader chunk) {
986+
Pointer bottom = UnalignedHeapChunk.getObjectStart(chunk);
987+
Pointer top = HeapChunk.getTopPointer(chunk);
988+
Pointer end = UnalignedHeapChunk.getObjectEnd(chunk);
989+
HeapChunkLogging.logChunk(log, chunk, bottom, top, end, false, "I", false);
990+
}
991+
}
958992
}
959993

960994
@TargetClass(value = java.lang.Runtime.class, onlyWith = UseSerialOrEpsilonGC.class)

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

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
package com.oracle.svm.core.genscavenge;
2626

27+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
28+
2729
import org.graalvm.nativeimage.Platform;
2830
import org.graalvm.nativeimage.Platforms;
2931
import org.graalvm.word.Pointer;
@@ -33,6 +35,8 @@
3335
import com.oracle.svm.core.MemoryWalker;
3436
import com.oracle.svm.core.NeverInline;
3537
import com.oracle.svm.core.Uninterruptible;
38+
import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader;
39+
import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader;
3640
import com.oracle.svm.core.heap.Heap;
3741
import com.oracle.svm.core.heap.ObjectVisitor;
3842
import com.oracle.svm.core.hub.LayoutEncoding;
@@ -66,6 +70,38 @@ public static void walkImageHeapObjects(ImageHeapInfo heapInfo, ObjectVisitor vi
6670
walkPartition(heapInfo.firstReadOnlyHugeObject, heapInfo.lastReadOnlyHugeObject, visitor, false);
6771
}
6872

73+
public static void walkImageHeapChunks(ImageHeapInfo heapInfo, HeapChunkVisitor visitor) {
74+
/* Walk all aligned chunks (can only be at the start of the image heap). */
75+
Object firstObject = heapInfo.firstObject;
76+
if (ObjectHeaderImpl.isAlignedObject(firstObject)) {
77+
HeapChunk.Header<?> alignedChunks = getImageHeapChunkForObject(firstObject, true);
78+
walkChunks(alignedChunks, visitor, true);
79+
}
80+
81+
/* Walk all unaligned chunks (can only be at the end of the image heap). */
82+
Object firstUnalignedObject = heapInfo.firstWritableHugeObject;
83+
if (firstUnalignedObject == null) {
84+
firstUnalignedObject = heapInfo.firstReadOnlyHugeObject;
85+
}
86+
if (firstUnalignedObject != null) {
87+
HeapChunk.Header<?> unalignedChunks = getImageHeapChunkForObject(firstUnalignedObject, false);
88+
walkChunks(unalignedChunks, visitor, false);
89+
}
90+
}
91+
92+
@NeverInline("Not performance critical")
93+
private static void walkChunks(HeapChunk.Header<?> firstChunk, HeapChunkVisitor visitor, boolean alignedChunks) {
94+
HeapChunk.Header<?> currentChunk = firstChunk;
95+
while (currentChunk.isNonNull()) {
96+
if (alignedChunks) {
97+
visitor.visitAlignedChunk((AlignedHeader) currentChunk);
98+
} else {
99+
visitor.visitUnalignedChunk((UnalignedHeader) currentChunk);
100+
}
101+
currentChunk = HeapChunk.getNext(currentChunk);
102+
}
103+
}
104+
69105
@NeverInline("Not performance critical")
70106
@Uninterruptible(reason = "Forced inlining (StoredContinuation objects must not move).")
71107
static void walkPartition(Object firstObject, Object lastObject, ObjectVisitor visitor, boolean alignedChunks) {
@@ -83,16 +119,9 @@ static void walkPartitionInline(Object firstObject, Object lastObject, ObjectVis
83119
Pointer lastPointer = Word.objectToUntrackedPointer(lastObject);
84120
Pointer current = firstPointer;
85121

86-
/* Compute the enclosing chunk without assuming that the image heap is aligned. */
87-
Pointer base = Heap.getHeap().getImageHeapStart();
88-
Pointer offset = current.subtract(base);
89-
UnsignedWord chunkOffset = alignedChunks ? UnsignedUtils.roundDown(offset, HeapParameters.getAlignedHeapChunkAlignment())
90-
: offset.subtract(UnalignedHeapChunk.getOffsetForObject(current));
91-
HeapChunk.Header<?> currentChunk = (HeapChunk.Header<?>) chunkOffset.add(base);
92-
93122
// Assumption: the order of chunks in their linked list is the same order as in memory,
94-
// and objects are laid out as a continuous sequence without any gaps.
95-
123+
// and objects in a chunk are laid out as a continuous sequence without any gaps.
124+
HeapChunk.Header<?> currentChunk = getImageHeapChunkForObject(firstObject, alignedChunks);
96125
do {
97126
Pointer limit = lastPointer;
98127
Pointer chunkTop = HeapChunk.getTopPointer(currentChunk);
@@ -106,8 +135,8 @@ static void walkPartitionInline(Object firstObject, Object lastObject, ObjectVis
106135
}
107136
if (current.belowThan(lastPointer)) {
108137
currentChunk = HeapChunk.getNext(currentChunk);
109-
current = alignedChunks ? AlignedHeapChunk.getObjectsStart((AlignedHeapChunk.AlignedHeader) currentChunk)
110-
: UnalignedHeapChunk.getObjectStart((UnalignedHeapChunk.UnalignedHeader) currentChunk);
138+
current = alignedChunks ? AlignedHeapChunk.getObjectsStart((AlignedHeader) currentChunk)
139+
: UnalignedHeapChunk.getObjectStart((UnalignedHeader) currentChunk);
111140
// Note: current can be equal to lastPointer now, despite not having visited it yet
112141
}
113142
} while (current.belowOrEqual(lastPointer));
@@ -118,6 +147,17 @@ static void walkPartitionInline(Object firstObject, Object lastObject, ObjectVis
118147
private static void visitObjectInline(ObjectVisitor visitor, Object currentObject) {
119148
visitor.visitObject(currentObject);
120149
}
150+
151+
/** Computes the enclosing chunk without assuming that the image heap is aligned. */
152+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
153+
private static HeapChunk.Header<?> getImageHeapChunkForObject(Object object, boolean alignedChunks) {
154+
Pointer objPtr = Word.objectToUntrackedPointer(object);
155+
Pointer base = Heap.getHeap().getImageHeapStart();
156+
Pointer offset = objPtr.subtract(base);
157+
UnsignedWord chunkOffset = alignedChunks ? UnsignedUtils.roundDown(offset, HeapParameters.getAlignedHeapChunkAlignment())
158+
: offset.subtract(UnalignedHeapChunk.getOffsetForObject(objPtr));
159+
return (HeapChunk.Header<?>) chunkOffset.add(base);
160+
}
121161
}
122162

123163
abstract class MemoryWalkerAccessBase implements MemoryWalker.NativeImageHeapRegionAccess<ImageHeapInfo> {

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
import com.oracle.svm.core.c.CGlobalData;
3737
import com.oracle.svm.core.c.CGlobalDataFactory;
3838
import com.oracle.svm.core.c.function.CEntryPointErrors;
39+
import com.oracle.svm.core.heap.Heap;
3940
import com.oracle.svm.core.os.CommittedMemoryProvider;
41+
import com.oracle.svm.core.util.PointerUtils;
4042
import com.oracle.svm.core.util.TimeUtils;
4143
import com.oracle.svm.core.util.VMError;
4244

@@ -145,7 +147,17 @@ public static long getIsolateId() {
145147

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

151163
@Uninterruptible(reason = "Thread state not yet set up.")

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev
754754
}
755755
}
756756
log.string(", stack(").zhex(VMThreads.StackEnd.get(thread)).string(",").zhex(VMThreads.StackBase.get(thread)).string(")");
757+
log.string(", OS thread ").signed(VMThreads.OSThreadIdTL.get(thread)).string(" (").zhex(VMThreads.OSThreadHandleTL.get(thread)).string(")");
757758
log.newline();
758759
printed++;
759760
}
@@ -876,7 +877,10 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev
876877
log.string("Platform: ").string(platform.getOS()).string("/").string(platform.getArchitecture()).newline();
877878
log.string("Page size: ").unsigned(SubstrateOptions.getPageSize()).newline();
878879
log.string("Supports isolates: ").bool(SubstrateOptions.SpawnIsolates.getValue()).newline();
879-
log.string("Containerized: ").string(String.valueOf(Container.singleton().isContainerized())).newline();
880+
if (RuntimeCompilation.isEnabled()) {
881+
log.string("Supports isolated compilation: ").bool(SubstrateOptions.supportCompileInIsolates()).newline();
882+
}
883+
log.string("Container support: ").bool(Container.isSupported()).newline();
880884
log.string("Object reference size: ").signed(ConfigurationValues.getObjectLayout().getReferenceSize()).newline();
881885
log.string("CPU features used for AOT compiled code: ").string(getBuildTimeCpuFeatures()).newline();
882886
log.indent(false);
@@ -898,12 +902,18 @@ public int maxInvocationCount() {
898902
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.")
899903
public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) {
900904
log.string("Runtime information:").indent(true);
901-
log.string("Isolate id: ").signed(Isolates.getIsolateId()).newline();
905+
log.string("Isolate id: ").signed(Isolates.getIsolateId());
906+
if (RuntimeCompilation.isEnabled() && IsolateArgumentParser.isCompilationIsolate()) {
907+
log.string(" (compilation isolate)");
908+
}
909+
log.newline();
910+
902911
log.string("Heap base: ").zhex(KnownIntrinsics.heapBase()).newline();
903912
if (SubstrateOptions.useRelativeCodePointers()) {
904913
log.string("Code base: ").zhex(KnownIntrinsics.codeBase()).newline();
905914
}
906915
log.string("CGlobalData base: ").zhex(CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS.getPointer()).newline();
916+
log.string("Containerized: ").bool(Container.singleton().isContainerized()).newline();
907917

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

975+
if (RuntimeCompilation.isEnabled()) {
976+
log.string("Compile in isolates: ").bool(SubstrateOptions.shouldCompileInIsolates()).newline();
977+
}
965978
log.indent(false);
966979
}
967980

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointErrors.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ private CEntryPointErrors() {
176176
@Description("The isolate could not be created because only a single isolate is supported.") //
177177
public static final int SINGLE_ISOLATE_ALREADY_CREATED = 33;
178178

179+
@Description("An invalid isolate was passed as an argument.") //
180+
public static final int INVALID_ISOLATE_ARGUMENT = 34;
181+
179182
public static String getDescription(int code) {
180183
String result = null;
181184
if (code >= 0 && code < DESCRIPTIONS.length) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public static VMThreads singleton() {
167167
* this field after being removed from the linked list.
168168
*/
169169
public static final FastThreadLocalWord<IsolateThread> nextTL = FastThreadLocalFactory.createWord("VMThreads.nextTL");
170-
private static final FastThreadLocalWord<OSThreadId> OSThreadIdTL = FastThreadLocalFactory.createWord("VMThreads.OSThreadIdTL");
170+
public static final FastThreadLocalWord<OSThreadId> OSThreadIdTL = FastThreadLocalFactory.createWord("VMThreads.OSThreadIdTL");
171171
public static final FastThreadLocalWord<OSThreadHandle> OSThreadHandleTL = FastThreadLocalFactory.createWord("VMThreads.OSThreadHandleTL");
172172
public static final FastThreadLocalWord<Isolate> IsolateTL = FastThreadLocalFactory.createWord("VMThreads.IsolateTL");
173173
/** The highest stack address. 0 if not available on this platform. */

0 commit comments

Comments
 (0)