Skip to content

Commit af65204

Browse files
christianhaeublelkorchi
authored andcommitted
[GR-52434] [GR-52613] [GR-52616] [GR-52921] Backport to 24.0: Small fixes and improvements.
PullRequest: graal/17153
2 parents bf0bb9b + 1a19902 commit af65204

File tree

11 files changed

+107
-132
lines changed

11 files changed

+107
-132
lines changed

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

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -718,32 +718,6 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev
718718
}
719719
}
720720

721-
private static class DumpTopDeoptimizedFrame extends DiagnosticThunk {
722-
@Override
723-
public int maxInvocationCount() {
724-
return 1;
725-
}
726-
727-
@Override
728-
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.")
729-
public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) {
730-
Pointer sp = context.getStackPointer();
731-
CodePointer ip = context.getInstructionPointer();
732-
733-
if (sp.isNonNull() && ip.isNonNull()) {
734-
long totalFrameSize = getTotalFrameSize(sp, ip);
735-
DeoptimizedFrame deoptFrame = Deoptimizer.checkDeoptimized(sp);
736-
if (deoptFrame != null) {
737-
log.string("Top frame info:").indent(true);
738-
log.string("RSP ").zhex(sp).string(" frame was deoptimized:").newline();
739-
log.string("SourcePC ").zhex(deoptFrame.getSourcePC()).newline();
740-
log.string("SourceTotalFrameSize ").signed(totalFrameSize).newline();
741-
log.indent(false);
742-
}
743-
}
744-
}
745-
}
746-
747721
private static class DumpThreads extends DiagnosticThunk {
748722
@Override
749723
public int maxInvocationCount() {
@@ -1254,9 +1228,6 @@ public static synchronized DiagnosticThunkRegistry singleton() {
12541228
thunks.add(new DumpRegisters());
12551229
thunks.add(new DumpInstructions());
12561230
thunks.add(new DumpTopOfCurrentThreadStack());
1257-
if (RuntimeCompilation.isEnabled()) {
1258-
thunks.add(new DumpTopDeoptimizedFrame());
1259-
}
12601231
thunks.add(new DumpCurrentThreadLocals());
12611232
thunks.add(new DumpCurrentThreadFrameAnchors());
12621233
thunks.add(new DumpCurrentThreadDecodedStackTrace());

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

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -170,42 +170,52 @@ protected static boolean tryEnterIsolate(RegisterDumper.Context context) {
170170
}
171171

172172
/* Try to determine the isolate via the thread register. */
173-
if (SubstrateOptions.MultiThreaded.getValue()) {
174-
/*
175-
* Set the thread register to null so that we don't execute this code more than once if
176-
* we trigger a recursive segfault.
177-
*/
178-
WriteCurrentVMThreadNode.writeCurrentVMThread(WordFactory.nullPointer());
179-
180-
IsolateThread isolateThread = (IsolateThread) RegisterDumper.singleton().getThreadPointer(context);
181-
if (isolateThread.isNonNull()) {
182-
isolate = VMThreads.IsolateTL.get(isolateThread);
183-
if (isValid(isolate)) {
184-
if (SubstrateOptions.SpawnIsolates.getValue()) {
185-
CEntryPointSnippets.setHeapBase(isolate);
186-
}
187-
188-
WriteCurrentVMThreadNode.writeCurrentVMThread(isolateThread);
189-
return true;
190-
}
191-
}
173+
if (SubstrateOptions.MultiThreaded.getValue() && tryEnterIsolateViaThreadRegister(context)) {
174+
return true;
192175
}
193176

194177
/* Try to determine the isolate via the heap base register. */
195-
if (SubstrateOptions.SpawnIsolates.getValue()) {
196-
/*
197-
* Set the heap base register to null so that we don't execute this code more than once
198-
* if we trigger a recursive segfault.
199-
*/
200-
CEntryPointSnippets.setHeapBase(WordFactory.nullPointer());
178+
return SubstrateOptions.SpawnIsolates.getValue() && tryEnterIsolateViaHeapBaseRegister(context);
179+
}
180+
181+
@Uninterruptible(reason = "Thread state not set up yet.")
182+
@NeverInline("Prevent register writes from floating")
183+
private static boolean tryEnterIsolateViaThreadRegister(RegisterDumper.Context context) {
184+
/*
185+
* Try to determine the isolate via the thread register. Set the thread register to null so
186+
* that we don't execute this code more than once if we trigger a recursive segfault.
187+
*/
188+
WriteCurrentVMThreadNode.writeCurrentVMThread(WordFactory.nullPointer());
201189

202-
isolate = (Isolate) RegisterDumper.singleton().getHeapBase(context);
190+
IsolateThread isolateThread = (IsolateThread) RegisterDumper.singleton().getThreadPointer(context);
191+
if (isolateThread.isNonNull()) {
192+
Isolate isolate = VMThreads.IsolateTL.get(isolateThread);
203193
if (isValid(isolate)) {
204-
int error = CEntryPointSnippets.enterAttachFromCrashHandler(isolate);
205-
return error == CEntryPointErrors.NO_ERROR;
194+
if (SubstrateOptions.SpawnIsolates.getValue()) {
195+
CEntryPointSnippets.setHeapBase(isolate);
196+
}
197+
198+
WriteCurrentVMThreadNode.writeCurrentVMThread(isolateThread);
199+
return true;
206200
}
207201
}
202+
return false;
203+
}
208204

205+
@Uninterruptible(reason = "Thread state not set up yet.")
206+
@NeverInline("Prevent register writes from floating")
207+
private static boolean tryEnterIsolateViaHeapBaseRegister(RegisterDumper.Context context) {
208+
/*
209+
* Set the heap base register to null so that we don't execute this code more than once if
210+
* we trigger a recursive segfault.
211+
*/
212+
CEntryPointSnippets.setHeapBase(WordFactory.nullPointer());
213+
214+
Isolate isolate = (Isolate) RegisterDumper.singleton().getHeapBase(context);
215+
if (isValid(isolate)) {
216+
int error = CEntryPointSnippets.enterAttachFromCrashHandler(isolate);
217+
return error == CEntryPointErrors.NO_ERROR;
218+
}
209219
return false;
210220
}
211221

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,11 @@ protected Pointer allocateCodeMemory(long size) {
4747
}
4848

4949
protected void makeCodeMemoryExecutableReadOnly(Pointer start, UnsignedWord size) {
50-
int result = RuntimeCodeInfoAccess.makeCodeMemoryExecutableReadOnly((CodePointer) start, size);
51-
VMError.guarantee(result == 0, "Failed to make code memory read only.");
50+
RuntimeCodeInfoAccess.makeCodeMemoryExecutableReadOnly((CodePointer) start, size);
5251
}
5352

5453
protected void makeCodeMemoryExecutableWritable(Pointer start, UnsignedWord size) {
55-
int result = RuntimeCodeInfoAccess.makeCodeMemoryExecutableWritable((CodePointer) start, size);
56-
VMError.guarantee(result == 0, "Failed to make code memory writable.");
54+
RuntimeCodeInfoAccess.makeCodeMemoryExecutableWritable((CodePointer) start, size);
5755
}
5856

5957
protected static void doInstallPrepared(SharedMethod method, CodeInfo codeInfo, SubstrateInstalledCode installedCode) {

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

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

27-
import java.util.EnumSet;
28-
2927
import org.graalvm.nativeimage.ImageSingletons;
3028
import org.graalvm.nativeimage.UnmanagedMemory;
3129
import org.graalvm.nativeimage.c.function.CodePointer;
@@ -46,6 +44,7 @@
4644
import com.oracle.svm.core.heap.Heap;
4745
import com.oracle.svm.core.heap.ObjectReferenceVisitor;
4846
import com.oracle.svm.core.os.CommittedMemoryProvider;
47+
import com.oracle.svm.core.os.VirtualMemoryProvider;
4948
import com.oracle.svm.core.util.DuplicatedInNativeCode;
5049
import com.oracle.svm.core.util.VMError;
5150

@@ -235,12 +234,23 @@ private static void releaseCodeMemory(CodePointer codeStart, UnsignedWord codeSi
235234
CommittedMemoryProvider.get().freeExecutableMemory(codeStart, codeSize, WordFactory.unsigned(SubstrateOptions.codeAlignment()));
236235
}
237236

238-
public static int makeCodeMemoryExecutableReadOnly(CodePointer codeStart, UnsignedWord codeSize) {
239-
return CommittedMemoryProvider.get().protect(codeStart, codeSize, EnumSet.of(CommittedMemoryProvider.Access.READ, CommittedMemoryProvider.Access.EXECUTE));
237+
public static void makeCodeMemoryExecutableReadOnly(CodePointer codeStart, UnsignedWord codeSize) {
238+
protectCodeMemory(codeStart, codeSize, VirtualMemoryProvider.Access.READ | VirtualMemoryProvider.Access.EXECUTE);
239+
}
240+
241+
public static void makeCodeMemoryExecutableWritable(CodePointer start, UnsignedWord size) {
242+
VMError.guarantee(RuntimeCodeCache.Options.WriteableCodeCache.getValue(), "memory must not be writable and executable at the same time unless we have a writable code cache");
243+
protectCodeMemory(start, size, VirtualMemoryProvider.Access.READ | VirtualMemoryProvider.Access.WRITE | VirtualMemoryProvider.Access.EXECUTE);
240244
}
241245

242-
public static int makeCodeMemoryExecutableWritable(CodePointer start, UnsignedWord size) {
243-
return CommittedMemoryProvider.get().protect(start, size, EnumSet.of(CommittedMemoryProvider.Access.READ, CommittedMemoryProvider.Access.WRITE, CommittedMemoryProvider.Access.EXECUTE));
246+
private static void protectCodeMemory(CodePointer codeStart, UnsignedWord codeSize, int permissions) {
247+
int result = VirtualMemoryProvider.get().protect(codeStart, codeSize, permissions);
248+
if (result != 0) {
249+
throw VMError.shouldNotReachHere("Failed to modify protection of code memory. This may be caused by " +
250+
"a. a too restrictive OS-limit of allowed memory mappings (see vm.max_map_count on Linux), " +
251+
"b. a too strict security policy if you are running on Security-Enhanced Linux (SELinux), or " +
252+
"c. a Native Image internal error.");
253+
}
244254
}
245255

246256
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ private static RuntimeException checkDeoptimizedError0(Pointer sourceSp) {
257257
throw VMError.shouldNotReachHere("Unable to retrieve Deoptimized frame");
258258
}
259259

260+
@Uninterruptible(reason = "Prevent stack walks from seeing an inconsistent stack.")
260261
private static void installDeoptimizedFrame(Pointer sourceSp, DeoptimizedFrame deoptimizedFrame) {
261262
/*
262263
* Replace the return address to the deoptimized method with a pointer to the deoptStub.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/OutOfMemoryUtil.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
import com.oracle.svm.core.headers.LibC;
3232
import com.oracle.svm.core.heap.dump.HeapDumping;
3333
import com.oracle.svm.core.jdk.JDKUtils;
34-
import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicBoolean;
3534
import com.oracle.svm.core.log.Log;
35+
import com.oracle.svm.core.stack.StackOverflowCheck;
3636
import com.oracle.svm.core.util.VMError;
3737

3838
/**
@@ -43,11 +43,6 @@
4343
public class OutOfMemoryUtil {
4444
private static final OutOfMemoryError OUT_OF_MEMORY_ERROR = new OutOfMemoryError("Garbage-collected heap size exceeded. Consider increasing the maximum Java heap size, for example with '-Xmx'.");
4545

46-
/**
47-
* Guard to ensure heap dump on OOME is performed at most once.
48-
*/
49-
private static final AtomicBoolean HEAP_DUMPED = new AtomicBoolean(false);
50-
5146
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Can't allocate when out of memory.")
5247
public static OutOfMemoryError heapSizeExceeded() {
5348
return reportOutOfMemoryError(OUT_OF_MEMORY_ERROR);
@@ -56,7 +51,18 @@ public static OutOfMemoryError heapSizeExceeded() {
5651
@Uninterruptible(reason = "Not uninterruptible but it doesn't matter for the callers.", calleeMustBe = false)
5752
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Can't allocate while out of memory.")
5853
public static OutOfMemoryError reportOutOfMemoryError(OutOfMemoryError error) {
59-
if (VMInspectionOptions.hasHeapDumpSupport() && SubstrateOptions.HeapDumpOnOutOfMemoryError.getValue() && HEAP_DUMPED.compareAndSet(false, true)) {
54+
StackOverflowCheck.singleton().makeYellowZoneAvailable();
55+
try {
56+
reportOutOfMemoryError0(error);
57+
} finally {
58+
StackOverflowCheck.singleton().protectYellowZone();
59+
}
60+
throw error;
61+
}
62+
63+
@Uninterruptible(reason = "Not uninterruptible but it doesn't matter for the callers.", calleeMustBe = false)
64+
private static void reportOutOfMemoryError0(OutOfMemoryError error) {
65+
if (VMInspectionOptions.hasHeapDumpSupport() && SubstrateOptions.HeapDumpOnOutOfMemoryError.getValue()) {
6066
HeapDumping.singleton().dumpHeapOnOutOfMemoryError();
6167
}
6268

@@ -68,6 +74,5 @@ public static OutOfMemoryError reportOutOfMemoryError(OutOfMemoryError error) {
6874
VMError.shouldNotReachHere("ExitOnOutOfMemoryError can only be used if the LibC support is present.");
6975
}
7076
}
71-
throw error;
7277
}
7378
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/dump/HeapDumpSupportImpl.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import com.oracle.svm.core.heap.Heap;
4747
import com.oracle.svm.core.heap.RestrictHeapAccess;
4848
import com.oracle.svm.core.heap.VMOperationInfos;
49+
import com.oracle.svm.core.locks.VMMutex;
4950
import com.oracle.svm.core.log.Log;
5051
import com.oracle.svm.core.os.RawFileOperationSupport;
5152
import com.oracle.svm.core.os.RawFileOperationSupport.FileCreationMode;
@@ -58,8 +59,10 @@
5859
public class HeapDumpSupportImpl extends HeapDumping {
5960
private final HeapDumpWriter writer;
6061
private final HeapDumpOperation heapDumpOperation;
62+
private final VMMutex outOfMemoryHeapDumpMutex = new VMMutex("outOfMemoryHeapDump");
6163

6264
private CCharPointer outOfMemoryHeapDumpPath;
65+
private boolean outOfMemoryHeapDumpAttempted;
6366

6467
@Platforms(Platform.HOSTED_ONLY.class)
6568
public HeapDumpSupportImpl(HeapDumpMetadata metadata) {
@@ -84,6 +87,23 @@ public void teardownDumpHeapOnOutOfMemoryError() {
8487
@Override
8588
@RestrictHeapAccess(access = NO_ALLOCATION, reason = "OutOfMemoryError heap dumping must not allocate.")
8689
public void dumpHeapOnOutOfMemoryError() {
90+
/*
91+
* Try exactly once to create an out-of-memory heap dump. If another thread triggers an
92+
* OutOfMemoryError while heap dumping is in progress, it needs to wait until heap dumping
93+
* finishes.
94+
*/
95+
outOfMemoryHeapDumpMutex.lock();
96+
try {
97+
if (!outOfMemoryHeapDumpAttempted) {
98+
dumpHeapOnOutOfMemoryError0();
99+
outOfMemoryHeapDumpAttempted = true;
100+
}
101+
} finally {
102+
outOfMemoryHeapDumpMutex.unlock();
103+
}
104+
}
105+
106+
private void dumpHeapOnOutOfMemoryError0() {
87107
CCharPointer path = outOfMemoryHeapDumpPath;
88108
if (path.isNull()) {
89109
Log.log().string("OutOfMemoryError heap dumping failed because the heap dump file path could not be allocated.").newline();

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,12 @@ public Log exception(Throwable t, int maxFrames) {
648648
}
649649

650650
Throwable cur = t;
651-
do {
651+
int maxCauses = 25;
652+
for (int i = 0; i < maxCauses && cur != null; i++) {
653+
if (i > 0) {
654+
newline().string("Caused by: ");
655+
}
656+
652657
/*
653658
* We do not want to call getMessage(), since it can be overridden by subclasses of
654659
* Throwable. So we access the raw detailMessage directly from the field in Throwable.
@@ -668,23 +673,20 @@ public Log exception(Throwable t, int maxFrames) {
668673
} else {
669674
StackTraceElement[] stackTrace = JDKUtils.getRawStackTrace(cur);
670675
if (stackTrace != null) {
671-
int i;
672-
for (i = 0; i < stackTrace.length && i < maxFrames; i++) {
673-
StackTraceElement element = stackTrace[i];
676+
int j;
677+
for (j = 0; j < stackTrace.length && j < maxFrames; j++) {
678+
StackTraceElement element = stackTrace[j];
674679
if (element != null) {
675680
printJavaFrame(element.getClassName(), element.getMethodName(), element.getFileName(), element.getLineNumber());
676681
}
677682
}
678-
int remaining = stackTrace.length - i;
683+
int remaining = stackTrace.length - j;
679684
printRemainingFramesCount(remaining);
680685
}
681686
}
682687

683688
cur = JDKUtils.getRawCause(cur);
684-
if (cur != null) {
685-
newline().string("Caused by: ");
686-
}
687-
} while (cur != null);
689+
}
688690

689691
return this;
690692
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_END;
3131
import static org.graalvm.word.WordFactory.nullPointer;
3232

33-
import java.util.EnumSet;
34-
3533
import jdk.graal.compiler.api.replacements.Fold;
3634
import org.graalvm.word.Pointer;
3735
import org.graalvm.word.PointerBase;
@@ -41,11 +39,9 @@
4139
import com.oracle.svm.core.SubstrateOptions;
4240
import com.oracle.svm.core.Uninterruptible;
4341
import com.oracle.svm.core.c.function.CEntryPointErrors;
44-
import com.oracle.svm.core.code.RuntimeCodeCache;
4542
import com.oracle.svm.core.config.ConfigurationValues;
4643
import com.oracle.svm.core.heap.Heap;
4744
import com.oracle.svm.core.util.UnsignedUtils;
48-
import com.oracle.svm.core.util.VMError;
4945

5046
public abstract class AbstractCommittedMemoryProvider implements CommittedMemoryProvider {
5147
@Fold
@@ -85,24 +81,6 @@ protected static int protectSingleIsolateImageHeap() {
8581
return CEntryPointErrors.NO_ERROR;
8682
}
8783

88-
@Override
89-
public int protect(PointerBase start, UnsignedWord nbytes, EnumSet<Access> accessFlags) {
90-
int vmAccessBits = VirtualMemoryProvider.Access.NONE;
91-
if (accessFlags.contains(CommittedMemoryProvider.Access.READ)) {
92-
vmAccessBits |= VirtualMemoryProvider.Access.READ;
93-
}
94-
if (accessFlags.contains(CommittedMemoryProvider.Access.WRITE)) {
95-
vmAccessBits |= VirtualMemoryProvider.Access.WRITE;
96-
}
97-
if (accessFlags.contains(CommittedMemoryProvider.Access.EXECUTE)) {
98-
if ((vmAccessBits & VirtualMemoryProvider.Access.WRITE) != 0 && !RuntimeCodeCache.Options.WriteableCodeCache.getValue()) {
99-
throw VMError.shouldNotReachHere("memory should never be writable and executable at the same time");
100-
}
101-
vmAccessBits |= VirtualMemoryProvider.Access.EXECUTE;
102-
}
103-
return VirtualMemoryProvider.get().protect(start, nbytes, vmAccessBits);
104-
}
105-
10684
@Override
10785
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
10886
public Pointer allocateAlignedChunk(UnsignedWord nbytes, UnsignedWord alignment) {

0 commit comments

Comments
 (0)