Skip to content

Commit

Permalink
[GR-52434] [GR-52613] [GR-52616] [GR-52921] Backport to 24.0: Small f…
Browse files Browse the repository at this point in the history
…ixes and improvements.

PullRequest: graal/17153
  • Loading branch information
christianhaeubl authored and elkorchi committed Mar 27, 2024
2 parents bf0bb9b + 1a19902 commit af65204
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -718,32 +718,6 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev
}
}

private static class DumpTopDeoptimizedFrame extends DiagnosticThunk {
@Override
public int maxInvocationCount() {
return 1;
}

@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) {
Pointer sp = context.getStackPointer();
CodePointer ip = context.getInstructionPointer();

if (sp.isNonNull() && ip.isNonNull()) {
long totalFrameSize = getTotalFrameSize(sp, ip);
DeoptimizedFrame deoptFrame = Deoptimizer.checkDeoptimized(sp);
if (deoptFrame != null) {
log.string("Top frame info:").indent(true);
log.string("RSP ").zhex(sp).string(" frame was deoptimized:").newline();
log.string("SourcePC ").zhex(deoptFrame.getSourcePC()).newline();
log.string("SourceTotalFrameSize ").signed(totalFrameSize).newline();
log.indent(false);
}
}
}
}

private static class DumpThreads extends DiagnosticThunk {
@Override
public int maxInvocationCount() {
Expand Down Expand Up @@ -1254,9 +1228,6 @@ public static synchronized DiagnosticThunkRegistry singleton() {
thunks.add(new DumpRegisters());
thunks.add(new DumpInstructions());
thunks.add(new DumpTopOfCurrentThreadStack());
if (RuntimeCompilation.isEnabled()) {
thunks.add(new DumpTopDeoptimizedFrame());
}
thunks.add(new DumpCurrentThreadLocals());
thunks.add(new DumpCurrentThreadFrameAnchors());
thunks.add(new DumpCurrentThreadDecodedStackTrace());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,42 +170,52 @@ protected static boolean tryEnterIsolate(RegisterDumper.Context context) {
}

/* Try to determine the isolate via the thread register. */
if (SubstrateOptions.MultiThreaded.getValue()) {
/*
* Set the thread register to null so that we don't execute this code more than once if
* we trigger a recursive segfault.
*/
WriteCurrentVMThreadNode.writeCurrentVMThread(WordFactory.nullPointer());

IsolateThread isolateThread = (IsolateThread) RegisterDumper.singleton().getThreadPointer(context);
if (isolateThread.isNonNull()) {
isolate = VMThreads.IsolateTL.get(isolateThread);
if (isValid(isolate)) {
if (SubstrateOptions.SpawnIsolates.getValue()) {
CEntryPointSnippets.setHeapBase(isolate);
}

WriteCurrentVMThreadNode.writeCurrentVMThread(isolateThread);
return true;
}
}
if (SubstrateOptions.MultiThreaded.getValue() && tryEnterIsolateViaThreadRegister(context)) {
return true;
}

/* Try to determine the isolate via the heap base register. */
if (SubstrateOptions.SpawnIsolates.getValue()) {
/*
* Set the heap base register to null so that we don't execute this code more than once
* if we trigger a recursive segfault.
*/
CEntryPointSnippets.setHeapBase(WordFactory.nullPointer());
return SubstrateOptions.SpawnIsolates.getValue() && tryEnterIsolateViaHeapBaseRegister(context);
}

@Uninterruptible(reason = "Thread state not set up yet.")
@NeverInline("Prevent register writes from floating")
private static boolean tryEnterIsolateViaThreadRegister(RegisterDumper.Context context) {
/*
* Try to determine the isolate via the thread register. Set the thread register to null so
* that we don't execute this code more than once if we trigger a recursive segfault.
*/
WriteCurrentVMThreadNode.writeCurrentVMThread(WordFactory.nullPointer());

isolate = (Isolate) RegisterDumper.singleton().getHeapBase(context);
IsolateThread isolateThread = (IsolateThread) RegisterDumper.singleton().getThreadPointer(context);
if (isolateThread.isNonNull()) {
Isolate isolate = VMThreads.IsolateTL.get(isolateThread);
if (isValid(isolate)) {
int error = CEntryPointSnippets.enterAttachFromCrashHandler(isolate);
return error == CEntryPointErrors.NO_ERROR;
if (SubstrateOptions.SpawnIsolates.getValue()) {
CEntryPointSnippets.setHeapBase(isolate);
}

WriteCurrentVMThreadNode.writeCurrentVMThread(isolateThread);
return true;
}
}
return false;
}

@Uninterruptible(reason = "Thread state not set up yet.")
@NeverInline("Prevent register writes from floating")
private static boolean tryEnterIsolateViaHeapBaseRegister(RegisterDumper.Context context) {
/*
* Set the heap base register to null so that we don't execute this code more than once if
* we trigger a recursive segfault.
*/
CEntryPointSnippets.setHeapBase(WordFactory.nullPointer());

Isolate isolate = (Isolate) RegisterDumper.singleton().getHeapBase(context);
if (isValid(isolate)) {
int error = CEntryPointSnippets.enterAttachFromCrashHandler(isolate);
return error == CEntryPointErrors.NO_ERROR;
}
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,11 @@ protected Pointer allocateCodeMemory(long size) {
}

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

protected void makeCodeMemoryExecutableWritable(Pointer start, UnsignedWord size) {
int result = RuntimeCodeInfoAccess.makeCodeMemoryExecutableWritable((CodePointer) start, size);
VMError.guarantee(result == 0, "Failed to make code memory writable.");
RuntimeCodeInfoAccess.makeCodeMemoryExecutableWritable((CodePointer) start, size);
}

protected static void doInstallPrepared(SharedMethod method, CodeInfo codeInfo, SubstrateInstalledCode installedCode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
*/
package com.oracle.svm.core.code;

import java.util.EnumSet;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.UnmanagedMemory;
import org.graalvm.nativeimage.c.function.CodePointer;
Expand All @@ -46,6 +44,7 @@
import com.oracle.svm.core.heap.Heap;
import com.oracle.svm.core.heap.ObjectReferenceVisitor;
import com.oracle.svm.core.os.CommittedMemoryProvider;
import com.oracle.svm.core.os.VirtualMemoryProvider;
import com.oracle.svm.core.util.DuplicatedInNativeCode;
import com.oracle.svm.core.util.VMError;

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

public static int makeCodeMemoryExecutableReadOnly(CodePointer codeStart, UnsignedWord codeSize) {
return CommittedMemoryProvider.get().protect(codeStart, codeSize, EnumSet.of(CommittedMemoryProvider.Access.READ, CommittedMemoryProvider.Access.EXECUTE));
public static void makeCodeMemoryExecutableReadOnly(CodePointer codeStart, UnsignedWord codeSize) {
protectCodeMemory(codeStart, codeSize, VirtualMemoryProvider.Access.READ | VirtualMemoryProvider.Access.EXECUTE);
}

public static void makeCodeMemoryExecutableWritable(CodePointer start, UnsignedWord size) {
VMError.guarantee(RuntimeCodeCache.Options.WriteableCodeCache.getValue(), "memory must not be writable and executable at the same time unless we have a writable code cache");
protectCodeMemory(start, size, VirtualMemoryProvider.Access.READ | VirtualMemoryProvider.Access.WRITE | VirtualMemoryProvider.Access.EXECUTE);
}

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

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ private static RuntimeException checkDeoptimizedError0(Pointer sourceSp) {
throw VMError.shouldNotReachHere("Unable to retrieve Deoptimized frame");
}

@Uninterruptible(reason = "Prevent stack walks from seeing an inconsistent stack.")
private static void installDeoptimizedFrame(Pointer sourceSp, DeoptimizedFrame deoptimizedFrame) {
/*
* Replace the return address to the deoptimized method with a pointer to the deoptStub.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
import com.oracle.svm.core.headers.LibC;
import com.oracle.svm.core.heap.dump.HeapDumping;
import com.oracle.svm.core.jdk.JDKUtils;
import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicBoolean;
import com.oracle.svm.core.log.Log;
import com.oracle.svm.core.stack.StackOverflowCheck;
import com.oracle.svm.core.util.VMError;

/**
Expand All @@ -43,11 +43,6 @@
public class OutOfMemoryUtil {
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'.");

/**
* Guard to ensure heap dump on OOME is performed at most once.
*/
private static final AtomicBoolean HEAP_DUMPED = new AtomicBoolean(false);

@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Can't allocate when out of memory.")
public static OutOfMemoryError heapSizeExceeded() {
return reportOutOfMemoryError(OUT_OF_MEMORY_ERROR);
Expand All @@ -56,7 +51,18 @@ public static OutOfMemoryError heapSizeExceeded() {
@Uninterruptible(reason = "Not uninterruptible but it doesn't matter for the callers.", calleeMustBe = false)
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Can't allocate while out of memory.")
public static OutOfMemoryError reportOutOfMemoryError(OutOfMemoryError error) {
if (VMInspectionOptions.hasHeapDumpSupport() && SubstrateOptions.HeapDumpOnOutOfMemoryError.getValue() && HEAP_DUMPED.compareAndSet(false, true)) {
StackOverflowCheck.singleton().makeYellowZoneAvailable();
try {
reportOutOfMemoryError0(error);
} finally {
StackOverflowCheck.singleton().protectYellowZone();
}
throw error;
}

@Uninterruptible(reason = "Not uninterruptible but it doesn't matter for the callers.", calleeMustBe = false)
private static void reportOutOfMemoryError0(OutOfMemoryError error) {
if (VMInspectionOptions.hasHeapDumpSupport() && SubstrateOptions.HeapDumpOnOutOfMemoryError.getValue()) {
HeapDumping.singleton().dumpHeapOnOutOfMemoryError();
}

Expand All @@ -68,6 +74,5 @@ public static OutOfMemoryError reportOutOfMemoryError(OutOfMemoryError error) {
VMError.shouldNotReachHere("ExitOnOutOfMemoryError can only be used if the LibC support is present.");
}
}
throw error;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.oracle.svm.core.heap.Heap;
import com.oracle.svm.core.heap.RestrictHeapAccess;
import com.oracle.svm.core.heap.VMOperationInfos;
import com.oracle.svm.core.locks.VMMutex;
import com.oracle.svm.core.log.Log;
import com.oracle.svm.core.os.RawFileOperationSupport;
import com.oracle.svm.core.os.RawFileOperationSupport.FileCreationMode;
Expand All @@ -58,8 +59,10 @@
public class HeapDumpSupportImpl extends HeapDumping {
private final HeapDumpWriter writer;
private final HeapDumpOperation heapDumpOperation;
private final VMMutex outOfMemoryHeapDumpMutex = new VMMutex("outOfMemoryHeapDump");

private CCharPointer outOfMemoryHeapDumpPath;
private boolean outOfMemoryHeapDumpAttempted;

@Platforms(Platform.HOSTED_ONLY.class)
public HeapDumpSupportImpl(HeapDumpMetadata metadata) {
Expand All @@ -84,6 +87,23 @@ public void teardownDumpHeapOnOutOfMemoryError() {
@Override
@RestrictHeapAccess(access = NO_ALLOCATION, reason = "OutOfMemoryError heap dumping must not allocate.")
public void dumpHeapOnOutOfMemoryError() {
/*
* Try exactly once to create an out-of-memory heap dump. If another thread triggers an
* OutOfMemoryError while heap dumping is in progress, it needs to wait until heap dumping
* finishes.
*/
outOfMemoryHeapDumpMutex.lock();
try {
if (!outOfMemoryHeapDumpAttempted) {
dumpHeapOnOutOfMemoryError0();
outOfMemoryHeapDumpAttempted = true;
}
} finally {
outOfMemoryHeapDumpMutex.unlock();
}
}

private void dumpHeapOnOutOfMemoryError0() {
CCharPointer path = outOfMemoryHeapDumpPath;
if (path.isNull()) {
Log.log().string("OutOfMemoryError heap dumping failed because the heap dump file path could not be allocated.").newline();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,12 @@ public Log exception(Throwable t, int maxFrames) {
}

Throwable cur = t;
do {
int maxCauses = 25;
for (int i = 0; i < maxCauses && cur != null; i++) {
if (i > 0) {
newline().string("Caused by: ");
}

/*
* We do not want to call getMessage(), since it can be overridden by subclasses of
* Throwable. So we access the raw detailMessage directly from the field in Throwable.
Expand All @@ -668,23 +673,20 @@ public Log exception(Throwable t, int maxFrames) {
} else {
StackTraceElement[] stackTrace = JDKUtils.getRawStackTrace(cur);
if (stackTrace != null) {
int i;
for (i = 0; i < stackTrace.length && i < maxFrames; i++) {
StackTraceElement element = stackTrace[i];
int j;
for (j = 0; j < stackTrace.length && j < maxFrames; j++) {
StackTraceElement element = stackTrace[j];
if (element != null) {
printJavaFrame(element.getClassName(), element.getMethodName(), element.getFileName(), element.getLineNumber());
}
}
int remaining = stackTrace.length - i;
int remaining = stackTrace.length - j;
printRemainingFramesCount(remaining);
}
}

cur = JDKUtils.getRawCause(cur);
if (cur != null) {
newline().string("Caused by: ");
}
} while (cur != null);
}

return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_END;
import static org.graalvm.word.WordFactory.nullPointer;

import java.util.EnumSet;

import jdk.graal.compiler.api.replacements.Fold;
import org.graalvm.word.Pointer;
import org.graalvm.word.PointerBase;
Expand All @@ -41,11 +39,9 @@
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.Uninterruptible;
import com.oracle.svm.core.c.function.CEntryPointErrors;
import com.oracle.svm.core.code.RuntimeCodeCache;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.core.heap.Heap;
import com.oracle.svm.core.util.UnsignedUtils;
import com.oracle.svm.core.util.VMError;

public abstract class AbstractCommittedMemoryProvider implements CommittedMemoryProvider {
@Fold
Expand Down Expand Up @@ -85,24 +81,6 @@ protected static int protectSingleIsolateImageHeap() {
return CEntryPointErrors.NO_ERROR;
}

@Override
public int protect(PointerBase start, UnsignedWord nbytes, EnumSet<Access> accessFlags) {
int vmAccessBits = VirtualMemoryProvider.Access.NONE;
if (accessFlags.contains(CommittedMemoryProvider.Access.READ)) {
vmAccessBits |= VirtualMemoryProvider.Access.READ;
}
if (accessFlags.contains(CommittedMemoryProvider.Access.WRITE)) {
vmAccessBits |= VirtualMemoryProvider.Access.WRITE;
}
if (accessFlags.contains(CommittedMemoryProvider.Access.EXECUTE)) {
if ((vmAccessBits & VirtualMemoryProvider.Access.WRITE) != 0 && !RuntimeCodeCache.Options.WriteableCodeCache.getValue()) {
throw VMError.shouldNotReachHere("memory should never be writable and executable at the same time");
}
vmAccessBits |= VirtualMemoryProvider.Access.EXECUTE;
}
return VirtualMemoryProvider.get().protect(start, nbytes, vmAccessBits);
}

@Override
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public Pointer allocateAlignedChunk(UnsignedWord nbytes, UnsignedWord alignment) {
Expand Down
Loading

0 comments on commit af65204

Please sign in to comment.