From 40bc2eccef6cc63fc45e6652896e741b5997a47c Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 24 Jun 2021 12:23:58 +0200 Subject: [PATCH 01/28] Print heap base as part of diagnostics. --- .../src/com/oracle/svm/core/genscavenge/HeapImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 0433f7a41549..7aea69c6dd4c 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 @@ -29,6 +29,7 @@ import java.util.List; import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.nodes.gc.BarrierSet; import org.graalvm.compiler.word.Word; @@ -58,6 +59,7 @@ import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.heap.PhysicalMemory; +import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.heap.ReferenceHandlerThreadSupport; import com.oracle.svm.core.heap.ReferenceInternals; import com.oracle.svm.core.heap.RuntimeCodeInfoGCSupport; @@ -68,6 +70,7 @@ import com.oracle.svm.core.nodes.CFunctionEpilogueNode; import com.oracle.svm.core.nodes.CFunctionPrologueNode; import com.oracle.svm.core.os.CommittedMemoryProvider; +import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.thread.JavaThreads; import com.oracle.svm.core.thread.ThreadStatus; import com.oracle.svm.core.thread.VMOperation; @@ -594,6 +597,9 @@ public void invokeWithoutAllocation(Log log) { log.string("[Heap settings and statistics: ").indent(true); log.string("Supports isolates: ").bool(SubstrateOptions.SpawnIsolates.getValue()).newline(); + if (ImageSingletons.lookup(CompressEncoding.class).hasBase()) { + log.string("Heap base: ").hex(KnownIntrinsics.heapBase()).newline(); + } log.string("Object reference size: ").signed(ConfigurationValues.getObjectLayout().getReferenceSize()).newline(); GCAccounting accounting = gc.getAccounting(); From b45921f1ed9cff75e0359315024fcf0d0010e411 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 24 Jun 2021 12:29:20 +0200 Subject: [PATCH 02/28] Use the state of the initial error if an error happens while printing diagnostics. --- .../oracle/svm/core/SubstrateDiagnostics.java | 92 +++++++++++++++---- 1 file changed, 72 insertions(+), 20 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index b9df27c46fbd..8d688641021f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -64,6 +64,8 @@ import com.oracle.svm.core.threadlocal.VMThreadLocalInfos; import com.oracle.svm.core.util.Counter; +import jdk.vm.ci.code.CodeUtil; + public class SubstrateDiagnostics { private static final int REGISTERS = 1; private static final int FRAME_ANCHORS = REGISTERS << 1; @@ -77,15 +79,13 @@ public class SubstrateDiagnostics { private static final int CURRENT_THREAD_RAW_STACKTRACE = COUNTERS << 1; private static final int CURRENT_THREAD_DECODED_STACKTRACE = CURRENT_THREAD_RAW_STACKTRACE << 1; private static final int OTHER_STACK_TRACES = CURRENT_THREAD_DECODED_STACKTRACE << 1; + private static final int NUM_NAMED_SECTIONS = CodeUtil.log2(OTHER_STACK_TRACES << 1); private static final Stage0StackFramePrintVisitor[] PRINT_VISITORS = new Stage0StackFramePrintVisitor[]{Stage0StackFramePrintVisitor.SINGLETON, Stage1StackFramePrintVisitor.SINGLETON, StackFramePrintVisitor.SINGLETON}; - private static final AtomicWord diagnosticThread = new AtomicWord<>(); private static final FastThreadLocalBytes threadOnlyAttachedForCrashHandler = FastThreadLocalFactory.createBytes(() -> 1); - - private static volatile int diagnosticSections = 0; - private static volatile int diagnosticThunkIndex = 0; + private static final PrintDiagnosticsState state = new PrintDiagnosticsState(); @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void setOnlyAttachedForCrashHandler(IsolateThread thread) { @@ -97,7 +97,15 @@ private static boolean isThreadOnlyAttachedForCrashHandler(IsolateThread thread) } public static boolean isInProgress() { - return diagnosticThread.get().isNonNull(); + return state.diagnosticThread.get().isNonNull(); + } + + public static boolean isInProgressByCurrentThread() { + return state.diagnosticThread.get() == CurrentIsolate.getCurrentThread(); + } + + public static int getSectionCount() { + return NUM_NAMED_SECTIONS + DiagnosticThunkRegister.getSingleton().size(); } /** Prints extensive diagnostic information to the given Log. */ @@ -112,14 +120,26 @@ public static void print(Log log, Pointer sp, CodePointer ip) { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") static void print(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context context) { log.newline(); - IsolateThread currentThread = CurrentIsolate.getCurrentThread(); - if (!diagnosticThread.compareAndSet(WordFactory.nullPointer(), currentThread) && diagnosticThread.get().notEqual(currentThread)) { + // Save the state of the initial error so that this state is consistently used, even if + // further errors occur while printing diagnostics. + if (!state.trySet(log, sp, ip, context) && !isInProgressByCurrentThread()) { log.string("Error: printDiagnostics already in progress by another thread.").newline(); log.newline(); return; } - if (diagnosticSections > 0) { + printDiagnosticsForCurrentState(); + } + + private static void printDiagnosticsForCurrentState() { + assert isInProgressByCurrentThread(); + + Log log = state.log; + Pointer sp = state.sp; + CodePointer ip = state.ip; + IsolateThread currentThread = CurrentIsolate.getCurrentThread(); + + if (state.diagnosticSections > 0) { log.newline(); log.string("An error occurred while printing diagnostics. The remaining part of this section will be skipped.").newline(); log.resetIndentation(); @@ -129,7 +149,7 @@ static void print(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context co // printed earlier. if (shouldPrint(REGISTERS)) { try { - dumpRegisters(log, context); + dumpRegisters(log, state.context); } catch (Exception e) { dumpException(log, "dumpRegisters", e); } @@ -209,10 +229,7 @@ static void print(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context co if (shouldPrint(OTHER_STACK_TRACES)) { if (VMOperation.isInProgressAtSafepoint()) { - /* - * Only used for diagnostics - iterate all threads without locking the threads - * mutex. - */ + // Iterate all threads without locking the threads. for (IsolateThread vmThread = VMThreads.firstThreadUnsafe(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) { if (vmThread == currentThread) { continue; @@ -227,23 +244,21 @@ static void print(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context co } int numDiagnosticThunks = DiagnosticThunkRegister.getSingleton().size(); - while (diagnosticThunkIndex < numDiagnosticThunks) { + while (state.diagnosticThunkIndex < numDiagnosticThunks) { try { - int index = diagnosticThunkIndex++; + int index = state.diagnosticThunkIndex++; DiagnosticThunkRegister.getSingleton().callDiagnosticThunk(log, index); } catch (Exception e) { dumpException(log, "callThunks", e); } } - diagnosticThunkIndex = 0; - diagnosticSections = 0; - diagnosticThread.set(WordFactory.nullPointer()); + state.clear(); } private static boolean shouldPrint(int sectionBit) { - if ((diagnosticSections & sectionBit) == 0) { - diagnosticSections |= sectionBit; + if ((state.diagnosticSections & sectionBit) == 0) { + state.diagnosticSections |= sectionBit; return true; } return false; @@ -440,6 +455,43 @@ private static void dumpStacktrace(Log log, IsolateThread vmThread) { log.indent(false); } + private static class PrintDiagnosticsState { + AtomicWord diagnosticThread = new AtomicWord<>(); + volatile int diagnosticSections; + volatile int diagnosticThunkIndex; + + Log log; + Pointer sp; + CodePointer ip; + RegisterDumper.Context context; + + @SuppressWarnings("hiding") + public boolean trySet(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context context) { + if (diagnosticThread.compareAndSet(WordFactory.nullPointer(), CurrentIsolate.getCurrentThread())) { + assert diagnosticSections == 0; + assert diagnosticThunkIndex == 0; + this.log = log; + this.sp = sp; + this.ip = ip; + this.context = context; + return true; + } + return false; + } + + public void clear() { + log = null; + sp = WordFactory.nullPointer(); + ip = WordFactory.nullPointer(); + context = WordFactory.nullPointer(); + + diagnosticThunkIndex = 0; + diagnosticSections = 0; + + diagnosticThread.set(WordFactory.nullPointer()); + } + } + /** The functional interface for a "thunk" that does not allocate. */ @FunctionalInterface public interface DiagnosticThunk { From 2c2c40df8bb4f124b35297a73155bad1344eca2f Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 24 Jun 2021 12:30:12 +0200 Subject: [PATCH 03/28] Allow implicit exceptions while printing diagnostics. --- .../src/com/oracle/svm/core/snippets/ImplicitExceptions.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java index ca5e2559aeb2..8867464e8ef4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java @@ -28,6 +28,7 @@ import java.lang.reflect.GenericSignatureFormatError; +import com.oracle.svm.core.SubstrateDiagnostics; import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.jdk.InternalVMMethod; import com.oracle.svm.core.jdk.StackTraceUtils; @@ -128,7 +129,7 @@ public static void deactivateImplicitExceptionsAreFatal() { } private static void vmErrorIfImplicitExceptionsAreFatal() { - if (implicitExceptionsAreFatal.get() > 0 || ExceptionUnwind.exceptionsAreFatal()) { + if ((implicitExceptionsAreFatal.get() > 0 || ExceptionUnwind.exceptionsAreFatal()) && !SubstrateDiagnostics.isInProgressByCurrentThread()) { throw VMError.shouldNotReachHere("Implicit exception thrown in code where such exceptions are fatal errors"); } } From 427d3ec597db402949e70cc73e57647861783670 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 24 Jun 2021 14:34:17 +0200 Subject: [PATCH 04/28] When printing diagnostics, print a hexdump of a short piece of the machine code instructions. --- .../com/oracle/svm/core/SubstrateDiagnostics.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 8d688641021f..e5436b977b01 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -43,6 +43,7 @@ import com.oracle.svm.core.code.CodeInfoAccess; import com.oracle.svm.core.code.CodeInfoTable; import com.oracle.svm.core.code.UntetheredCodeInfo; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.deopt.DeoptimizationSupport; import com.oracle.svm.core.deopt.DeoptimizedFrame; import com.oracle.svm.core.deopt.Deoptimizer; @@ -79,7 +80,8 @@ public class SubstrateDiagnostics { private static final int CURRENT_THREAD_RAW_STACKTRACE = COUNTERS << 1; private static final int CURRENT_THREAD_DECODED_STACKTRACE = CURRENT_THREAD_RAW_STACKTRACE << 1; private static final int OTHER_STACK_TRACES = CURRENT_THREAD_DECODED_STACKTRACE << 1; - private static final int NUM_NAMED_SECTIONS = CodeUtil.log2(OTHER_STACK_TRACES << 1); + private static final int INSTRUCTIONS = OTHER_STACK_TRACES << 1; + private static final int NUM_NAMED_SECTIONS = CodeUtil.log2(INSTRUCTIONS << 1); private static final Stage0StackFramePrintVisitor[] PRINT_VISITORS = new Stage0StackFramePrintVisitor[]{Stage0StackFramePrintVisitor.SINGLETON, Stage1StackFramePrintVisitor.SINGLETON, StackFramePrintVisitor.SINGLETON}; @@ -243,6 +245,10 @@ private static void printDiagnosticsForCurrentState() { } } + if (shouldPrint(INSTRUCTIONS)) { + dumpInstructions(log, ip); + } + int numDiagnosticThunks = DiagnosticThunkRegister.getSingleton().size(); while (state.diagnosticThunkIndex < numDiagnosticThunks) { try { @@ -455,6 +461,13 @@ private static void dumpStacktrace(Log log, IsolateThread vmThread) { log.indent(false); } + private static void dumpInstructions(Log log, CodePointer ip) { + log.string("Instructions (ip=").hex(ip).string(")").newline(); + log.indent(true); + log.hexdump(((Pointer) ip).subtract(32), 1, 64); + log.indent(false); + } + private static class PrintDiagnosticsState { AtomicWord diagnosticThread = new AtomicWord<>(); volatile int diagnosticSections; From ddef9997e1144c3a57759ceeab31cc9a36739aa0 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 24 Jun 2021 14:37:12 +0200 Subject: [PATCH 05/28] Print more information about signals. --- .../posix/PosixSubstrateSegfaultHandler.java | 23 +++++++++--- .../oracle/svm/core/posix/headers/Signal.java | 14 ++++++- .../WindowsSubstrateSegfaultHandler.java | 37 ++++++++++++++++++- .../core/windows/headers/ErrHandlingAPI.java | 17 ++++++++- .../svm/core/SubstrateSegfaultHandler.java | 10 +++-- .../core/threadlocal/VMThreadLocalInfos.java | 2 +- 6 files changed, 91 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java index 3f05415babf9..86b6c51a35b7 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java @@ -30,6 +30,7 @@ import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.struct.SizeOf; import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.word.PointerBase; import org.graalvm.word.WordFactory; import com.oracle.svm.core.SubstrateSegfaultHandler; @@ -40,6 +41,7 @@ import com.oracle.svm.core.c.function.CEntryPointOptions.NoEpilogue; import com.oracle.svm.core.c.function.CEntryPointOptions.NoPrologue; import com.oracle.svm.core.c.function.CEntryPointOptions.Publish; +import com.oracle.svm.core.log.Log; import com.oracle.svm.core.os.MemoryProtectionKeyProvider; import com.oracle.svm.core.posix.headers.LibC; import com.oracle.svm.core.posix.headers.Signal; @@ -68,15 +70,26 @@ private static void dispatch(@SuppressWarnings("unused") int signalNumber, @Supp } if (tryEnterIsolate(uContext)) { - if (MemoryProtectionKeyProvider.isAvailable()) { - MemoryProtectionKeyProvider.singleton().printSignalInfo(sigInfo); - } - - dump(uContext); + dump(sigInfo, uContext); throw VMError.shouldNotReachHere(); } } + @Override + protected void printSignalInfo(Log log, PointerBase signalInfo) { + if (MemoryProtectionKeyProvider.isAvailable()) { + MemoryProtectionKeyProvider.singleton().printSignalInfo(signalInfo); + } else { + siginfo_t sigInfo = (siginfo_t) signalInfo; + log.string("siginfo: si_signo: ").signed(sigInfo.si_signo()).string(", si_code: ").signed(sigInfo.si_code()); + if (sigInfo.si_errno() != 0) { + log.string(", si_errno: ").signed(sigInfo.si_errno()); + } + log.string(", si_addr: ").signed(sigInfo.si_addr()); + log.newline(); + } + } + /** The address of the signal handler for signals handled by Java code, above. */ private static final CEntryPointLiteral advancedSignalDispatcher = CEntryPointLiteral.create(PosixSubstrateSegfaultHandler.class, "dispatch", int.class, siginfo_t.class, ucontext_t.class); diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java index 66a9f1fa8d65..7afc4359a386 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java @@ -38,6 +38,7 @@ import org.graalvm.nativeimage.c.struct.CFieldOffset; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.nativeimage.c.type.VoidPointer; import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.PointerBase; @@ -91,8 +92,19 @@ public interface SignalDispatcher extends CFunctionPointer { @CFunction public static native int raise(int signum); - @CStruct + @CStruct(isIncomplete = true) public interface siginfo_t extends PointerBase { + @CField + int si_signo(); + + @CField + int si_errno(); + + @CField + int si_code(); + + @CField + VoidPointer si_addr(); } @Platforms(Platform.LINUX.class) diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java index e38b22c83f5f..1db56dc1ea6d 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java @@ -26,12 +26,15 @@ import static com.oracle.svm.core.annotate.RestrictHeapAccess.Access.NO_ALLOCATION; import static com.oracle.svm.core.annotate.RestrictHeapAccess.Access.NO_HEAP_ACCESS; +import static com.oracle.svm.core.windows.headers.ErrHandlingAPI.EXCEPTION_ACCESS_VIOLATION; +import static com.oracle.svm.core.windows.headers.ErrHandlingAPI.EXCEPTION_IN_PAGE_ERROR; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CEntryPoint; import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.word.PointerBase; import com.oracle.svm.core.SubstrateSegfaultHandler; import com.oracle.svm.core.annotate.AutomaticFeature; @@ -42,6 +45,7 @@ import com.oracle.svm.core.c.function.CEntryPointOptions.NoPrologue; import com.oracle.svm.core.c.function.CEntryPointOptions.NotIncludedAutomatically; import com.oracle.svm.core.c.function.CEntryPointOptions.Publish; +import com.oracle.svm.core.log.Log; import com.oracle.svm.core.util.VMError; import com.oracle.svm.core.windows.headers.ErrHandlingAPI; @@ -93,13 +97,44 @@ private static int handler(ErrHandlingAPI.EXCEPTION_POINTERS exceptionInfo) { ErrHandlingAPI.CONTEXT context = exceptionInfo.ContextRecord(); if (tryEnterIsolate(context)) { - dump(context); + dump(exceptionInfo, context); throw shouldNotReachHere(); } /* Nothing we can do. */ return ErrHandlingAPI.EXCEPTION_CONTINUE_SEARCH(); } + @Override + protected void printSignalInfo(Log log, PointerBase signalInfo) { + ErrHandlingAPI.EXCEPTION_POINTERS exceptionInfo = (ErrHandlingAPI.EXCEPTION_POINTERS) signalInfo; + ErrHandlingAPI.EXCEPTION_RECORD exceptionRecord = exceptionInfo.ExceptionRecord(); + + int exceptionCode = exceptionRecord.ExceptionCode(); + log.string("siginfo: ExceptionCode: ").signed(exceptionCode); + + int numParameters = exceptionRecord.NumberParameters(); + if ((exceptionCode == EXCEPTION_ACCESS_VIOLATION() || exceptionCode == EXCEPTION_IN_PAGE_ERROR()) && numParameters >= 2) { + long exParam0 = exceptionRecord.ExceptionInformation(0).read(); + if (exParam0 == 0) { + log.string(", reading address"); + } else if (exParam0 == 1) { + log.string(", writing address"); + } else if (exParam0 == 8) { + log.string(", data execution prevention violation at address"); + } else { + log.string(", ExceptionInformation=").zhex(exParam0); + } + log.string(" ").zhex(exceptionRecord.ExceptionInformation(1).read()); + } else { + if (numParameters > 0) { + log.string(", ExceptionInformation="); + for (int i = 0; i < numParameters; i++) { + log.string(" ").zhex(exceptionRecord.ExceptionInformation(i).read()); + } + } + } + } + @Uninterruptible(reason = "Called from uninterruptible code.") @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in segfault handler.", overridesCallers = true) private static RuntimeException shouldNotReachHere() { diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java index 1e12e0cf5219..9e2e319e1f13 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java @@ -31,7 +31,10 @@ import org.graalvm.nativeimage.c.function.CFunction; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.struct.CField; +import org.graalvm.nativeimage.c.struct.CFieldAddress; import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.nativeimage.c.type.CLongPointer; +import org.graalvm.nativeimage.c.type.VoidPointer; import org.graalvm.word.PointerBase; import com.oracle.svm.core.RegisterDumper; @@ -62,15 +65,27 @@ public interface EXCEPTION_POINTERS extends PointerBase { } /** Contains a description of the exception. */ - @CStruct + @CStruct(isIncomplete = true) public interface EXCEPTION_RECORD extends PointerBase { @CField int ExceptionCode(); + + @CField + VoidPointer ExceptionAddress(); + + @CField + int NumberParameters(); + + @CFieldAddress + CLongPointer ExceptionInformation(int index); } @CConstant public static native int EXCEPTION_ACCESS_VIOLATION(); + @CConstant + public static native int EXCEPTION_IN_PAGE_ERROR(); + /** Contains processor-specific register data. */ @CStruct public interface CONTEXT extends RegisterDumper.Context { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java index 90a983d12f3d..41c9cb45cd89 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java @@ -97,6 +97,8 @@ public static class Options { /** Installs the platform dependent segfault handler. */ protected abstract void install(); + protected abstract void printSignalInfo(Log log, PointerBase signalInfo); + /** Called from the platform dependent segfault handler to enter the isolate. */ @Uninterruptible(reason = "Called from uninterruptible code.") @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in segfault handler.", overridesCallers = true) @@ -134,14 +136,14 @@ protected static boolean tryEnterIsolate(RegisterDumper.Context context) { /** Called from the platform dependent segfault handler to print diagnostics. */ @Uninterruptible(reason = "Must be uninterruptible until we get immune to safepoints.", calleeMustBe = false) @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in segfault handler.", overridesCallers = true) - protected static void dump(RegisterDumper.Context context) { + protected static void dump(PointerBase signalInfo, RegisterDumper.Context context) { VMThreads.StatusSupport.setStatusIgnoreSafepoints(); StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError(); - dumpInterruptibly(context); + dumpInterruptibly(signalInfo, context); } - private static void dumpInterruptibly(RegisterDumper.Context context) { + private static void dumpInterruptibly(PointerBase signalInfo, RegisterDumper.Context context) { PointerBase callerIP = RegisterDumper.singleton().getIP(context); LogHandler logHandler = ImageSingletons.lookup(LogHandler.class); String msg = "[ [ SubstrateSegfaultHandler caught a segfault. ] ]"; @@ -150,6 +152,8 @@ private static void dumpInterruptibly(RegisterDumper.Context context) { log.newline(); log.string(msg).newline(); + ImageSingletons.lookup(SubstrateSegfaultHandler.class).printSignalInfo(log, signalInfo); + PointerBase sp = RegisterDumper.singleton().getSP(context); PointerBase ip = RegisterDumper.singleton().getIP(context); SubstrateDiagnostics.print(log, (Pointer) sp, (CodePointer) ip, context); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java index a27102187f5a..467a94e4f1ad 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java @@ -29,11 +29,11 @@ import org.graalvm.compiler.word.ObjectAccess; import org.graalvm.compiler.word.Word; -import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.word.Pointer; import org.graalvm.word.WordBase; import org.graalvm.word.WordFactory; From 54cb5b238dc917ece8ed2b2bd28e8febfe9324d3 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 24 Jun 2021 14:58:12 +0200 Subject: [PATCH 06/28] Minor output formatting fix. --- .../src/com/oracle/svm/core/genscavenge/HeapImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7aea69c6dd4c..9fb681bcb846 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 @@ -268,7 +268,7 @@ void report(Log log) { } Log report(Log log, boolean traceHeapChunks) { - log.newline().string("[Heap:").indent(true); + log.string("[Heap:").indent(true); getYoungGeneration().report(log, traceHeapChunks).newline(); getOldGeneration().report(log, traceHeapChunks).newline(); getChunkProvider().report(log, traceHeapChunks); From 9fcd79de443fa0dae29ff2cbec710bd25880630a Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 24 Jun 2021 16:12:48 +0200 Subject: [PATCH 07/28] Minor renaming. --- .../src/com/oracle/svm/core/SubstrateDiagnostics.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index e5436b977b01..eacde2756dea 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -43,7 +43,6 @@ import com.oracle.svm.core.code.CodeInfoAccess; import com.oracle.svm.core.code.CodeInfoTable; import com.oracle.svm.core.code.UntetheredCodeInfo; -import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.deopt.DeoptimizationSupport; import com.oracle.svm.core.deopt.DeoptimizedFrame; import com.oracle.svm.core.deopt.Deoptimizer; @@ -106,7 +105,12 @@ public static boolean isInProgressByCurrentThread() { return state.diagnosticThread.get() == CurrentIsolate.getCurrentThread(); } - public static int getSectionCount() { + /** + * The segfault handler will invoke {@link #print} recursively if a fatal error happens while + * printing diagnostics. The value returned by this method can be used to limit the maximum + * recursion depth if necessary. + */ + public static int maxRetries() { return NUM_NAMED_SECTIONS + DiagnosticThunkRegister.getSingleton().size(); } From 436bc88b7fa253775205c7002a531e72eb9399a5 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 24 Jun 2021 17:51:09 +0200 Subject: [PATCH 08/28] Added some stack information to VM diagnostics. --- .../darwin/DarwinStackOverflowSupport.java | 5 +++ .../linux/LinuxStackOverflowSupport.java | 20 ++++++++-- .../windows/WindowsStackOverflowSupport.java | 20 ++++++++++ .../oracle/svm/core/SubstrateDiagnostics.java | 40 ++++++++++++++----- .../snippets/StackOverflowCheckImpl.java | 13 +++++- .../src/com/oracle/svm/core/log/Log.java | 12 ++++++ .../src/com/oracle/svm/core/log/RealLog.java | 5 +++ .../svm/core/stack/StackOverflowCheck.java | 5 +++ .../com/oracle/svm/core/thread/VMThreads.java | 6 +++ 9 files changed, 111 insertions(+), 15 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinStackOverflowSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinStackOverflowSupport.java index 92869f211b24..b214a4c02399 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinStackOverflowSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinStackOverflowSupport.java @@ -35,6 +35,11 @@ import com.oracle.svm.core.stack.StackOverflowCheck; class DarwinStackOverflowSupport implements StackOverflowCheck.OSSupport { + @Override + public UnsignedWord lookupStackBase() { + Pthread.pthread_t self = Pthread.pthread_self(); + return DarwinPthread.pthread_get_stackaddr_np(self); + } @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") @Override diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java index d4b36f26f27e..f7a80d191252 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java @@ -37,17 +37,29 @@ import com.oracle.svm.core.stack.StackOverflowCheck; class LinuxStackOverflowSupport implements StackOverflowCheck.OSSupport { - - @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") @Override - public UnsignedWord lookupStackEnd() { + public UnsignedWord lookupStackBase() { Pthread.pthread_attr_t attr = StackValue.get(Pthread.pthread_attr_t.class); PosixUtils.checkStatusIs0(Pthread.pthread_getattr_np(Pthread.pthread_self(), attr), "LinuxStackOverflowSupport: pthread_getattr_np"); + UnsignedWord result = lookupStackStart(attr); + PosixUtils.checkStatusIs0(Pthread.pthread_attr_destroy(attr), "LinuxStackOverflowSupport: pthread_attr_destroy"); + return result; + } + private static UnsignedWord lookupStackStart(Pthread.pthread_attr_t attr) { WordPointer stackaddrPtr = StackValue.get(WordPointer.class); WordPointer stacksizePtr = StackValue.get(WordPointer.class); PosixUtils.checkStatusIs0(Pthread.pthread_attr_getstack(attr, stackaddrPtr, stacksizePtr), "LinuxStackOverflowSupport: pthread_attr_getstack"); - UnsignedWord stackaddr = stackaddrPtr.read(); + return stackaddrPtr.read(); + } + + @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") + @Override + public UnsignedWord lookupStackEnd() { + Pthread.pthread_attr_t attr = StackValue.get(Pthread.pthread_attr_t.class); + PosixUtils.checkStatusIs0(Pthread.pthread_getattr_np(Pthread.pthread_self(), attr), "LinuxStackOverflowSupport: pthread_getattr_np"); + + UnsignedWord stackaddr = lookupStackStart(attr); /* * The block of memory returned by pthread_attr_getstack() includes guard pages where diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsStackOverflowSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsStackOverflowSupport.java index 3ef8834b04b9..cf305f85336c 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsStackOverflowSupport.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsStackOverflowSupport.java @@ -32,6 +32,7 @@ import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.annotate.Uninterruptible; @@ -40,6 +41,25 @@ @Platforms({Platform.WINDOWS.class}) class WindowsStackOverflowSupport implements StackOverflowCheck.OSSupport { + @Override + public UnsignedWord lookupStackBase() { + int sizeOfMInfo = SizeOf.get(MemoryAPI.MEMORY_BASIC_INFORMATION.class); + MemoryAPI.MEMORY_BASIC_INFORMATION minfo = StackValue.get(sizeOfMInfo); + MemoryAPI.VirtualQuery(minfo, minfo, WordFactory.unsigned(sizeOfMInfo)); + Pointer stackBottom = (Pointer) minfo.AllocationBase(); + UnsignedWord stackSize = minfo.RegionSize(); + + // Add up the sizes of all the regions with the same AllocationBase. + while (true) { + MemoryAPI.VirtualQuery(stackBottom.add(stackSize), minfo, WordFactory.unsigned(sizeOfMInfo)); + if (stackBottom.equal(minfo.AllocationBase())) { + stackSize = stackSize.add(minfo.RegionSize()); + } else { + break; + } + } + return stackBottom.add(stackSize); + } @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index eacde2756dea..a882e3c254ef 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -71,8 +71,9 @@ public class SubstrateDiagnostics { private static final int FRAME_ANCHORS = REGISTERS << 1; private static final int DEOPT_STUB_POINTERS = FRAME_ANCHORS << 1; private static final int TOP_FRAME = DEOPT_STUB_POINTERS << 1; - private static final int THREADS = TOP_FRAME << 1; - private static final int THREAD_STATES = THREADS << 1; + private static final int THREADS_FULL = TOP_FRAME << 1; + private static final int THREADS_REDUCED = TOP_FRAME << 1; + private static final int THREAD_STATES = THREADS_REDUCED << 1; private static final int VM_OPERATIONS = THREAD_STATES << 1; private static final int RUNTIME_COMPILATIONS = VM_OPERATIONS << 1; private static final int COUNTERS = RUNTIME_COMPILATIONS << 1; @@ -185,9 +186,18 @@ private static void printDiagnosticsForCurrentState() { } } - if (shouldPrint(THREADS)) { + if (shouldPrint(THREADS_FULL)) { try { - dumpVMThreads(log); + dumpVMThreads(log, true); + skip(THREADS_REDUCED); + } catch (Exception e) { + dumpException(log, "dumpVMThreads", e); + } + } + + if (shouldPrint(THREADS_REDUCED)) { + try { + dumpVMThreads(log, false); } catch (Exception e) { dumpException(log, "dumpVMThreads", e); } @@ -274,6 +284,10 @@ private static boolean shouldPrint(int sectionBit) { return false; } + private static void skip(int sectionBit) { + state.diagnosticSections |= sectionBit; + } + private static void dumpException(Log log, String context, Exception e) { log.newline().string("[!!! Exception during ").string(context).string(": ").string(e.getClass().getName()).string("]").newline(); } @@ -365,13 +379,21 @@ private static long getTotalFrameSize0(CodePointer ip, CodeInfo codeInfo) { return CodeInfoAccess.lookupTotalFrameSize(codeInfo, CodeInfoAccess.relativeIP(codeInfo, ip)); } - private static void dumpVMThreads(Log log) { - log.string("VMThreads info:").newline(); + private static void dumpVMThreads(Log log, String prefix, boolean accessThreadObject) { + log.string(prefix).string(" VMThreads info:").newline(); log.indent(true); /* Only used for diagnostics - iterate all threads without locking the threads mutex. */ - for (IsolateThread vmThread = VMThreads.firstThreadUnsafe(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) { - log.string("VMThread ").zhex(vmThread.rawValue()).spaces(2).string(VMThreads.StatusSupport.getStatusString(vmThread)) - .spaces(2).object(JavaThreads.fromVMThread(vmThread)).newline(); + for (IsolateThread thread = VMThreads.firstThreadUnsafe(); thread.isNonNull(); thread = VMThreads.nextThread(thread)) { + log.zhex(thread.rawValue()).string(VMThreads.StatusSupport.getStatusString(thread)); + if (accessThreadObject) { + Thread threadObj = JavaThreads.fromVMThread(thread); + log.string(" \"").string(threadObj.getName()).string("\" - ").object(threadObj).string(")"); + if (threadObj.isDaemon()) { + log.string(" daemon "); + } + } + log.string(", stack(").zhex(VMThreads.StackEnd.get(thread)).string(",").zhex(VMThreads.StackBase.get(thread)).string(")"); + log.newline(); } log.indent(false); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java index fe9c54efa999..5e6e4737ca1e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java @@ -85,6 +85,7 @@ import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.stack.StackOverflowCheck; import com.oracle.svm.core.thread.ThreadingSupportImpl; +import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.threadlocal.FastThreadLocal; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.FastThreadLocalInt; @@ -94,7 +95,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; final class StackOverflowCheckImpl implements StackOverflowCheck { - + // The stack boundary for the stack overflow check static final FastThreadLocalWord stackBoundaryTL = FastThreadLocalFactory.createWord().setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); /** @@ -126,7 +127,15 @@ public void initialize(IsolateThread thread) { /* * Get the real physical end of the stack. Everything past this point is memory-protected. */ - UnsignedWord stackEnd = ImageSingletons.lookup(StackOverflowCheck.OSSupport.class).lookupStackEnd(); + OSSupport osSupport = ImageSingletons.lookup(StackOverflowCheck.OSSupport.class); + UnsignedWord stackBase = osSupport.lookupStackBase(); + UnsignedWord stackEnd = osSupport.lookupStackEnd(); + + // TEMP (chaeubl): this should be moved somewhere else... - also OSSupport should be named + // differently. + // Initialize the stack base and the stack end. + VMThreads.StackBase.set(thread, stackBase); + VMThreads.StackEnd.set(thread, stackEnd); /* * Set up our yellow and red zones. That memory is not memory protected, it is a soft limit diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java index 2ad4e2c60d74..ec08a2f1791c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java @@ -271,6 +271,13 @@ public final Log string(byte[] value) { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, mayBeInlined = true, reason = "Must not allocate when logging.") public abstract Log hex(long value); + /** + * Prints the value, treated as an unsigned value, in hexadecimal format zero filled to + * 16-digits. + */ + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, mayBeInlined = true, reason = "Must not allocate when logging.") + public abstract Log zhex(WordBase value); + /** * Prints the value, treated as an unsigned value, in hexadecimal format zero filled to * 16-digits. @@ -549,6 +556,11 @@ public Log autoflush(boolean onOrOff) { return this; } + @Override + public Log zhex(WordBase value) { + return this; + } + @Override public Log zhex(long value) { return this; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java index eff09c2e6f64..11864341fe9a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java @@ -442,6 +442,11 @@ private void rawString(char[] value) { rawBytes(value, 0, value.length); } + @Override + public Log zhex(WordBase value) { + return zhex(value.rawValue()); + } + @NeverInline("Logging is always slow-path code") @Override public Log zhex(long value) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java index cac98ff4ec9e..fd52965ad4ed 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java @@ -29,6 +29,7 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.option.HostedOptionKey; @@ -87,6 +88,10 @@ class Options { * platforms use this direction. */ interface OSSupport { + default UnsignedWord lookupStackBase() { + return WordFactory.zero(); + } + @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") UnsignedWord lookupStackEnd(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index d79be8c0208f..e7955d006cfd 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -139,6 +139,12 @@ public static VMThreads singleton() { private static final FastThreadLocalWord OSThreadIdTL = FastThreadLocalFactory.createWord(); protected static final FastThreadLocalWord OSThreadHandleTL = FastThreadLocalFactory.createWord(); public static final FastThreadLocalWord IsolateTL = FastThreadLocalFactory.createWord(); + public static final FastThreadLocalWord StackBase = FastThreadLocalFactory.createWord(); + /** + * The end of the stack. Note that this value does not necessarily match the value that is used + * for the stack overflow check. + */ + public static final FastThreadLocalWord StackEnd = FastThreadLocalFactory.createWord(); private static final int STATE_UNINITIALIZED = 1; private static final int STATE_INITIALIZING = 2; From fe6241531d11234b09a532d8e58da5ffbe2f99cf Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 29 Jun 2021 13:42:53 +0200 Subject: [PATCH 09/28] Improve the robustness of printing diagnostics. --- .../genscavenge/GreyToBlackObjectVisitor.java | 2 +- .../oracle/svm/core/genscavenge/HeapImpl.java | 2 +- .../oracle/svm/core/SubstrateDiagnostics.java | 748 +++++++++++------- .../svm/core/code/RuntimeCodeCache.java | 66 +- .../oracle/svm/core/deopt/Deoptimizer.java | 16 +- .../svm/core/thread/VMOperationControl.java | 39 +- .../core/threadlocal/VMThreadLocalInfos.java | 18 +- 7 files changed, 542 insertions(+), 349 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java index 12ae60131ee4..1818a21b8052 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java @@ -133,7 +133,7 @@ public void noteObject(Object o) { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") - public void invokeWithoutAllocation(Log log) { + public void printDiagnostics(Log log) { if (historyCount > 0) { log.string("[GreyToBlackObjectVisitor.RealDiagnosticReporter.invoke:") .string(" history / count: ") 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 9fb681bcb846..039dfa843529 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 @@ -591,7 +591,7 @@ public Reference getAndClearReferencePendingList() { private static class HeapDiagnosticsPrinter implements DiagnosticThunk { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void invokeWithoutAllocation(Log log) { + public void printDiagnostics(Log log) { HeapImpl heap = HeapImpl.getHeapImpl(); GCImpl gc = GCImpl.getGCImpl(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index a882e3c254ef..d6c0de826607 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -37,12 +37,14 @@ import org.graalvm.word.Pointer; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.annotate.AlwaysInline; import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.code.CodeInfo; import com.oracle.svm.core.code.CodeInfoAccess; import com.oracle.svm.core.code.CodeInfoTable; import com.oracle.svm.core.code.UntetheredCodeInfo; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.deopt.DeoptimizationSupport; import com.oracle.svm.core.deopt.DeoptimizedFrame; import com.oracle.svm.core.deopt.Deoptimizer; @@ -63,26 +65,11 @@ import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.VMThreadLocalInfos; import com.oracle.svm.core.util.Counter; +import com.oracle.svm.core.util.VMError; import jdk.vm.ci.code.CodeUtil; public class SubstrateDiagnostics { - private static final int REGISTERS = 1; - private static final int FRAME_ANCHORS = REGISTERS << 1; - private static final int DEOPT_STUB_POINTERS = FRAME_ANCHORS << 1; - private static final int TOP_FRAME = DEOPT_STUB_POINTERS << 1; - private static final int THREADS_FULL = TOP_FRAME << 1; - private static final int THREADS_REDUCED = TOP_FRAME << 1; - private static final int THREAD_STATES = THREADS_REDUCED << 1; - private static final int VM_OPERATIONS = THREAD_STATES << 1; - private static final int RUNTIME_COMPILATIONS = VM_OPERATIONS << 1; - private static final int COUNTERS = RUNTIME_COMPILATIONS << 1; - private static final int CURRENT_THREAD_RAW_STACKTRACE = COUNTERS << 1; - private static final int CURRENT_THREAD_DECODED_STACKTRACE = CURRENT_THREAD_RAW_STACKTRACE << 1; - private static final int OTHER_STACK_TRACES = CURRENT_THREAD_DECODED_STACKTRACE << 1; - private static final int INSTRUCTIONS = OTHER_STACK_TRACES << 1; - private static final int NUM_NAMED_SECTIONS = CodeUtil.log2(INSTRUCTIONS << 1); - private static final Stage0StackFramePrintVisitor[] PRINT_VISITORS = new Stage0StackFramePrintVisitor[]{Stage0StackFramePrintVisitor.SINGLETON, Stage1StackFramePrintVisitor.SINGLETON, StackFramePrintVisitor.SINGLETON}; @@ -154,395 +141,554 @@ private static void printDiagnosticsForCurrentState() { // Print the various sections of the diagnostics and skip all sections that were already // printed earlier. - if (shouldPrint(REGISTERS)) { + int numDiagnosticThunks = DiagnosticThunkRegister.getSingleton().size(); + while (state.diagnosticThunkIndex < numDiagnosticThunks) { try { - dumpRegisters(log, state.context); + int index = state.diagnosticThunkIndex++; + DiagnosticThunkRegister.getSingleton().callDiagnosticThunk(log, index); } catch (Exception e) { - dumpException(log, "dumpRegisters", e); + dumpException(log, "callThunks", e); } } - if (shouldPrint(FRAME_ANCHORS)) { - try { - dumpJavaFrameAnchors(log); - } catch (Exception e) { - dumpException(log, "dumpJavaFrameAnchors", e); - } + // Reset the state. + for (DiagnosticThunk thunk : thunks) { + thunk.reset(); } + state.clear(); + } - if (shouldPrint(DEOPT_STUB_POINTERS)) { - try { - dumpDeoptStubPointer(log); - } catch (Exception e) { - dumpException(log, "dumpDeoptStubPointer", e); - } + private static boolean shouldPrint(int sectionBit) { + if ((state.diagnosticSections & sectionBit) == 0) { + state.diagnosticSections |= sectionBit; + return true; } + return false; + } - if (shouldPrint(TOP_FRAME)) { - try { - dumpTopFrame(log, sp, ip); - } catch (Exception e) { - dumpException(log, "dumpTopFrame", e); - } - } + private static void skip(int sectionBit) { + state.diagnosticSections |= sectionBit; + } - if (shouldPrint(THREADS_FULL)) { - try { - dumpVMThreads(log, true); - skip(THREADS_REDUCED); - } catch (Exception e) { - dumpException(log, "dumpVMThreads", e); - } + @Uninterruptible(reason = "Prevent deoptimization of stack frames while in this method.") + private static long getTotalFrameSize(Pointer sp, CodePointer ip) { + DeoptimizedFrame deoptFrame = Deoptimizer.checkDeoptimized(sp); + if (deoptFrame != null) { + return deoptFrame.getSourceTotalFrameSize(); } - if (shouldPrint(THREADS_REDUCED)) { + UntetheredCodeInfo untetheredInfo = CodeInfoTable.lookupCodeInfo(ip); + if (untetheredInfo.isNonNull()) { + Object tether = CodeInfoAccess.acquireTether(untetheredInfo); try { - dumpVMThreads(log, false); - } catch (Exception e) { - dumpException(log, "dumpVMThreads", e); + CodeInfo codeInfo = CodeInfoAccess.convert(untetheredInfo, tether); + return getTotalFrameSize0(ip, codeInfo); + } finally { + CodeInfoAccess.releaseTether(untetheredInfo, tether); } } + return -1; + } - if (shouldPrint(THREAD_STATES)) { - try { - dumpVMThreadState(log, currentThread); - } catch (Exception e) { - dumpException(log, "dumpVMThreadState", e); - } + @Uninterruptible(reason = "Wrap the now safe call to interruptibly look up the frame size.", calleeMustBe = false) + private static long getTotalFrameSize0(CodePointer ip, CodeInfo codeInfo) { + return CodeInfoAccess.lookupTotalFrameSize(codeInfo, CodeInfoAccess.relativeIP(codeInfo, ip)); + } + + private static boolean printFrameAnchors(Log log, IsolateThread thread) { + log.string("Java frame anchors:").newline(); + log.indent(true); + JavaFrameAnchor anchor = JavaFrameAnchors.getFrameAnchor(thread); + if (anchor.isNull()) { + log.string("No anchors").newline(); + } + while (anchor.isNonNull()) { + log.string("Anchor ").zhex(anchor.rawValue()).string(" LastJavaSP ").zhex(anchor.getLastJavaSP().rawValue()).string(" LastJavaIP ").zhex(anchor.getLastJavaIP().rawValue()).newline(); + anchor = anchor.getPreviousAnchor(); } + log.indent(false); + return true; + } - if (shouldPrint(VM_OPERATIONS)) { - try { - dumpRecentVMOperations(log); - } catch (Exception e) { - dumpException(log, "dumpRecentVMOperations", e); + private static class PrintDiagnosticsState { + AtomicWord diagnosticThread = new AtomicWord<>(); + volatile int diagnosticSections; + volatile int diagnosticThunkIndex; + + Log log; + Pointer sp; + CodePointer ip; + RegisterDumper.Context context; + + @SuppressWarnings("hiding") + public boolean trySet(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context context) { + if (diagnosticThread.compareAndSet(WordFactory.nullPointer(), CurrentIsolate.getCurrentThread())) { + assert diagnosticSections == 0; + assert diagnosticThunkIndex == 0; + this.log = log; + this.sp = sp; + this.ip = ip; + this.context = context; + return true; } + return false; } - if (shouldPrint(RUNTIME_COMPILATIONS)) { - dumpRuntimeCompilation(log); - } + public void clear() { + log = null; + sp = WordFactory.nullPointer(); + ip = WordFactory.nullPointer(); + context = WordFactory.nullPointer(); - if (shouldPrint(COUNTERS)) { - try { - dumpCounters(log); - } catch (Exception e) { - dumpException(log, "dumpCounters", e); - } + diagnosticThunkIndex = 0; + diagnosticSections = 0; + + diagnosticThread.set(WordFactory.nullPointer()); } + } - if (shouldPrint(CURRENT_THREAD_RAW_STACKTRACE)) { + public static abstract class DiagnosticThunk { + private volatile int count; + + @AlwaysInline("Avoid the virtual call inside.") + public void printDiagnostics(Log log) { try { - dumpStacktraceRaw(log, sp); + printDiagnostics(log, count++); } catch (Exception e) { - dumpException(log, "dumpStacktraceRaw", e); + dumpException(log, this.getClass().getName(), e); } } - if (shouldPrint(CURRENT_THREAD_DECODED_STACKTRACE)) { - dumpStacktrace(log, sp, ip); + public void reset() { + count = 0; } - if (shouldPrint(OTHER_STACK_TRACES)) { - if (VMOperation.isInProgressAtSafepoint()) { - // Iterate all threads without locking the threads. - for (IsolateThread vmThread = VMThreads.firstThreadUnsafe(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) { - if (vmThread == currentThread) { - continue; - } - try { - dumpStacktrace(log, vmThread); - } catch (Exception e) { - dumpException(log, "dumpStacktrace", e); - } - } - } - } + /** + * Prints diagnostic information. This method may be invoked multiple times if an error + * occurred while printing diagnostics. For subsequent invocations, this method should try + * to print less information so that it is less likely that an error occurs. + */ + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") + protected abstract boolean printDiagnostics(Log log, int invocationCount); - if (shouldPrint(INSTRUCTIONS)) { - dumpInstructions(log, ip); + protected static void dumpException(Log log, String context, Exception e) { + log.newline().string("[!!! Exception during ").string(context).string(": ").string(e.getClass().getName()).string("]").newline(); } + } - int numDiagnosticThunks = DiagnosticThunkRegister.getSingleton().size(); - while (state.diagnosticThunkIndex < numDiagnosticThunks) { - try { - int index = state.diagnosticThunkIndex++; - DiagnosticThunkRegister.getSingleton().callDiagnosticThunk(log, index); - } catch (Exception e) { - dumpException(log, "callThunks", e); + private static class DumpRegisters extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: + return dumpRegisters(log); + default: + return false; } } - state.clear(); - } - - private static boolean shouldPrint(int sectionBit) { - if ((state.diagnosticSections & sectionBit) == 0) { - state.diagnosticSections |= sectionBit; + private static boolean dumpRegisters(Log log) { + RegisterDumper.Context context = state.context; + if (context.isNonNull()) { + log.string("General Purpose Register Set values:").newline(); + log.indent(true); + RegisterDumper.singleton().dumpRegisters(log, context); + log.indent(false); + } return true; } - return false; } - private static void skip(int sectionBit) { - state.diagnosticSections |= sectionBit; - } + private static class DumpInstructions extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: // fall-through + case 1: + return printBytesBeforeAndAfterIp(log, invocationCount); + case 2: + return printWord(log); + default: + return false; + } + } - private static void dumpException(Log log, String context, Exception e) { - log.newline().string("[!!! Exception during ").string(context).string(": ").string(e.getClass().getName()).string("]").newline(); - } + private static boolean printBytesBeforeAndAfterIp(Log log, int invocationCount) { + // print 64 or 32 instruction bytes. + int bytesToPrint = 64 >> (invocationCount + 1); + return hexDump(log, state.ip, bytesToPrint, bytesToPrint); + } - private static void dumpRegisters(Log log, RegisterDumper.Context context) { - if (context.isNonNull()) { - log.string("General Purpose Register Set values:").newline(); + private static boolean printWord(Log log) { + // just print one word starting at the ip + return hexDump(log, state.ip, 0, ConfigurationValues.getTarget().wordSize); + } + + private static boolean hexDump(Log log, CodePointer ip, int bytesBefore, int bytesAfter) { + log.string("Printing Instructions (ip=").hex(ip).string(")").newline(); log.indent(true); - RegisterDumper.singleton().dumpRegisters(log, context); + log.hexdump(((Pointer) ip).subtract(bytesBefore), 1, bytesAfter); log.indent(false); + return true; } } - private static void dumpJavaFrameAnchors(Log log) { - log.string("JavaFrameAnchor dump:").newline(); - log.indent(true); - JavaFrameAnchor anchor = JavaFrameAnchors.getFrameAnchor(); - if (anchor.isNull()) { - log.string("No anchors").newline(); - } - while (anchor.isNonNull()) { - log.string("Anchor ").zhex(anchor.rawValue()).string(" LastJavaSP ").zhex(anchor.getLastJavaSP().rawValue()).string(" LastJavaIP ").zhex(anchor.getLastJavaIP().rawValue()).newline(); - anchor = anchor.getPreviousAnchor(); + private static class DumpDeoptStubPointer extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: + return printDeoptStubPointer(log); + default: + return false; + } } - log.indent(false); - } - private static void dumpDeoptStubPointer(Log log) { - if (DeoptimizationSupport.enabled()) { - log.string("DeoptStubPointer address: ").zhex(DeoptimizationSupport.getDeoptStubPointer().rawValue()).newline().newline(); + private static boolean printDeoptStubPointer(Log log) { + if (DeoptimizationSupport.enabled()) { + log.string("DeoptStubPointer address: ").zhex(DeoptimizationSupport.getDeoptStubPointer().rawValue()).newline().newline(); + } + return true; } } - private static void dumpTopFrame(Log log, Pointer sp, CodePointer ip) { - log.string("TopFrame info:").newline(); - log.indent(true); - if (sp.isNonNull() && ip.isNonNull()) { - long totalFrameSize = getTotalFrameSize(sp, ip); - DeoptimizedFrame deoptFrame = Deoptimizer.checkDeoptimized(sp); - if (deoptFrame != null) { - log.string("RSP ").zhex(sp.rawValue()).string(" frame was deoptimized:").newline(); - log.string("SourcePC ").zhex(deoptFrame.getSourcePC().rawValue()).newline(); - log.string("SourceTotalFrameSize ").signed(totalFrameSize).newline(); - } else if (totalFrameSize != -1) { - log.string("TotalFrameSize in CodeInfoTable ").signed(totalFrameSize).newline(); + private static class DumpTopFrame extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: + return printTopFrame(log); + default: + return false; } + } - if (totalFrameSize == -1) { - log.string("Does not look like a Java Frame. Use JavaFrameAnchors to find LastJavaSP:").newline(); - JavaFrameAnchor anchor = JavaFrameAnchors.getFrameAnchor(); - while (anchor.isNonNull() && anchor.getLastJavaSP().belowOrEqual(sp)) { - anchor = anchor.getPreviousAnchor(); + private static boolean printTopFrame(Log log) { + // We already dump all safe values first, so there is nothing we could retry if an error + // occurs. + Pointer sp = state.sp; + CodePointer ip = state.ip; + + log.string("TopFrame info:").newline(); + log.indent(true); + if (sp.isNonNull() && ip.isNonNull()) { + long totalFrameSize = getTotalFrameSize(sp, ip); + DeoptimizedFrame deoptFrame = Deoptimizer.checkDeoptimized(sp); + if (deoptFrame != null) { + log.string("RSP ").zhex(sp.rawValue()).string(" frame was deoptimized:").newline(); + log.string("SourcePC ").zhex(deoptFrame.getSourcePC().rawValue()).newline(); + log.string("SourceTotalFrameSize ").signed(totalFrameSize).newline(); + } else if (totalFrameSize != -1) { + log.string("TotalFrameSize in CodeInfoTable ").signed(totalFrameSize).newline(); } - if (anchor.isNonNull()) { - log.string("Found matching Anchor:").zhex(anchor.rawValue()).newline(); - Pointer lastSp = anchor.getLastJavaSP(); - log.string("LastJavaSP ").zhex(lastSp.rawValue()).newline(); - CodePointer lastIp = anchor.getLastJavaIP(); - log.string("LastJavaIP ").zhex(lastIp.rawValue()).newline(); + if (totalFrameSize == -1) { + log.string("Does not look like a Java Frame. Use JavaFrameAnchors to find LastJavaSP:").newline(); + JavaFrameAnchor anchor = JavaFrameAnchors.getFrameAnchor(); + while (anchor.isNonNull() && anchor.getLastJavaSP().belowOrEqual(sp)) { + anchor = anchor.getPreviousAnchor(); + } + + if (anchor.isNonNull()) { + log.string("Found matching Anchor:").zhex(anchor.rawValue()).newline(); + Pointer lastSp = anchor.getLastJavaSP(); + log.string("LastJavaSP ").zhex(lastSp.rawValue()).newline(); + CodePointer lastIp = anchor.getLastJavaIP(); + log.string("LastJavaIP ").zhex(lastIp.rawValue()).newline(); + } } } + log.indent(false); + return true; } - log.indent(false); } - @Uninterruptible(reason = "Prevent deoptimization of stack frames while in this method.") - private static long getTotalFrameSize(Pointer sp, CodePointer ip) { - DeoptimizedFrame deoptFrame = Deoptimizer.checkDeoptimized(sp); - if (deoptFrame != null) { - return deoptFrame.getSourceTotalFrameSize(); + private static class DumpThreads extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: + return dumpThreads(log, "Full", true); + case 1: + return dumpThreads(log, "Reduced", false); + default: + return false; + } } - UntetheredCodeInfo untetheredInfo = CodeInfoTable.lookupCodeInfo(ip); - if (untetheredInfo.isNonNull()) { - Object tether = CodeInfoAccess.acquireTether(untetheredInfo); - try { - CodeInfo codeInfo = CodeInfoAccess.convert(untetheredInfo, tether); - return getTotalFrameSize0(ip, codeInfo); - } finally { - CodeInfoAccess.releaseTether(untetheredInfo, tether); + private static boolean dumpThreads(Log log, String prefix, boolean accessThreadObject) { + log.string(prefix).string(" thread info:").newline(); + log.indent(true); + // Only used for diagnostics - iterate all threads without locking the thread mutex. + for (IsolateThread thread = VMThreads.firstThreadUnsafe(); thread.isNonNull(); thread = VMThreads.nextThread(thread)) { + log.zhex(thread.rawValue()).string(VMThreads.StatusSupport.getStatusString(thread)); + if (accessThreadObject) { + Thread threadObj = JavaThreads.fromVMThread(thread); + log.string(" \"").string(threadObj.getName()).string("\" - ").object(threadObj).string(")"); + if (threadObj.isDaemon()) { + log.string(" daemon "); + } + } + log.string(", stack(").zhex(VMThreads.StackEnd.get(thread)).string(",").zhex(VMThreads.StackBase.get(thread)).string(")"); + log.newline(); } + log.indent(false); + return true; } - return -1; } - @Uninterruptible(reason = "Wrap the now safe call to interruptibly look up the frame size.", calleeMustBe = false) - private static long getTotalFrameSize0(CodePointer ip, CodeInfo codeInfo) { - return CodeInfoAccess.lookupTotalFrameSize(codeInfo, CodeInfoAccess.relativeIP(codeInfo, ip)); - } + private static class DumpThreadLocals extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: // fall-through + case 1: + return printThreadLocals(log, invocationCount); + default: + return false; + } + } - private static void dumpVMThreads(Log log, String prefix, boolean accessThreadObject) { - log.string(prefix).string(" VMThreads info:").newline(); - log.indent(true); - /* Only used for diagnostics - iterate all threads without locking the threads mutex. */ - for (IsolateThread thread = VMThreads.firstThreadUnsafe(); thread.isNonNull(); thread = VMThreads.nextThread(thread)) { - log.zhex(thread.rawValue()).string(VMThreads.StatusSupport.getStatusString(thread)); - if (accessThreadObject) { - Thread threadObj = JavaThreads.fromVMThread(thread); - log.string(" \"").string(threadObj.getName()).string("\" - ").object(threadObj).string(")"); - if (threadObj.isDaemon()) { - log.string(" daemon "); + private static boolean printThreadLocals(Log log, int invocationCount) { + IsolateThread currentThread = CurrentIsolate.getCurrentThread(); + if (isThreadOnlyAttachedForCrashHandler(currentThread)) { + if (invocationCount == 0) { + log.string("The current thread ").zhex(currentThread.rawValue()).string(" does not have a full set of VM thread locals as it is an unattached thread.").newline(); + log.newline(); } + } else { + log.string("VM thread locals for the current thread ").zhex(currentThread.rawValue()).string(":").newline(); + log.indent(true); + VMThreadLocalInfos.dumpToLog(log, currentThread, invocationCount == 0); + log.indent(false); } - log.string(", stack(").zhex(VMThreads.StackEnd.get(thread)).string(",").zhex(VMThreads.StackBase.get(thread)).string(")"); - log.newline(); + return true; } - log.indent(false); } - private static void dumpVMThreadState(Log log, IsolateThread currentThread) { - if (isThreadOnlyAttachedForCrashHandler(currentThread)) { - log.string("The current thread ").zhex(currentThread.rawValue()).string(" does not have a VM Thread State as it is an unattached thread.").newline(); - log.newline(); - } else { - log.string("VM Thread State for current thread ").zhex(currentThread.rawValue()).string(":").newline(); - log.indent(true); - VMThreadLocalInfos.dumpToLog(log, currentThread); - log.indent(false); + private static class DumpCurrentVMOperations extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: // fall-through + case 1: + return printCurrentVMOperation(log, invocationCount); + default: + return false; + } } - } - private static void dumpRecentVMOperations(Log log) { - log.string("VMOperation dump:").newline(); - log.indent(true); - VMOperationControl.logRecentEvents(log); - log.indent(false); + private static boolean printCurrentVMOperation(Log log, int invocationCount) { + VMOperationControl.logCurrentVMOperation(log, invocationCount == 0); + return true; + } } - static void dumpRuntimeCompilation(Log log) { - if (DeoptimizationSupport.enabled()) { - log.newline().string("RuntimeCodeCache dump:").newline(); - log.indent(true); - try { - CodeInfoTable.getRuntimeCodeCache().logRecentOperations(log); - } catch (Exception e) { - dumpException(log, "dumpRecentRuntimeCodeCacheOperations", e); + private static class DumpVMOperationHistory extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: // fall-through + case 1: + return printVMOperationHistory(log, invocationCount); + default: + return false; } - log.newline(); - try { - CodeInfoTable.getRuntimeCodeCache().logTable(log); - } catch (Exception e) { - dumpException(log, "dumpRuntimeCodeCacheTable", e); + } + + private static boolean printVMOperationHistory(Log log, int invocationCount) { + VMOperationControl.logRecentEvents(log, invocationCount == 0); + return true; + } + } + + private static class DumpRecentRuntimeCodeCacheOperations extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: // fall-through + case 1: + return printRecentRuntimeCodeCacheOperations(log, invocationCount); + default: + return false; } - log.indent(false); + } - try { - dumpRecentDeopts(log); - } catch (Exception e) { - dumpException(log, "dumpRecentDeopts", e); + private static boolean printRecentRuntimeCodeCacheOperations(Log log, int invocationCount) { + if (DeoptimizationSupport.enabled()) { + CodeInfoTable.getRuntimeCodeCache().logRecentOperations(log, invocationCount == 0); } + return true; } } - private static void dumpRecentDeopts(Log log) { - log.string("Deoptimizer dump:").newline(); - log.indent(true); - Deoptimizer.logRecentDeoptimizationEvents(log); - log.indent(false); - } + private static class DumpRuntimeCodeCache extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: // fall-through + case 1: + return printRuntimeCodeCache(log, invocationCount); + default: + return false; + } + } - private static void dumpCounters(Log log) { - log.string("Dump Counters:").newline(); - log.indent(true); - Counter.logValues(); - log.indent(false); + private static boolean printRuntimeCodeCache(Log log, int invocationCount) { + if (DeoptimizationSupport.enabled()) { + CodeInfoTable.getRuntimeCodeCache().logTable(log, invocationCount == 0); + } + return true; + } } - private static void dumpStacktraceRaw(Log log, Pointer sp) { - log.string("Raw Stacktrace:").newline(); - log.indent(true); - /* - * We have to be careful here and not dump too much of the stack: if there are not many - * frames on the stack, we segfault when going past the beginning of the stack. - */ - log.hexdump(sp, 8, 16); - log.indent(false); - } + private static class DumpRecentDeoptimizations extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: // fall-through + case 1: + return printRecentDeoptimizations(log, invocationCount); + default: + return false; + } + } - private static void dumpStacktrace(Log log, Pointer sp, CodePointer ip) { - for (int i = 0; i < PRINT_VISITORS.length; i++) { - try { - log.string("Stacktrace Stage ").signed(i).string(":").newline(); - log.indent(true); - ThreadStackPrinter.printStacktrace(sp, ip, PRINT_VISITORS[i], log); - log.indent(false); - } catch (Exception e) { - dumpException(log, "dumpStacktrace", e); + private static boolean printRecentDeoptimizations(Log log, int invocationCount) { + if (DeoptimizationSupport.enabled()) { + Deoptimizer.logRecentDeoptimizationEvents(log, invocationCount == 0); } + return true; } } - private static void dumpStacktrace(Log log, IsolateThread vmThread) { - log.string("Full Stacktrace for VMThread ").zhex(vmThread.rawValue()).string(":").newline(); - log.indent(true); - JavaStackWalker.walkThread(vmThread, StackFramePrintVisitor.SINGLETON, log); - log.indent(false); - } + private static class DumpCounters extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: + return printCounters(log); + default: + return false; + } + } - private static void dumpInstructions(Log log, CodePointer ip) { - log.string("Instructions (ip=").hex(ip).string(")").newline(); - log.indent(true); - log.hexdump(((Pointer) ip).subtract(32), 1, 64); - log.indent(false); + private static boolean printCounters(Log log) { + log.string("Counters:").newline(); + log.indent(true); + Counter.logValues(); + log.indent(false); + return true; + } } - private static class PrintDiagnosticsState { - AtomicWord diagnosticThread = new AtomicWord<>(); - volatile int diagnosticSections; - volatile int diagnosticThunkIndex; - - Log log; - Pointer sp; - CodePointer ip; - RegisterDumper.Context context; + private static class DumpCurrentThreadFrameAnchors extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: + return printFrameAnchors(log, CurrentIsolate.getCurrentThread()); + default: + return false; + } + } + } - @SuppressWarnings("hiding") - public boolean trySet(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context context) { - if (diagnosticThread.compareAndSet(WordFactory.nullPointer(), CurrentIsolate.getCurrentThread())) { - assert diagnosticSections == 0; - assert diagnosticThunkIndex == 0; - this.log = log; - this.sp = sp; - this.ip = ip; - this.context = context; - return true; + private static class DumpCurrentThreadRawStackTrace extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: + return printRawStackTrace(log); + default: + return false; } - return false; } - public void clear() { - log = null; - sp = WordFactory.nullPointer(); - ip = WordFactory.nullPointer(); - context = WordFactory.nullPointer(); + private static boolean printRawStackTrace(Log log) { + log.string("Raw stacktrace:").newline(); + log.indent(true); + /* + * We have to be careful here and not dump too much of the stack: if there are not many + * frames on the stack, we segfault when going past the beginning of the stack. + */ + log.hexdump(state.sp, 8, 16); + log.indent(false); + return true; + } + } - diagnosticThunkIndex = 0; - diagnosticSections = 0; + private static class DumpCurrentThreadDecodedStackTrace extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: + return printDecodedStackTrace(log); + default: + return false; + } + } - diagnosticThread.set(WordFactory.nullPointer()); + private static boolean printDecodedStackTrace(Log log) { + Pointer sp = state.sp; + CodePointer ip = state.ip; + for (int i = 0; i < PRINT_VISITORS.length; i++) { + try { + log.string("Stacktrace Stage ").signed(i).string(":").newline(); + log.indent(true); + ThreadStackPrinter.printStacktrace(sp, ip, PRINT_VISITORS[i], log); + log.indent(false); + } catch (Exception e) { + dumpException(log, "dumpStacktrace", e); + } + } + return true; } } - /** The functional interface for a "thunk" that does not allocate. */ - @FunctionalInterface - public interface DiagnosticThunk { + private static class PrintOtherStackTraces extends DiagnosticThunk { + @Override + protected boolean printDiagnostics(Log log, int invocationCount) { + switch (invocationCount) { + case 0: + return printOtherStackTraces(log); + default: + return false; + } + } - /** The method to be supplied by the implementor. */ - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") - void invokeWithoutAllocation(Log log); + private static boolean printOtherStackTraces(Log log) { + if (VMOperation.isInProgressAtSafepoint()) { + // Iterate all threads without checking if the thread mutex is locked (it should be + // locked by this thread though because we are at a safepoint). + for (IsolateThread vmThread = VMThreads.firstThreadUnsafe(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) { + if (vmThread == CurrentIsolate.getCurrentThread()) { + continue; + } + try { + log.string("Thread ").zhex(vmThread.rawValue()).string(":").newline(); + log.indent(true); + printFrameAnchors(log, vmThread); + printStacktrace(log, vmThread); + log.indent(false); + } catch (Exception e) { + dumpException(log, "dumpStacktrace", e); + } + } + } + return true; + } + + private static void printStacktrace(Log log, IsolateThread vmThread) { + log.string("Full Stacktrace for VMThread ").zhex(vmThread.rawValue()).string(":").newline(); + log.indent(true); + JavaStackWalker.walkThread(vmThread, StackFramePrintVisitor.SINGLETON, log); + log.indent(false); + } } public static class DiagnosticThunkRegister { - - DiagnosticThunk[] diagnosticThunkRegistry; + DiagnosticThunk[] diagnosticThunks; /** * Get the register. @@ -561,27 +707,27 @@ public static synchronized DiagnosticThunkRegister getSingleton() { @Platforms(Platform.HOSTED_ONLY.class) DiagnosticThunkRegister() { - this.diagnosticThunkRegistry = new DiagnosticThunk[0]; + this.diagnosticThunks = new DiagnosticThunk[0]; } /** Register a diagnostic thunk to be called after a segfault. */ @Platforms(Platform.HOSTED_ONLY.class) /* { Checkstyle: allow synchronization. */ public synchronized void register(DiagnosticThunk diagnosticThunk) { - final DiagnosticThunk[] newArray = Arrays.copyOf(diagnosticThunkRegistry, diagnosticThunkRegistry.length + 1); + final DiagnosticThunk[] newArray = Arrays.copyOf(diagnosticThunks, diagnosticThunks.length + 1); newArray[newArray.length - 1] = diagnosticThunk; - diagnosticThunkRegistry = newArray; + diagnosticThunks = newArray; } /* } Checkstyle: disallow synchronization. */ @Fold int size() { - return diagnosticThunkRegistry.length; + return diagnosticThunks.length; } /** Call each registered diagnostic thunk. */ void callDiagnosticThunk(Log log, int index) { - diagnosticThunkRegistry[index].invokeWithoutAllocation(log); + diagnosticThunks[index].printDiagnostics(log); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java index 7cd89e6b92d6..f6ae3f11171f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java @@ -48,6 +48,7 @@ import com.oracle.svm.core.deopt.DeoptimizedFrame; import com.oracle.svm.core.deopt.Deoptimizer; import com.oracle.svm.core.deopt.SubstrateInstalledCode; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.stack.JavaStackWalker; @@ -171,7 +172,7 @@ private void addMethodOperation(CodeInfo info) { assert verifyTable(); if (Options.TraceCodeCache.getValue()) { Log.log().string("[" + INFO_ADD + " method: "); - logCodeInfo(Log.log(), info); + logCodeInfo(Log.log(), info, true); Log.log().string("]").newline(); } @@ -189,7 +190,7 @@ private void addMethodOperation(CodeInfo info) { NonmovableArrays.setWord(codeInfos, insertionPoint, info); if (Options.TraceCodeCache.getValue()) { - logTable(); + logTable(true); } assert verifyTable(); } @@ -232,7 +233,7 @@ private void prepareInvalidation(CodeInfo info) { assert verifyTable(); if (Options.TraceCodeCache.getValue()) { Log.log().string("[").string(INFO_INVALIDATE).string(" method: "); - logCodeInfo(Log.log(), info); + logCodeInfo(Log.log(), info, true); Log.log().string("]").newline(); } @@ -264,7 +265,7 @@ private void finishInvalidation(CodeInfo info, boolean notifyGC) { RuntimeCodeInfoAccess.partialReleaseAfterInvalidate(info, notifyGC); if (Options.TraceCodeCache.getValue()) { - logTable(); + logTable(true); } assert verifyTable(); } @@ -293,50 +294,64 @@ private boolean verifyTable() { return true; } - public void logTable() { - logTable(Log.log()); + public void logTable(boolean allowJavaHeapAccess) { + logTable(Log.log(), allowJavaHeapAccess); } - private static final RingBuffer.Consumer consumer = (context, e) -> e.log(Log.log()); + private static final RingBuffer.Consumer PRINT_WITH_JAVA_HEAP_DATA = RuntimeCodeCache::printEntryWithJavaHeapData; + private static final RingBuffer.Consumer PRINT_WITHOUT_JAVA_HEAP_DATA = RuntimeCodeCache::printEntryWithoutJavaHeapData; - public void logRecentOperations(Log log) { - log.string("== [Recent RuntimeCodeCache operations: "); - recentCodeCacheOperations.foreach(consumer); - log.string("]").newline(); + public void logRecentOperations(Log log, boolean allowJavaHeapAccess) { + log.string("Recent RuntimeCodeCache operations: "); + recentCodeCacheOperations.foreach(log, allowJavaHeapAccess ? PRINT_WITH_JAVA_HEAP_DATA : PRINT_WITHOUT_JAVA_HEAP_DATA); } - public void logTable(Log log) { - log.string("== [RuntimeCodeCache: ").signed(numCodeInfos).string(" methods"); + private static void printEntryWithJavaHeapData(Object context, CodeCacheLogEntry entry) { + printEntry(context, entry, true); + } + + private static void printEntryWithoutJavaHeapData(Object context, CodeCacheLogEntry entry) { + printEntry(context, entry, false); + } + + private static void printEntry(Object context, CodeCacheLogEntry entry, boolean allowJavaHeapAccess) { + Log log = (Log) context; + entry.log(log, allowJavaHeapAccess); + } + + public void logTable(Log log, boolean allowJavaHeapAccess) { + log.string("RuntimeCodeCache contains ").signed(numCodeInfos).string(" methods"); for (int i = 0; i < numCodeInfos; i++) { - logCodeInfo(log, i); + logCodeInfo(log, i, allowJavaHeapAccess); } - log.string("]").newline(); } @Uninterruptible(reason = "Must prevent the GC from freeing the CodeInfo object.") - private void logCodeInfo(Log log, int i) { + private void logCodeInfo(Log log, int i, boolean allowJavaHeapAccess) { UntetheredCodeInfo untetheredInfo = NonmovableArrays.getWord(codeInfos, i); Object tether = CodeInfoAccess.acquireTether(untetheredInfo); try { CodeInfo info = CodeInfoAccess.convert(untetheredInfo, tether); - logCodeInfo0(log, info); + logCodeInfo0(log, info, allowJavaHeapAccess); } finally { CodeInfoAccess.releaseTether(untetheredInfo, tether); } } @Uninterruptible(reason = "Pass the now protected CodeInfo to interruptible code.", calleeMustBe = false) - private static void logCodeInfo0(Log log, CodeInfo info) { + private static void logCodeInfo0(Log log, CodeInfo info, boolean allowJavaHeapAccess) { log.newline().hex(CodeInfoAccess.getCodeStart(info)).string(" "); - logCodeInfo(log, info); + logCodeInfo(log, info, allowJavaHeapAccess); } - private static void logCodeInfo(Log log, CodeInfo info) { - logCodeInfo(log, CodeInfoAccess.getName(info), CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info), CodeInfoAccess.getCodeSize(info)); + private static void logCodeInfo(Log log, CodeInfo info, boolean allowJavaHeapAccess) { + logCodeInfo(log, allowJavaHeapAccess, CodeInfoAccess.getName(info), CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info), CodeInfoAccess.getCodeSize(info)); } - private static void logCodeInfo(Log log, String codeName, CodePointer codeStart, CodePointer codeEnd, UnsignedWord codeSize) { - log.string(codeName); + private static void logCodeInfo(Log log, boolean allowJavaHeapAccess, String codeName, CodePointer codeStart, CodePointer codeEnd, UnsignedWord codeSize) { + if (allowJavaHeapAccess) { + log.string(codeName); + } log.string(" ip: ").hex(codeStart).string(" - ").hex(codeEnd); log.string(" size: ").unsigned(codeSize); /* @@ -397,6 +412,7 @@ private static class CodeCacheLogEntry { } public void setValues(long sequenceNumber, String kind, String codeName, CodePointer codeStart, CodePointer codeEnd, UnsignedWord codeSize) { + assert Heap.getHeap().isInImageHeap(kind); this.sequenceNumber = sequenceNumber; this.kind = kind; this.codeName = codeName; @@ -405,11 +421,11 @@ public void setValues(long sequenceNumber, String kind, String codeName, CodePoi this.codeSize = codeSize; } - public void log(Log log) { + public void log(Log log, boolean allowJavaHeapAccess) { log.newline(); if (kind != null) { log.string(kind).string(": "); - logCodeInfo(log, codeName, codeStart, codeEnd, codeSize); + logCodeInfo(log, allowJavaHeapAccess, codeName, codeStart, codeEnd, codeSize); log.string(" ").unsigned(sequenceNumber).string(":{"); } else { log.string("}:").unsigned(sequenceNumber); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java index 831262fe3014..0a81853cca73 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java @@ -84,6 +84,8 @@ import com.oracle.svm.core.thread.JavaVMOperation; import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.thread.VMOperationControl.VMOpHistory; +import com.oracle.svm.core.thread.VMOperationControl.VMOpStatusChange; import com.oracle.svm.core.util.RingBuffer; import com.oracle.svm.core.util.VMError; @@ -406,7 +408,7 @@ public static void invalidateMethodOfFrame(Pointer sourceSp, SpeculationReason s } } else { if (installedCode == null) { - CodeInfoTable.getRuntimeCodeCache().logTable(); + CodeInfoTable.getRuntimeCodeCache().logTable(true); throw VMError.shouldNotReachHere( "Only runtime compiled methods can be invalidated. sp = " + Long.toHexString(sourceSp.rawValue()) + ", returnAddress = " + Long.toHexString(returnAddress.rawValue())); } @@ -751,10 +753,14 @@ private static void logDeoptSourceFrameOperation(Pointer sp, DeoptimizedFrame de } }; - public static void logRecentDeoptimizationEvents(Log log) { - log.string("== [Recent Deoptimizer Events: ").newline(); - recentDeoptimizationEvents.foreach(log, deoptEventsConsumer); - log.string("]").newline(); + public static void logRecentDeoptimizationEvents(Log log, boolean allowJavaHeapAccess) { + if (allowJavaHeapAccess) { + log.string("Recent deoptimization events: ").newline(); + recentDeoptimizationEvents.foreach(log, deoptEventsConsumer); + log.string("]").newline(); + } else { + log.string("Deoptimization events could not be printed.").newline(); + } } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java index ff0c6559df46..5fefc428c553 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java @@ -46,6 +46,7 @@ import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.RestrictHeapAccess.Access; import com.oracle.svm.core.annotate.Uninterruptible; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.locks.VMCondition; import com.oracle.svm.core.locks.VMMutex; import com.oracle.svm.core.log.Log; @@ -192,7 +193,7 @@ public static boolean mayExecuteVmOperations() { } } - public static void logRecentEvents(Log log) { + public static void logCurrentVMOperation(Log log, boolean allowJavaHeapAccess) { /* * All reads in this method are racy as the currently executed VM operation could finish and * a different VM operation could start. So, the read data is not necessarily consistent. @@ -201,15 +202,19 @@ public static void logRecentEvents(Log log) { VMOperation op = control.inProgress.operation; if (op == null) { log.string("No VMOperation in progress").newline(); - } else { + } else if (allowJavaHeapAccess) { log.string("VMOperation in progress: ").string(op.getName()).newline(); log.string(" safepoint: ").bool(op.getCausesSafepoint()).newline(); log.string(" queuingThread: ").zhex(control.inProgress.queueingThread.rawValue()).newline(); log.string(" executingThread: ").zhex(control.inProgress.executingThread.rawValue()).newline(); + } else { + log.string("VMOperation in progress: ").zhex(Word.objectToUntrackedPointer(op)).newline(); } log.newline(); + } - control.history.print(log); + public static void logRecentEvents(Log log, boolean allowJavaHeapAccess) { + get().history.print(log, allowJavaHeapAccess); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -866,7 +871,8 @@ public IsolateThread getExecutingThread() { */ private static class VMOpHistory { private final RingBuffer history; - private static final RingBuffer.Consumer PRINT_ENTRY = VMOpHistory::printEntry; + private static final RingBuffer.Consumer PRINT_WITH_JAVA_HEAP_DATA = VMOpHistory::printEntryWithJavaHeapData; + private static final RingBuffer.Consumer PRINT_WITHOUT_JAVA_HEAP_DATA = VMOpHistory::printEntryWithoutJavaHeapData; @Platforms(Platform.HOSTED_ONLY.class) VMOpHistory() { @@ -875,6 +881,7 @@ private static class VMOpHistory { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public void add(VMOpStatus status, VMOperation operation, IsolateThread queueingThread, IsolateThread executingThread) { + assert Heap.getHeap().isInImageHeap(status); VMOpStatusChange entry = history.next(); entry.timestamp = System.currentTimeMillis(); entry.status = status; @@ -884,15 +891,23 @@ public void add(VMOpStatus status, VMOperation operation, IsolateThread queueing entry.executingThread = executingThread; } - public void print(Log log) { + public void print(Log log, boolean allowJavaHeapAccess) { log.string("The ").signed(history.size()).string(" most recent VM operation status changes (oldest first):").indent(true); - history.foreach(log, PRINT_ENTRY); + history.foreach(log, allowJavaHeapAccess ? PRINT_WITH_JAVA_HEAP_DATA : PRINT_WITHOUT_JAVA_HEAP_DATA); log.indent(false); } - private static void printEntry(Object context, VMOpStatusChange entry) { + private static void printEntryWithJavaHeapData(Object context, VMOpStatusChange entry) { + printEntry(context, entry, true); + } + + private static void printEntryWithoutJavaHeapData(Object context, VMOpStatusChange entry) { + printEntry(context, entry, false); + } + + private static void printEntry(Object context, VMOpStatusChange entry, boolean allowJavaHeapAccess) { Log log = (Log) context; - entry.print(log); + entry.print(log, allowJavaHeapAccess); } } @@ -919,10 +934,14 @@ private static class VMOpStatusChange { VMOpStatusChange() { } - void print(Log log) { + void print(Log log, boolean allowJavaHeapAccess) { VMOpStatus localStatus = status; if (localStatus != null) { - log.unsigned(timestamp).string(" - ").string(localStatus.name()).string(" ").string(operation).string(" (safepoint: ").bool(causesSafepoint).string(", queueingThread: ") + log.unsigned(timestamp).string(" - ").string(localStatus.name()); + if (allowJavaHeapAccess) { + log.string(" ").string(operation); + } + log.string(" (safepoint: ").bool(causesSafepoint).string(", queueingThread: ") .zhex(queueingThread.rawValue()).string(", executingThread: ").zhex(executingThread.rawValue()).string(")").newline(); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java index 467a94e4f1ad..4f718f6de67d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java @@ -41,6 +41,7 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.annotate.Uninterruptible; +import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.log.Log; public class VMThreadLocalInfos { @@ -59,7 +60,7 @@ public static boolean setInfos(Collection infos) { } } - public static void dumpToLog(Log log, IsolateThread thread) { + public static void dumpToLog(Log log, IsolateThread thread, boolean allowJavaHeapAccess) { for (VMThreadLocalInfo info : ImageSingletons.lookup(VMThreadLocalInfos.class).infos) { log.signed(info.offset).string(" (").signed(info.sizeInBytes).string(" bytes): ").string(info.name).string(" = "); if (info.threadLocalClass == FastThreadLocalInt.class) { @@ -72,12 +73,17 @@ public static void dumpToLog(Log log, IsolateThread thread) { WordBase value = primitiveData(thread).readWord(WordFactory.signed(info.offset)); log.string("(Word) ").signed(value).string(" ").zhex(value.rawValue()); } else if (info.threadLocalClass == FastThreadLocalObject.class) { - Object value = ObjectAccess.readObject(objectData(thread), WordFactory.signed(info.offset)); - log.string("(Object) "); - if (value == null) { - log.string("null"); + if (allowJavaHeapAccess) { + Object value = ObjectAccess.readObject(objectData(thread), WordFactory.signed(info.offset)); + log.string("(Object) "); + if (value == null) { + log.string("null"); + } else { + log.string(value.getClass().getName()).string(" ").zhex(Word.objectToUntrackedPointer(value).rawValue()); + } } else { - log.string(value.getClass().getName()).string(" ").zhex(Word.objectToUntrackedPointer(value).rawValue()); + Word value = ReferenceAccess.singleton().readObjectAsUntrackedPointer(Word.objectToUntrackedPointer(objectData(thread)).add(info.offset), true); + log.string("(Object) ").zhex(value); } } else if (info.threadLocalClass == FastThreadLocalBytes.class) { log.string("(bytes) ").indent(true); From 3cab5d72b65354021fb244ede84dbecccf463db2 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 1 Jul 2021 12:20:59 +0200 Subject: [PATCH 10/28] VMMutex and CodeInfo-related changes. --- .../oracle/svm/core/genscavenge/HeapImpl.java | 30 +- .../posix/pthread/PthreadVMLockSupport.java | 38 +- .../core/windows/WindowsVMLockSupport.java | 37 +- .../oracle/svm/core/SubstrateDiagnostics.java | 385 +++++++----------- .../svm/core/SubstrateSegfaultHandler.java | 12 +- .../com/oracle/svm/core/SubstrateUtil.java | 4 +- .../com/oracle/svm/core/code/CodeInfo.java | 18 + .../oracle/svm/core/code/CodeInfoTable.java | 6 +- .../svm/core/code/RuntimeCodeCache.java | 142 +------ .../svm/core/code/RuntimeCodeInfoAccess.java | 8 +- .../svm/core/code/RuntimeCodeInfoHistory.java | 162 ++++++++ .../svm/core/code/RuntimeCodeInfoMemory.java | 36 +- .../oracle/svm/core/deopt/Deoptimizer.java | 1 - .../core/jdk/UninterruptibleHashtable.java | 8 +- .../locks/SingleThreadedVMLockSupport.java | 9 +- .../oracle/svm/core/locks/VMLockSupport.java | 79 ++++ .../com/oracle/svm/core/locks/VMMutex.java | 15 +- .../svm/core/stack/StackOverflowCheck.java | 2 + .../svm/core/thread/VMOperationControl.java | 6 +- .../com/oracle/svm/core/thread/VMThreads.java | 7 +- .../com/oracle/svm/jfr/JfrRecorderThread.java | 2 +- .../oracle/svm/jfr/JfrSymbolRepository.java | 5 + ...trateOptimizedCallTargetInstalledCode.java | 2 + 23 files changed, 578 insertions(+), 436 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java 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 039dfa843529..c92ba64a5b35 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 @@ -59,7 +59,6 @@ import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.heap.PhysicalMemory; -import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.heap.ReferenceHandlerThreadSupport; import com.oracle.svm.core.heap.ReferenceInternals; import com.oracle.svm.core.heap.RuntimeCodeInfoGCSupport; @@ -82,7 +81,7 @@ public final class HeapImpl extends Heap { /** Synchronization means for notifying {@link #refPendingList} waiters without deadlocks. */ - private static final VMMutex REF_MUTEX = new VMMutex(); + private static final VMMutex REF_MUTEX = new VMMutex("ReferencePendingList"); private static final VMCondition REF_CONDITION = new VMCondition(REF_MUTEX); // Singleton instances, created during image generation. @@ -113,7 +112,8 @@ public HeapImpl(FeatureAccess access) { this.gcImpl = new GCImpl(access); this.runtimeCodeInfoGcSupport = new RuntimeCodeInfoGCSupportImpl(); this.heapPolicy = new HeapPolicy(); - SubstrateDiagnostics.DiagnosticThunkRegister.getSingleton().register(new HeapDiagnosticsPrinter()); + SubstrateDiagnostics.DiagnosticThunkRegister.getSingleton().register(new DumpHeapSettingsAndStatistics()); + SubstrateDiagnostics.DiagnosticThunkRegister.getSingleton().register(new DumpChunkInformation()); } @Fold @@ -588,11 +588,16 @@ public Reference getAndClearReferencePendingList() { } } - private static class HeapDiagnosticsPrinter implements DiagnosticThunk { + private static class DumpHeapSettingsAndStatistics extends DiagnosticThunk { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log) { - HeapImpl heap = HeapImpl.getHeapImpl(); + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printHeapSettingsAndStatistics(log); + } + } + + private static void printHeapSettingsAndStatistics(Log log) { GCImpl gc = GCImpl.getGCImpl(); log.string("[Heap settings and statistics: ").indent(true); @@ -607,7 +612,20 @@ public void printDiagnostics(Log log) { log.string("Complete collections: ").unsigned(accounting.getCompleteCollectionCount()); log.redent(false).string("]").newline(); log.newline(); + } + } + private static class DumpChunkInformation extends DiagnosticThunk { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printChunkInformation(log); + } + } + + private static void printChunkInformation(Log log) { + HeapImpl heap = HeapImpl.getHeapImpl(); heap.logImageHeapPartitionBoundaries(log).newline(); zapValuesToLog(log).newline(); heap.report(log, true).newline(); diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java index 4f3a42050bde..8e10d8674795 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.posix.pthread; +import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.ImageSingletons; @@ -44,6 +45,7 @@ import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.locks.ClassInstanceReplacer; import com.oracle.svm.core.locks.VMCondition; +import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.locks.VMMutex; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.posix.headers.Errno; @@ -63,7 +65,7 @@ final class PthreadVMLockFeature implements Feature { private final ClassInstanceReplacer mutexReplacer = new ClassInstanceReplacer(VMMutex.class) { @Override protected VMMutex createReplacement(VMMutex source) { - return new PthreadVMMutex(); + return new PthreadVMMutex(source.getName()); } }; @@ -81,7 +83,8 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { @Override public void duringSetup(DuringSetupAccess access) { - ImageSingletons.add(PthreadVMLockSupport.class, new PthreadVMLockSupport()); + PthreadVMLockSupport support = new PthreadVMLockSupport(); + ImageSingletons.add(VMLockSupport.class, support); access.registerObjectReplacer(mutexReplacer); access.registerObjectReplacer(conditionReplacer); } @@ -105,14 +108,14 @@ public void beforeCompilation(BeforeCompilationAccess access) { nextIndex += conditionSize; } - PthreadVMLockSupport lockSupport = ImageSingletons.lookup(PthreadVMLockSupport.class); + PthreadVMLockSupport lockSupport = PthreadVMLockSupport.singleton(); lockSupport.mutexes = mutexes; lockSupport.conditions = conditions; lockSupport.pthreadStructs = new byte[nextIndex]; } } -public final class PthreadVMLockSupport { +public final class PthreadVMLockSupport extends VMLockSupport { /** All mutexes, so that we can initialize them at run time when the VM starts. */ @UnknownObjectField(types = PthreadVMMutex[].class)// protected PthreadVMMutex[] mutexes; @@ -130,18 +133,24 @@ public final class PthreadVMLockSupport { @UnknownObjectField(types = byte[].class)// protected byte[] pthreadStructs; + @Fold + public static PthreadVMLockSupport singleton() { + return (PthreadVMLockSupport) ImageSingletons.lookup(VMLockSupport.class); + } + /** * Must be called once early during startup, before any mutex or condition is used. */ @Uninterruptible(reason = "Called from uninterruptible code. Too early for safepoints.") public static boolean initialize() { - for (PthreadVMMutex mutex : ImageSingletons.lookup(PthreadVMLockSupport.class).mutexes) { + PthreadVMLockSupport support = PthreadVMLockSupport.singleton(); + for (PthreadVMMutex mutex : support.mutexes) { if (Pthread.pthread_mutex_init(mutex.getStructPointer(), WordFactory.nullPointer()) != 0) { return false; } } - for (PthreadVMCondition condition : ImageSingletons.lookup(PthreadVMLockSupport.class).conditions) { + for (PthreadVMCondition condition : support.conditions) { if (PthreadConditionUtils.initCondition(condition.getStructPointer()) != 0) { return false; } @@ -162,6 +171,16 @@ protected static void checkResult(int result, String functionName) { ImageSingletons.lookup(LogHandler.class).fatalError(); } } + + @Override + public PthreadVMMutex[] getMutexes() { + return mutexes; + } + + @Override + public PthreadVMCondition[] getConditions() { + return conditions; + } } final class PthreadVMMutex extends VMMutex { @@ -169,12 +188,13 @@ final class PthreadVMMutex extends VMMutex { protected UnsignedWord structOffset; @Platforms(Platform.HOSTED_ONLY.class) - protected PthreadVMMutex() { + protected PthreadVMMutex(String name) { + super(name); } @Uninterruptible(reason = "Called from uninterruptible code.") protected Pthread.pthread_mutex_t getStructPointer() { - return (Pthread.pthread_mutex_t) Word.objectToUntrackedPointer(ImageSingletons.lookup(PthreadVMLockSupport.class).pthreadStructs).add(structOffset); + return (Pthread.pthread_mutex_t) Word.objectToUntrackedPointer(PthreadVMLockSupport.singleton().pthreadStructs).add(structOffset); } @Override @@ -232,7 +252,7 @@ protected PthreadVMCondition(PthreadVMMutex mutex) { @Uninterruptible(reason = "Called from uninterruptible code.") protected Pthread.pthread_cond_t getStructPointer() { - return (Pthread.pthread_cond_t) Word.objectToUntrackedPointer(ImageSingletons.lookup(PthreadVMLockSupport.class).pthreadStructs).add(structOffset); + return (Pthread.pthread_cond_t) Word.objectToUntrackedPointer(PthreadVMLockSupport.singleton().pthreadStructs).add(structOffset); } @Override diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java index eb43885bd41f..49a555f2d534 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.windows; +import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.ImageSingletons; @@ -43,6 +44,7 @@ import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.locks.ClassInstanceReplacer; import com.oracle.svm.core.locks.VMCondition; +import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.locks.VMMutex; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.thread.VMThreads; @@ -65,7 +67,7 @@ final class WindowsVMLockFeature implements Feature { private final ClassInstanceReplacer mutexReplacer = new ClassInstanceReplacer(VMMutex.class) { @Override protected WindowsVMMutex createReplacement(VMMutex source) { - return new WindowsVMMutex(); + return new WindowsVMMutex(source.getName()); } }; @@ -83,7 +85,7 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { @Override public void duringSetup(DuringSetupAccess access) { - ImageSingletons.add(WindowsVMLockSupport.class, new WindowsVMLockSupport()); + ImageSingletons.add(VMLockSupport.class, new WindowsVMLockSupport()); access.registerObjectReplacer(mutexReplacer); access.registerObjectReplacer(conditionReplacer); } @@ -107,14 +109,14 @@ public void beforeCompilation(BeforeCompilationAccess access) { nextIndex += conditionSize; } - WindowsVMLockSupport lockSupport = ImageSingletons.lookup(WindowsVMLockSupport.class); + WindowsVMLockSupport lockSupport = WindowsVMLockSupport.singleton(); lockSupport.mutexes = mutexes; lockSupport.conditions = conditions; lockSupport.syncStructs = new byte[nextIndex]; } } -public final class WindowsVMLockSupport { +public final class WindowsVMLockSupport extends VMLockSupport { /** All mutexes, so that we can initialize them at run time when the VM starts. */ @UnknownObjectField(types = WindowsVMMutex[].class)// WindowsVMMutex[] mutexes; @@ -132,16 +134,22 @@ public final class WindowsVMLockSupport { @UnknownObjectField(types = byte[].class)// byte[] syncStructs; + @Fold + public static WindowsVMLockSupport singleton() { + return (WindowsVMLockSupport) ImageSingletons.lookup(VMLockSupport.class); + } + /** * Must be called once early during startup, before any mutex or condition is used. */ @Uninterruptible(reason = "Called from uninterruptible code. Too early for safepoints.") public static void initialize() { - for (WindowsVMMutex mutex : ImageSingletons.lookup(WindowsVMLockSupport.class).mutexes) { + WindowsVMLockSupport support = WindowsVMLockSupport.singleton(); + for (WindowsVMMutex mutex : support.mutexes) { // critical sections on windows always support recursive locking Process.InitializeCriticalSection(mutex.getStructPointer()); } - for (WindowsVMCondition condition : ImageSingletons.lookup(WindowsVMLockSupport.class).conditions) { + for (WindowsVMCondition condition : support.conditions) { Process.InitializeConditionVariable(condition.getStructPointer()); } } @@ -159,6 +167,16 @@ static void checkResult(int result, String functionName) { ImageSingletons.lookup(LogHandler.class).fatalError(); } } + + @Override + public VMMutex[] getMutexes() { + return mutexes; + } + + @Override + public VMCondition[] getConditions() { + return conditions; + } } final class WindowsVMMutex extends VMMutex { @@ -166,12 +184,13 @@ final class WindowsVMMutex extends VMMutex { UnsignedWord structOffset; @Platforms(Platform.HOSTED_ONLY.class) - protected WindowsVMMutex() { + protected WindowsVMMutex(String name) { + super(name); } @Uninterruptible(reason = "Called from uninterruptible code.") Process.PCRITICAL_SECTION getStructPointer() { - return (Process.PCRITICAL_SECTION) Word.objectToUntrackedPointer(ImageSingletons.lookup(WindowsVMLockSupport.class).syncStructs).add(structOffset); + return (Process.PCRITICAL_SECTION) Word.objectToUntrackedPointer(WindowsVMLockSupport.singleton().syncStructs).add(structOffset); } @Override @@ -229,7 +248,7 @@ final class WindowsVMCondition extends VMCondition { @Uninterruptible(reason = "Called from uninterruptible code.") Process.PCONDITION_VARIABLE getStructPointer() { - return (Process.PCONDITION_VARIABLE) Word.objectToUntrackedPointer(ImageSingletons.lookup(WindowsVMLockSupport.class).syncStructs).add(structOffset); + return (Process.PCONDITION_VARIABLE) Word.objectToUntrackedPointer(WindowsVMLockSupport.singleton().syncStructs).add(structOffset); } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index d6c0de826607..1296ea6ab82c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -27,6 +27,7 @@ import java.util.Arrays; import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; @@ -35,20 +36,23 @@ import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.word.Pointer; +import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; -import com.oracle.svm.core.annotate.AlwaysInline; import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.code.CodeInfo; import com.oracle.svm.core.code.CodeInfoAccess; import com.oracle.svm.core.code.CodeInfoTable; +import com.oracle.svm.core.code.RuntimeCodeInfoHistory; +import com.oracle.svm.core.code.RuntimeCodeInfoMemory; import com.oracle.svm.core.code.UntetheredCodeInfo; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.deopt.DeoptimizationSupport; import com.oracle.svm.core.deopt.DeoptimizedFrame; import com.oracle.svm.core.deopt.Deoptimizer; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicWord; +import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.stack.JavaFrameAnchor; import com.oracle.svm.core.stack.JavaFrameAnchors; @@ -65,9 +69,6 @@ import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.VMThreadLocalInfos; import com.oracle.svm.core.util.Counter; -import com.oracle.svm.core.util.VMError; - -import jdk.vm.ci.code.CodeUtil; public class SubstrateDiagnostics { private static final Stage0StackFramePrintVisitor[] PRINT_VISITORS = new Stage0StackFramePrintVisitor[]{Stage0StackFramePrintVisitor.SINGLETON, Stage1StackFramePrintVisitor.SINGLETON, @@ -103,8 +104,8 @@ public static int maxRetries() { } /** Prints extensive diagnostic information to the given Log. */ - public static void print(Log log, Pointer sp, CodePointer ip) { - print(log, sp, ip, WordFactory.nullPointer()); + public static boolean print(Log log, Pointer sp, CodePointer ip) { + return print(log, sp, ip, WordFactory.nullPointer()); } /** @@ -112,28 +113,25 @@ public static void print(Log log, Pointer sp, CodePointer ip) { * diagnostics, it can happen that the same thread enters this method multiple times. */ @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") - static void print(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context context) { + static boolean print(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context context) { log.newline(); // Save the state of the initial error so that this state is consistently used, even if // further errors occur while printing diagnostics. if (!state.trySet(log, sp, ip, context) && !isInProgressByCurrentThread()) { log.string("Error: printDiagnostics already in progress by another thread.").newline(); log.newline(); - return; + return false; } printDiagnosticsForCurrentState(); + return true; } private static void printDiagnosticsForCurrentState() { assert isInProgressByCurrentThread(); Log log = state.log; - Pointer sp = state.sp; - CodePointer ip = state.ip; - IsolateThread currentThread = CurrentIsolate.getCurrentThread(); - - if (state.diagnosticSections > 0) { + if (state.diagnosticThunkIndex > 0) { log.newline(); log.string("An error occurred while printing diagnostics. The remaining part of this section will be skipped.").newline(); log.resetIndentation(); @@ -143,31 +141,24 @@ private static void printDiagnosticsForCurrentState() { // printed earlier. int numDiagnosticThunks = DiagnosticThunkRegister.getSingleton().size(); while (state.diagnosticThunkIndex < numDiagnosticThunks) { + DiagnosticThunk thunk = DiagnosticThunkRegister.getSingleton().getThunk(state.diagnosticThunkIndex); try { - int index = state.diagnosticThunkIndex++; - DiagnosticThunkRegister.getSingleton().callDiagnosticThunk(log, index); + int invocationCount = state.invocationCount++; + thunk.printDiagnostics(log, invocationCount); + + state.diagnosticThunkIndex++; + state.invocationCount = 0; } catch (Exception e) { - dumpException(log, "callThunks", e); + dumpException(log, thunk, e); } } // Reset the state. - for (DiagnosticThunk thunk : thunks) { - thunk.reset(); - } state.clear(); } - private static boolean shouldPrint(int sectionBit) { - if ((state.diagnosticSections & sectionBit) == 0) { - state.diagnosticSections |= sectionBit; - return true; - } - return false; - } - - private static void skip(int sectionBit) { - state.diagnosticSections |= sectionBit; + private static void dumpException(Log log, DiagnosticThunk thunk, Exception e) { + log.newline().string("[!!! Exception while dumping ").string(thunk.getClass().getName()).string(": ").string(e.getClass().getName()).string("]").newline(); } @Uninterruptible(reason = "Prevent deoptimization of stack frames while in this method.") @@ -212,8 +203,8 @@ private static boolean printFrameAnchors(Log log, IsolateThread thread) { private static class PrintDiagnosticsState { AtomicWord diagnosticThread = new AtomicWord<>(); - volatile int diagnosticSections; volatile int diagnosticThunkIndex; + volatile int invocationCount; Log log; Pointer sp; @@ -223,8 +214,8 @@ private static class PrintDiagnosticsState { @SuppressWarnings("hiding") public boolean trySet(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context context) { if (diagnosticThread.compareAndSet(WordFactory.nullPointer(), CurrentIsolate.getCurrentThread())) { - assert diagnosticSections == 0; assert diagnosticThunkIndex == 0; + assert invocationCount == 0; this.log = log; this.sp = sp; this.ip = ip; @@ -241,53 +232,22 @@ public void clear() { context = WordFactory.nullPointer(); diagnosticThunkIndex = 0; - diagnosticSections = 0; + invocationCount = 0; diagnosticThread.set(WordFactory.nullPointer()); } } - public static abstract class DiagnosticThunk { - private volatile int count; - - @AlwaysInline("Avoid the virtual call inside.") - public void printDiagnostics(Log log) { - try { - printDiagnostics(log, count++); - } catch (Exception e) { - dumpException(log, this.getClass().getName(), e); - } - } - - public void reset() { - count = 0; - } - - /** - * Prints diagnostic information. This method may be invoked multiple times if an error - * occurred while printing diagnostics. For subsequent invocations, this method should try - * to print less information so that it is less likely that an error occurs. - */ - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") - protected abstract boolean printDiagnostics(Log log, int invocationCount); - - protected static void dumpException(Log log, String context, Exception e) { - log.newline().string("[!!! Exception during ").string(context).string(": ").string(e.getClass().getName()).string("]").newline(); - } - } - private static class DumpRegisters extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: - return dumpRegisters(log); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printRegisters(log); } } - private static boolean dumpRegisters(Log log) { + private static void printRegisters(Log log) { RegisterDumper.Context context = state.context; if (context.isNonNull()) { log.string("General Purpose Register Set values:").newline(); @@ -295,75 +255,85 @@ private static boolean dumpRegisters(Log log) { RegisterDumper.singleton().dumpRegisters(log, context); log.indent(false); } - return true; } } private static class DumpInstructions extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: // fall-through - case 1: - return printBytesBeforeAndAfterIp(log, invocationCount); - case 2: - return printWord(log); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount < 2) { + printBytesBeforeAndAfterIp(log, invocationCount); + } else if (invocationCount == 2) { + printWord(log); } } - private static boolean printBytesBeforeAndAfterIp(Log log, int invocationCount) { + private static void printBytesBeforeAndAfterIp(Log log, int invocationCount) { // print 64 or 32 instruction bytes. int bytesToPrint = 64 >> (invocationCount + 1); - return hexDump(log, state.ip, bytesToPrint, bytesToPrint); + hexDump(log, state.ip, bytesToPrint, bytesToPrint); } - private static boolean printWord(Log log) { + private static void printWord(Log log) { // just print one word starting at the ip - return hexDump(log, state.ip, 0, ConfigurationValues.getTarget().wordSize); + hexDump(log, state.ip, 0, ConfigurationValues.getTarget().wordSize); } - private static boolean hexDump(Log log, CodePointer ip, int bytesBefore, int bytesAfter) { + private static void hexDump(Log log, CodePointer ip, int bytesBefore, int bytesAfter) { log.string("Printing Instructions (ip=").hex(ip).string(")").newline(); - log.indent(true); log.hexdump(((Pointer) ip).subtract(bytesBefore), 1, bytesAfter); - log.indent(false); - return true; } } - private static class DumpDeoptStubPointer extends DiagnosticThunk { + private static class DumpTopOfCurrentThreadStack extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: - return printDeoptStubPointer(log); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printTopOfStack(log); + } + } + + private static void printTopOfStack(Log log) { + Pointer sp = state.sp; + Log.log().string("Top of stack: (sp=").zhex(sp).string(")"); + + UnsignedWord stackBase = VMThreads.StackBase.get(); + if (stackBase.equal(0)) { + Log.log().string("Cannot print stack information as the stack base is unknown.").newline(); + } else { + int bytesToPrint = 512; + UnsignedWord availableBytes = stackBase.subtract(sp); + if (availableBytes.belowThan(bytesToPrint)) { + bytesToPrint = NumUtil.safeToInt(availableBytes.rawValue()); + } + + log.hexdump(sp, 8, bytesToPrint); } } + } - private static boolean printDeoptStubPointer(Log log) { - if (DeoptimizationSupport.enabled()) { + private static class DumpDeoptStubPointer extends DiagnosticThunk { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0 && DeoptimizationSupport.enabled()) { log.string("DeoptStubPointer address: ").zhex(DeoptimizationSupport.getDeoptStubPointer().rawValue()).newline().newline(); } - return true; } } private static class DumpTopFrame extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: - return printTopFrame(log); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printTopFrame(log); } } - private static boolean printTopFrame(Log log) { + private static void printTopFrame(Log log) { // We already dump all safe values first, so there is nothing we could retry if an error // occurs. Pointer sp = state.sp; @@ -399,25 +369,20 @@ private static boolean printTopFrame(Log log) { } } log.indent(false); - return true; } } private static class DumpThreads extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: - return dumpThreads(log, "Full", true); - case 1: - return dumpThreads(log, "Reduced", false); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount < 2) { + dumpThreads(log, invocationCount == 0); } } - private static boolean dumpThreads(Log log, String prefix, boolean accessThreadObject) { - log.string(prefix).string(" thread info:").newline(); + private static void dumpThreads(Log log, boolean accessThreadObject) { + log.string("Thread info:").newline(); log.indent(true); // Only used for diagnostics - iterate all threads without locking the thread mutex. for (IsolateThread thread = VMThreads.firstThreadUnsafe(); thread.isNonNull(); thread = VMThreads.nextThread(thread)) { @@ -433,23 +398,19 @@ private static boolean dumpThreads(Log log, String prefix, boolean accessThreadO log.newline(); } log.indent(false); - return true; } } private static class DumpThreadLocals extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: // fall-through - case 1: - return printThreadLocals(log, invocationCount); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount < 2) { + printThreadLocals(log, invocationCount); } } - private static boolean printThreadLocals(Log log, int invocationCount) { + private static void printThreadLocals(Log log, int invocationCount) { IsolateThread currentThread = CurrentIsolate.getCurrentThread(); if (isThreadOnlyAttachedForCrashHandler(currentThread)) { if (invocationCount == 0) { @@ -462,146 +423,92 @@ private static boolean printThreadLocals(Log log, int invocationCount) { VMThreadLocalInfos.dumpToLog(log, currentThread, invocationCount == 0); log.indent(false); } - return true; } } private static class DumpCurrentVMOperations extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: // fall-through - case 1: - return printCurrentVMOperation(log, invocationCount); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount < 2) { + VMOperationControl.logCurrentVMOperation(log, invocationCount == 0); } } - - private static boolean printCurrentVMOperation(Log log, int invocationCount) { - VMOperationControl.logCurrentVMOperation(log, invocationCount == 0); - return true; - } } private static class DumpVMOperationHistory extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: // fall-through - case 1: - return printVMOperationHistory(log, invocationCount); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount < 2) { + VMOperationControl.logRecentEvents(log, invocationCount == 0); } } - - private static boolean printVMOperationHistory(Log log, int invocationCount) { - VMOperationControl.logRecentEvents(log, invocationCount == 0); - return true; - } } - private static class DumpRecentRuntimeCodeCacheOperations extends DiagnosticThunk { + private static class DumpCodeCacheHistory extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: // fall-through - case 1: - return printRecentRuntimeCodeCacheOperations(log, invocationCount); - default: - return false; - } - } - - private static boolean printRecentRuntimeCodeCacheOperations(Log log, int invocationCount) { - if (DeoptimizationSupport.enabled()) { - CodeInfoTable.getRuntimeCodeCache().logRecentOperations(log, invocationCount == 0); + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount < 2 && DeoptimizationSupport.enabled()) { + RuntimeCodeInfoHistory.singleton().printRecentOperations(log, invocationCount == 0); } - return true; } } private static class DumpRuntimeCodeCache extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: // fall-through - case 1: - return printRuntimeCodeCache(log, invocationCount); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount < 2 && DeoptimizationSupport.enabled()) { + RuntimeCodeInfoMemory.singleton().logTable(log, invocationCount == 0); } } - - private static boolean printRuntimeCodeCache(Log log, int invocationCount) { - if (DeoptimizationSupport.enabled()) { - CodeInfoTable.getRuntimeCodeCache().logTable(log, invocationCount == 0); - } - return true; - } } private static class DumpRecentDeoptimizations extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: // fall-through - case 1: - return printRecentDeoptimizations(log, invocationCount); - default: - return false; - } - } - - private static boolean printRecentDeoptimizations(Log log, int invocationCount) { - if (DeoptimizationSupport.enabled()) { + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount < 2 && DeoptimizationSupport.enabled()) { Deoptimizer.logRecentDeoptimizationEvents(log, invocationCount == 0); } - return true; } } private static class DumpCounters extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: - return printCounters(log); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printCounters(log); } } - private static boolean printCounters(Log log) { + private static void printCounters(Log log) { log.string("Counters:").newline(); log.indent(true); Counter.logValues(); log.indent(false); - return true; } } private static class DumpCurrentThreadFrameAnchors extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: - return printFrameAnchors(log, CurrentIsolate.getCurrentThread()); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printFrameAnchors(log, CurrentIsolate.getCurrentThread()); } } } private static class DumpCurrentThreadRawStackTrace extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: - return printRawStackTrace(log); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printRawStackTrace(log); } } @@ -620,16 +527,14 @@ private static boolean printRawStackTrace(Log log) { private static class DumpCurrentThreadDecodedStackTrace extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: - return printDecodedStackTrace(log); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printDecodedStackTrace(log); } } - private static boolean printDecodedStackTrace(Log log) { + private boolean printDecodedStackTrace(Log log) { Pointer sp = state.sp; CodePointer ip = state.ip; for (int i = 0; i < PRINT_VISITORS.length; i++) { @@ -639,25 +544,23 @@ private static boolean printDecodedStackTrace(Log log) { ThreadStackPrinter.printStacktrace(sp, ip, PRINT_VISITORS[i], log); log.indent(false); } catch (Exception e) { - dumpException(log, "dumpStacktrace", e); + dumpException(log, this, e); } } return true; } } - private static class PrintOtherStackTraces extends DiagnosticThunk { + private static class DumpOtherStackTraces extends DiagnosticThunk { @Override - protected boolean printDiagnostics(Log log, int invocationCount) { - switch (invocationCount) { - case 0: - return printOtherStackTraces(log); - default: - return false; + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printOtherStackTraces(log); } } - private static boolean printOtherStackTraces(Log log) { + private boolean printOtherStackTraces(Log log) { if (VMOperation.isInProgressAtSafepoint()) { // Iterate all threads without checking if the thread mutex is locked (it should be // locked by this thread though because we are at a safepoint). @@ -666,13 +569,13 @@ private static boolean printOtherStackTraces(Log log) { continue; } try { - log.string("Thread ").zhex(vmThread.rawValue()).string(":").newline(); + log.string("Thread ").zhex(vmThread.rawValue()).newline(); log.indent(true); printFrameAnchors(log, vmThread); printStacktrace(log, vmThread); log.indent(false); } catch (Exception e) { - dumpException(log, "dumpStacktrace", e); + dumpException(log, this, e); } } } @@ -680,13 +583,27 @@ private static boolean printOtherStackTraces(Log log) { } private static void printStacktrace(Log log, IsolateThread vmThread) { - log.string("Full Stacktrace for VMThread ").zhex(vmThread.rawValue()).string(":").newline(); + log.string("Full stacktrace").newline(); log.indent(true); JavaStackWalker.walkThread(vmThread, StackFramePrintVisitor.SINGLETON, log); log.indent(false); } } + public static abstract class DiagnosticThunk { + /** + * Prints diagnostic information. A typical implementation should use a state machine to + * execute different code depending on the invocation count (i.e., an invocationCount of 1 + * means that this method already failed once before). + * + * This method may be invoked multiple times if an error (e.g., exception or segfault) + * occurred while executing this method. Therefore, this method should always check the + * invocationCount argument before executing any code. + */ + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") + public abstract void printDiagnostics(Log log, int invocationCount); + } + public static class DiagnosticThunkRegister { DiagnosticThunk[] diagnosticThunks; @@ -707,7 +624,10 @@ public static synchronized DiagnosticThunkRegister getSingleton() { @Platforms(Platform.HOSTED_ONLY.class) DiagnosticThunkRegister() { - this.diagnosticThunks = new DiagnosticThunk[0]; + this.diagnosticThunks = new DiagnosticThunk[]{new DumpRegisters(), new DumpInstructions(), new DumpTopOfCurrentThreadStack(), new DumpDeoptStubPointer(), new DumpTopFrame(), + new DumpThreads(), new DumpThreadLocals(), new DumpCurrentVMOperations(), new DumpVMOperationHistory(), new DumpCodeCacheHistory(), + new DumpRuntimeCodeCache(), new DumpRecentDeoptimizations(), new DumpCounters(), new DumpCurrentThreadFrameAnchors(), new DumpCurrentThreadRawStackTrace(), + new DumpCurrentThreadDecodedStackTrace(), new DumpOtherStackTraces(), new VMLockSupport.DumpVMMutexes()}; } /** Register a diagnostic thunk to be called after a segfault. */ @@ -725,9 +645,8 @@ int size() { return diagnosticThunks.length; } - /** Call each registered diagnostic thunk. */ - void callDiagnosticThunk(Log log, int index) { - diagnosticThunks[index].printDiagnostics(log); + DiagnosticThunk getThunk(int index) { + return diagnosticThunks[index]; } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java index 41c9cb45cd89..c97c9069d4bb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java @@ -28,6 +28,7 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.options.Option; +import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageInfo; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; @@ -150,16 +151,17 @@ private static void dumpInterruptibly(PointerBase signalInfo, RegisterDumper.Con Log log = Log.enterFatalContext(logHandler, (CodePointer) callerIP, msg, null); if (log != null) { log.newline(); - log.string(msg).newline(); - + log.string("[ [ SubstrateSegfaultHandler caught a segfault in thread ").zhex(CurrentIsolate.getCurrentThread()).string(" ] ]").newline(); ImageSingletons.lookup(SubstrateSegfaultHandler.class).printSignalInfo(log, signalInfo); PointerBase sp = RegisterDumper.singleton().getSP(context); PointerBase ip = RegisterDumper.singleton().getIP(context); SubstrateDiagnostics.print(log, (Pointer) sp, (CodePointer) ip, context); - - log.string("Segfault detected, aborting process. Use runtime option -R:-InstallSegfaultHandler if you don't want to use SubstrateSegfaultHandler.").newline(); - log.newline(); + boolean printedDiagnostics = SubstrateDiagnostics.print(log, (Pointer) sp, (CodePointer) ip, context); + if (printedDiagnostics) { + log.string("Segfault detected, aborting process. Use runtime option -R:-InstallSegfaultHandler if you don't want to use SubstrateSegfaultHandler.").newline(); + log.newline(); + } } logHandler.fatalError(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java index 407b104765a6..3f7a2ba8bd5c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java @@ -253,8 +253,8 @@ public interface Thunk { } /** Prints extensive diagnostic information to the given Log. */ - public static void printDiagnostics(Log log, Pointer sp, CodePointer ip) { - SubstrateDiagnostics.print(log, sp, ip, WordFactory.nullPointer()); + public static boolean printDiagnostics(Log log, Pointer sp, CodePointer ip) { + return SubstrateDiagnostics.print(log, sp, ip, WordFactory.nullPointer()); } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java index c9f8eb1f61ab..b99ef987f03d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java @@ -74,4 +74,22 @@ public interface CodeInfo extends UntetheredCodeInfo { @DuplicatedInNativeCode // int STATE_UNREACHABLE = STATE_PARTIALLY_FREED + 1; + public static String stateToString(int codeInfoState) { + switch (codeInfoState) { + case STATE_CREATED: + return "created"; + case STATE_CODE_CONSTANTS_LIVE: + return "code constants live"; + case STATE_NON_ENTRANT: + return "non entrant"; + case STATE_READY_FOR_INVALIDATION: + return "ready for invalidation"; + case STATE_PARTIALLY_FREED: + return "partially freed"; + case STATE_UNREACHABLE: + return "unreachable"; + default: + return "invalid state"; + } + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java index 17d54ca21a0e..7cdbc0c1d959 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java @@ -222,18 +222,14 @@ private static void invalidateCodeAtSafepoint0(CodeInfo info) { private static void invalidateCodeAtSafepoint(CodeInfo info) { VMOperation.guaranteeInProgressAtSafepoint("Must be at a safepoint"); RuntimeCodeCache codeCache = getRuntimeCodeCache(); - long num = codeCache.logMethodOperation(info, RuntimeCodeCache.INFO_INVALIDATE); codeCache.invalidateMethod(info); - codeCache.logMethodOperationEnd(num); } @RestrictHeapAccess(access = Access.NO_ALLOCATION, reason = "Called by the GC") public static void invalidateNonStackCodeAtSafepoint(CodeInfo info) { VMOperation.guaranteeGCInProgress("Must only be called during a GC."); RuntimeCodeCache codeCache = getRuntimeCodeCache(); - long num = codeCache.logMethodOperation(info, RuntimeCodeCache.INFO_INVALIDATE); codeCache.invalidateNonStackMethod(info); - codeCache.logMethodOperationEnd(num); } @Uninterruptible(reason = "Prevent the GC from freeing the CodeInfo.", callerMustBe = true) @@ -279,7 +275,9 @@ public void duringSetup(DuringSetupAccess access) { ImageSingletons.add(CodeInfoDecoderCounters.class, new CodeInfoDecoderCounters()); ImageSingletons.add(CodeInfoEncoder.Counters.class, new CodeInfoEncoder.Counters()); ImageSingletons.add(ImageCodeInfo.class, new ImageCodeInfo()); + ImageSingletons.add(RuntimeCodeInfoHistory.class, new RuntimeCodeInfoHistory()); ImageSingletons.add(RuntimeCodeCache.class, new RuntimeCodeCache()); + ImageSingletons.add(RuntimeCodeInfoMemory.class, new RuntimeCodeInfoMemory()); } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java index f6ae3f11171f..bd11c4daac99 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java @@ -48,7 +48,6 @@ import com.oracle.svm.core.deopt.DeoptimizedFrame; import com.oracle.svm.core.deopt.Deoptimizer; import com.oracle.svm.core.deopt.SubstrateInstalledCode; -import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.stack.JavaStackWalker; @@ -56,7 +55,6 @@ import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.util.Counter; -import com.oracle.svm.core.util.RingBuffer; public class RuntimeCodeCache { @@ -68,18 +66,12 @@ public static class Options { public static final RuntimeOptionKey WriteableCodeCache = new RuntimeOptionKey<>(false); } - private final RingBuffer recentCodeCacheOperations = new RingBuffer<>(30, CodeCacheLogEntry::new); - private long codeCacheOperationSequenceNumber; - private final Counter.Group counters = new Counter.Group(CodeInfoTable.Options.CodeCacheCounters, "RuntimeCodeInfo"); private final Counter lookupMethodCount = new Counter(counters, "lookupMethod", ""); private final Counter addMethodCount = new Counter(counters, "addMethod", ""); private final Counter invalidateMethodCount = new Counter(counters, "invalidateMethod", ""); private final CodeNotOnStackVerifier codeNotOnStackVerifier = new CodeNotOnStackVerifier(); - static final String INFO_ADD = "Add"; - static final String INFO_INVALIDATE = "Invalidate"; - private static final int INITIAL_TABLE_SIZE = 100; private NonmovableArray codeInfos; @@ -160,22 +152,14 @@ private static int binarySearch(NonmovableArray a, int fromI } public void addMethod(CodeInfo info) { - VMOperation.guaranteeInProgressAtSafepoint("Modifying code tables that are used by the GC"); + assert VMOperation.isInProgressAtSafepoint() : "Modifying code tables that are used by the GC"; InstalledCodeObserverSupport.activateObservers(RuntimeCodeInfoAccess.getCodeObserverHandles(info)); - long num = logMethodOperation(info, INFO_ADD); addMethodOperation(info); - logMethodOperationEnd(num); } private void addMethodOperation(CodeInfo info) { addMethodCount.inc(); assert verifyTable(); - if (Options.TraceCodeCache.getValue()) { - Log.log().string("[" + INFO_ADD + " method: "); - logCodeInfo(Log.log(), info, true); - Log.log().string("]").newline(); - } - if (codeInfos.isNull() || numCodeInfos >= NonmovableArrays.lengthOf(codeInfos)) { enlargeTable(); assert verifyTable(); @@ -189,9 +173,7 @@ private void addMethodOperation(CodeInfo info) { numCodeInfos++; NonmovableArrays.setWord(codeInfos, insertionPoint, info); - if (Options.TraceCodeCache.getValue()) { - logTable(true); - } + RuntimeCodeInfoHistory.singleton().logAdd(info); assert verifyTable(); } @@ -231,11 +213,6 @@ private void prepareInvalidation(CodeInfo info) { VMOperation.guaranteeInProgressAtSafepoint("Modifying code tables that are used by the GC"); invalidateMethodCount.inc(); assert verifyTable(); - if (Options.TraceCodeCache.getValue()) { - Log.log().string("[").string(INFO_INVALIDATE).string(" method: "); - logCodeInfo(Log.log(), info, true); - Log.log().string("]").newline(); - } SubstrateInstalledCode installedCode = RuntimeCodeInfoAccess.getInstalledCode(info); if (installedCode != null) { @@ -263,10 +240,6 @@ private void finishInvalidation(CodeInfo info, boolean notifyGC) { NonmovableArrays.setWord(codeInfos, numCodeInfos, WordFactory.nullPointer()); RuntimeCodeInfoAccess.partialReleaseAfterInvalidate(info, notifyGC); - - if (Options.TraceCodeCache.getValue()) { - logTable(true); - } assert verifyTable(); } @@ -294,83 +267,6 @@ private boolean verifyTable() { return true; } - public void logTable(boolean allowJavaHeapAccess) { - logTable(Log.log(), allowJavaHeapAccess); - } - - private static final RingBuffer.Consumer PRINT_WITH_JAVA_HEAP_DATA = RuntimeCodeCache::printEntryWithJavaHeapData; - private static final RingBuffer.Consumer PRINT_WITHOUT_JAVA_HEAP_DATA = RuntimeCodeCache::printEntryWithoutJavaHeapData; - - public void logRecentOperations(Log log, boolean allowJavaHeapAccess) { - log.string("Recent RuntimeCodeCache operations: "); - recentCodeCacheOperations.foreach(log, allowJavaHeapAccess ? PRINT_WITH_JAVA_HEAP_DATA : PRINT_WITHOUT_JAVA_HEAP_DATA); - } - - private static void printEntryWithJavaHeapData(Object context, CodeCacheLogEntry entry) { - printEntry(context, entry, true); - } - - private static void printEntryWithoutJavaHeapData(Object context, CodeCacheLogEntry entry) { - printEntry(context, entry, false); - } - - private static void printEntry(Object context, CodeCacheLogEntry entry, boolean allowJavaHeapAccess) { - Log log = (Log) context; - entry.log(log, allowJavaHeapAccess); - } - - public void logTable(Log log, boolean allowJavaHeapAccess) { - log.string("RuntimeCodeCache contains ").signed(numCodeInfos).string(" methods"); - for (int i = 0; i < numCodeInfos; i++) { - logCodeInfo(log, i, allowJavaHeapAccess); - } - } - - @Uninterruptible(reason = "Must prevent the GC from freeing the CodeInfo object.") - private void logCodeInfo(Log log, int i, boolean allowJavaHeapAccess) { - UntetheredCodeInfo untetheredInfo = NonmovableArrays.getWord(codeInfos, i); - Object tether = CodeInfoAccess.acquireTether(untetheredInfo); - try { - CodeInfo info = CodeInfoAccess.convert(untetheredInfo, tether); - logCodeInfo0(log, info, allowJavaHeapAccess); - } finally { - CodeInfoAccess.releaseTether(untetheredInfo, tether); - } - } - - @Uninterruptible(reason = "Pass the now protected CodeInfo to interruptible code.", calleeMustBe = false) - private static void logCodeInfo0(Log log, CodeInfo info, boolean allowJavaHeapAccess) { - log.newline().hex(CodeInfoAccess.getCodeStart(info)).string(" "); - logCodeInfo(log, info, allowJavaHeapAccess); - } - - private static void logCodeInfo(Log log, CodeInfo info, boolean allowJavaHeapAccess) { - logCodeInfo(log, allowJavaHeapAccess, CodeInfoAccess.getName(info), CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info), CodeInfoAccess.getCodeSize(info)); - } - - private static void logCodeInfo(Log log, boolean allowJavaHeapAccess, String codeName, CodePointer codeStart, CodePointer codeEnd, UnsignedWord codeSize) { - if (allowJavaHeapAccess) { - log.string(codeName); - } - log.string(" ip: ").hex(codeStart).string(" - ").hex(codeEnd); - log.string(" size: ").unsigned(codeSize); - /* - * Note that we are not trying to output the InstalledCode object. It is not a pinned - * object, so when log printing (for, e.g., a fatal error) occurs during a GC, then the VM - * could segfault. - */ - } - - long logMethodOperation(CodeInfo info, String kind) { - long current = ++codeCacheOperationSequenceNumber; - recentCodeCacheOperations.next().setValues(current, kind, CodeInfoAccess.getName(info), CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info), CodeInfoAccess.getCodeSize(info)); - return current; - } - - void logMethodOperationEnd(long operationNumber) { - recentCodeCacheOperations.next().setValues(operationNumber, null, null, WordFactory.nullPointer(), WordFactory.nullPointer(), WordFactory.unsigned(0)); - } - public boolean walkRuntimeMethods(MemoryWalker.Visitor visitor) { VMOperation.guaranteeInProgress("Modifying code tables that are used by the GC"); boolean continueVisiting = true; @@ -399,40 +295,6 @@ private static boolean visitRuntimeMethod0(MemoryWalker.Visitor visitor, CodeInf return visitor.visitCode(codeInfo, ImageSingletons.lookup(CodeInfoMemoryWalker.class)); } - private static class CodeCacheLogEntry { - private long sequenceNumber; - private String kind; - private String codeName; - private CodePointer codeStart; - private CodePointer codeEnd; - private UnsignedWord codeSize; - - @Platforms(Platform.HOSTED_ONLY.class) - CodeCacheLogEntry() { - } - - public void setValues(long sequenceNumber, String kind, String codeName, CodePointer codeStart, CodePointer codeEnd, UnsignedWord codeSize) { - assert Heap.getHeap().isInImageHeap(kind); - this.sequenceNumber = sequenceNumber; - this.kind = kind; - this.codeName = codeName; - this.codeStart = codeStart; - this.codeEnd = codeEnd; - this.codeSize = codeSize; - } - - public void log(Log log, boolean allowJavaHeapAccess) { - log.newline(); - if (kind != null) { - log.string(kind).string(": "); - logCodeInfo(log, allowJavaHeapAccess, codeName, codeStart, codeEnd, codeSize); - log.string(" ").unsigned(sequenceNumber).string(":{"); - } else { - log.string("}:").unsigned(sequenceNumber); - } - } - } - private static final class CodeNotOnStackVerifier extends StackFrameVisitor { private CodeInfo codeInfoToCheck; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java index 22f2fd0cbe66..ce698a09143a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java @@ -191,7 +191,7 @@ public static CodeInfo allocateMethodInfo() { } public static CodeInfo allocateMethodInfo(NonmovableObjectArray objectData) { - CodeInfoImpl info = UnmanagedMemory.calloc(SizeOf.unsigned(CodeInfoImpl.class)); + CodeInfoImpl info = UnmanagedMemory.calloc(getSizeOfCodeInfo()); assert objectData.isNonNull() && NonmovableArrays.lengthOf(objectData) == CodeInfoImpl.OBJFIELDS_COUNT; info.setObjectFields(objectData); @@ -201,6 +201,10 @@ public static CodeInfo allocateMethodInfo(NonmovableObjectArray objectDa return info; } + public static UnsignedWord getSizeOfCodeInfo() { + return SizeOf.unsigned(CodeInfoImpl.class); + } + static void partialReleaseAfterInvalidate(CodeInfo info, boolean notifyGC) { InstalledCodeObserverSupport.removeObservers(RuntimeCodeInfoAccess.getCodeObserverHandles(info)); releaseMemory(info, notifyGC); @@ -224,6 +228,7 @@ private static void releaseMemory(CodeInfo info, boolean notifyGC) { * walk even when CodeInfo data is already partially freed. */ CodeInfoAccess.setState(info, CodeInfo.STATE_PARTIALLY_FREED); + RuntimeCodeInfoHistory.singleton().logInvalidate(info); } public static CodePointer allocateCodeMemory(UnsignedWord size) { @@ -274,6 +279,7 @@ public static void releaseMethodInfoMemory(CodeInfo info, boolean notifyGC) { if (!cast(info).getAllObjectsAreInImageHeap()) { forEachArray(info, RELEASE_ACTION); } + RuntimeCodeInfoHistory.singleton().logFree(info); ImageSingletons.lookup(UnmanagedMemorySupport.class).free(info); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java new file mode 100644 index 000000000000..c438b6b9b4e7 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2021, 2021, 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.code; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.function.CodePointer; +import org.graalvm.word.UnsignedWord; + +import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.log.Log; +import com.oracle.svm.core.thread.VMOperation; +import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.util.RingBuffer; + +public class RuntimeCodeInfoHistory { + private static final RingBuffer.Consumer PRINT_WITH_JAVA_HEAP_DATA = RuntimeCodeInfoHistory::printEntryWithJavaHeapData; + private static final RingBuffer.Consumer PRINT_WITHOUT_JAVA_HEAP_DATA = RuntimeCodeInfoHistory::printEntryWithoutJavaHeapData; + + private final RingBuffer recentOperations; + + @Platforms(Platform.HOSTED_ONLY.class) + RuntimeCodeInfoHistory() { + recentOperations = new RingBuffer<>(20, CodeCacheLogEntry::new); + } + + @Fold + public static RuntimeCodeInfoHistory singleton() { + return ImageSingletons.lookup(RuntimeCodeInfoHistory.class); + } + + public void logAdd(CodeInfo info) { + logOperation("Added", info); + } + + public void logMakeNonEntrant(CodeInfo info) { + logOperation("Made non-entrant", info); + } + + public void logInvalidate(CodeInfo info) { + logOperation("Invalidated", info); + } + + private void logOperation(String kind, CodeInfo info) { + assert VMOperation.isInProgressAtSafepoint(); + + traceCodeCache(kind, info, true); + recentOperations.next().setValues(kind, info, CodeInfoAccess.getState(info), CodeInfoAccess.getName(info), CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info), + CodeInfoAccess.getCodeSize(info)); + } + + public void logFree(CodeInfo info) { + assert VMOperation.isInProgressAtSafepoint() || VMThreads.isTearingDown(); + + traceCodeCache("Freed", info, false); + recentOperations.next().setValues("Freed", info, CodeInfoAccess.getState(info), null, CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info), CodeInfoAccess.getCodeSize(info)); + } + + private static void traceCodeCache(String kind, CodeInfo info, boolean allowJavaHeapAccess) { + if (RuntimeCodeCache.Options.TraceCodeCache.getValue()) { + Log.log().string(kind).string(" method: "); + printCodeInfo(Log.log(), info, allowJavaHeapAccess); + } + } + + static void printCodeInfo(Log log, CodeInfo info, boolean allowJavaHeapAccess) { + printCodeInfo(log, allowJavaHeapAccess, info, CodeInfoAccess.getState(info), CodeInfoAccess.getName(info), CodeInfoAccess.getCodeStart(info), + CodeInfoAccess.getCodeEnd(info), CodeInfoAccess.getCodeSize(info)); + } + + private static void printCodeInfo(Log log, boolean allowJavaHeapAccess, CodeInfo codeInfo, int codeInfoState, String codeName, CodePointer codeStart, CodePointer codeEnd, UnsignedWord codeSize) { + log.string("[").zhex(codeInfo).string(" - ").zhex(((UnsignedWord) codeInfo).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()).subtract(1)).string("]"); + log.string(" (").string(CodeInfo.stateToString(codeInfoState)).string(")"); + if (allowJavaHeapAccess) { + log.spaces(1).string(codeName); + } + log.string(", ip: [").zhex(codeStart).string(" - ").zhex(codeEnd).string("]"); + log.string(", size: ").unsigned(codeSize); + log.newline(); + /* + * Note that we are not trying to output the InstalledCode object. It is not a pinned + * object, so when log printing (for, e.g., a fatal error) occurs during a GC, then the VM + * could segfault. + */ + } + + public void printRecentOperations(Log log, boolean allowJavaHeapAccess) { + log.string("Recent RuntimeCodeCache operations: "); + recentOperations.foreach(log, allowJavaHeapAccess ? PRINT_WITH_JAVA_HEAP_DATA : PRINT_WITHOUT_JAVA_HEAP_DATA); + } + + private static void printEntryWithJavaHeapData(Object context, CodeCacheLogEntry entry) { + printEntry(context, entry, true); + } + + private static void printEntryWithoutJavaHeapData(Object context, CodeCacheLogEntry entry) { + printEntry(context, entry, false); + } + + private static void printEntry(Object context, CodeCacheLogEntry entry, boolean allowJavaHeapAccess) { + Log log = (Log) context; + entry.log(log, allowJavaHeapAccess); + } + + private static class CodeCacheLogEntry { + private long timestamp; + private String kind; + private String codeName; + private CodeInfo codeInfo; + private int codeInfoState; + private CodePointer codeStart; + private CodePointer codeEnd; + private UnsignedWord codeSize; + + @Platforms(Platform.HOSTED_ONLY.class) + CodeCacheLogEntry() { + } + + public void setValues(String kind, CodeInfo codeInfo, int codeInfoState, String codeName, CodePointer codeStart, CodePointer codeEnd, UnsignedWord codeSize) { + assert Heap.getHeap().isInImageHeap(kind); + this.timestamp = System.currentTimeMillis(); + this.kind = kind; + this.codeInfo = codeInfo; + this.codeInfoState = codeInfoState; + this.codeName = codeName; + this.codeStart = codeStart; + this.codeEnd = codeEnd; + this.codeSize = codeSize; + } + + public void log(Log log, boolean allowJavaHeapAccess) { + if (kind != null) { + log.unsigned(timestamp).string(" - ").string(kind).string(": "); + printCodeInfo(log, allowJavaHeapAccess, codeInfo, codeInfoState, codeName, codeStart, codeEnd, codeSize); + } + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java index 071aec06be27..a85ed6e3b74b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java @@ -30,16 +30,15 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.word.WordFactory; import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.c.NonmovableArray; import com.oracle.svm.core.c.NonmovableArrays; import com.oracle.svm.core.code.RuntimeCodeCache.CodeInfoVisitor; import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.log.Log; import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.util.VMError; @@ -243,6 +242,31 @@ private static int nextIndex(int index, int length) { return (index + 1 < length) ? (index + 1) : 0; } + /** Potentially unsafe and may therefore only be used when printing diagnostics. */ + public void logTable(Log log, boolean allowJavaHeapAccess) { + log.string("RuntimeCodeInfoMemory contains ").signed(count).string(" methods"); + for (int i = 0; i < NonmovableArrays.lengthOf(table); i++) { + logCodeInfo(log, i, allowJavaHeapAccess); + } + } + + @Uninterruptible(reason = "Must prevent the GC from freeing the CodeInfo object.") + private void logCodeInfo(Log log, int i, boolean allowJavaHeapAccess) { + UntetheredCodeInfo untetheredInfo = NonmovableArrays.getWord(table, i); + Object tether = CodeInfoAccess.acquireTether(untetheredInfo); + try { + CodeInfo info = CodeInfoAccess.convert(untetheredInfo, tether); + logCodeInfo0(log, info, allowJavaHeapAccess); + } finally { + CodeInfoAccess.releaseTether(untetheredInfo, tether); + } + } + + @Uninterruptible(reason = "Pass the now protected CodeInfo to interruptible code.", calleeMustBe = false) + private static void logCodeInfo0(Log log, CodeInfo info, boolean allowJavaHeapAccess) { + RuntimeCodeInfoHistory.printCodeInfo(log, info, allowJavaHeapAccess); + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public void tearDown() { if (table.isNonNull()) { @@ -264,11 +288,3 @@ public void tearDown() { } } } - -@AutomaticFeature -class RuntimeMethodInfoMemoryFeature implements Feature { - @Override - public void afterRegistration(AfterRegistrationAccess access) { - ImageSingletons.add(RuntimeCodeInfoMemory.class, new RuntimeCodeInfoMemory()); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java index 0a81853cca73..6981e9a676fd 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java @@ -408,7 +408,6 @@ public static void invalidateMethodOfFrame(Pointer sourceSp, SpeculationReason s } } else { if (installedCode == null) { - CodeInfoTable.getRuntimeCodeCache().logTable(true); throw VMError.shouldNotReachHere( "Only runtime compiled methods can be invalidated. sp = " + Long.toHexString(sourceSp.rawValue()) + ", returnAddress = " + Long.toHexString(returnAddress.rawValue())); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleHashtable.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleHashtable.java index 1f7c4f164467..90b336f40c74 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleHashtable.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleHashtable.java @@ -44,14 +44,14 @@ public abstract class UninterruptibleHashtable private int size; @Platforms(Platform.HOSTED_ONLY.class) - public UninterruptibleHashtable() { - this(DEFAULT_TABLE_LENGTH); + public UninterruptibleHashtable(String name) { + this(name, DEFAULT_TABLE_LENGTH); } @Platforms(Platform.HOSTED_ONLY.class) - public UninterruptibleHashtable(int primeLength) { + public UninterruptibleHashtable(String name, int primeLength) { this.table = createTable(primeLength); - this.mutex = new VMMutex(); + this.mutex = new VMMutex(name); this.size = 0; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java index 66303d25e6ba..67aa0d8d116a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.locks; +import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.Feature; @@ -37,7 +38,7 @@ * Support of {@link VMMutex} and {@link VMCondition} in single-threaded environments. No real * locking is necessary. */ -final class SingleThreadedVMLockSupport { +final class SingleThreadedVMLockSupport extends VMLockSupport { // Empty class to have the same name as the source file. } @@ -47,7 +48,7 @@ final class SingleThreadedVMLockFeature implements Feature { private final ClassInstanceReplacer mutexReplacer = new ClassInstanceReplacer(VMMutex.class) { @Override protected VMMutex createReplacement(VMMutex source) { - return new SingleThreadedVMMutex(); + return new SingleThreadedVMMutex(source.getName()); } }; @@ -65,6 +66,7 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { @Override public void duringSetup(DuringSetupAccess access) { + ImageSingletons.add(VMLockSupport.class, new SingleThreadedVMLockSupport()); access.registerObjectReplacer(mutexReplacer); access.registerObjectReplacer(conditionReplacer); } @@ -79,7 +81,8 @@ public void beforeCompilation(BeforeCompilationAccess access) { final class SingleThreadedVMMutex extends VMMutex { @Platforms(Platform.HOSTED_ONLY.class) - protected SingleThreadedVMMutex() { + protected SingleThreadedVMMutex(String name) { + super(name); } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java new file mode 100644 index 000000000000..7a22fa3e4261 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021, 2021, 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.locks; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.IsolateThread; + +import com.oracle.svm.core.SubstrateDiagnostics.DiagnosticThunk; +import com.oracle.svm.core.annotate.RestrictHeapAccess; +import com.oracle.svm.core.log.Log; + +public abstract class VMLockSupport { + public VMMutex[] getMutexes() { + return null; + } + + public VMCondition[] getConditions() { + return null; + } + + public static class DumpVMMutexes extends DiagnosticThunk { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { + if (invocationCount == 0) { + printVMMutexes(log); + } + } + + private static void printVMMutexes(Log log) { + log.string("VM mutexes:").newline(); + log.indent(true); + + VMLockSupport support = ImageSingletons.lookup(VMLockSupport.class); + VMMutex[] mutexes = support.getMutexes(); + if (mutexes == null) { + log.string("No mutex information is available."); + } else { + for (int i = 0; i < mutexes.length; i++) { + VMMutex mutex = mutexes[i]; + IsolateThread owner = mutex.owner; + if (owner.isNonNull()) { + log.string(mutex.getName()).string(" is locked by "); + if (owner.equal(VMMutex.UNSPECIFIED_OWNER)) { + log.string(" an unspecified thread."); + } else { + log.string(" thread ").zhex(owner); + } + log.newline(); + } + } + } + + log.indent(false); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMMutex.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMMutex.java index 180e95d2d186..fc3dbea34951 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMMutex.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMMutex.java @@ -50,12 +50,23 @@ * with platform-specific implementations. */ public class VMMutex { - private static final UnsignedWord UNSPECIFIED_OWNER = WordFactory.unsigned(-1); + static final UnsignedWord UNSPECIFIED_OWNER = WordFactory.unsigned(-1); - private IsolateThread owner; + private final String name; + IsolateThread owner; @Platforms(Platform.HOSTED_ONLY.class) public VMMutex() { + this.name = "Unspecified"; + } + + @Platforms(Platform.HOSTED_ONLY.class) + public VMMutex(String name) { + this.name = name; + } + + public String getName() { + return name; } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java index fd52965ad4ed..1256f271ab1a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java @@ -88,10 +88,12 @@ class Options { * platforms use this direction. */ interface OSSupport { + /** The highest address of the stack or zero if not supported. */ default UnsignedWord lookupStackBase() { return WordFactory.zero(); } + /** The lowest address of the stack. */ @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") UnsignedWord lookupStackEnd(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java index 5fefc428c553..50dae293dbc3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java @@ -445,7 +445,7 @@ private static final class WorkQueues { this.nativeSafepointOperations = new NativeVMOperationQueue(prefix + "NativeSafepointOperations"); this.javaNonSafepointOperations = new JavaVMOperationQueue(prefix + "JavaNonSafepointOperations"); this.javaSafepointOperations = new JavaVMOperationQueue(prefix + "JavaSafepointOperations"); - this.mutex = createMutex(needsLocking); + this.mutex = createMutex(prefix + "VMOperationControlWorkQueue", needsLocking); this.operationQueued = createCondition(); this.operationFinished = createCondition(); } @@ -675,9 +675,9 @@ private void assertIsLocked() { } @Platforms(value = Platform.HOSTED_ONLY.class) - private static VMMutex createMutex(boolean needsLocking) { + private static VMMutex createMutex(String mutexName, boolean needsLocking) { if (needsLocking) { - return new VMMutex(); + return new VMMutex(mutexName); } return null; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index e7955d006cfd..d517a73d9f77 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -109,7 +109,7 @@ public static VMThreads singleton() { * still holds that mutex. * */ - protected static final VMMutex THREAD_MUTEX = new VMMutex(); + protected static final VMMutex THREAD_MUTEX = new VMMutex("Thread"); /** * A condition variable for waiting for and notifying on changes to the {@link IsolateThread} @@ -139,10 +139,11 @@ public static VMThreads singleton() { private static final FastThreadLocalWord OSThreadIdTL = FastThreadLocalFactory.createWord(); protected static final FastThreadLocalWord OSThreadHandleTL = FastThreadLocalFactory.createWord(); public static final FastThreadLocalWord IsolateTL = FastThreadLocalFactory.createWord(); + /** The highest stack address. */ public static final FastThreadLocalWord StackBase = FastThreadLocalFactory.createWord(); /** - * The end of the stack. Note that this value does not necessarily match the value that is used - * for the stack overflow check. + * The lowest stack address. Note that this value does not necessarily match the value that is + * used for the stack overflow check. */ public static final FastThreadLocalWord StackEnd = FastThreadLocalFactory.createWord(); diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrRecorderThread.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrRecorderThread.java index b48106c54815..85841f379416 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrRecorderThread.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrRecorderThread.java @@ -51,7 +51,7 @@ public JfrRecorderThread(JfrGlobalMemory globalMemory, JfrUnlockedChunkWriter un super("JFR Recorder Thread"); this.globalMemory = globalMemory; this.unlockedChunkWriter = unlockedChunkWriter; - this.mutex = new VMMutex(); + this.mutex = new VMMutex("JfrRecorder"); this.condition = new VMCondition(mutex); setDaemon(true); } diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java index 1c13be2f4341..b1241d5e7bae 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java @@ -162,6 +162,11 @@ private interface JfrSymbol extends UninterruptibleEntry { } private static class JfrSymbolHashtable extends UninterruptibleHashtable { + @Platforms(Platform.HOSTED_ONLY.class) + public JfrSymbolHashtable() { + super("JfrSymbolHashtable"); + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override protected JfrSymbol[] createTable(int size) { diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java index af42c977035f..009d36e12d9b 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java @@ -34,6 +34,7 @@ import com.oracle.svm.core.code.CodeInfo; import com.oracle.svm.core.code.CodeInfoAccess; import com.oracle.svm.core.code.CodeInfoTable; +import com.oracle.svm.core.code.RuntimeCodeInfoHistory; import com.oracle.svm.core.code.UntetheredCodeInfo; import com.oracle.svm.core.code.UntetheredCodeInfoAccess; import com.oracle.svm.core.deopt.SubstrateInstalledCode; @@ -148,6 +149,7 @@ private void invalidateWithoutDeoptimization0() { try { // Indicates to GC that the code can be freed once there are no activations left CodeInfo codeInfo = CodeInfoAccess.convert(untetheredInfo, tether); CodeInfoAccess.setState(codeInfo, CodeInfo.STATE_NON_ENTRANT); + RuntimeCodeInfoHistory.singleton().logMakeNonEntrant(codeInfo); } finally { CodeInfoAccess.releaseTether(untetheredInfo, tether); } From dd80fa579bcba8a4e0b3c855b47d19149c70500b Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 1 Jul 2021 14:39:07 +0200 Subject: [PATCH 11/28] Format pointers more consistently. Refactored DiagnosticThunk. --- .../oracle/svm/core/genscavenge/GCImpl.java | 24 +- .../core/genscavenge/GreyObjectsWalker.java | 6 +- .../genscavenge/GreyToBlackObjectVisitor.java | 5 +- .../core/genscavenge/HeapChunkProvider.java | 2 +- .../oracle/svm/core/genscavenge/HeapImpl.java | 22 +- .../svm/core/genscavenge/HeapVerifier.java | 52 ++-- .../svm/core/genscavenge/ImageHeapWalker.java | 14 +- .../svm/core/genscavenge/PathExhibitor.java | 12 +- .../oracle/svm/core/genscavenge/Space.java | 14 +- .../core/genscavenge/remset/CardTable.java | 6 +- .../genscavenge/remset/FirstObjectTable.java | 13 +- .../oracle/svm/core/SubstrateDiagnostics.java | 224 +++++++++++------- .../svm/core/code/RuntimeCodeInfoHistory.java | 4 +- .../oracle/svm/core/deopt/Deoptimizer.java | 12 +- .../oracle/svm/core/locks/VMLockSupport.java | 11 +- .../src/com/oracle/svm/core/log/RealLog.java | 2 +- .../svm/core/thread/VMOperationControl.java | 4 +- 17 files changed, 229 insertions(+), 198 deletions(-) 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 a4629b00c2eb..99e10ccbae88 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 @@ -399,10 +399,10 @@ private static void verbosePostCondition() { log.string("[GCImpl.postcondition: Eden space should be empty after a collection.").newline(); /* Print raw fields before trying to walk the chunk lists. */ log.string(" These should all be 0:").newline(); - log.string(" Eden space first AlignedChunk: ").hex(youngGen.getEden().getFirstAlignedHeapChunk()).newline(); - log.string(" Eden space last AlignedChunk: ").hex(youngGen.getEden().getLastAlignedHeapChunk()).newline(); - log.string(" Eden space first UnalignedChunk: ").hex(youngGen.getEden().getFirstUnalignedHeapChunk()).newline(); - log.string(" Eden space last UnalignedChunk: ").hex(youngGen.getEden().getLastUnalignedHeapChunk()).newline(); + log.string(" Eden space first AlignedChunk: ").zhex(youngGen.getEden().getFirstAlignedHeapChunk()).newline(); + log.string(" Eden space last AlignedChunk: ").zhex(youngGen.getEden().getLastAlignedHeapChunk()).newline(); + log.string(" Eden space first UnalignedChunk: ").zhex(youngGen.getEden().getFirstUnalignedHeapChunk()).newline(); + log.string(" Eden space last UnalignedChunk: ").zhex(youngGen.getEden().getLastUnalignedHeapChunk()).newline(); youngGen.getEden().report(log, true).newline(); log.string("]").newline(); } @@ -411,10 +411,10 @@ private static void verbosePostCondition() { log.string("[GCImpl.postcondition: Survivor toSpace should be empty after a collection.").newline(); /* Print raw fields before trying to walk the chunk lists. */ log.string(" These should all be 0:").newline(); - log.string(" Survivor space ").signed(i).string(" first AlignedChunk: ").hex(youngGen.getSurvivorToSpaceAt(i).getFirstAlignedHeapChunk()).newline(); - log.string(" Survivor space ").signed(i).string(" last AlignedChunk: ").hex(youngGen.getSurvivorToSpaceAt(i).getLastAlignedHeapChunk()).newline(); - log.string(" Survivor space ").signed(i).string(" first UnalignedChunk: ").hex(youngGen.getSurvivorToSpaceAt(i).getFirstUnalignedHeapChunk()).newline(); - log.string(" Survivor space ").signed(i).string(" last UnalignedChunk: ").hex(youngGen.getSurvivorToSpaceAt(i).getLastUnalignedHeapChunk()).newline(); + log.string(" Survivor space ").signed(i).string(" first AlignedChunk: ").zhex(youngGen.getSurvivorToSpaceAt(i).getFirstAlignedHeapChunk()).newline(); + log.string(" Survivor space ").signed(i).string(" last AlignedChunk: ").zhex(youngGen.getSurvivorToSpaceAt(i).getLastAlignedHeapChunk()).newline(); + log.string(" Survivor space ").signed(i).string(" first UnalignedChunk: ").zhex(youngGen.getSurvivorToSpaceAt(i).getFirstUnalignedHeapChunk()).newline(); + log.string(" Survivor space ").signed(i).string(" last UnalignedChunk: ").zhex(youngGen.getSurvivorToSpaceAt(i).getLastUnalignedHeapChunk()).newline(); youngGen.getSurvivorToSpaceAt(i).report(log, true).newline(); log.string("]").newline(); } @@ -423,10 +423,10 @@ private static void verbosePostCondition() { log.string("[GCImpl.postcondition: oldGen toSpace should be empty after a collection.").newline(); /* Print raw fields before trying to walk the chunk lists. */ log.string(" These should all be 0:").newline(); - log.string(" oldGen toSpace first AlignedChunk: ").hex(oldGen.getToSpace().getFirstAlignedHeapChunk()).newline(); - log.string(" oldGen toSpace last AlignedChunk: ").hex(oldGen.getToSpace().getLastAlignedHeapChunk()).newline(); - log.string(" oldGen.toSpace first UnalignedChunk: ").hex(oldGen.getToSpace().getFirstUnalignedHeapChunk()).newline(); - log.string(" oldGen.toSpace last UnalignedChunk: ").hex(oldGen.getToSpace().getLastUnalignedHeapChunk()).newline(); + log.string(" oldGen toSpace first AlignedChunk: ").zhex(oldGen.getToSpace().getFirstAlignedHeapChunk()).newline(); + log.string(" oldGen toSpace last AlignedChunk: ").zhex(oldGen.getToSpace().getLastAlignedHeapChunk()).newline(); + log.string(" oldGen.toSpace first UnalignedChunk: ").zhex(oldGen.getToSpace().getFirstUnalignedHeapChunk()).newline(); + log.string(" oldGen.toSpace last UnalignedChunk: ").zhex(oldGen.getToSpace().getLastUnalignedHeapChunk()).newline(); oldGen.getToSpace().report(log, true).newline(); oldGen.getFromSpace().report(log, true).newline(); log.string("]").newline(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyObjectsWalker.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyObjectsWalker.java index d1c39c54051c..3788ec2572df 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyObjectsWalker.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyObjectsWalker.java @@ -62,11 +62,11 @@ void setScanStart(Space s) { space = s; AlignedHeapChunk.AlignedHeader aChunk = s.getLastAlignedHeapChunk(); alignedHeapChunk = aChunk; - trace.string(" alignedHeapChunk: ").hex(alignedHeapChunk).string(" isNull: ").bool(aChunk.isNull()); + trace.string(" alignedHeapChunk: ").zhex(alignedHeapChunk).string(" isNull: ").bool(aChunk.isNull()); alignedTop = (aChunk.isNonNull() ? HeapChunk.getTopPointer(aChunk) : WordFactory.nullPointer()); - trace.string(" alignedTop: ").hex(alignedTop); + trace.string(" alignedTop: ").zhex(alignedTop); unalignedHeapChunk = s.getLastUnalignedHeapChunk(); - trace.string(" unalignedChunkPointer: ").hex(unalignedHeapChunk).string("]").newline(); + trace.string(" unalignedChunkPointer: ").zhex(unalignedHeapChunk).string("]").newline(); } /** Compare the snapshot to the current state of the Space to see if there are grey Objects. */ diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java index 1818a21b8052..8e54eb15aaac 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java @@ -131,7 +131,6 @@ public void noteObject(Object o) { historyCount += 1; } - @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") public void printDiagnostics(Log log) { if (historyCount > 0) { @@ -149,11 +148,11 @@ public void printDiagnostics(Log log) { int index = countToIndex(historyCount + count); log.string(" index: ").unsigned(index, 3, Log.RIGHT_ALIGN); Word objectEntry = objectHistory[index]; - log.string(" objectEntry: ").hex(objectEntry); + log.string(" objectEntry: ").zhex(objectEntry); UnsignedWord headerEntry = headerHistory[index]; Pointer headerHub = (Pointer) ObjectHeaderImpl.clearBits(headerEntry); UnsignedWord headerHeaderBits = ObjectHeaderImpl.getHeaderBitsFromHeaderCarefully(headerEntry); - log.string(" headerEntry: ").hex(headerEntry).string(" = ").hex(headerHub).string(" | ").hex(headerHeaderBits).string(" / "); + log.string(" headerEntry: ").zhex(headerEntry).string(" = ").zhex(headerHub).string(" | ").zhex(headerHeaderBits).string(" / "); boolean headerInImageHeap = imageHeapInfo.isInReadOnlyReferencePartition(headerHub) || imageHeapInfo.isInReadOnlyRelocatablePartition(headerHub); if (headerInImageHeap) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java index 9d327253006f..bdc614bade43 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java @@ -271,7 +271,7 @@ Log report(Log log, boolean traceHeapChunks) { if (unusedAlignedChunks.get().isNonNull()) { log.newline().string("aligned chunks:").redent(true); for (AlignedHeapChunk.AlignedHeader aChunk = unusedAlignedChunks.get(); aChunk.isNonNull(); aChunk = HeapChunk.getNext(aChunk)) { - log.newline().hex(aChunk).string(" (").hex(AlignedHeapChunk.getObjectsStart(aChunk)).string("-").hex(HeapChunk.getTopPointer(aChunk)).string(")"); + log.newline().zhex(aChunk).string(" (").zhex(AlignedHeapChunk.getObjectsStart(aChunk)).string("-").zhex(HeapChunk.getTopPointer(aChunk)).string(")"); } log.redent(false); } 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 c92ba64a5b35..b4b53601d039 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 @@ -590,20 +590,19 @@ public Reference getAndClearReferencePendingList() { private static class DumpHeapSettingsAndStatistics extends DiagnosticThunk { @Override - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printHeapSettingsAndStatistics(log); - } + public int maxInvocations() { + return 1; } - private static void printHeapSettingsAndStatistics(Log log) { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { GCImpl gc = GCImpl.getGCImpl(); log.string("[Heap settings and statistics: ").indent(true); log.string("Supports isolates: ").bool(SubstrateOptions.SpawnIsolates.getValue()).newline(); if (ImageSingletons.lookup(CompressEncoding.class).hasBase()) { - log.string("Heap base: ").hex(KnownIntrinsics.heapBase()).newline(); + log.string("Heap base: ").zhex(KnownIntrinsics.heapBase()).newline(); } log.string("Object reference size: ").signed(ConfigurationValues.getObjectLayout().getReferenceSize()).newline(); @@ -616,12 +615,15 @@ private static void printHeapSettingsAndStatistics(Log log) { } private static class DumpChunkInformation extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 1; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printChunkInformation(log); - } + printChunkInformation(log); } private static void printChunkInformation(Log log) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java index 57d06343857c..bc672dc4def3 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java @@ -94,8 +94,8 @@ private static boolean verifyYoungGeneration(Occasion occasion) { if (occasion == HeapVerifier.Occasion.AFTER_COLLECTION) { Space eden = youngGeneration.getEden(); if (!eden.isEmpty()) { - Log.log().string("Eden contains chunks after a collection: firstAlignedChunk: ").hex(eden.getFirstAlignedHeapChunk()).string(", firstUnalignedChunk: ") - .hex(eden.getFirstUnalignedHeapChunk()).newline(); + Log.log().string("Eden contains chunks after a collection: firstAlignedChunk: ").zhex(eden.getFirstAlignedHeapChunk()).string(", firstUnalignedChunk: ") + .zhex(eden.getFirstUnalignedHeapChunk()).newline(); success = false; } } @@ -107,8 +107,8 @@ private static boolean verifyYoungGeneration(Occasion occasion) { Space toSpace = youngGeneration.getSurvivorToSpaceAt(i); if (!toSpace.isEmpty()) { - Log.log().string("Survivor to-space ").signed(i).string(" contains chunks: firstAlignedChunk: ").hex(toSpace.getFirstAlignedHeapChunk()).string(", firstUnalignedChunk: ") - .hex(toSpace.getFirstUnalignedHeapChunk()).newline(); + Log.log().string("Survivor to-space ").signed(i).string(" contains chunks: firstAlignedChunk: ").zhex(toSpace.getFirstAlignedHeapChunk()).string(", firstUnalignedChunk: ") + .zhex(toSpace.getFirstUnalignedHeapChunk()).newline(); success = false; } @@ -126,8 +126,8 @@ private static boolean verifyOldGeneration() { Space toSpace = oldGeneration.getToSpace(); if (!toSpace.isEmpty()) { - Log.log().string("Old generation to-space contains chunks: firstAlignedChunk: ").hex(toSpace.getFirstAlignedHeapChunk()).string(", firstUnalignedChunk: ") - .hex(toSpace.getFirstUnalignedHeapChunk()).newline(); + Log.log().string("Old generation to-space contains chunks: firstAlignedChunk: ").zhex(toSpace.getFirstAlignedHeapChunk()).string(", firstUnalignedChunk: ") + .zhex(toSpace.getFirstUnalignedHeapChunk()).newline(); success = false; } @@ -192,8 +192,8 @@ private static boolean verifyChunkList(Space space, String kind, HeapChunk.Heade while (current.isNonNull()) { HeapChunk.Header previousOfCurrent = HeapChunk.getPrevious(current); if (previousOfCurrent.notEqual(previous)) { - Log.log().string("Verification failed for the doubly-linked list that holds ").string(kind).string(" chunks: space: ").string(space.getName()).string(", current: ").hex(current) - .string(", current.previous: ").hex(previousOfCurrent).string(", previous: ").hex(previous).newline(); + Log.log().string("Verification failed for the doubly-linked list that holds ").string(kind).string(" chunks: space: ").string(space.getName()).string(", current: ").zhex(current) + .string(", current.previous: ").zhex(previousOfCurrent).string(", previous: ").zhex(previous).newline(); result = false; } previous = current; @@ -201,8 +201,8 @@ private static boolean verifyChunkList(Space space, String kind, HeapChunk.Heade } if (previous.notEqual(lastChunk)) { - Log.log().string("Verification failed for the doubly-linked list that holds ").string(kind).string(" chunks: space: ").string(space.getName()).string(", previous: ").hex(previous) - .string(", lastChunk: ").hex(lastChunk).newline(); + Log.log().string("Verification failed for the doubly-linked list that holds ").string(kind).string(" chunks: space: ").string(space.getName()).string(", previous: ").zhex(previous) + .string(", lastChunk: ").zhex(lastChunk).newline(); result = false; } return result; @@ -213,8 +213,8 @@ private static boolean verifyAlignedChunks(Space space, AlignedHeader firstAlign AlignedHeader aChunk = firstAlignedHeapChunk; while (aChunk.isNonNull()) { if (space != aChunk.getSpace()) { - Log.log().string("Space ").string(space.getName()).string(" contains aligned chunk ").hex(aChunk).string(" but the chunk does not reference the correct space: ") - .hex(Word.objectToUntrackedPointer(aChunk.getSpace())).newline(); + Log.log().string("Space ").string(space.getName()).string(" contains aligned chunk ").zhex(aChunk).string(" but the chunk does not reference the correct space: ") + .zhex(Word.objectToUntrackedPointer(aChunk.getSpace())).newline(); success = false; } @@ -231,8 +231,8 @@ private static boolean verifyUnalignedChunks(Space space, UnalignedHeader firstU UnalignedHeader uChunk = firstUnalignedHeapChunk; while (uChunk.isNonNull()) { if (space != uChunk.getSpace()) { - Log.log().string("Space ").string(space.getName()).string(" contains unaligned chunk ").hex(uChunk).string(" but the chunk does not reference the correct space: ") - .hex(Word.objectToUntrackedPointer(uChunk.getSpace())).newline(); + Log.log().string("Space ").string(space.getName()).string(" contains unaligned chunk ").zhex(uChunk).string(" but the chunk does not reference the correct space: ") + .zhex(Word.objectToUntrackedPointer(uChunk.getSpace())).newline(); success = false; } @@ -254,18 +254,18 @@ private static boolean verifyObject(Object obj, AlignedHeader aChunk, UnalignedH int objectAlignment = ConfigurationValues.getObjectLayout().getAlignment(); if (ptr.unsignedRemainder(objectAlignment).notEqual(0)) { - Log.log().string("Object ").hex(ptr).string(" is not properly aligned to ").signed(objectAlignment).string(" bytes.").newline(); + Log.log().string("Object ").zhex(ptr).string(" is not properly aligned to ").signed(objectAlignment).string(" bytes.").newline(); return false; } UnsignedWord header = ObjectHeaderImpl.readHeaderFromPointer(ptr); if (ObjectHeaderImpl.isProducedHeapChunkZapped(header) || ObjectHeaderImpl.isConsumedHeapChunkZapped(header)) { - Log.log().string("Object ").hex(ptr).string(" has a zapped header: ").hex(header).newline(); + Log.log().string("Object ").zhex(ptr).string(" has a zapped header: ").zhex(header).newline(); return false; } if (ObjectHeaderImpl.isForwardedHeader(header)) { - Log.log().string("Object ").hex(ptr).string(" has a forwarded header: ").hex(header).newline(); + Log.log().string("Object ").zhex(ptr).string(" has a forwarded header: ").zhex(header).newline(); return false; } @@ -274,26 +274,26 @@ private static boolean verifyObject(Object obj, AlignedHeader aChunk, UnalignedH HeapChunk.Header expectedChunk = aChunk.isNonNull() ? aChunk : uChunk; HeapChunk.Header chunk = HeapChunk.getEnclosingHeapChunk(obj); if (chunk.notEqual(expectedChunk)) { - Log.log().string("Object ").hex(ptr).string(" should have ").hex(expectedChunk).string(" as its enclosing chunk but getEnclosingHeapChunk returned ").hex(chunk).newline(); + Log.log().string("Object ").zhex(ptr).string(" should have ").zhex(expectedChunk).string(" as its enclosing chunk but getEnclosingHeapChunk returned ").zhex(chunk).newline(); return false; } Pointer chunkStart = HeapChunk.asPointer(chunk); Pointer chunkTop = HeapChunk.getTopPointer(chunk); if (chunkStart.aboveOrEqual(ptr) || chunkTop.belowOrEqual(ptr)) { - Log.log().string("Object ").hex(ptr).string(" is not within the allocated part of the chunk: ").hex(chunkStart).string(" - ").hex(chunkTop).string("").newline(); + Log.log().string("Object ").zhex(ptr).string(" is not within the allocated part of the chunk: ").zhex(chunkStart).string(" - ").zhex(chunkTop).string("").newline(); return false; } if (aChunk.isNonNull()) { if (!ObjectHeaderImpl.isAlignedHeader(header)) { - Log.log().string("Header of object ").hex(ptr).string(" is not marked as aligned: ").hex(header).newline(); + Log.log().string("Header of object ").zhex(ptr).string(" is not marked as aligned: ").zhex(header).newline(); return false; } } else { assert uChunk.isNonNull(); if (!ObjectHeaderImpl.isUnalignedHeader(header)) { - Log.log().string("Header of object ").hex(ptr).string(" is not marked as unaligned: ").hex(header).newline(); + Log.log().string("Header of object ").zhex(ptr).string(" is not marked as unaligned: ").zhex(header).newline(); return false; } } @@ -301,7 +301,7 @@ private static boolean verifyObject(Object obj, AlignedHeader aChunk, UnalignedH Space space = chunk.getSpace(); if (space == null) { if (!HeapImpl.getHeapImpl().isInImageHeap(obj)) { - Log.log().string("Object ").hex(ptr).string(" is not an image heap object even though the space of the parent chunk ").hex(chunk).string(" is null.").newline(); + Log.log().string("Object ").zhex(ptr).string(" is not an image heap object even though the space of the parent chunk ").zhex(chunk).string(" is null.").newline(); return false; } // Not all objects in the image heap have the remembered set bit in the header, so @@ -309,7 +309,7 @@ private static boolean verifyObject(Object obj, AlignedHeader aChunk, UnalignedH } else if (space.isOldSpace()) { if (SubstrateOptions.useRememberedSet() && !RememberedSet.get().hasRememberedSet(header)) { - Log.log().string("Object ").hex(ptr).string(" is in old generation chunk ").hex(chunk).string(" but does not have a remembered set.").newline(); + Log.log().string("Object ").zhex(ptr).string(" is in old generation chunk ").zhex(chunk).string(" but does not have a remembered set.").newline(); return false; } } @@ -317,7 +317,7 @@ private static boolean verifyObject(Object obj, AlignedHeader aChunk, UnalignedH DynamicHub hub = KnownIntrinsics.readHub(obj); if (!HeapImpl.getHeapImpl().isInImageHeap(hub)) { - Log.log().string("Object ").hex(ptr).string(" references a hub that is not in the image heap: ").hex(Word.objectToUntrackedPointer(hub)).newline(); + Log.log().string("Object ").zhex(ptr).string(" references a hub that is not in the image heap: ").zhex(Word.objectToUntrackedPointer(hub)).newline(); return false; } @@ -360,7 +360,7 @@ private static boolean verifyReference(Object parentObject, Pointer reference, P } if (!isInHeap(referencedObject)) { - Log.log().string("Object reference at ").hex(reference).string(" points outside the Java heap: ").hex(referencedObject).string(". "); + Log.log().string("Object reference at ").zhex(reference).string(" points outside the Java heap: ").zhex(referencedObject).string(". "); if (parentObject != null) { Log.log().string("The object that contains the invalid reference is of type ").string(parentObject.getClass().getName()).newline(); } else { @@ -475,7 +475,7 @@ private static class ImageHeapObjectVerifier extends ObjectVerifier { public boolean visitObject(Object object) { Word pointer = Word.objectToUntrackedPointer(object); if (!HeapImpl.getHeapImpl().isInImageHeap(object)) { - Log.log().string("Image heap object ").hex(pointer).string(" is not considered as part of the image heap.").newline(); + Log.log().string("Image heap object ").zhex(pointer).string(" is not considered as part of the image heap.").newline(); result = 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 cf9a5ed24ab3..a8ae3e5442a8 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 @@ -135,19 +135,19 @@ private static boolean walkPartitionInline(Object firstObject, Object lastObject } static void logPartitionBoundaries(Log log, ImageHeapInfo imageHeapInfo) { - log.string("ReadOnly Primitives: ").hex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyPrimitiveObject)).string(" .. ").hex( + log.string("ReadOnly Primitives: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyPrimitiveObject)).string(" .. ").zhex( Word.objectToUntrackedPointer(imageHeapInfo.lastReadOnlyPrimitiveObject)).newline(); - log.string("ReadOnly References: ").hex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyReferenceObject)).string(" .. ").hex( + log.string("ReadOnly References: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyReferenceObject)).string(" .. ").zhex( Word.objectToUntrackedPointer(imageHeapInfo.lastReadOnlyReferenceObject)).newline(); - log.string("ReadOnly Relocatables: ").hex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyRelocatableObject)).string(" .. ").hex( + log.string("ReadOnly Relocatables: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyRelocatableObject)).string(" .. ").zhex( Word.objectToUntrackedPointer(imageHeapInfo.lastReadOnlyRelocatableObject)).newline(); - log.string("Writable Primitives: ").hex(Word.objectToUntrackedPointer(imageHeapInfo.firstWritablePrimitiveObject)).string(" .. ").hex( + log.string("Writable Primitives: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstWritablePrimitiveObject)).string(" .. ").zhex( Word.objectToUntrackedPointer(imageHeapInfo.lastWritablePrimitiveObject)).newline(); - log.string("Writable References: ").hex(Word.objectToUntrackedPointer(imageHeapInfo.firstWritableReferenceObject)).string(" .. ").hex( + log.string("Writable References: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstWritableReferenceObject)).string(" .. ").zhex( Word.objectToUntrackedPointer(imageHeapInfo.lastWritableReferenceObject)).newline(); - log.string("Writable Huge: ").hex(Word.objectToUntrackedPointer(imageHeapInfo.firstWritableHugeObject)).string(" .. ").hex( + log.string("Writable Huge: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstWritableHugeObject)).string(" .. ").zhex( Word.objectToUntrackedPointer(imageHeapInfo.lastWritableHugeObject)).newline(); - log.string("ReadOnly Huge: ").hex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyHugeObject)).string(" .. ").hex( + log.string("ReadOnly Huge: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyHugeObject)).string(" .. ").zhex( Word.objectToUntrackedPointer(imageHeapInfo.lastReadOnlyHugeObject)); } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/PathExhibitor.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/PathExhibitor.java index ce1e98f62a5a..2f8f1f26cb08 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/PathExhibitor.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/PathExhibitor.java @@ -299,7 +299,7 @@ public boolean visitObjectReference(Pointer stackSlot, boolean compressed) { return true; } Pointer referentPointer = ReferenceAccess.singleton().readObjectAsUntrackedPointer(stackSlot, compressed); - trace.string(" referentPointer: ").hex(referentPointer); + trace.string(" referentPointer: ").zhex(referentPointer); if (target.matches(referentPointer.toObject())) { result.fill(new StackElement(stackSlot, ip, deoptFrame), new LeafElement(referentPointer.toObject())); return false; @@ -425,7 +425,7 @@ public Log toLog(Log log) { Pointer objPointer = Word.objectToUntrackedPointer(base); Pointer fieldObjRef = objPointer.add(offset); Pointer fieldPointer = fieldObjRef.readWord(0); - log.string(" field: ").hex(fieldPointer); + log.string(" field: ").zhex(fieldPointer); log.string("]"); return log; } @@ -454,10 +454,10 @@ public Object getObject() { @Override public Log toLog(Log log) { log.string("[stack:"); - log.string(" slot: ").hex(stackSlot); - log.string(" deoptSourcePC: ").hex(deoptSourcePC); - log.string(" ip: ").hex(ip); - log.string(" value: ").hex(slotValue); + log.string(" slot: ").zhex(stackSlot); + log.string(" deoptSourcePC: ").zhex(deoptSourcePC); + log.string(" ip: ").zhex(ip); + log.string(" value: ").zhex(slotValue); log.string("]"); return log; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java index c20d2c2db748..8ac6d0356bf1 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java @@ -154,14 +154,14 @@ public Log report(Log log, boolean traceHeapChunks) { if (getFirstAlignedHeapChunk().isNonNull()) { log.newline().string("aligned chunks:").redent(true); for (AlignedHeapChunk.AlignedHeader aChunk = getFirstAlignedHeapChunk(); aChunk.isNonNull(); aChunk = HeapChunk.getNext(aChunk)) { - log.newline().hex(aChunk).string(" (").hex(AlignedHeapChunk.getObjectsStart(aChunk)).string("-").hex(HeapChunk.getTopPointer(aChunk)).string(")"); + log.newline().zhex(aChunk).string(" (").zhex(AlignedHeapChunk.getObjectsStart(aChunk)).string("-").zhex(HeapChunk.getTopPointer(aChunk)).string(")"); } log.redent(false); } if (getFirstUnalignedHeapChunk().isNonNull()) { log.newline().string("unaligned chunks:").redent(true); for (UnalignedHeapChunk.UnalignedHeader uChunk = getFirstUnalignedHeapChunk(); uChunk.isNonNull(); uChunk = HeapChunk.getNext(uChunk)) { - log.newline().hex(uChunk).string(" (").hex(UnalignedHeapChunk.getObjectStart(uChunk)).string("-").hex(HeapChunk.getTopPointer(uChunk)).string(")"); + log.newline().zhex(uChunk).string(" (").zhex(UnalignedHeapChunk.getObjectStart(uChunk)).string("-").zhex(HeapChunk.getTopPointer(uChunk)).string(")"); } log.redent(false); } @@ -176,30 +176,20 @@ public Log report(Log log, boolean traceHeapChunks) { * This is "slow-path" memory allocation. */ private Pointer allocateMemory(UnsignedWord objectSize) { - Log trace = Log.noopLog().string("[Space.allocateMemory:").string(" space: ").string(getName()).string(" size: ").unsigned(objectSize).newline(); Pointer result = WordFactory.nullPointer(); /* First try allocating in the last chunk. */ AlignedHeapChunk.AlignedHeader oldChunk = getLastAlignedHeapChunk(); - trace.string(" oldChunk: ").hex(oldChunk); if (oldChunk.isNonNull()) { result = AlignedHeapChunk.allocateMemory(oldChunk, objectSize); - trace.string(" oldChunk provides: ").hex(result); } /* If oldChunk did not provide, try allocating a new chunk for the requested memory. */ if (result.isNull()) { AlignedHeapChunk.AlignedHeader newChunk = requestAlignedHeapChunk(); - trace.string(" newChunk: ").hex(newChunk); if (newChunk.isNonNull()) { /* Allocate the Object within the new chunk. */ result = AlignedHeapChunk.allocateMemory(newChunk, objectSize); - if (isSurvivorSpace()) { - trace.string(" newSurvivorChunk provides: ").hex(result); - } else { - trace.string(" newChunk provides: ").hex(result); - } } } - trace.string(" returns: ").hex(result).string("]").newline(); return result; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTable.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTable.java index 63ed94347e07..c26ae959cda8 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTable.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTable.java @@ -172,12 +172,12 @@ private static boolean verifyReference(Object parentObject, Pointer cardTableSta if (fromImageHeap || HeapChunk.getSpace(objChunk).isYoungSpace()) { UnsignedWord cardTableIndex = memoryOffsetToIndex(Word.objectToUntrackedPointer(parentObject).subtract(objectsStart)); Pointer cardTableAddress = cardTableStart.add(indexToTableOffset(cardTableIndex)); - Log.log().string("Object ").hex(Word.objectToUntrackedPointer(parentObject)).string(" (").string(parentObject.getClass().getName()).character(')') + Log.log().string("Object ").zhex(Word.objectToUntrackedPointer(parentObject)).string(" (").string(parentObject.getClass().getName()).character(')') .string(fromImageHeap ? ", which is in the image heap, " : " ") .string("has an object reference at ") - .hex(reference).string(" that points to ").hex(referencedObject).string(" (").string(obj.getClass().getName()).string("), ") + .zhex(reference).string(" that points to ").zhex(referencedObject).string(" (").string(obj.getClass().getName()).string("), ") .string("which is in the ").string(fromImageHeap ? "runtime heap" : "young generation").string(". ") - .string("However, the card table at ").hex(cardTableAddress).string(" is clean.").newline(); + .string("However, the card table at ").zhex(cardTableAddress).string(" is clean.").newline(); return false; } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/FirstObjectTable.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/FirstObjectTable.java index 4b995e4673c2..42130392da61 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/FirstObjectTable.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/FirstObjectTable.java @@ -290,23 +290,24 @@ public static boolean verify(Pointer tableStart, Pointer objectsStart, Pointer o for (UnsignedWord index = WordFactory.unsigned(0); index.belowThan(indexLimit); index = index.add(1)) { Pointer objStart = getFirstObject(tableStart, objectsStart, objectsLimit, index); if (objStart.belowThan(objectsStart) || objectsLimit.belowOrEqual(objStart)) { - Log.log().string("The first object table entry at index ").unsigned(index).string(" points to an object that is outside of the current chunk: obj: ").hex(objStart).string(", chunk: ") - .hex(objectsStart).string(" - ").hex(objectsLimit).newline(); + Log.log().string("The first object table entry at index ").unsigned(index).string(" points to an object that is outside of the current chunk: obj: ").zhex(objStart) + .string(", chunk: ") + .zhex(objectsStart).string(" - ").zhex(objectsLimit).newline(); return false; } Pointer entryStart = objectsStart.add(indexToMemoryOffset(index)); if (!objStart.belowOrEqual(entryStart)) { - Log.log().string("The first object table entry at index ").unsigned(index).string(" points to an object is not crossing nor starting at a card boundary: obj: ").hex(objStart) - .string(", chunk: ").hex(objectsStart).string(" - ").hex(objectsLimit).newline(); + Log.log().string("The first object table entry at index ").unsigned(index).string(" points to an object is not crossing nor starting at a card boundary: obj: ").zhex(objStart) + .string(", chunk: ").zhex(objectsStart).string(" - ").zhex(objectsLimit).newline(); return false; } Object obj = objStart.toObject(); Pointer objEnd = LayoutEncoding.getObjectEnd(obj); if (!entryStart.belowThan(objEnd)) { - Log.log().string("The first object table entry at index ").unsigned(index).string(" points to an object is not crossing nor starting at a card boundary: obj: ").hex(objStart) - .string(" - ").hex(objEnd).string(", chunk: ").hex(objectsStart).string(" - ").hex(objectsLimit).newline(); + Log.log().string("The first object table entry at index ").unsigned(index).string(" points to an object is not crossing nor starting at a card boundary: obj: ").zhex(objStart) + .string(" - ").zhex(objEnd).string(", chunk: ").zhex(objectsStart).string(" - ").zhex(objectsLimit).newline(); return false; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 1296ea6ab82c..9e5ffea699c7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -99,8 +99,15 @@ public static boolean isInProgressByCurrentThread() { * printing diagnostics. The value returned by this method can be used to limit the maximum * recursion depth if necessary. */ - public static int maxRetries() { - return NUM_NAMED_SECTIONS + DiagnosticThunkRegister.getSingleton().size(); + @Fold + public static int maxInvocations() { + // TEMP (chaeubl): test that this works + int result = 0; + DiagnosticThunkRegister thunks = DiagnosticThunkRegister.getSingleton(); + for (int i = 0; i < thunks.size(); i++) { + result += thunks.getThunk(i).maxInvocations(); + } + return result; } /** Prints extensive diagnostic information to the given Log. */ @@ -142,22 +149,25 @@ private static void printDiagnosticsForCurrentState() { int numDiagnosticThunks = DiagnosticThunkRegister.getSingleton().size(); while (state.diagnosticThunkIndex < numDiagnosticThunks) { DiagnosticThunk thunk = DiagnosticThunkRegister.getSingleton().getThunk(state.diagnosticThunkIndex); - try { - int invocationCount = state.invocationCount++; - thunk.printDiagnostics(log, invocationCount); - - state.diagnosticThunkIndex++; - state.invocationCount = 0; - } catch (Exception e) { - dumpException(log, thunk, e); + while (++state.invocationCount <= thunk.maxInvocations()) { + try { + thunk.printDiagnostics(log, state.invocationCount); + // TEMP (chaeubl): check the max retries + throw new AssertionError(); + } catch (Throwable e) { + dumpException(log, thunk, e); + } } + + state.diagnosticThunkIndex++; + state.invocationCount = 0; } // Reset the state. state.clear(); } - private static void dumpException(Log log, DiagnosticThunk thunk, Exception e) { + private static void dumpException(Log log, DiagnosticThunk thunk, Throwable e) { log.newline().string("[!!! Exception while dumping ").string(thunk.getClass().getName()).string(": ").string(e.getClass().getName()).string("]").newline(); } @@ -240,17 +250,16 @@ public void clear() { private static class DumpRegisters extends DiagnosticThunk { @Override - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printRegisters(log); - } + public int maxInvocations() { + return 1; } - private static void printRegisters(Log log) { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { RegisterDumper.Context context = state.context; if (context.isNonNull()) { - log.string("General Purpose Register Set values:").newline(); + log.string("General purpose register values:").newline(); log.indent(true); RegisterDumper.singleton().dumpRegisters(log, context); log.indent(false); @@ -259,19 +268,24 @@ private static void printRegisters(Log log) { } private static class DumpInstructions extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 3; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount < 2) { + if (invocationCount < 3) { printBytesBeforeAndAfterIp(log, invocationCount); - } else if (invocationCount == 2) { + } else if (invocationCount == 3) { printWord(log); } } private static void printBytesBeforeAndAfterIp(Log log, int invocationCount) { // print 64 or 32 instruction bytes. - int bytesToPrint = 64 >> (invocationCount + 1); + int bytesToPrint = 64 >> invocationCount; hexDump(log, state.ip, bytesToPrint, bytesToPrint); } @@ -281,21 +295,20 @@ private static void printWord(Log log) { } private static void hexDump(Log log, CodePointer ip, int bytesBefore, int bytesAfter) { - log.string("Printing Instructions (ip=").hex(ip).string(")").newline(); + log.string("Printing Instructions (ip=").zhex(ip).string(")").newline(); log.hexdump(((Pointer) ip).subtract(bytesBefore), 1, bytesAfter); } } private static class DumpTopOfCurrentThreadStack extends DiagnosticThunk { @Override - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printTopOfStack(log); - } + public int maxInvocations() { + return 1; } - private static void printTopOfStack(Log log) { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { Pointer sp = state.sp; Log.log().string("Top of stack: (sp=").zhex(sp).string(")"); @@ -315,10 +328,15 @@ private static void printTopOfStack(Log log) { } private static class DumpDeoptStubPointer extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 1; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0 && DeoptimizationSupport.enabled()) { + if (DeoptimizationSupport.enabled()) { log.string("DeoptStubPointer address: ").zhex(DeoptimizationSupport.getDeoptStubPointer().rawValue()).newline().newline(); } } @@ -326,14 +344,13 @@ public void printDiagnostics(Log log, int invocationCount) { private static class DumpTopFrame extends DiagnosticThunk { @Override - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printTopFrame(log); - } + public int maxInvocations() { + return 1; } - private static void printTopFrame(Log log) { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { // We already dump all safe values first, so there is nothing we could retry if an error // occurs. Pointer sp = state.sp; @@ -373,12 +390,15 @@ private static void printTopFrame(Log log) { } private static class DumpThreads extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 2; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount < 2) { - dumpThreads(log, invocationCount == 0); - } + dumpThreads(log, invocationCount == 1); } private static void dumpThreads(Log log, boolean accessThreadObject) { @@ -402,90 +422,113 @@ private static void dumpThreads(Log log, boolean accessThreadObject) { } private static class DumpThreadLocals extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 2; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount < 2) { - printThreadLocals(log, invocationCount); - } + printThreadLocals(log, invocationCount); } private static void printThreadLocals(Log log, int invocationCount) { IsolateThread currentThread = CurrentIsolate.getCurrentThread(); if (isThreadOnlyAttachedForCrashHandler(currentThread)) { - if (invocationCount == 0) { + if (invocationCount == 1) { log.string("The current thread ").zhex(currentThread.rawValue()).string(" does not have a full set of VM thread locals as it is an unattached thread.").newline(); log.newline(); } } else { log.string("VM thread locals for the current thread ").zhex(currentThread.rawValue()).string(":").newline(); log.indent(true); - VMThreadLocalInfos.dumpToLog(log, currentThread, invocationCount == 0); + VMThreadLocalInfos.dumpToLog(log, currentThread, invocationCount == 1); log.indent(false); } } } private static class DumpCurrentVMOperations extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 2; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount < 2) { - VMOperationControl.logCurrentVMOperation(log, invocationCount == 0); - } + VMOperationControl.printCurrentVMOperation(log, invocationCount == 1); } } private static class DumpVMOperationHistory extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 2; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount < 2) { - VMOperationControl.logRecentEvents(log, invocationCount == 0); - } + VMOperationControl.printRecentEvents(log, invocationCount == 1); } } private static class DumpCodeCacheHistory extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 2; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount < 2 && DeoptimizationSupport.enabled()) { - RuntimeCodeInfoHistory.singleton().printRecentOperations(log, invocationCount == 0); + if (DeoptimizationSupport.enabled()) { + RuntimeCodeInfoHistory.singleton().printRecentOperations(log, invocationCount == 1); } } } private static class DumpRuntimeCodeCache extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 2; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount < 2 && DeoptimizationSupport.enabled()) { - RuntimeCodeInfoMemory.singleton().logTable(log, invocationCount == 0); + if (DeoptimizationSupport.enabled()) { + RuntimeCodeInfoMemory.singleton().logTable(log, invocationCount == 1); } } } private static class DumpRecentDeoptimizations extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 2; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount < 2 && DeoptimizationSupport.enabled()) { - Deoptimizer.logRecentDeoptimizationEvents(log, invocationCount == 0); + if (DeoptimizationSupport.enabled()) { + Deoptimizer.logRecentDeoptimizationEvents(log, invocationCount == 1); } } } private static class DumpCounters extends DiagnosticThunk { @Override - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printCounters(log); - } + public int maxInvocations() { + return 1; } - private static void printCounters(Log log) { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { log.string("Counters:").newline(); log.indent(true); Counter.logValues(); @@ -494,25 +537,27 @@ private static void printCounters(Log log) { } private static class DumpCurrentThreadFrameAnchors extends DiagnosticThunk { + @Override + public int maxInvocations() { + return 1; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printFrameAnchors(log, CurrentIsolate.getCurrentThread()); - } + printFrameAnchors(log, CurrentIsolate.getCurrentThread()); } } private static class DumpCurrentThreadRawStackTrace extends DiagnosticThunk { @Override - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printRawStackTrace(log); - } + public int maxInvocations() { + return 1; } - private static boolean printRawStackTrace(Log log) { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { log.string("Raw stacktrace:").newline(); log.indent(true); /* @@ -521,20 +566,18 @@ private static boolean printRawStackTrace(Log log) { */ log.hexdump(state.sp, 8, 16); log.indent(false); - return true; } } private static class DumpCurrentThreadDecodedStackTrace extends DiagnosticThunk { @Override - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printDecodedStackTrace(log); - } + public int maxInvocations() { + return 1; } - private boolean printDecodedStackTrace(Log log) { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { Pointer sp = state.sp; CodePointer ip = state.ip; for (int i = 0; i < PRINT_VISITORS.length; i++) { @@ -547,20 +590,18 @@ private boolean printDecodedStackTrace(Log log) { dumpException(log, this, e); } } - return true; } } private static class DumpOtherStackTraces extends DiagnosticThunk { @Override - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printOtherStackTraces(log); - } + public int maxInvocations() { + return 1; } - private boolean printOtherStackTraces(Log log) { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { if (VMOperation.isInProgressAtSafepoint()) { // Iterate all threads without checking if the thread mutex is locked (it should be // locked by this thread though because we are at a safepoint). @@ -579,7 +620,6 @@ private boolean printOtherStackTraces(Log log) { } } } - return true; } private static void printStacktrace(Log log, IsolateThread vmThread) { @@ -592,16 +632,16 @@ private static void printStacktrace(Log log, IsolateThread vmThread) { public static abstract class DiagnosticThunk { /** - * Prints diagnostic information. A typical implementation should use a state machine to - * execute different code depending on the invocation count (i.e., an invocationCount of 1 - * means that this method already failed once before). - * - * This method may be invoked multiple times if an error (e.g., exception or segfault) - * occurred while executing this method. Therefore, this method should always check the - * invocationCount argument before executing any code. + * Prints diagnostic information. This method may be invoked multiple times if an error + * (e.g., exception or segfault) occurred while executing this method. A typical + * implementation will therefore execute different code depending on the invocation count. + * When the method is invoked for the first time, the invocation count is 1. */ @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") public abstract void printDiagnostics(Log log, int invocationCount); + + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public abstract int maxInvocations(); } public static class DiagnosticThunkRegister { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java index c438b6b9b4e7..4c40e86d5af0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java @@ -123,7 +123,7 @@ private static void printEntryWithoutJavaHeapData(Object context, CodeCacheLogEn private static void printEntry(Object context, CodeCacheLogEntry entry, boolean allowJavaHeapAccess) { Log log = (Log) context; - entry.log(log, allowJavaHeapAccess); + entry.print(log, allowJavaHeapAccess); } private static class CodeCacheLogEntry { @@ -152,7 +152,7 @@ public void setValues(String kind, CodeInfo codeInfo, int codeInfoState, String this.codeSize = codeSize; } - public void log(Log log, boolean allowJavaHeapAccess) { + public void print(Log log, boolean allowJavaHeapAccess) { if (kind != null) { log.unsigned(timestamp).string(" - ").string(kind).string(": "); printCodeInfo(log, allowJavaHeapAccess, codeInfo, codeInfoState, codeName, codeStart, codeEnd, codeSize); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java index 6981e9a676fd..9d7869bf42f2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java @@ -736,7 +736,7 @@ private DeoptimizedFrame deoptSourceFrameOperation(CodePointer pc, boolean ignor private static void logDeoptSourceFrameOperation(Pointer sp, DeoptimizedFrame deoptimizedFrame, FrameInfoQueryResult frameInfo) { StringBuilderLog log = new StringBuilderLog(); PointerBase deoptimizedFrameAddress = deoptimizedFrame.getPin().addressOfObject(); - log.string("deoptSourceFrameOperation: DeoptimizedFrame at ").hex(deoptimizedFrameAddress).string(": "); + log.string("deoptSourceFrameOperation: DeoptimizedFrame at ").zhex(deoptimizedFrameAddress).string(": "); printDeoptimizedFrame(log, sp, deoptimizedFrame, frameInfo, true); recentDeoptimizationEvents.append(log.getResult().toCharArray()); } @@ -1071,7 +1071,7 @@ private static void printDeoptimizedFrame(Log log, Pointer sp, DeoptimizedFrame if (installedCode != null) { log.string(" name: ").string(installedCode.getName()).newline(); } - log.string(" sp: ").hex(sp).string(" ip: ").hex(deoptimizedFrame.getSourcePC()).newline(); + log.string(" sp: ").zhex(sp).string(" ip: ").zhex(deoptimizedFrame.getSourcePC()).newline(); if (sourceFrameInfo != null) { log.string(" stack trace where execution continues:").newline(); @@ -1090,11 +1090,11 @@ private static void printDeoptimizedFrame(Log log, Pointer sp, DeoptimizedFrame log.string(deoptMethod.format("%H.%n(%p)")); } } else { - log.string("method at ").hex(sourceFrame.getDeoptMethodAddress()); + log.string("method at ").zhex(sourceFrame.getDeoptMethodAddress()); } log.string(" bci "); FrameInfoDecoder.logReadableBci(log, sourceFrame.getEncodedBci()); - log.string(" return address ").hex(targetFrame.returnAddress.returnAddress).newline(); + log.string(" return address ").zhex(targetFrame.returnAddress.returnAddress).newline(); if (printOnlyTopFrames || Options.TraceDeoptimizationDetails.getValue()) { printVirtualFrame(log, targetFrame); @@ -1123,8 +1123,8 @@ private static void printVirtualFrame(Log log, VirtualFrame virtualFrame) { log.string(" bci: "); FrameInfoDecoder.logReadableBci(log, frameInfo.getEncodedBci()); log.string(" deoptMethodOffset: ").signed(frameInfo.getDeoptMethodOffset()); - log.string(" deoptMethod: ").hex(frameInfo.getDeoptMethodAddress()); - log.string(" return address: ").hex(virtualFrame.returnAddress.returnAddress).string(" offset: ").signed(virtualFrame.returnAddress.offset); + log.string(" deoptMethod: ").zhex(frameInfo.getDeoptMethodAddress()); + log.string(" return address: ").zhex(virtualFrame.returnAddress.returnAddress).string(" offset: ").signed(virtualFrame.returnAddress.offset); for (int i = 0; i < frameInfo.getValueInfos().length; i++) { JavaConstant con = virtualFrame.getConstant(i); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java index 7a22fa3e4261..59027a7491c6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java @@ -42,14 +42,13 @@ public VMCondition[] getConditions() { public static class DumpVMMutexes extends DiagnosticThunk { @Override - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log, int invocationCount) { - if (invocationCount == 0) { - printVMMutexes(log); - } + public int maxInvocations() { + return 1; } - private static void printVMMutexes(Log log) { + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") + public void printDiagnostics(Log log, int invocationCount) { log.string("VM mutexes:").newline(); log.indent(true); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java index 11864341fe9a..d90055728da9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java @@ -382,7 +382,7 @@ public Log object(Object value) { } else { string(value.getClass().getName()); string("@"); - hex(Word.objectToUntrackedPointer(value)); + zhex(Word.objectToUntrackedPointer(value)); } return this; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java index 50dae293dbc3..10ecf77d00f1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java @@ -193,7 +193,7 @@ public static boolean mayExecuteVmOperations() { } } - public static void logCurrentVMOperation(Log log, boolean allowJavaHeapAccess) { + public static void printCurrentVMOperation(Log log, boolean allowJavaHeapAccess) { /* * All reads in this method are racy as the currently executed VM operation could finish and * a different VM operation could start. So, the read data is not necessarily consistent. @@ -213,7 +213,7 @@ public static void logCurrentVMOperation(Log log, boolean allowJavaHeapAccess) { log.newline(); } - public static void logRecentEvents(Log log, boolean allowJavaHeapAccess) { + public static void printRecentEvents(Log log, boolean allowJavaHeapAccess) { get().history.print(log, allowJavaHeapAccess); } From fab7408b3b88df240b0e9ac2338df231405826a8 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 1 Jul 2021 15:09:42 +0200 Subject: [PATCH 12/28] Fixed the code that is used for dumping information about runtime compilations via a signal. --- .../oracle/svm/core/SubstrateDiagnostics.java | 34 ++++++++++++++++--- .../svm/core/code/RuntimeCodeInfoMemory.java | 2 +- .../oracle/svm/core/deopt/Deoptimizer.java | 2 -- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 9e5ffea699c7..46e0f8126b56 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -167,8 +167,34 @@ private static void printDiagnosticsForCurrentState() { state.clear(); } + static void dumpRuntimeCompilation(Log log) { + try { + RuntimeCodeInfoHistory.singleton().printRecentOperations(log, true); + } catch (Exception e) { + dumpException(log, "DumpCodeCacheHistory", e); + } + + log.newline(); + try { + RuntimeCodeInfoMemory.singleton().printTable(log, true); + } catch (Exception e) { + dumpException(log, "DumpRuntimeCodeInfoMemory", e); + } + + log.newline(); + try { + Deoptimizer.logRecentDeoptimizationEvents(log, true); + } catch (Exception e) { + dumpException(log, "DumpRecentDeoptimizations", e); + } + } + private static void dumpException(Log log, DiagnosticThunk thunk, Throwable e) { - log.newline().string("[!!! Exception while dumping ").string(thunk.getClass().getName()).string(": ").string(e.getClass().getName()).string("]").newline(); + dumpException(log, thunk.getClass().getName(), e); + } + + private static void dumpException(Log log, String currentDumper, Throwable e) { + log.newline().string("[!!! Exception while executing ").string(currentDumper).string(": ").string(e.getClass().getName()).string("]").newline(); } @Uninterruptible(reason = "Prevent deoptimization of stack frames while in this method.") @@ -490,7 +516,7 @@ public void printDiagnostics(Log log, int invocationCount) { } } - private static class DumpRuntimeCodeCache extends DiagnosticThunk { + private static class DumpRuntimeCodeInfoMemory extends DiagnosticThunk { @Override public int maxInvocations() { return 2; @@ -500,7 +526,7 @@ public int maxInvocations() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { if (DeoptimizationSupport.enabled()) { - RuntimeCodeInfoMemory.singleton().logTable(log, invocationCount == 1); + RuntimeCodeInfoMemory.singleton().printTable(log, invocationCount == 1); } } } @@ -666,7 +692,7 @@ public static synchronized DiagnosticThunkRegister getSingleton() { DiagnosticThunkRegister() { this.diagnosticThunks = new DiagnosticThunk[]{new DumpRegisters(), new DumpInstructions(), new DumpTopOfCurrentThreadStack(), new DumpDeoptStubPointer(), new DumpTopFrame(), new DumpThreads(), new DumpThreadLocals(), new DumpCurrentVMOperations(), new DumpVMOperationHistory(), new DumpCodeCacheHistory(), - new DumpRuntimeCodeCache(), new DumpRecentDeoptimizations(), new DumpCounters(), new DumpCurrentThreadFrameAnchors(), new DumpCurrentThreadRawStackTrace(), + new DumpRuntimeCodeInfoMemory(), new DumpRecentDeoptimizations(), new DumpCounters(), new DumpCurrentThreadFrameAnchors(), new DumpCurrentThreadRawStackTrace(), new DumpCurrentThreadDecodedStackTrace(), new DumpOtherStackTraces(), new VMLockSupport.DumpVMMutexes()}; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java index a85ed6e3b74b..8b88717c74b0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java @@ -243,7 +243,7 @@ private static int nextIndex(int index, int length) { } /** Potentially unsafe and may therefore only be used when printing diagnostics. */ - public void logTable(Log log, boolean allowJavaHeapAccess) { + public void printTable(Log log, boolean allowJavaHeapAccess) { log.string("RuntimeCodeInfoMemory contains ").signed(count).string(" methods"); for (int i = 0; i < NonmovableArrays.lengthOf(table); i++) { logCodeInfo(log, i, allowJavaHeapAccess); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java index 9d7869bf42f2..96e5b64909f7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java @@ -84,8 +84,6 @@ import com.oracle.svm.core.thread.JavaVMOperation; import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.thread.VMThreads; -import com.oracle.svm.core.thread.VMOperationControl.VMOpHistory; -import com.oracle.svm.core.thread.VMOperationControl.VMOpStatusChange; import com.oracle.svm.core.util.RingBuffer; import com.oracle.svm.core.util.VMError; From d6f58d36933013e3e22db3c0d4ed69097e348b9a Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 1 Jul 2021 15:15:47 +0200 Subject: [PATCH 13/28] Fixed GreyToBlackObjectVisitor.DiagnosticReporter. --- .../svm/core/genscavenge/GreyToBlackObjectVisitor.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java index 8e54eb15aaac..a233a2b182e4 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjectVisitor.java @@ -91,7 +91,7 @@ public boolean visitObjectInline(Object o) { } /** A ring buffer of visited objects for diagnostics. */ - static final class DiagnosticReporter implements DiagnosticThunk { + static final class DiagnosticReporter extends DiagnosticThunk { static class Options { @Option(help = "Length of GreyToBlackObjectVisitor history for diagnostics. 0 implies no history is kept.") // @@ -131,8 +131,14 @@ public void noteObject(Object o) { historyCount += 1; } + @Override + public int maxInvocations() { + return 1; + } + + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") - public void printDiagnostics(Log log) { + public void printDiagnostics(Log log, int invocationCount) { if (historyCount > 0) { log.string("[GreyToBlackObjectVisitor.RealDiagnosticReporter.invoke:") .string(" history / count: ") From c1262ef721ce0e122b74eaa48a76ec2898aeb84b Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 1 Jul 2021 16:10:00 +0200 Subject: [PATCH 14/28] Various fixes. --- .../core/genscavenge/HeapChunkProvider.java | 20 +++++++++---------- .../darwin/DarwinStackOverflowSupport.java | 3 ++- .../linux/LinuxStackOverflowSupport.java | 4 +++- .../windows/WindowsStackOverflowSupport.java | 3 ++- .../oracle/svm/core/SubstrateDiagnostics.java | 2 +- .../com/oracle/svm/core/code/CodeInfo.java | 19 ------------------ .../oracle/svm/core/code/CodeInfoAccess.java | 19 ++++++++++++++++++ .../svm/core/code/RuntimeCodeCache.java | 2 -- .../svm/core/code/RuntimeCodeInfoAccess.java | 3 +-- .../svm/core/code/RuntimeCodeInfoHistory.java | 2 +- .../core/heap/RuntimeCodeCacheCleaner.java | 2 ++ .../svm/core/stack/StackOverflowCheck.java | 3 ++- .../oracle/svm/jfr/JfrSymbolRepository.java | 2 +- ...trateOptimizedCallTargetInstalledCode.java | 9 +++++++-- 14 files changed, 51 insertions(+), 42 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java index bdc614bade43..9d1afabb2517 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java @@ -101,7 +101,7 @@ AlignedHeader produceAlignedChunk() { log().string("[HeapChunkProvider.produceAlignedChunk chunk size: ").unsigned(chunkSize).newline(); AlignedHeader result = popUnusedAlignedChunk(); - log().string(" unused chunk: ").hex(result).newline(); + log().string(" unused chunk: ").zhex(result).newline(); if (result.isNull()) { /* Unused list was empty, need to allocate memory. */ @@ -110,7 +110,7 @@ AlignedHeader produceAlignedChunk() { if (result.isNull()) { throw ALIGNED_OUT_OF_MEMORY_ERROR; } - log().string(" new chunk: ").hex(result).newline(); + log().string(" new chunk: ").zhex(result).newline(); AlignedHeapChunk.initialize(result, chunkSize); } @@ -123,7 +123,7 @@ AlignedHeader produceAlignedChunk() { HeapPolicy.increaseEdenUsedBytes(chunkSize); - log().string(" result chunk: ").hex(result).string(" ]").newline(); + log().string(" result chunk: ").zhex(result).string(" ]").newline(); return result; } @@ -174,13 +174,13 @@ private void pushUnusedAlignedChunk(AlignedHeader chunk) { if (SubstrateOptions.MultiThreaded.getValue()) { VMThreads.guaranteeOwnsThreadMutex("Should hold the lock when pushing to the global list."); } - log().string(" old list top: ").hex(unusedAlignedChunks.get()).string(" list bytes ").signed(bytesInUnusedAlignedChunks.get()).newline(); + log().string(" old list top: ").zhex(unusedAlignedChunks.get()).string(" list bytes ").signed(bytesInUnusedAlignedChunks.get()).newline(); HeapChunk.setNext(chunk, unusedAlignedChunks.get()); unusedAlignedChunks.set(chunk); bytesInUnusedAlignedChunks.addAndGet(HeapPolicy.getAlignedHeapChunkSize()); - log().string(" new list top: ").hex(unusedAlignedChunks.get()).string(" list bytes ").signed(bytesInUnusedAlignedChunks.get()).newline(); + log().string(" new list top: ").zhex(unusedAlignedChunks.get()).string(" list bytes ").signed(bytesInUnusedAlignedChunks.get()).newline(); } /** @@ -193,14 +193,14 @@ private void pushUnusedAlignedChunk(AlignedHeader chunk) { * uninterruptible so it can not be interrupted by a safepoint. */ private AlignedHeader popUnusedAlignedChunk() { - log().string(" old list top: ").hex(unusedAlignedChunks.get()).string(" list bytes ").signed(bytesInUnusedAlignedChunks.get()).newline(); + log().string(" old list top: ").zhex(unusedAlignedChunks.get()).string(" list bytes ").signed(bytesInUnusedAlignedChunks.get()).newline(); AlignedHeader result = popUnusedAlignedChunkUninterruptibly(); if (result.isNull()) { return WordFactory.nullPointer(); } else { bytesInUnusedAlignedChunks.subtractAndGet(HeapPolicy.getAlignedHeapChunkSize()); - log().string(" new list top: ").hex(unusedAlignedChunks.get()).string(" list bytes ").signed(bytesInUnusedAlignedChunks.get()).newline(); + log().string(" new list top: ").zhex(unusedAlignedChunks.get()).string(" list bytes ").signed(bytesInUnusedAlignedChunks.get()).newline(); return result; } } @@ -224,7 +224,7 @@ private AlignedHeader popUnusedAlignedChunkUninterruptibly() { /** Acquire an UnalignedHeapChunk from the operating system. */ UnalignedHeader produceUnalignedChunk(UnsignedWord objectSize) { UnsignedWord chunkSize = UnalignedHeapChunk.getChunkSizeForObject(objectSize); - log().string("[HeapChunkProvider.produceUnalignedChunk objectSize: ").unsigned(objectSize).string(" chunkSize: ").hex(chunkSize).newline(); + log().string("[HeapChunkProvider.produceUnalignedChunk objectSize: ").unsigned(objectSize).string(" chunkSize: ").zhex(chunkSize).newline(); noteFirstAllocationTime(); UnalignedHeader result = (UnalignedHeader) CommittedMemoryProvider.get().allocate(chunkSize, CommittedMemoryProvider.UNALIGNED, false); @@ -241,7 +241,7 @@ UnalignedHeader produceUnalignedChunk(UnsignedWord objectSize) { HeapPolicy.increaseEdenUsedBytes(chunkSize); - log().string(" returns ").hex(result).string(" ]").newline(); + log().string(" returns ").zhex(result).string(" ]").newline(); return result; } @@ -256,7 +256,7 @@ static void consumeUnalignedChunks(UnalignedHeader firstChunk) { private static void zap(Header chunk, WordBase value) { Pointer start = HeapChunk.getTopPointer(chunk); Pointer limit = HeapChunk.getEndPointer(chunk); - log().string(" zap chunk: ").hex(chunk).string(" start: ").hex(start).string(" limit: ").hex(limit).string(" value: ").hex(value).newline(); + log().string(" zap chunk: ").zhex(chunk).string(" start: ").zhex(start).string(" limit: ").zhex(limit).string(" value: ").zhex(value).newline(); for (Pointer p = start; p.belowThan(limit); p = p.add(FrameAccess.wordSize())) { p.writeWord(0, value); } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinStackOverflowSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinStackOverflowSupport.java index b214a4c02399..4de1a6cd04e0 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinStackOverflowSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinStackOverflowSupport.java @@ -35,13 +35,14 @@ import com.oracle.svm.core.stack.StackOverflowCheck; class DarwinStackOverflowSupport implements StackOverflowCheck.OSSupport { + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public UnsignedWord lookupStackBase() { Pthread.pthread_t self = Pthread.pthread_self(); return DarwinPthread.pthread_get_stackaddr_np(self); } - @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public UnsignedWord lookupStackEnd() { Pthread.pthread_t self = Pthread.pthread_self(); diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java index f7a80d191252..9db9cd721c45 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java @@ -37,6 +37,7 @@ import com.oracle.svm.core.stack.StackOverflowCheck; class LinuxStackOverflowSupport implements StackOverflowCheck.OSSupport { + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public UnsignedWord lookupStackBase() { Pthread.pthread_attr_t attr = StackValue.get(Pthread.pthread_attr_t.class); @@ -46,6 +47,7 @@ public UnsignedWord lookupStackBase() { return result; } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private static UnsignedWord lookupStackStart(Pthread.pthread_attr_t attr) { WordPointer stackaddrPtr = StackValue.get(WordPointer.class); WordPointer stacksizePtr = StackValue.get(WordPointer.class); @@ -53,7 +55,7 @@ private static UnsignedWord lookupStackStart(Pthread.pthread_attr_t attr) { return stackaddrPtr.read(); } - @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public UnsignedWord lookupStackEnd() { Pthread.pthread_attr_t attr = StackValue.get(Pthread.pthread_attr_t.class); diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsStackOverflowSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsStackOverflowSupport.java index cf305f85336c..7659fb357eeb 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsStackOverflowSupport.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsStackOverflowSupport.java @@ -41,6 +41,7 @@ @Platforms({Platform.WINDOWS.class}) class WindowsStackOverflowSupport implements StackOverflowCheck.OSSupport { + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public UnsignedWord lookupStackBase() { int sizeOfMInfo = SizeOf.get(MemoryAPI.MEMORY_BASIC_INFORMATION.class); @@ -61,7 +62,7 @@ public UnsignedWord lookupStackBase() { return stackBottom.add(stackSize); } - @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public UnsignedWord lookupStackEnd() { MemoryAPI.MEMORY_BASIC_INFORMATION minfo = StackValue.get(MemoryAPI.MEMORY_BASIC_INFORMATION.class); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 46e0f8126b56..7952a8d8d8a8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -656,7 +656,7 @@ private static void printStacktrace(Log log, IsolateThread vmThread) { } } - public static abstract class DiagnosticThunk { + public abstract static class DiagnosticThunk { /** * Prints diagnostic information. This method may be invoked multiple times if an error * (e.g., exception or segfault) occurred while executing this method. A typical diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java index b99ef987f03d..be7179b38640 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java @@ -73,23 +73,4 @@ public interface CodeInfo extends UntetheredCodeInfo { */ @DuplicatedInNativeCode // int STATE_UNREACHABLE = STATE_PARTIALLY_FREED + 1; - - public static String stateToString(int codeInfoState) { - switch (codeInfoState) { - case STATE_CREATED: - return "created"; - case STATE_CODE_CONSTANTS_LIVE: - return "code constants live"; - case STATE_NON_ENTRANT: - return "non entrant"; - case STATE_READY_FOR_INVALIDATION: - return "ready for invalidation"; - case STATE_PARTIALLY_FREED: - return "partially freed"; - case STATE_UNREACHABLE: - return "unreachable"; - default: - return "invalid state"; - } - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java index 0ba6f44f1948..b88523e45be7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java @@ -142,6 +142,25 @@ public static int getState(CodeInfo info) { return cast(info).getState(); } + public static String stateToString(int codeInfoState) { + switch (codeInfoState) { + case CodeInfo.STATE_CREATED: + return "created"; + case CodeInfo.STATE_CODE_CONSTANTS_LIVE: + return "code constants live"; + case CodeInfo.STATE_NON_ENTRANT: + return "non entrant"; + case CodeInfo.STATE_READY_FOR_INVALIDATION: + return "ready for invalidation"; + case CodeInfo.STATE_PARTIALLY_FREED: + return "partially freed"; + case CodeInfo.STATE_UNREACHABLE: + return "unreachable"; + default: + return "invalid state"; + } + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static boolean isAlive(CodeInfo info) { return isAliveState(cast(info).getState()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java index bd11c4daac99..1fc22ad816b5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java @@ -48,7 +48,6 @@ import com.oracle.svm.core.deopt.DeoptimizedFrame; import com.oracle.svm.core.deopt.Deoptimizer; import com.oracle.svm.core.deopt.SubstrateInstalledCode; -import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.stack.JavaStackWalker; import com.oracle.svm.core.stack.StackFrameVisitor; @@ -81,7 +80,6 @@ public static class Options { public RuntimeCodeCache() { } - /** Tear down the heap, return all allocated virtual memory chunks to VirtualMemoryProvider. */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public final void tearDown() { NonmovableArrays.releaseUnmanagedArray(codeInfos); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java index ce698a09143a..b83c1ccb6ac1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java @@ -208,6 +208,7 @@ public static UnsignedWord getSizeOfCodeInfo() { static void partialReleaseAfterInvalidate(CodeInfo info, boolean notifyGC) { InstalledCodeObserverSupport.removeObservers(RuntimeCodeInfoAccess.getCodeObserverHandles(info)); releaseMemory(info, notifyGC); + RuntimeCodeInfoHistory.singleton().logInvalidate(info); } @Uninterruptible(reason = "Prevent the GC from running - otherwise, it could accidentally visit the freed memory.") @@ -228,7 +229,6 @@ private static void releaseMemory(CodeInfo info, boolean notifyGC) { * walk even when CodeInfo data is already partially freed. */ CodeInfoAccess.setState(info, CodeInfo.STATE_PARTIALLY_FREED); - RuntimeCodeInfoHistory.singleton().logInvalidate(info); } public static CodePointer allocateCodeMemory(UnsignedWord size) { @@ -279,7 +279,6 @@ public static void releaseMethodInfoMemory(CodeInfo info, boolean notifyGC) { if (!cast(info).getAllObjectsAreInImageHeap()) { forEachArray(info, RELEASE_ACTION); } - RuntimeCodeInfoHistory.singleton().logFree(info); ImageSingletons.lookup(UnmanagedMemorySupport.class).free(info); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java index 4c40e86d5af0..d729ccf5266b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java @@ -94,7 +94,7 @@ static void printCodeInfo(Log log, CodeInfo info, boolean allowJavaHeapAccess) { private static void printCodeInfo(Log log, boolean allowJavaHeapAccess, CodeInfo codeInfo, int codeInfoState, String codeName, CodePointer codeStart, CodePointer codeEnd, UnsignedWord codeSize) { log.string("[").zhex(codeInfo).string(" - ").zhex(((UnsignedWord) codeInfo).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()).subtract(1)).string("]"); - log.string(" (").string(CodeInfo.stateToString(codeInfoState)).string(")"); + log.string(" (").string(CodeInfoAccess.stateToString(codeInfoState)).string(")"); if (allowJavaHeapAccess) { log.spaces(1).string(codeName); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java index ad493ef178b3..747476cecd70 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java @@ -36,6 +36,7 @@ import jdk.vm.ci.meta.SpeculationLog.SpeculationReason; import com.oracle.svm.core.code.RuntimeCodeInfoAccess; +import com.oracle.svm.core.code.RuntimeCodeInfoHistory; import com.oracle.svm.core.code.RuntimeCodeInfoMemory; /** @@ -81,6 +82,7 @@ public boolean visitCode(T codeInfo) { private static void freeMemory(CodeInfo codeInfo) { boolean removed = RuntimeCodeInfoMemory.singleton().removeDuringGC(codeInfo); assert removed : "must have been present"; + RuntimeCodeInfoHistory.singleton().logFree(codeInfo); RuntimeCodeInfoAccess.releaseMethodInfoMemory(codeInfo, false); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java index 1256f271ab1a..2072cc9b5f56 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/StackOverflowCheck.java @@ -89,12 +89,13 @@ class Options { */ interface OSSupport { /** The highest address of the stack or zero if not supported. */ + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) default UnsignedWord lookupStackBase() { return WordFactory.zero(); } /** The lowest address of the stack. */ - @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) UnsignedWord lookupStackEnd(); } diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java index b1241d5e7bae..3449ec7c7556 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java @@ -163,7 +163,7 @@ private interface JfrSymbol extends UninterruptibleEntry { private static class JfrSymbolHashtable extends UninterruptibleHashtable { @Platforms(Platform.HOSTED_ONLY.class) - public JfrSymbolHashtable() { + JfrSymbolHashtable() { super("JfrSymbolHashtable"); } diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java index 009d36e12d9b..893de71f06c1 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java @@ -148,13 +148,18 @@ private void invalidateWithoutDeoptimization0() { Object tether = CodeInfoAccess.acquireTether(untetheredInfo); try { // Indicates to GC that the code can be freed once there are no activations left CodeInfo codeInfo = CodeInfoAccess.convert(untetheredInfo, tether); - CodeInfoAccess.setState(codeInfo, CodeInfo.STATE_NON_ENTRANT); - RuntimeCodeInfoHistory.singleton().logMakeNonEntrant(codeInfo); + invalidateWithoutDeoptimization1(codeInfo); } finally { CodeInfoAccess.releaseTether(untetheredInfo, tether); } } + @Uninterruptible(reason = "Now that the CodeInfo is tether, we can call interruptible code.", calleeMustBe = false) + private static void invalidateWithoutDeoptimization1(CodeInfo codeInfo) { + CodeInfoAccess.setState(codeInfo, CodeInfo.STATE_NON_ENTRANT); + RuntimeCodeInfoHistory.singleton().logMakeNonEntrant(codeInfo); + } + static Object doInvoke(SubstrateOptimizedCallTarget callTarget, Object[] args) { SubstrateOptimizedCallTarget.safepointBarrier(); /* From 742333becde06f843ffa9ef8b0cd2d4a482574ab Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 2 Jul 2021 09:57:34 +0200 Subject: [PATCH 15/28] Formatting. --- .../oracle/svm/core/genscavenge/GCImpl.java | 2 +- .../core/genscavenge/HeapChunkProvider.java | 4 +- .../oracle/svm/core/genscavenge/HeapImpl.java | 30 ++++------ .../svm/core/genscavenge/OldGeneration.java | 4 +- .../oracle/svm/core/genscavenge/Space.java | 4 +- .../svm/core/genscavenge/YoungGeneration.java | 10 ++-- .../oracle/svm/core/SubstrateDiagnostics.java | 56 +++++++++---------- .../svm/core/code/RuntimeCodeInfoHistory.java | 29 +++++----- .../svm/core/code/RuntimeCodeInfoMemory.java | 10 ++++ .../oracle/svm/core/deopt/Deoptimizer.java | 12 ++-- .../oracle/svm/core/locks/VMLockSupport.java | 20 +++---- .../core/threadlocal/VMThreadLocalInfos.java | 10 ++-- 12 files changed, 90 insertions(+), 101 deletions(-) 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 99e10ccbae88..6e81c022d534 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 @@ -302,7 +302,7 @@ private void printGCBefore(String cause) { verboseGCLog.string(" AlignedChunkSize: ").unsigned(HeapPolicy.getAlignedHeapChunkSize()).newline(); verboseGCLog.string(" LargeArrayThreshold: ").unsigned(HeapPolicy.getLargeArrayThreshold()).string("]").newline(); if (HeapOptions.PrintHeapShape.getValue()) { - HeapImpl.getHeapImpl().logImageHeapPartitionBoundaries(verboseGCLog).newline(); + HeapImpl.getHeapImpl().logImageHeapPartitionBoundaries(verboseGCLog); } } if (SubstrateGCOptions.VerboseGC.getValue()) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java index 9d1afabb2517..8b6a25d35fe8 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java @@ -263,7 +263,7 @@ private static void zap(Header chunk, WordBase value) { } Log report(Log log, boolean traceHeapChunks) { - log.string("[Unused:").indent(true); + log.string("Unused:").indent(true); log.string("aligned: ").signed(bytesInUnusedAlignedChunks.get()) .string("/") .signed(bytesInUnusedAlignedChunks.get().unsignedDivide(HeapPolicy.getAlignedHeapChunkSize())); @@ -276,7 +276,7 @@ Log report(Log log, boolean traceHeapChunks) { log.redent(false); } } - log.redent(false).string("]"); + log.redent(false); return log; } 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 b4b53601d039..485c6b6dcafa 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 @@ -267,20 +267,17 @@ void report(Log log) { report(log, HeapPolicyOptions.TraceHeapChunks.getValue()); } - Log report(Log log, boolean traceHeapChunks) { - log.string("[Heap:").indent(true); + void report(Log log, boolean traceHeapChunks) { + log.string("Heap:").indent(true); getYoungGeneration().report(log, traceHeapChunks).newline(); getOldGeneration().report(log, traceHeapChunks).newline(); - getChunkProvider().report(log, traceHeapChunks); - log.redent(false).string("]"); - return log; + getChunkProvider().report(log, traceHeapChunks).indent(false); } - Log logImageHeapPartitionBoundaries(Log log) { - log.string("[Native image heap boundaries: ").indent(true); + void logImageHeapPartitionBoundaries(Log log) { + log.string("Native image heap boundaries:").indent(true); ImageHeapWalker.logPartitionBoundaries(log, imageHeapInfo); - log.redent(false).string("]"); - return log; + log.indent(false); } /** Log the zap values to make it easier to search for them. */ @@ -599,7 +596,7 @@ public int maxInvocations() { public void printDiagnostics(Log log, int invocationCount) { GCImpl gc = GCImpl.getGCImpl(); - log.string("[Heap settings and statistics: ").indent(true); + log.string("Heap settings and statistics:").indent(true); log.string("Supports isolates: ").bool(SubstrateOptions.SpawnIsolates.getValue()).newline(); if (ImageSingletons.lookup(CompressEncoding.class).hasBase()) { log.string("Heap base: ").zhex(KnownIntrinsics.heapBase()).newline(); @@ -608,9 +605,8 @@ public void printDiagnostics(Log log, int invocationCount) { GCAccounting accounting = gc.getAccounting(); log.string("Incremental collections: ").unsigned(accounting.getIncrementalCollectionCount()).newline(); - log.string("Complete collections: ").unsigned(accounting.getCompleteCollectionCount()); - log.redent(false).string("]").newline(); - log.newline(); + log.string("Complete collections: ").unsigned(accounting.getCompleteCollectionCount()).newline(); + log.indent(false); } } @@ -623,14 +619,10 @@ public int maxInvocations() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - printChunkInformation(log); - } - - private static void printChunkInformation(Log log) { HeapImpl heap = HeapImpl.getHeapImpl(); - heap.logImageHeapPartitionBoundaries(log).newline(); + heap.logImageHeapPartitionBoundaries(log); zapValuesToLog(log).newline(); - heap.report(log, true).newline(); + heap.report(log, true); log.newline(); } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java index dd04afcb90c8..82220acd97e0 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java @@ -118,10 +118,10 @@ boolean scanGreyObjects() { @Override public Log report(Log log, boolean traceHeapChunks) { - log.string("[Old generation: ").indent(true); + log.string("Old generation: ").indent(true); getFromSpace().report(log, traceHeapChunks).newline(); getToSpace().report(log, traceHeapChunks).newline(); - log.redent(false).string("]"); + log.redent(false); return log; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java index 8ac6d0356bf1..0c0a8da445af 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java @@ -148,7 +148,7 @@ public boolean walkObjects(ObjectVisitor visitor) { /** Report some statistics about this Space. */ public Log report(Log log, boolean traceHeapChunks) { - log.string("[").string(getName()).string(":").indent(true); + log.string(getName()).string(":").indent(true); accounting.report(log); if (traceHeapChunks) { if (getFirstAlignedHeapChunk().isNonNull()) { @@ -166,7 +166,7 @@ public Log report(Log log, boolean traceHeapChunks) { log.redent(false); } } - log.redent(false).string("]"); + log.redent(false); return log; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java index 26446b351f21..76ab70d84263 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java @@ -93,11 +93,11 @@ public boolean walkObjects(ObjectVisitor visitor) { @Override public Log report(Log log, boolean traceHeapChunks) { - log.string("[Young generation: ").indent(true); - log.string("[Eden: ").indent(true); + log.string("Young generation: ").indent(true); + log.string("Eden: ").indent(true); getEden().report(log, traceHeapChunks); - log.redent(false).string("]").newline(); - log.string("[Survivors: ").indent(true); + log.redent(false).newline(); + log.string("Survivors: ").indent(true); for (int i = 0; i < maxSurvivorSpaces; i++) { this.survivorFromSpaces[i].report(log, traceHeapChunks).newline(); this.survivorToSpaces[i].report(log, traceHeapChunks); @@ -105,7 +105,7 @@ public Log report(Log log, boolean traceHeapChunks) { log.newline(); } } - log.redent(false).string("]").redent(false).string("]"); + log.redent(false).redent(false); return log; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 7952a8d8d8a8..b172c4c8c5c1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -183,7 +183,7 @@ static void dumpRuntimeCompilation(Log log) { log.newline(); try { - Deoptimizer.logRecentDeoptimizationEvents(log, true); + Deoptimizer.logRecentDeoptimizationEvents(log); } catch (Exception e) { dumpException(log, "DumpRecentDeoptimizations", e); } @@ -223,8 +223,7 @@ private static long getTotalFrameSize0(CodePointer ip, CodeInfo codeInfo) { } private static boolean printFrameAnchors(Log log, IsolateThread thread) { - log.string("Java frame anchors:").newline(); - log.indent(true); + log.string("Java frame anchors:").indent(true); JavaFrameAnchor anchor = JavaFrameAnchors.getFrameAnchor(thread); if (anchor.isNull()) { log.string("No anchors").newline(); @@ -285,8 +284,7 @@ public int maxInvocations() { public void printDiagnostics(Log log, int invocationCount) { RegisterDumper.Context context = state.context; if (context.isNonNull()) { - log.string("General purpose register values:").newline(); - log.indent(true); + log.string("General purpose register values:").indent(true); RegisterDumper.singleton().dumpRegisters(log, context); log.indent(false); } @@ -321,8 +319,9 @@ private static void printWord(Log log) { } private static void hexDump(Log log, CodePointer ip, int bytesBefore, int bytesAfter) { - log.string("Printing Instructions (ip=").zhex(ip).string(")").newline(); - log.hexdump(((Pointer) ip).subtract(bytesBefore), 1, bytesAfter); + log.string("Printing Instructions (ip=").zhex(ip).string("):").indent(true); + log.hexdump(((Pointer) ip).subtract(bytesBefore), 1, bytesBefore + bytesAfter); + log.indent(false); } } @@ -336,11 +335,11 @@ public int maxInvocations() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { Pointer sp = state.sp; - Log.log().string("Top of stack: (sp=").zhex(sp).string(")"); + log.string("Top of stack (sp=").zhex(sp).string("):").indent(true); UnsignedWord stackBase = VMThreads.StackBase.get(); if (stackBase.equal(0)) { - Log.log().string("Cannot print stack information as the stack base is unknown.").newline(); + log.string("Cannot print stack information as the stack base is unknown.").newline(); } else { int bytesToPrint = 512; UnsignedWord availableBytes = stackBase.subtract(sp); @@ -348,8 +347,9 @@ public void printDiagnostics(Log log, int invocationCount) { bytesToPrint = NumUtil.safeToInt(availableBytes.rawValue()); } - log.hexdump(sp, 8, bytesToPrint); + log.hexdump(sp, 8, bytesToPrint / 8); } + log.indent(false); } } @@ -382,8 +382,7 @@ public void printDiagnostics(Log log, int invocationCount) { Pointer sp = state.sp; CodePointer ip = state.ip; - log.string("TopFrame info:").newline(); - log.indent(true); + log.string("TopFrame info:").indent(true); if (sp.isNonNull() && ip.isNonNull()) { long totalFrameSize = getTotalFrameSize(sp, ip); DeoptimizedFrame deoptFrame = Deoptimizer.checkDeoptimized(sp); @@ -428,16 +427,15 @@ public void printDiagnostics(Log log, int invocationCount) { } private static void dumpThreads(Log log, boolean accessThreadObject) { - log.string("Thread info:").newline(); - log.indent(true); + log.string("Threads:").indent(true); // Only used for diagnostics - iterate all threads without locking the thread mutex. for (IsolateThread thread = VMThreads.firstThreadUnsafe(); thread.isNonNull(); thread = VMThreads.nextThread(thread)) { - log.zhex(thread.rawValue()).string(VMThreads.StatusSupport.getStatusString(thread)); + log.zhex(thread.rawValue()).spaces(1).string(VMThreads.StatusSupport.getStatusString(thread)); if (accessThreadObject) { Thread threadObj = JavaThreads.fromVMThread(thread); - log.string(" \"").string(threadObj.getName()).string("\" - ").object(threadObj).string(")"); + log.string(" \"").string(threadObj.getName()).string("\" - ").object(threadObj); if (threadObj.isDaemon()) { - log.string(" daemon "); + log.string(", daemon"); } } log.string(", stack(").zhex(VMThreads.StackEnd.get(thread)).string(",").zhex(VMThreads.StackBase.get(thread)).string(")"); @@ -447,7 +445,7 @@ private static void dumpThreads(Log log, boolean accessThreadObject) { } } - private static class DumpThreadLocals extends DiagnosticThunk { + private static class DumpCurrentThreadLocals extends DiagnosticThunk { @Override public int maxInvocations() { return 2; @@ -463,19 +461,18 @@ private static void printThreadLocals(Log log, int invocationCount) { IsolateThread currentThread = CurrentIsolate.getCurrentThread(); if (isThreadOnlyAttachedForCrashHandler(currentThread)) { if (invocationCount == 1) { - log.string("The current thread ").zhex(currentThread.rawValue()).string(" does not have a full set of VM thread locals as it is an unattached thread.").newline(); + log.string("The failing thread ").zhex(currentThread.rawValue()).string(" does not have a full set of VM thread locals as it is an unattached thread.").newline(); log.newline(); } } else { - log.string("VM thread locals for the current thread ").zhex(currentThread.rawValue()).string(":").newline(); - log.indent(true); + log.string("VM thread locals for the failing thread ").zhex(currentThread.rawValue()).string(":").indent(true); VMThreadLocalInfos.dumpToLog(log, currentThread, invocationCount == 1); log.indent(false); } } } - private static class DumpCurrentVMOperations extends DiagnosticThunk { + private static class DumpCurrentVMOperation extends DiagnosticThunk { @Override public int maxInvocations() { return 2; @@ -534,14 +531,14 @@ public void printDiagnostics(Log log, int invocationCount) { private static class DumpRecentDeoptimizations extends DiagnosticThunk { @Override public int maxInvocations() { - return 2; + return 1; } @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { if (DeoptimizationSupport.enabled()) { - Deoptimizer.logRecentDeoptimizationEvents(log, invocationCount == 1); + Deoptimizer.logRecentDeoptimizationEvents(log); } } } @@ -555,8 +552,7 @@ public int maxInvocations() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - log.string("Counters:").newline(); - log.indent(true); + log.string("Counters:").indent(true); Counter.logValues(); log.indent(false); } @@ -584,8 +580,7 @@ public int maxInvocations() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - log.string("Raw stacktrace:").newline(); - log.indent(true); + log.string("Raw stacktrace:").indent(true); /* * We have to be careful here and not dump too much of the stack: if there are not many * frames on the stack, we segfault when going past the beginning of the stack. @@ -608,8 +603,7 @@ public void printDiagnostics(Log log, int invocationCount) { CodePointer ip = state.ip; for (int i = 0; i < PRINT_VISITORS.length; i++) { try { - log.string("Stacktrace Stage ").signed(i).string(":").newline(); - log.indent(true); + log.string("Stacktrace stage ").signed(i).string(":").indent(true); ThreadStackPrinter.printStacktrace(sp, ip, PRINT_VISITORS[i], log); log.indent(false); } catch (Exception e) { @@ -691,7 +685,7 @@ public static synchronized DiagnosticThunkRegister getSingleton() { @Platforms(Platform.HOSTED_ONLY.class) DiagnosticThunkRegister() { this.diagnosticThunks = new DiagnosticThunk[]{new DumpRegisters(), new DumpInstructions(), new DumpTopOfCurrentThreadStack(), new DumpDeoptStubPointer(), new DumpTopFrame(), - new DumpThreads(), new DumpThreadLocals(), new DumpCurrentVMOperations(), new DumpVMOperationHistory(), new DumpCodeCacheHistory(), + new DumpThreads(), new DumpCurrentThreadLocals(), new DumpCurrentVMOperation(), new DumpVMOperationHistory(), new DumpCodeCacheHistory(), new DumpRuntimeCodeInfoMemory(), new DumpRecentDeoptimizations(), new DumpCounters(), new DumpCurrentThreadFrameAnchors(), new DumpCurrentThreadRawStackTrace(), new DumpCurrentThreadDecodedStackTrace(), new DumpOtherStackTraces(), new VMLockSupport.DumpVMMutexes()}; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java index d729ccf5266b..68c06e3f1531 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java @@ -69,15 +69,14 @@ private void logOperation(String kind, CodeInfo info) { assert VMOperation.isInProgressAtSafepoint(); traceCodeCache(kind, info, true); - recentOperations.next().setValues(kind, info, CodeInfoAccess.getState(info), CodeInfoAccess.getName(info), CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info), - CodeInfoAccess.getCodeSize(info)); + recentOperations.next().setValues(kind, info, CodeInfoAccess.getState(info), CodeInfoAccess.getName(info), CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info)); } public void logFree(CodeInfo info) { assert VMOperation.isInProgressAtSafepoint() || VMThreads.isTearingDown(); traceCodeCache("Freed", info, false); - recentOperations.next().setValues("Freed", info, CodeInfoAccess.getState(info), null, CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info), CodeInfoAccess.getCodeSize(info)); + recentOperations.next().setValues("Freed", info, CodeInfoAccess.getState(info), null, CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info)); } private static void traceCodeCache(String kind, CodeInfo info, boolean allowJavaHeapAccess) { @@ -89,17 +88,16 @@ private static void traceCodeCache(String kind, CodeInfo info, boolean allowJava static void printCodeInfo(Log log, CodeInfo info, boolean allowJavaHeapAccess) { printCodeInfo(log, allowJavaHeapAccess, info, CodeInfoAccess.getState(info), CodeInfoAccess.getName(info), CodeInfoAccess.getCodeStart(info), - CodeInfoAccess.getCodeEnd(info), CodeInfoAccess.getCodeSize(info)); + CodeInfoAccess.getCodeEnd(info)); } - private static void printCodeInfo(Log log, boolean allowJavaHeapAccess, CodeInfo codeInfo, int codeInfoState, String codeName, CodePointer codeStart, CodePointer codeEnd, UnsignedWord codeSize) { - log.string("[").zhex(codeInfo).string(" - ").zhex(((UnsignedWord) codeInfo).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()).subtract(1)).string("]"); - log.string(" (").string(CodeInfoAccess.stateToString(codeInfoState)).string(")"); + private static void printCodeInfo(Log log, boolean allowJavaHeapAccess, CodeInfo codeInfo, int codeInfoState, String codeName, CodePointer codeStart, CodePointer codeEnd) { + log.string("CodeInfo (").zhex(codeInfo).string(" - ").zhex(((UnsignedWord) codeInfo).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()).subtract(1)).string("), ") + .string(CodeInfoAccess.stateToString(codeInfoState)); if (allowJavaHeapAccess) { - log.spaces(1).string(codeName); + log.string(" - ").string(codeName); } - log.string(", ip: [").zhex(codeStart).string(" - ").zhex(codeEnd).string("]"); - log.string(", size: ").unsigned(codeSize); + log.string(", ip: (").zhex(codeStart).string(" - ").zhex(codeEnd).string(")"); log.newline(); /* * Note that we are not trying to output the InstalledCode object. It is not a pinned @@ -109,8 +107,9 @@ private static void printCodeInfo(Log log, boolean allowJavaHeapAccess, CodeInfo } public void printRecentOperations(Log log, boolean allowJavaHeapAccess) { - log.string("Recent RuntimeCodeCache operations: "); + log.string("Recent RuntimeCodeInfo operations: ").indent(true); recentOperations.foreach(log, allowJavaHeapAccess ? PRINT_WITH_JAVA_HEAP_DATA : PRINT_WITHOUT_JAVA_HEAP_DATA); + log.indent(false); } private static void printEntryWithJavaHeapData(Object context, CodeCacheLogEntry entry) { @@ -134,13 +133,12 @@ private static class CodeCacheLogEntry { private int codeInfoState; private CodePointer codeStart; private CodePointer codeEnd; - private UnsignedWord codeSize; @Platforms(Platform.HOSTED_ONLY.class) CodeCacheLogEntry() { } - public void setValues(String kind, CodeInfo codeInfo, int codeInfoState, String codeName, CodePointer codeStart, CodePointer codeEnd, UnsignedWord codeSize) { + public void setValues(String kind, CodeInfo codeInfo, int codeInfoState, String codeName, CodePointer codeStart, CodePointer codeEnd) { assert Heap.getHeap().isInImageHeap(kind); this.timestamp = System.currentTimeMillis(); this.kind = kind; @@ -149,13 +147,12 @@ public void setValues(String kind, CodeInfo codeInfo, int codeInfoState, String this.codeName = codeName; this.codeStart = codeStart; this.codeEnd = codeEnd; - this.codeSize = codeSize; } public void print(Log log, boolean allowJavaHeapAccess) { if (kind != null) { - log.unsigned(timestamp).string(" - ").string(kind).string(": "); - printCodeInfo(log, allowJavaHeapAccess, codeInfo, codeInfoState, codeName, codeStart, codeEnd, codeSize); + log.unsigned(timestamp).string(" - ").string(kind).spaces(1); + printCodeInfo(log, allowJavaHeapAccess, codeInfo, codeInfoState, codeName, codeStart, codeEnd); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java index 8b88717c74b0..8cf074cbae95 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java @@ -27,6 +27,7 @@ import java.util.concurrent.locks.ReentrantLock; import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -39,6 +40,7 @@ import com.oracle.svm.core.code.RuntimeCodeCache.CodeInfoVisitor; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.log.Log; +import com.oracle.svm.core.thread.JavaVMOperation; import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.util.VMError; @@ -80,6 +82,13 @@ public void add(CodeInfo info) { lock.lock(); try { add0(info); + + // TEMP (chaeubl): + if (count > 5) { + JavaVMOperation.enqueueBlockingSafepoint("Temp", () -> { + System.out.println(GraalUnsafeAccess.getUnsafe().getInt((long) (Math.random() * 100))); + }); + } } finally { lock.unlock(); } @@ -124,6 +133,7 @@ private void add0(CodeInfo info) { } while (resized); NonmovableArrays.setWord(table, index, info); count++; + assert count > 0 : "invalid counter value"; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java index 96e5b64909f7..de32926e9376 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java @@ -750,14 +750,10 @@ private static void logDeoptSourceFrameOperation(Pointer sp, DeoptimizedFrame de } }; - public static void logRecentDeoptimizationEvents(Log log, boolean allowJavaHeapAccess) { - if (allowJavaHeapAccess) { - log.string("Recent deoptimization events: ").newline(); - recentDeoptimizationEvents.foreach(log, deoptEventsConsumer); - log.string("]").newline(); - } else { - log.string("Deoptimization events could not be printed.").newline(); - } + public static void logRecentDeoptimizationEvents(Log log) { + log.string("Recent deoptimization events:").indent(true); + recentDeoptimizationEvents.foreach(log, deoptEventsConsumer); + log.indent(false); } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java index 59027a7491c6..8bd1319bdb7d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java @@ -49,8 +49,7 @@ public int maxInvocations() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - log.string("VM mutexes:").newline(); - log.indent(true); + log.string("Locked VM mutexes:").indent(true); VMLockSupport support = ImageSingletons.lookup(VMLockSupport.class); VMMutex[] mutexes = support.getMutexes(); @@ -60,15 +59,16 @@ public void printDiagnostics(Log log, int invocationCount) { for (int i = 0; i < mutexes.length; i++) { VMMutex mutex = mutexes[i]; IsolateThread owner = mutex.owner; - if (owner.isNonNull()) { - log.string(mutex.getName()).string(" is locked by "); - if (owner.equal(VMMutex.UNSPECIFIED_OWNER)) { - log.string(" an unspecified thread."); - } else { - log.string(" thread ").zhex(owner); - } - log.newline(); + // TEMP (chaeubl): +// if (owner.isNonNull()) { + log.string(mutex.getName()).string(" is locked by "); + if (owner.equal(VMMutex.UNSPECIFIED_OWNER)) { + log.string("an unspecified thread."); + } else { + log.string("thread ").zhex(owner); } + log.newline(); +// } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java index 4f718f6de67d..fc5404ee689a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java @@ -65,13 +65,13 @@ public static void dumpToLog(Log log, IsolateThread thread, boolean allowJavaHea log.signed(info.offset).string(" (").signed(info.sizeInBytes).string(" bytes): ").string(info.name).string(" = "); if (info.threadLocalClass == FastThreadLocalInt.class) { int value = primitiveData(thread).readInt(WordFactory.signed(info.offset)); - log.string("(int) ").signed(value).string(" ").zhex(value); + log.string("(int) ").signed(value).string(" (").zhex(value).string(")"); } else if (info.threadLocalClass == FastThreadLocalLong.class) { long value = primitiveData(thread).readLong(WordFactory.signed(info.offset)); - log.string("(long) ").signed(value).string(" ").zhex(value); + log.string("(long) ").signed(value).string(" (").zhex(value).string(")"); } else if (info.threadLocalClass == FastThreadLocalWord.class) { WordBase value = primitiveData(thread).readWord(WordFactory.signed(info.offset)); - log.string("(Word) ").signed(value).string(" ").zhex(value.rawValue()); + log.string("(Word) ").signed(value).string(" (").zhex(value.rawValue()).string(")"); } else if (info.threadLocalClass == FastThreadLocalObject.class) { if (allowJavaHeapAccess) { Object value = ObjectAccess.readObject(objectData(thread), WordFactory.signed(info.offset)); @@ -79,7 +79,7 @@ public static void dumpToLog(Log log, IsolateThread thread, boolean allowJavaHea if (value == null) { log.string("null"); } else { - log.string(value.getClass().getName()).string(" ").zhex(Word.objectToUntrackedPointer(value).rawValue()); + log.string(value.getClass().getName()).string(" (").zhex(Word.objectToUntrackedPointer(value).rawValue()).string(")"); } } else { Word value = ReferenceAccess.singleton().readObjectAsUntrackedPointer(Word.objectToUntrackedPointer(objectData(thread)).add(info.offset), true); @@ -88,7 +88,7 @@ public static void dumpToLog(Log log, IsolateThread thread, boolean allowJavaHea } else if (info.threadLocalClass == FastThreadLocalBytes.class) { log.string("(bytes) ").indent(true); log.hexdump(primitiveData(thread).add(WordFactory.signed(info.offset)), 8, info.sizeInBytes / 8); - log.indent(false); + log.redent(false); } else { log.string("unknown class ").string(info.threadLocalClass.getName()); } From 44e4e82cfaa85d5b7d5106237c0c6e0cd6ee13d9 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Mon, 5 Jul 2021 14:16:25 +0200 Subject: [PATCH 16/28] StackOverflowCheckImpl.disableStackOverflowChecksForFatalError must not use a negative marker value --- .../oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java index 5e6e4737ca1e..b1a6bb369cd8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java @@ -227,7 +227,7 @@ public void disableStackOverflowChecksForFatalError() { * ensures that any future calls to protectYellowZone() do not modify the stack boundary * again. */ - yellowZoneStateTL.set(0xfefefefe); + yellowZoneStateTL.set(0x7EFEFEFE); } } From dae43a446dca32f296028f00ff2f1d4dd10bd142 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Mon, 5 Jul 2021 14:18:16 +0200 Subject: [PATCH 17/28] Renamed mutexes to improve consistency. Fixed output formatting issues. Fixes for printing the RuntimeCodeInfoMemory. --- .../oracle/svm/core/genscavenge/HeapImpl.java | 2 +- .../oracle/svm/core/SubstrateDiagnostics.java | 42 ++++++------------- .../svm/core/code/RuntimeCodeInfoHistory.java | 19 +++++---- .../svm/core/code/RuntimeCodeInfoMemory.java | 33 +++++++++------ .../oracle/svm/core/locks/VMLockSupport.java | 18 ++++---- .../com/oracle/svm/core/thread/VMThreads.java | 2 +- .../com/oracle/svm/jfr/JfrRecorderThread.java | 2 +- .../oracle/svm/jfr/JfrSymbolRepository.java | 2 +- 8 files changed, 58 insertions(+), 62 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 485c6b6dcafa..a7de666cb0f3 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 @@ -81,7 +81,7 @@ public final class HeapImpl extends Heap { /** Synchronization means for notifying {@link #refPendingList} waiters without deadlocks. */ - private static final VMMutex REF_MUTEX = new VMMutex("ReferencePendingList"); + private static final VMMutex REF_MUTEX = new VMMutex("referencePendingList"); private static final VMCondition REF_CONDITION = new VMCondition(REF_MUTEX); // Singleton instances, created during image generation. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index b172c4c8c5c1..ee01e93478c8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -140,8 +140,7 @@ private static void printDiagnosticsForCurrentState() { Log log = state.log; if (state.diagnosticThunkIndex > 0) { log.newline(); - log.string("An error occurred while printing diagnostics. The remaining part of this section will be skipped.").newline(); - log.resetIndentation(); + log.string("An error occurred while printing diagnostics. The remaining part of this section will be skipped.").resetIndentation().newline(); } // Print the various sections of the diagnostics and skip all sections that were already @@ -168,6 +167,7 @@ private static void printDiagnosticsForCurrentState() { } static void dumpRuntimeCompilation(Log log) { + assert VMOperation.isInProgressAtSafepoint(); try { RuntimeCodeInfoHistory.singleton().printRecentOperations(log, true); } catch (Exception e) { @@ -194,7 +194,8 @@ private static void dumpException(Log log, DiagnosticThunk thunk, Throwable e) { } private static void dumpException(Log log, String currentDumper, Throwable e) { - log.newline().string("[!!! Exception while executing ").string(currentDumper).string(": ").string(e.getClass().getName()).string("]").newline(); + log.newline().string("[!!! Exception while executing ").string(currentDumper).string(": ").string(e.getClass().getName()).string("]"); + log.resetIndentation().newline(); } @Uninterruptible(reason = "Prevent deoptimization of stack frames while in this method.") @@ -339,7 +340,11 @@ public void printDiagnostics(Log log, int invocationCount) { UnsignedWord stackBase = VMThreads.StackBase.get(); if (stackBase.equal(0)) { - log.string("Cannot print stack information as the stack base is unknown.").newline(); + /* + * We have to be careful here and not dump too much of the stack: if there are not + * many frames on the stack, we segfault when going past the beginning of the stack. + */ + log.hexdump(state.sp, 8, 16); } else { int bytesToPrint = 512; UnsignedWord availableBytes = stackBase.subtract(sp); @@ -571,25 +576,6 @@ public void printDiagnostics(Log log, int invocationCount) { } } - private static class DumpCurrentThreadRawStackTrace extends DiagnosticThunk { - @Override - public int maxInvocations() { - return 1; - } - - @Override - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") - public void printDiagnostics(Log log, int invocationCount) { - log.string("Raw stacktrace:").indent(true); - /* - * We have to be careful here and not dump too much of the stack: if there are not many - * frames on the stack, we segfault when going past the beginning of the stack. - */ - log.hexdump(state.sp, 8, 16); - log.indent(false); - } - } - private static class DumpCurrentThreadDecodedStackTrace extends DiagnosticThunk { @Override public int maxInvocations() { @@ -630,8 +616,7 @@ public void printDiagnostics(Log log, int invocationCount) { continue; } try { - log.string("Thread ").zhex(vmThread.rawValue()).newline(); - log.indent(true); + log.string("Thread ").zhex(vmThread.rawValue()).string(":").indent(true); printFrameAnchors(log, vmThread); printStacktrace(log, vmThread); log.indent(false); @@ -643,8 +628,7 @@ public void printDiagnostics(Log log, int invocationCount) { } private static void printStacktrace(Log log, IsolateThread vmThread) { - log.string("Full stacktrace").newline(); - log.indent(true); + log.string("Full stacktrace:").indent(true); JavaStackWalker.walkThread(vmThread, StackFramePrintVisitor.SINGLETON, log); log.indent(false); } @@ -686,8 +670,8 @@ public static synchronized DiagnosticThunkRegister getSingleton() { DiagnosticThunkRegister() { this.diagnosticThunks = new DiagnosticThunk[]{new DumpRegisters(), new DumpInstructions(), new DumpTopOfCurrentThreadStack(), new DumpDeoptStubPointer(), new DumpTopFrame(), new DumpThreads(), new DumpCurrentThreadLocals(), new DumpCurrentVMOperation(), new DumpVMOperationHistory(), new DumpCodeCacheHistory(), - new DumpRuntimeCodeInfoMemory(), new DumpRecentDeoptimizations(), new DumpCounters(), new DumpCurrentThreadFrameAnchors(), new DumpCurrentThreadRawStackTrace(), - new DumpCurrentThreadDecodedStackTrace(), new DumpOtherStackTraces(), new VMLockSupport.DumpVMMutexes()}; + new DumpRuntimeCodeInfoMemory(), new DumpRecentDeoptimizations(), new DumpCounters(), new DumpCurrentThreadFrameAnchors(), new DumpCurrentThreadDecodedStackTrace(), + new DumpOtherStackTraces(), new VMLockSupport.DumpVMMutexes()}; } /** Register a diagnostic thunk to be called after a segfault. */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java index 68c06e3f1531..a74095f6cf06 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java @@ -86,16 +86,16 @@ private static void traceCodeCache(String kind, CodeInfo info, boolean allowJava } } - static void printCodeInfo(Log log, CodeInfo info, boolean allowJavaHeapAccess) { - printCodeInfo(log, allowJavaHeapAccess, info, CodeInfoAccess.getState(info), CodeInfoAccess.getName(info), CodeInfoAccess.getCodeStart(info), - CodeInfoAccess.getCodeEnd(info)); + private static void printCodeInfo(Log log, CodeInfo info, boolean allowJavaHeapAccess) { + String name = allowJavaHeapAccess ? CodeInfoAccess.getName(info) : null; + printCodeInfo(log, info, CodeInfoAccess.getState(info), name, CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info)); } - private static void printCodeInfo(Log log, boolean allowJavaHeapAccess, CodeInfo codeInfo, int codeInfoState, String codeName, CodePointer codeStart, CodePointer codeEnd) { + static void printCodeInfo(Log log, UntetheredCodeInfo codeInfo, int state, String name, CodePointer codeStart, CodePointer codeEnd) { log.string("CodeInfo (").zhex(codeInfo).string(" - ").zhex(((UnsignedWord) codeInfo).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()).subtract(1)).string("), ") - .string(CodeInfoAccess.stateToString(codeInfoState)); - if (allowJavaHeapAccess) { - log.string(" - ").string(codeName); + .string(CodeInfoAccess.stateToString(state)); + if (name != null) { + log.string(" - ").string(name); } log.string(", ip: (").zhex(codeStart).string(" - ").zhex(codeEnd).string(")"); log.newline(); @@ -107,7 +107,7 @@ private static void printCodeInfo(Log log, boolean allowJavaHeapAccess, CodeInfo } public void printRecentOperations(Log log, boolean allowJavaHeapAccess) { - log.string("Recent RuntimeCodeInfo operations: ").indent(true); + log.string("Recent RuntimeCodeInfo operations (oldest first): ").indent(true); recentOperations.foreach(log, allowJavaHeapAccess ? PRINT_WITH_JAVA_HEAP_DATA : PRINT_WITHOUT_JAVA_HEAP_DATA); log.indent(false); } @@ -152,7 +152,8 @@ public void setValues(String kind, CodeInfo codeInfo, int codeInfoState, String public void print(Log log, boolean allowJavaHeapAccess) { if (kind != null) { log.unsigned(timestamp).string(" - ").string(kind).spaces(1); - printCodeInfo(log, allowJavaHeapAccess, codeInfo, codeInfoState, codeName, codeStart, codeEnd); + String name = allowJavaHeapAccess ? codeName : null; + printCodeInfo(log, codeInfo, codeInfoState, name, codeStart, codeEnd); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java index 8cf074cbae95..8fad0c3ff736 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java @@ -31,8 +31,10 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.SubstrateDiagnostics; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.c.NonmovableArray; @@ -254,27 +256,34 @@ private static int nextIndex(int index, int length) { /** Potentially unsafe and may therefore only be used when printing diagnostics. */ public void printTable(Log log, boolean allowJavaHeapAccess) { - log.string("RuntimeCodeInfoMemory contains ").signed(count).string(" methods"); - for (int i = 0; i < NonmovableArrays.lengthOf(table); i++) { - logCodeInfo(log, i, allowJavaHeapAccess); + assert VMOperation.isInProgressAtSafepoint() || SubstrateDiagnostics.isInProgressByCurrentThread(); + log.string("RuntimeCodeInfoMemory contains ").signed(count).string(" methods:").indent(true); + if (table.isNonNull()) { + for (int i = 0; i < NonmovableArrays.lengthOf(table); i++) { + logCodeInfo(log, i, allowJavaHeapAccess); + } } + log.indent(false); } @Uninterruptible(reason = "Must prevent the GC from freeing the CodeInfo object.") private void logCodeInfo(Log log, int i, boolean allowJavaHeapAccess) { - UntetheredCodeInfo untetheredInfo = NonmovableArrays.getWord(table, i); - Object tether = CodeInfoAccess.acquireTether(untetheredInfo); - try { - CodeInfo info = CodeInfoAccess.convert(untetheredInfo, tether); - logCodeInfo0(log, info, allowJavaHeapAccess); - } finally { - CodeInfoAccess.releaseTether(untetheredInfo, tether); + UntetheredCodeInfo info = NonmovableArrays.getWord(table, i); + if (info.isNonNull()) { + /* + * Newly created CodeInfo objects do ont have a tether yet. So, we can't use tethering + * to keep the CodeInfo object alive. Instead, we read all relevant values in + * uninterruptible code and pass those values to interruptible code that does the + * printing. + */ + String name = allowJavaHeapAccess ? UntetheredCodeInfoAccess.getName(info) : null; + logCodeInfo0(log, info, UntetheredCodeInfoAccess.getState(info), name, UntetheredCodeInfoAccess.getCodeStart(info), UntetheredCodeInfoAccess.getCodeEnd(info)); } } @Uninterruptible(reason = "Pass the now protected CodeInfo to interruptible code.", calleeMustBe = false) - private static void logCodeInfo0(Log log, CodeInfo info, boolean allowJavaHeapAccess) { - RuntimeCodeInfoHistory.printCodeInfo(log, info, allowJavaHeapAccess); + private static void logCodeInfo0(Log log, UntetheredCodeInfo codeInfo, int state, String name, CodePointer codeStart, CodePointer codeEnd) { + RuntimeCodeInfoHistory.printCodeInfo(log, codeInfo, state, name, codeStart, codeEnd); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java index 8bd1319bdb7d..95f5f2bac2d9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java @@ -49,7 +49,7 @@ public int maxInvocations() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - log.string("Locked VM mutexes:").indent(true); + log.string("VM mutexes:").indent(true); VMLockSupport support = ImageSingletons.lookup(VMLockSupport.class); VMMutex[] mutexes = support.getMutexes(); @@ -59,16 +59,18 @@ public void printDiagnostics(Log log, int invocationCount) { for (int i = 0; i < mutexes.length; i++) { VMMutex mutex = mutexes[i]; IsolateThread owner = mutex.owner; - // TEMP (chaeubl): -// if (owner.isNonNull()) { - log.string(mutex.getName()).string(" is locked by "); - if (owner.equal(VMMutex.UNSPECIFIED_OWNER)) { - log.string("an unspecified thread."); + log.string("mutex \"").string(mutex.getName()).string("\" "); + if (owner.isNull()) { + log.string("is unlocked."); } else { - log.string("thread ").zhex(owner); + log.string("is locked by "); + if (owner.equal(VMMutex.UNSPECIFIED_OWNER)) { + log.string("an unspecified thread."); + } else { + log.string("thread ").zhex(owner); + } } log.newline(); -// } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index d517a73d9f77..f80a0500b05f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -109,7 +109,7 @@ public static VMThreads singleton() { * still holds that mutex. * */ - protected static final VMMutex THREAD_MUTEX = new VMMutex("Thread"); + protected static final VMMutex THREAD_MUTEX = new VMMutex("thread"); /** * A condition variable for waiting for and notifying on changes to the {@link IsolateThread} diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrRecorderThread.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrRecorderThread.java index 85841f379416..179fa8e0782d 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrRecorderThread.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrRecorderThread.java @@ -51,7 +51,7 @@ public JfrRecorderThread(JfrGlobalMemory globalMemory, JfrUnlockedChunkWriter un super("JFR Recorder Thread"); this.globalMemory = globalMemory; this.unlockedChunkWriter = unlockedChunkWriter; - this.mutex = new VMMutex("JfrRecorder"); + this.mutex = new VMMutex("jfrRecorder"); this.condition = new VMCondition(mutex); setDaemon(true); } diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java index 3449ec7c7556..a1f82973ebc7 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java @@ -164,7 +164,7 @@ private interface JfrSymbol extends UninterruptibleEntry { private static class JfrSymbolHashtable extends UninterruptibleHashtable { @Platforms(Platform.HOSTED_ONLY.class) JfrSymbolHashtable() { - super("JfrSymbolHashtable"); + super("jfrSymbolHashtable"); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) From 150f6ec4d0255e13fb4593e5968e06ed741b4640 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 6 Jul 2021 10:53:22 +0200 Subject: [PATCH 18/28] Print location information. --- .../oracle/svm/core/genscavenge/HeapImpl.java | 107 +++++++++++++++++- .../svm/core/genscavenge/HeapVerifier.java | 50 +------- .../svm/core/genscavenge/ImageHeapInfo.java | 32 ++++-- .../svm/core/genscavenge/ImageHeapWalker.java | 17 --- .../core/posix/UContextRegisterDumper.java | 6 +- .../AArch64UContextRegisterDumper.java | 70 ++++++------ .../amd64/AMD64UContextRegisterDumper.java | 38 +++---- .../darwin/DarwinUContextRegisterDumper.java | 38 +++---- .../core/windows/WindowsRegisterDumper.java | 42 +++---- .../com/oracle/svm/core/RegisterDumper.java | 12 +- .../oracle/svm/core/SubstrateDiagnostics.java | 11 +- .../svm/core/code/RuntimeCodeInfoHistory.java | 1 + .../svm/core/code/RuntimeCodeInfoMemory.java | 41 ++++++- .../src/com/oracle/svm/core/heap/Heap.java | 13 ++- .../com/oracle/svm/core/thread/VMThreads.java | 32 ++++++ 15 files changed, 324 insertions(+), 186 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 a7de666cb0f3..243e08bd6297 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 @@ -144,8 +144,8 @@ public boolean isInImageHeap(Object obj) { @Override @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInImageHeap(Pointer pointer) { - return imageHeapInfo.isInImageHeap(pointer) || (AuxiliaryImageHeap.isPresent() && AuxiliaryImageHeap.singleton().containsObject(pointer)); + public boolean isInImageHeap(Pointer objPointer) { + return imageHeapInfo.isInImageHeap(objPointer) || (AuxiliaryImageHeap.isPresent() && AuxiliaryImageHeap.singleton().containsObject(objPointer)); } @Override @@ -276,7 +276,7 @@ void report(Log log, boolean traceHeapChunks) { void logImageHeapPartitionBoundaries(Log log) { log.string("Native image heap boundaries:").indent(true); - ImageHeapWalker.logPartitionBoundaries(log, imageHeapInfo); + imageHeapInfo.print(log); log.indent(false); } @@ -585,6 +585,107 @@ public Reference getAndClearReferencePendingList() { } } + @Override + public boolean printLocationInfo(Log log, UnsignedWord v) { + Pointer value = (Pointer) v; + if (imageHeapInfo.isInReadOnlyPrimitivePartition(value)) { + log.string("points into the image heap (read-only primitives)"); + return true; + } + + if (imageHeapInfo.isInReadOnlyReferencePartition(value)) { + log.string("points into the image heap (read-only references)"); + return true; + } + + if (imageHeapInfo.isInReadOnlyRelocatablePartition(value)) { + log.string("points into the image heap (read-only relocatables)"); + return true; + } + + if (imageHeapInfo.isInWritablePrimitivePartition(value)) { + log.string("points into the image heap (writable primitives)"); + return true; + } + + if (imageHeapInfo.isInWritableReferencePartition(value)) { + log.string("points into the image heap (writable references)"); + return true; + } + + if (imageHeapInfo.isInWritableHugePartition(value)) { + log.string("points into the image heap (writable huge)"); + return true; + } + + if (imageHeapInfo.isInReadOnlyHugePartition(value)) { + log.string("points into the image heap (read-only huge)"); + return true; + } + + if (AuxiliaryImageHeap.isPresent() && AuxiliaryImageHeap.singleton().containsObject(value)) { + log.string("points into the auxiliary image heap"); + return true; + } + + if (isInYoungGen(value)) { + log.string("points into the young generation"); + return true; + } + + if (isInOldGen(value)) { + log.string("points into the old generation"); + return true; + } + + return false; + } + + boolean isInHeap(Pointer ptr) { + return isInImageHeap(ptr) || isInYoungGen(ptr) || isInOldGen(ptr); + } + + private boolean isInYoungGen(Pointer ptr) { + if (findPointerInSpace(youngGeneration.getEden(), ptr)) { + return true; + } + + for (int i = 0; i < youngGeneration.getMaxSurvivorSpaces(); i++) { + if (findPointerInSpace(youngGeneration.getSurvivorFromSpaceAt(i), ptr)) { + return true; + } + if (findPointerInSpace(youngGeneration.getSurvivorToSpaceAt(i), ptr)) { + return true; + } + } + return false; + } + + private boolean isInOldGen(Pointer ptr) { + return findPointerInSpace(oldGeneration.getFromSpace(), ptr) || findPointerInSpace(oldGeneration.getToSpace(), ptr); + } + + private static boolean findPointerInSpace(Space space, Pointer p) { + AlignedHeapChunk.AlignedHeader aChunk = space.getFirstAlignedHeapChunk(); + while (aChunk.isNonNull()) { + Pointer start = AlignedHeapChunk.getObjectsStart(aChunk); + if (start.belowOrEqual(p) && p.belowThan(HeapChunk.getTopPointer(aChunk))) { + return true; + } + aChunk = HeapChunk.getNext(aChunk); + } + + UnalignedHeapChunk.UnalignedHeader uChunk = space.getFirstUnalignedHeapChunk(); + while (uChunk.isNonNull()) { + Pointer start = UnalignedHeapChunk.getObjectStart(uChunk); + if (start.belowOrEqual(p) && p.belowThan(HeapChunk.getTopPointer(uChunk))) { + return true; + } + uChunk = HeapChunk.getNext(uChunk); + } + return false; + } + private static class DumpHeapSettingsAndStatistics extends DiagnosticThunk { @Override public int maxInvocations() { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java index bc672dc4def3..9790e7f69fe4 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java @@ -359,7 +359,7 @@ private static boolean verifyReference(Object parentObject, Pointer reference, P return true; } - if (!isInHeap(referencedObject)) { + if (!HeapImpl.getHeapImpl().isInHeap(referencedObject)) { Log.log().string("Object reference at ").zhex(reference).string(" points outside the Java heap: ").zhex(referencedObject).string(". "); if (parentObject != null) { Log.log().string("The object that contains the invalid reference is of type ").string(parentObject.getClass().getName()).newline(); @@ -372,54 +372,6 @@ private static boolean verifyReference(Object parentObject, Pointer reference, P return true; } - private static boolean isInHeap(Pointer ptr) { - HeapImpl heap = HeapImpl.getHeapImpl(); - return heap.isInImageHeap(ptr) || isInYoungGen(ptr) || isInOldGen(ptr); - } - - private static boolean isInYoungGen(Pointer ptr) { - YoungGeneration youngGen = HeapImpl.getHeapImpl().getYoungGeneration(); - if (findPointerInSpace(youngGen.getEden(), ptr)) { - return true; - } - - for (int i = 0; i < youngGen.getMaxSurvivorSpaces(); i++) { - if (findPointerInSpace(youngGen.getSurvivorFromSpaceAt(i), ptr)) { - return true; - } - if (findPointerInSpace(youngGen.getSurvivorToSpaceAt(i), ptr)) { - return true; - } - } - return false; - } - - private static boolean isInOldGen(Pointer ptr) { - OldGeneration oldGen = HeapImpl.getHeapImpl().getOldGeneration(); - return findPointerInSpace(oldGen.getFromSpace(), ptr) || findPointerInSpace(oldGen.getToSpace(), ptr); - } - - private static boolean findPointerInSpace(Space space, Pointer p) { - AlignedHeapChunk.AlignedHeader aChunk = space.getFirstAlignedHeapChunk(); - while (aChunk.isNonNull()) { - Pointer start = AlignedHeapChunk.getObjectsStart(aChunk); - if (start.belowOrEqual(p) && p.belowThan(HeapChunk.getTopPointer(aChunk))) { - return true; - } - aChunk = HeapChunk.getNext(aChunk); - } - - UnalignedHeapChunk.UnalignedHeader uChunk = space.getFirstUnalignedHeapChunk(); - while (uChunk.isNonNull()) { - Pointer start = UnalignedHeapChunk.getObjectStart(uChunk); - if (start.belowOrEqual(p) && p.belowThan(HeapChunk.getTopPointer(uChunk))) { - return true; - } - uChunk = HeapChunk.getNext(uChunk); - } - return false; - } - private static class ImageHeapRegionVerifier implements MemoryWalker.ImageHeapRegionVisitor { private final ImageHeapObjectVerifier objectVerifier; 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 9bb0430f8942..22dcbca688c8 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 @@ -34,6 +34,8 @@ import com.oracle.svm.core.annotate.UnknownPrimitiveField; import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader; import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader; +import com.oracle.svm.core.hub.LayoutEncoding; +import com.oracle.svm.core.log.Log; import com.oracle.svm.core.snippets.KnownIntrinsics; /** @@ -129,49 +131,49 @@ public void initialize(Object firstReadOnlyPrimitiveObject, Object lastReadOnlyP @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInReadOnlyPrimitivePartition(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstReadOnlyPrimitiveObject).belowOrEqual(ptr) && ptr.belowOrEqual(Word.objectToUntrackedPointer(lastReadOnlyPrimitiveObject)); + return Word.objectToUntrackedPointer(firstReadOnlyPrimitiveObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastReadOnlyPrimitiveObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInReadOnlyReferencePartition(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstReadOnlyReferenceObject).belowOrEqual(ptr) && ptr.belowOrEqual(Word.objectToUntrackedPointer(lastReadOnlyReferenceObject)); + return Word.objectToUntrackedPointer(firstReadOnlyReferenceObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastReadOnlyReferenceObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInReadOnlyRelocatablePartition(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstReadOnlyRelocatableObject).belowOrEqual(ptr) && ptr.belowOrEqual(Word.objectToUntrackedPointer(lastReadOnlyRelocatableObject)); + return Word.objectToUntrackedPointer(firstReadOnlyRelocatableObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastReadOnlyRelocatableObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInWritablePrimitivePartition(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstWritablePrimitiveObject).belowOrEqual(ptr) && ptr.belowOrEqual(Word.objectToUntrackedPointer(lastWritablePrimitiveObject)); + return Word.objectToUntrackedPointer(firstWritablePrimitiveObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastWritablePrimitiveObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInWritableReferencePartition(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstWritableReferenceObject).belowOrEqual(ptr) && ptr.belowOrEqual(Word.objectToUntrackedPointer(lastWritableReferenceObject)); + return Word.objectToUntrackedPointer(firstWritableReferenceObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastWritableReferenceObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInWritableHugePartition(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstWritableHugeObject).belowOrEqual(ptr) && ptr.belowOrEqual(Word.objectToUntrackedPointer(lastWritableHugeObject)); + return Word.objectToUntrackedPointer(firstWritableHugeObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastWritableHugeObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInReadOnlyHugePartition(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstReadOnlyHugeObject).belowOrEqual(ptr) && ptr.belowOrEqual(Word.objectToUntrackedPointer(lastReadOnlyHugeObject)); + return Word.objectToUntrackedPointer(firstReadOnlyHugeObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastReadOnlyHugeObject)); } /** * This method only returns the correct result for pointers that point to the the start of an * object. This is sufficient for all our current use cases. This code must be as fast as - * possible at the GC uses it for every visited reference. + * possible as the GC uses it for every visited reference. */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInImageHeap(Pointer objectPointer) { @@ -192,6 +194,10 @@ public UnalignedHeader getFirstWritableUnalignedChunk() { return asImageHeapChunk(offsetOfFirstWritableUnalignedChunk); } + private static Word getObjectEnd(Object obj) { + return Word.objectToUntrackedPointer(obj).add(LayoutEncoding.getSizeFromObject(obj)); + } + @SuppressWarnings("unchecked") private static > T asImageHeapChunk(long offsetInImageHeap) { if (offsetInImageHeap < 0) { @@ -200,4 +206,14 @@ private static > T asImageHeapChunk(long offsetInI UnsignedWord offset = WordFactory.unsigned(offsetInImageHeap); return (T) KnownIntrinsics.heapBase().add(offset); } + + public void print(Log log) { + log.string("ReadOnly Primitives: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyPrimitiveObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyPrimitiveObject)).newline(); + log.string("ReadOnly References: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyReferenceObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyReferenceObject)).newline(); + log.string("ReadOnly Relocatables: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyRelocatableObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyRelocatableObject)).newline(); + log.string("Writable Primitives: ").zhex(Word.objectToUntrackedPointer(firstWritablePrimitiveObject)).string(" - ").zhex(getObjectEnd(lastWritablePrimitiveObject)).newline(); + log.string("Writable References: ").zhex(Word.objectToUntrackedPointer(firstWritableReferenceObject)).string(" - ").zhex(getObjectEnd(lastWritableReferenceObject)).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)); + } } 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 a8ae3e5442a8..16d4900d3e35 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 @@ -133,23 +133,6 @@ private static boolean walkPartitionInline(Object firstObject, Object lastObject } while (current.belowOrEqual(lastPointer)); return true; } - - static void logPartitionBoundaries(Log log, ImageHeapInfo imageHeapInfo) { - log.string("ReadOnly Primitives: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyPrimitiveObject)).string(" .. ").zhex( - Word.objectToUntrackedPointer(imageHeapInfo.lastReadOnlyPrimitiveObject)).newline(); - log.string("ReadOnly References: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyReferenceObject)).string(" .. ").zhex( - Word.objectToUntrackedPointer(imageHeapInfo.lastReadOnlyReferenceObject)).newline(); - log.string("ReadOnly Relocatables: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyRelocatableObject)).string(" .. ").zhex( - Word.objectToUntrackedPointer(imageHeapInfo.lastReadOnlyRelocatableObject)).newline(); - log.string("Writable Primitives: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstWritablePrimitiveObject)).string(" .. ").zhex( - Word.objectToUntrackedPointer(imageHeapInfo.lastWritablePrimitiveObject)).newline(); - log.string("Writable References: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstWritableReferenceObject)).string(" .. ").zhex( - Word.objectToUntrackedPointer(imageHeapInfo.lastWritableReferenceObject)).newline(); - log.string("Writable Huge: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstWritableHugeObject)).string(" .. ").zhex( - Word.objectToUntrackedPointer(imageHeapInfo.lastWritableHugeObject)).newline(); - log.string("ReadOnly Huge: ").zhex(Word.objectToUntrackedPointer(imageHeapInfo.firstReadOnlyHugeObject)).string(" .. ").zhex( - Word.objectToUntrackedPointer(imageHeapInfo.lastReadOnlyHugeObject)); - } } abstract class MemoryWalkerAccessBase implements MemoryWalker.NativeImageHeapRegionAccess { diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/UContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/UContextRegisterDumper.java index 751ac2f90749..b2f03bc9fe90 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/UContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/UContextRegisterDumper.java @@ -32,7 +32,7 @@ import com.oracle.svm.core.posix.headers.Signal.ucontext_t; public interface UContextRegisterDumper extends RegisterDumper { - void dumpRegisters(Log log, ucontext_t uContext); + void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo); PointerBase getHeapBase(ucontext_t uContext); @@ -43,8 +43,8 @@ public interface UContextRegisterDumper extends RegisterDumper { PointerBase getIP(ucontext_t uContext); @Override - default void dumpRegisters(Log log, Context context) { - dumpRegisters(log, (ucontext_t) context); + default void dumpRegisters(Log log, Context context, boolean printLocationInfo) { + dumpRegisters(log, (ucontext_t) context, printLocationInfo); } @Override diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java index ca2586afeb1c..0a97ead1766e 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java @@ -59,43 +59,43 @@ public void afterRegistration(AfterRegistrationAccess access) { class AArch64UContextRegisterDumper implements UContextRegisterDumper { @Override - public void dumpRegisters(Log log, ucontext_t uContext) { + public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo) { mcontext_t sigcontext = uContext.uc_mcontext(); GregsPointer regs = sigcontext.regs(); - dumpReg(log, "R0 ", regs.read(0)); - dumpReg(log, "R1 ", regs.read(1)); - dumpReg(log, "R2 ", regs.read(2)); - dumpReg(log, "R3 ", regs.read(3)); - dumpReg(log, "R4 ", regs.read(4)); - dumpReg(log, "R5 ", regs.read(5)); - dumpReg(log, "R6 ", regs.read(6)); - dumpReg(log, "R7 ", regs.read(7)); - dumpReg(log, "R8 ", regs.read(8)); - dumpReg(log, "R9 ", regs.read(9)); - dumpReg(log, "R10 ", regs.read(10)); - dumpReg(log, "R11 ", regs.read(11)); - dumpReg(log, "R12 ", regs.read(12)); - dumpReg(log, "R13 ", regs.read(13)); - dumpReg(log, "R14 ", regs.read(14)); - dumpReg(log, "R15 ", regs.read(15)); - dumpReg(log, "R16 ", regs.read(16)); - dumpReg(log, "R17 ", regs.read(17)); - dumpReg(log, "R18 ", regs.read(18)); - dumpReg(log, "R19 ", regs.read(19)); - dumpReg(log, "R20 ", regs.read(20)); - dumpReg(log, "R21 ", regs.read(21)); - dumpReg(log, "R22 ", regs.read(22)); - dumpReg(log, "R23 ", regs.read(23)); - dumpReg(log, "R24 ", regs.read(24)); - dumpReg(log, "R25 ", regs.read(25)); - dumpReg(log, "R26 ", regs.read(26)); - dumpReg(log, "R27 ", regs.read(27)); - dumpReg(log, "R28 ", regs.read(28)); - dumpReg(log, "R29 ", regs.read(29)); - dumpReg(log, "R30 ", regs.read(30)); - dumpReg(log, "R31 ", regs.read(31)); - dumpReg(log, "SP ", sigcontext.sp()); - dumpReg(log, "PC ", sigcontext.pc()); + dumpReg(log, "R0 ", regs.read(0), printLocationInfo); + dumpReg(log, "R1 ", regs.read(1), printLocationInfo); + dumpReg(log, "R2 ", regs.read(2), printLocationInfo); + dumpReg(log, "R3 ", regs.read(3), printLocationInfo); + dumpReg(log, "R4 ", regs.read(4), printLocationInfo); + dumpReg(log, "R5 ", regs.read(5), printLocationInfo); + dumpReg(log, "R6 ", regs.read(6), printLocationInfo); + dumpReg(log, "R7 ", regs.read(7), printLocationInfo); + dumpReg(log, "R8 ", regs.read(8), printLocationInfo); + dumpReg(log, "R9 ", regs.read(9), printLocationInfo); + dumpReg(log, "R10 ", regs.read(10), printLocationInfo); + dumpReg(log, "R11 ", regs.read(11), printLocationInfo); + dumpReg(log, "R12 ", regs.read(12), printLocationInfo); + dumpReg(log, "R13 ", regs.read(13), printLocationInfo); + dumpReg(log, "R14 ", regs.read(14), printLocationInfo); + dumpReg(log, "R15 ", regs.read(15), printLocationInfo); + dumpReg(log, "R16 ", regs.read(16), printLocationInfo); + dumpReg(log, "R17 ", regs.read(17), printLocationInfo); + dumpReg(log, "R18 ", regs.read(18), printLocationInfo); + dumpReg(log, "R19 ", regs.read(19), printLocationInfo); + dumpReg(log, "R20 ", regs.read(20), printLocationInfo); + dumpReg(log, "R21 ", regs.read(21), printLocationInfo); + dumpReg(log, "R22 ", regs.read(22), printLocationInfo); + dumpReg(log, "R23 ", regs.read(23), printLocationInfo); + dumpReg(log, "R24 ", regs.read(24), printLocationInfo); + dumpReg(log, "R25 ", regs.read(25), printLocationInfo); + dumpReg(log, "R26 ", regs.read(26), printLocationInfo); + dumpReg(log, "R27 ", regs.read(27), printLocationInfo); + dumpReg(log, "R28 ", regs.read(28), printLocationInfo); + dumpReg(log, "R29 ", regs.read(29), printLocationInfo); + dumpReg(log, "R30 ", regs.read(30), printLocationInfo); + dumpReg(log, "R31 ", regs.read(31), printLocationInfo); + dumpReg(log, "SP ", sigcontext.sp(), printLocationInfo); + dumpReg(log, "PC ", sigcontext.pc(), printLocationInfo); } @Override diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java index a1a2bc263504..4ac8fdd7237d 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java @@ -59,26 +59,26 @@ public void afterRegistration(AfterRegistrationAccess access) { class AMD64UContextRegisterDumper implements UContextRegisterDumper { @Override - public void dumpRegisters(Log log, ucontext_t uContext) { + public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo) { GregsPointer gregs = uContext.uc_mcontext_gregs(); - dumpReg(log, "RAX ", gregs.read(GregEnum.REG_RAX())); - dumpReg(log, "RBX ", gregs.read(GregEnum.REG_RBX())); - dumpReg(log, "RCX ", gregs.read(GregEnum.REG_RCX())); - dumpReg(log, "RDX ", gregs.read(GregEnum.REG_RDX())); - dumpReg(log, "RBP ", gregs.read(GregEnum.REG_RBP())); - dumpReg(log, "RSI ", gregs.read(GregEnum.REG_RSI())); - dumpReg(log, "RDI ", gregs.read(GregEnum.REG_RDI())); - dumpReg(log, "RSP ", gregs.read(GregEnum.REG_RSP())); - dumpReg(log, "R8 ", gregs.read(GregEnum.REG_R8())); - dumpReg(log, "R9 ", gregs.read(GregEnum.REG_R9())); - dumpReg(log, "R10 ", gregs.read(GregEnum.REG_R10())); - dumpReg(log, "R11 ", gregs.read(GregEnum.REG_R11())); - dumpReg(log, "R12 ", gregs.read(GregEnum.REG_R12())); - dumpReg(log, "R13 ", gregs.read(GregEnum.REG_R13())); - dumpReg(log, "R14 ", gregs.read(GregEnum.REG_R14())); - dumpReg(log, "R15 ", gregs.read(GregEnum.REG_R15())); - dumpReg(log, "EFL ", gregs.read(GregEnum.REG_EFL())); - dumpReg(log, "RIP ", gregs.read(GregEnum.REG_RIP())); + dumpReg(log, "RAX ", gregs.read(GregEnum.REG_RAX()), printLocationInfo); + dumpReg(log, "RBX ", gregs.read(GregEnum.REG_RBX()), printLocationInfo); + dumpReg(log, "RCX ", gregs.read(GregEnum.REG_RCX()), printLocationInfo); + dumpReg(log, "RDX ", gregs.read(GregEnum.REG_RDX()), printLocationInfo); + dumpReg(log, "RBP ", gregs.read(GregEnum.REG_RBP()), printLocationInfo); + dumpReg(log, "RSI ", gregs.read(GregEnum.REG_RSI()), printLocationInfo); + dumpReg(log, "RDI ", gregs.read(GregEnum.REG_RDI()), printLocationInfo); + dumpReg(log, "RSP ", gregs.read(GregEnum.REG_RSP()), printLocationInfo); + dumpReg(log, "R8 ", gregs.read(GregEnum.REG_R8()), printLocationInfo); + dumpReg(log, "R9 ", gregs.read(GregEnum.REG_R9()), printLocationInfo); + dumpReg(log, "R10 ", gregs.read(GregEnum.REG_R10()), printLocationInfo); + dumpReg(log, "R11 ", gregs.read(GregEnum.REG_R11()), printLocationInfo); + dumpReg(log, "R12 ", gregs.read(GregEnum.REG_R12()), printLocationInfo); + dumpReg(log, "R13 ", gregs.read(GregEnum.REG_R13()), printLocationInfo); + dumpReg(log, "R14 ", gregs.read(GregEnum.REG_R14()), printLocationInfo); + dumpReg(log, "R15 ", gregs.read(GregEnum.REG_R15()), printLocationInfo); + dumpReg(log, "EFL ", gregs.read(GregEnum.REG_EFL()), printLocationInfo); + dumpReg(log, "RIP ", gregs.read(GregEnum.REG_RIP()), printLocationInfo); } @Override diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java index 99d95156cadf..27cb096d82cf 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java @@ -58,26 +58,26 @@ public void afterRegistration(AfterRegistrationAccess access) { class DarwinUContextRegisterDumper implements UContextRegisterDumper { @Override - public void dumpRegisters(Log log, ucontext_t uContext) { + public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo) { Signal.MContext64 sigcontext = uContext.uc_mcontext64(); - dumpReg(log, "RAX ", ((Pointer) sigcontext).readLong(sigcontext.rax_offset())); - dumpReg(log, "RBX ", ((Pointer) sigcontext).readLong(sigcontext.rbx_offset())); - dumpReg(log, "RCX ", ((Pointer) sigcontext).readLong(sigcontext.rcx_offset())); - dumpReg(log, "RDX ", ((Pointer) sigcontext).readLong(sigcontext.rdx_offset())); - dumpReg(log, "RBP ", ((Pointer) sigcontext).readLong(sigcontext.rbp_offset())); - dumpReg(log, "RSI ", ((Pointer) sigcontext).readLong(sigcontext.rsi_offset())); - dumpReg(log, "RDI ", ((Pointer) sigcontext).readLong(sigcontext.rdi_offset())); - dumpReg(log, "RSP ", ((Pointer) sigcontext).readLong(sigcontext.rsp_offset())); - dumpReg(log, "R8 ", ((Pointer) sigcontext).readLong(sigcontext.r8_offset())); - dumpReg(log, "R9 ", ((Pointer) sigcontext).readLong(sigcontext.r9_offset())); - dumpReg(log, "R10 ", ((Pointer) sigcontext).readLong(sigcontext.r10_offset())); - dumpReg(log, "R11 ", ((Pointer) sigcontext).readLong(sigcontext.r11_offset())); - dumpReg(log, "R12 ", ((Pointer) sigcontext).readLong(sigcontext.r12_offset())); - dumpReg(log, "R13 ", ((Pointer) sigcontext).readLong(sigcontext.r13_offset())); - dumpReg(log, "R14 ", ((Pointer) sigcontext).readLong(sigcontext.r14_offset())); - dumpReg(log, "R15 ", ((Pointer) sigcontext).readLong(sigcontext.r15_offset())); - dumpReg(log, "EFL ", ((Pointer) sigcontext).readLong(sigcontext.efl_offset())); - dumpReg(log, "RIP ", ((Pointer) sigcontext).readLong(sigcontext.rip_offset())); + dumpReg(log, "RAX ", ((Pointer) sigcontext).readLong(sigcontext.rax_offset()), printLocationInfo); + dumpReg(log, "RBX ", ((Pointer) sigcontext).readLong(sigcontext.rbx_offset()), printLocationInfo); + dumpReg(log, "RCX ", ((Pointer) sigcontext).readLong(sigcontext.rcx_offset()), printLocationInfo); + dumpReg(log, "RDX ", ((Pointer) sigcontext).readLong(sigcontext.rdx_offset()), printLocationInfo); + dumpReg(log, "RBP ", ((Pointer) sigcontext).readLong(sigcontext.rbp_offset()), printLocationInfo); + dumpReg(log, "RSI ", ((Pointer) sigcontext).readLong(sigcontext.rsi_offset()), printLocationInfo); + dumpReg(log, "RDI ", ((Pointer) sigcontext).readLong(sigcontext.rdi_offset()), printLocationInfo); + dumpReg(log, "RSP ", ((Pointer) sigcontext).readLong(sigcontext.rsp_offset()), printLocationInfo); + dumpReg(log, "R8 ", ((Pointer) sigcontext).readLong(sigcontext.r8_offset()), printLocationInfo); + dumpReg(log, "R9 ", ((Pointer) sigcontext).readLong(sigcontext.r9_offset()), printLocationInfo); + dumpReg(log, "R10 ", ((Pointer) sigcontext).readLong(sigcontext.r10_offset()), printLocationInfo); + dumpReg(log, "R11 ", ((Pointer) sigcontext).readLong(sigcontext.r11_offset()), printLocationInfo); + dumpReg(log, "R12 ", ((Pointer) sigcontext).readLong(sigcontext.r12_offset()), printLocationInfo); + dumpReg(log, "R13 ", ((Pointer) sigcontext).readLong(sigcontext.r13_offset()), printLocationInfo); + dumpReg(log, "R14 ", ((Pointer) sigcontext).readLong(sigcontext.r14_offset()), printLocationInfo); + dumpReg(log, "R15 ", ((Pointer) sigcontext).readLong(sigcontext.r15_offset()), printLocationInfo); + dumpReg(log, "EFL ", ((Pointer) sigcontext).readLong(sigcontext.efl_offset()), printLocationInfo); + dumpReg(log, "RIP ", ((Pointer) sigcontext).readLong(sigcontext.rip_offset()), printLocationInfo); } @Override diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java index e9d22fca35cf..845f7800aeb2 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java @@ -53,29 +53,29 @@ public void afterRegistration(AfterRegistrationAccess access) { public class WindowsRegisterDumper implements RegisterDumper { @Override - public void dumpRegisters(Log log, Context context) { - dumpRegisters(log, (CONTEXT) context); + public void dumpRegisters(Log log, Context context, boolean printLocationInfo) { + dumpRegisters(log, (CONTEXT) context, printLocationInfo); } - private static void dumpRegisters(Log log, CONTEXT context) { - dumpReg(log, "RAX ", context.Rax()); - dumpReg(log, "RBX ", context.Rbx()); - dumpReg(log, "RCX ", context.Rcx()); - dumpReg(log, "RDX ", context.Rdx()); - dumpReg(log, "RBP ", context.Rbp()); - dumpReg(log, "RSI ", context.Rsi()); - dumpReg(log, "RDI ", context.Rdi()); - dumpReg(log, "RSP ", context.Rsp()); - dumpReg(log, "R8 ", context.R8()); - dumpReg(log, "R9 ", context.R9()); - dumpReg(log, "R10 ", context.R10()); - dumpReg(log, "R11 ", context.R11()); - dumpReg(log, "R12 ", context.R12()); - dumpReg(log, "R13 ", context.R13()); - dumpReg(log, "R14 ", context.R14()); - dumpReg(log, "R15 ", context.R15()); - dumpReg(log, "EFL ", context.EFlags()); - dumpReg(log, "RIP ", context.Rip()); + private static void dumpRegisters(Log log, CONTEXT context, boolean printLocationInfo) { + dumpReg(log, "RAX ", context.Rax(), printLocationInfo); + dumpReg(log, "RBX ", context.Rbx(), printLocationInfo); + dumpReg(log, "RCX ", context.Rcx(), printLocationInfo); + dumpReg(log, "RDX ", context.Rdx(), printLocationInfo); + dumpReg(log, "RBP ", context.Rbp(), printLocationInfo); + dumpReg(log, "RSI ", context.Rsi(), printLocationInfo); + dumpReg(log, "RDI ", context.Rdi(), printLocationInfo); + dumpReg(log, "RSP ", context.Rsp(), printLocationInfo); + dumpReg(log, "R8 ", context.R8(), printLocationInfo); + dumpReg(log, "R9 ", context.R9(), printLocationInfo); + dumpReg(log, "R10 ", context.R10(), printLocationInfo); + dumpReg(log, "R11 ", context.R11(), printLocationInfo); + dumpReg(log, "R12 ", context.R12(), printLocationInfo); + dumpReg(log, "R13 ", context.R13(), printLocationInfo); + dumpReg(log, "R14 ", context.R14(), printLocationInfo); + dumpReg(log, "R15 ", context.R15(), printLocationInfo); + dumpReg(log, "EFL ", context.EFlags(), printLocationInfo); + dumpReg(log, "RIP ", context.Rip(), printLocationInfo); } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RegisterDumper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RegisterDumper.java index 3d985e0c8fec..cebd2cfa1eef 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RegisterDumper.java @@ -26,6 +26,7 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.log.Log; @@ -40,14 +41,19 @@ static RegisterDumper singleton() { return ImageSingletons.lookup(RegisterDumper.class); } - static void dumpReg(Log log, String label, long value) { - log.string(label).zhex(value).newline(); + static void dumpReg(Log log, String label, long value, boolean printLocationInfo) { + log.string(label).zhex(value); + if (printLocationInfo) { + log.spaces(1); + SubstrateDiagnostics.printLocationInfo(log, WordFactory.unsigned(value)); + } + log.newline(); } interface Context extends PointerBase { } - void dumpRegisters(Log log, Context context); + void dumpRegisters(Log log, Context context, boolean printLocationInfo); PointerBase getHeapBase(Context context); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index ee01e93478c8..27684f32db26 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -51,6 +51,7 @@ import com.oracle.svm.core.deopt.DeoptimizationSupport; import com.oracle.svm.core.deopt.DeoptimizedFrame; import com.oracle.svm.core.deopt.Deoptimizer; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicWord; import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.log.Log; @@ -110,6 +111,12 @@ public static int maxInvocations() { return result; } + public static void printLocationInfo(Log log, UnsignedWord value) { + if (value.notEqual(0) && !RuntimeCodeInfoMemory.singleton().printLocationInfo(log, value) && !VMThreads.printLocationInfo(log, value) && !Heap.getHeap().printLocationInfo(log, value)) { + log.string("is an unknown value"); + } + } + /** Prints extensive diagnostic information to the given Log. */ public static boolean print(Log log, Pointer sp, CodePointer ip) { return print(log, sp, ip, WordFactory.nullPointer()); @@ -277,7 +284,7 @@ public void clear() { private static class DumpRegisters extends DiagnosticThunk { @Override public int maxInvocations() { - return 1; + return 2; } @Override @@ -286,7 +293,7 @@ public void printDiagnostics(Log log, int invocationCount) { RegisterDumper.Context context = state.context; if (context.isNonNull()) { log.string("General purpose register values:").indent(true); - RegisterDumper.singleton().dumpRegisters(log, context); + RegisterDumper.singleton().dumpRegisters(log, context, invocationCount == 1); log.indent(false); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java index a74095f6cf06..f9940210fc44 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java @@ -91,6 +91,7 @@ private static void printCodeInfo(Log log, CodeInfo info, boolean allowJavaHeapA printCodeInfo(log, info, CodeInfoAccess.getState(info), name, CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info)); } + // TEMP (chaeubl): move this somewhere else... static void printCodeInfo(Log log, UntetheredCodeInfo codeInfo, int state, String name, CodePointer codeStart, CodePointer codeEnd) { log.string("CodeInfo (").zhex(codeInfo).string(" - ").zhex(((UnsignedWord) codeInfo).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()).subtract(1)).string("), ") .string(CodeInfoAccess.stateToString(state)); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java index 8fad0c3ff736..86e316aa7a5f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java @@ -32,6 +32,7 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CodePointer; +import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; import com.oracle.svm.core.SubstrateDiagnostics; @@ -254,20 +255,20 @@ private static int nextIndex(int index, int length) { return (index + 1 < length) ? (index + 1) : 0; } - /** Potentially unsafe and may therefore only be used when printing diagnostics. */ public void printTable(Log log, boolean allowJavaHeapAccess) { - assert VMOperation.isInProgressAtSafepoint() || SubstrateDiagnostics.isInProgressByCurrentThread(); + assert VMOperation.isInProgressAtSafepoint() || + SubstrateDiagnostics.isInProgressByCurrentThread() : "outside of a safepoint, this may only be used for printing diagnostics as the table could be freed at any time"; log.string("RuntimeCodeInfoMemory contains ").signed(count).string(" methods:").indent(true); if (table.isNonNull()) { for (int i = 0; i < NonmovableArrays.lengthOf(table); i++) { - logCodeInfo(log, i, allowJavaHeapAccess); + printCodeInfo(log, i, allowJavaHeapAccess); } } log.indent(false); } @Uninterruptible(reason = "Must prevent the GC from freeing the CodeInfo object.") - private void logCodeInfo(Log log, int i, boolean allowJavaHeapAccess) { + private void printCodeInfo(Log log, int i, boolean allowJavaHeapAccess) { UntetheredCodeInfo info = NonmovableArrays.getWord(table, i); if (info.isNonNull()) { /* @@ -277,12 +278,12 @@ private void logCodeInfo(Log log, int i, boolean allowJavaHeapAccess) { * printing. */ String name = allowJavaHeapAccess ? UntetheredCodeInfoAccess.getName(info) : null; - logCodeInfo0(log, info, UntetheredCodeInfoAccess.getState(info), name, UntetheredCodeInfoAccess.getCodeStart(info), UntetheredCodeInfoAccess.getCodeEnd(info)); + printCodeInfo0(log, info, UntetheredCodeInfoAccess.getState(info), name, UntetheredCodeInfoAccess.getCodeStart(info), UntetheredCodeInfoAccess.getCodeEnd(info)); } } @Uninterruptible(reason = "Pass the now protected CodeInfo to interruptible code.", calleeMustBe = false) - private static void logCodeInfo0(Log log, UntetheredCodeInfo codeInfo, int state, String name, CodePointer codeStart, CodePointer codeEnd) { + private static void printCodeInfo0(Log log, UntetheredCodeInfo codeInfo, int state, String name, CodePointer codeStart, CodePointer codeEnd) { RuntimeCodeInfoHistory.printCodeInfo(log, codeInfo, state, name, codeStart, codeEnd); } @@ -306,4 +307,32 @@ public void tearDown() { table = NonmovableArrays.nullArray(); } } + + public boolean printLocationInfo(Log log, UnsignedWord value) { + assert SubstrateDiagnostics.isInProgressByCurrentThread() : "may only be used for printing diagnostics as the table could be freed at any time"; + if (table.isNonNull()) { + for (int i = 0; i < NonmovableArrays.lengthOf(table); i++) { + // TEMP (chaeubl): print the name of the code info object if javaAccess is allowed + UntetheredCodeInfo info = NonmovableArrays.getWord(table, i); + if (info.equal(value)) { + log.string("is a CodeInfo object"); + return true; + } + + UnsignedWord codeInfoEnd = ((UnsignedWord) info).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()); + if (value.aboveOrEqual(value) && value.belowThan(codeInfoEnd)) { + log.string("points within a CodeInfo object"); + return true; + } + + UnsignedWord codeStart = (UnsignedWord) UntetheredCodeInfoAccess.getCodeStart(info); + UnsignedWord codeEnd = (UnsignedWord) UntetheredCodeInfoAccess.getCodeEnd(info); + if (value.aboveOrEqual(codeStart) && value.belowOrEqual(codeEnd)) { + log.string("is at codeStart+").unsigned(value.subtract(codeStart)).string(" in CodeInfo ").zhex(info); + return true; + } + } + } + return false; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 71f6a10733bb..609ee2f8e0fd 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -35,10 +35,12 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.word.Pointer; +import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.PredefinedClassesSupport; +import com.oracle.svm.core.log.Log; import com.oracle.svm.core.os.CommittedMemoryProvider; import jdk.vm.ci.meta.MetaAccessProvider; @@ -166,7 +168,10 @@ public List> getLoadedClasses() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public abstract boolean isInImageHeap(Object object); - /** Returns true if the object at the given address is located in the image heap. */ + /** + * Returns true if the object at the given address is located in the image heap. This method + * only works reliably for pointers to the start of an object. + */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public abstract boolean isInImageHeap(Pointer objectPtr); @@ -187,4 +192,10 @@ public List> getLoadedClasses() { * May return {@code null}. */ public abstract Reference getAndClearReferencePendingList(); + + /** + * If the passed value is within the Java heap, this method prints some information about that + * value and returns true. Otherwise, the method returns false. + */ + public abstract boolean printLocationInfo(Log log, UnsignedWord value); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index f80a0500b05f..d8ed212f3227 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -30,6 +30,7 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.replacements.ReplacementsUtil; import org.graalvm.compiler.replacements.nodes.AssertionNode; +import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; @@ -43,6 +44,8 @@ import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.thread; import com.oracle.svm.core.annotate.NeverInline; import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.Uninterruptible; @@ -53,12 +56,15 @@ import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicWord; import com.oracle.svm.core.locks.VMCondition; import com.oracle.svm.core.locks.VMMutex; +import com.oracle.svm.core.log.Log; import com.oracle.svm.core.threadlocal.FastThreadLocal; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.FastThreadLocalInt; import com.oracle.svm.core.threadlocal.FastThreadLocalWord; +import com.oracle.svm.core.threadlocal.VMThreadLocalMTSupport; import com.oracle.svm.core.util.UnsignedUtils; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.thread.VMThreadMTFeature; /** * Utility methods for the manipulation and iteration of {@link IsolateThread}s. @@ -570,6 +576,32 @@ public static boolean ownsThreadMutex() { return THREAD_MUTEX.isOwner(); } + public static boolean printLocationInfo(Log log, UnsignedWord value) { + for (IsolateThread thread = firstThreadUnsafe(); thread.isNonNull(); thread = nextThread(thread)) { + if (thread.equal(value)) { + log.string("is a thread"); + return true; + } + + UnsignedWord stackBase = StackBase.get(thread); + UnsignedWord stackEnd = StackEnd.get(thread); + if (value.belowOrEqual(stackBase) && value.aboveOrEqual(stackEnd)) { + log.string("is pointing into the stack for thread ").zhex(thread); + return true; + } + + if (SubstrateOptions.MultiThreaded.getValue()) { + int sizeOfThreadLocals = ImageSingletons.lookup(VMThreadLocalMTSupport.class).vmThreadSize; + UnsignedWord endOfThreadLocals = ((UnsignedWord) thread).add(sizeOfThreadLocals); + if (value.aboveOrEqual((UnsignedWord) thread) && value.belowThan(endOfThreadLocals)) { + log.string("is pointing into the thread locals for thread ").zhex(thread); + return true; + } + } + } + return false; + } + /* * Access to platform-specific implementations. */ From 726f646b5f195260c08929b5593dacb15f636009 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 6 Jul 2021 15:59:57 +0200 Subject: [PATCH 19/28] More location printing and fixes. --- .../core/genscavenge/AlignedHeapChunk.java | 4 + .../oracle/svm/core/genscavenge/HeapImpl.java | 104 +++++++++++++----- .../svm/core/genscavenge/ImageHeapInfo.java | 4 + .../core/genscavenge/ObjectHeaderImpl.java | 21 ++++ .../genscavenge/ThreadLocalAllocation.java | 2 +- .../core/genscavenge/UnalignedHeapChunk.java | 5 + .../core/posix/UContextRegisterDumper.java | 6 +- .../AArch64UContextRegisterDumper.java | 70 ++++++------ .../amd64/AMD64UContextRegisterDumper.java | 38 +++---- .../darwin/DarwinUContextRegisterDumper.java | 38 +++---- .../linux/LinuxStackOverflowSupport.java | 17 +-- .../core/windows/WindowsRegisterDumper.java | 42 +++---- .../com/oracle/svm/core/RegisterDumper.java | 6 +- .../oracle/svm/core/SubstrateDiagnostics.java | 16 +-- .../svm/core/code/RuntimeCodeInfoAccess.java | 2 + .../svm/core/code/RuntimeCodeInfoMemory.java | 61 +++++++--- .../src/com/oracle/svm/core/heap/Heap.java | 2 +- .../oracle/svm/core/hub/LayoutEncoding.java | 1 + .../src/com/oracle/svm/core/log/RealLog.java | 2 + .../com/oracle/svm/core/thread/VMThreads.java | 5 +- 20 files changed, 279 insertions(+), 167 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java index e035233ba932..09b15b87976f 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java @@ -97,6 +97,10 @@ public static Pointer getObjectsStart(AlignedHeader that) { return HeapChunk.asPointer(that).add(getObjectsStartOffset()); } + public static Pointer getObjectsEnd(AlignedHeader that) { + return HeapChunk.getEndPointer(that); + } + /** Allocate uninitialized memory within this AlignedHeapChunk. */ static Pointer allocateMemory(AlignedHeader that, UnsignedWord size) { Pointer result = WordFactory.nullPointer(); 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 243e08bd6297..a12b4c5b4f8d 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 @@ -52,6 +52,9 @@ import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader; +import com.oracle.svm.core.genscavenge.ThreadLocalAllocation.Descriptor; +import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader; import com.oracle.svm.core.genscavenge.remset.RememberedSet; import com.oracle.svm.core.heap.GC; import com.oracle.svm.core.heap.Heap; @@ -62,6 +65,7 @@ import com.oracle.svm.core.heap.ReferenceHandlerThreadSupport; import com.oracle.svm.core.heap.ReferenceInternals; import com.oracle.svm.core.heap.RuntimeCodeInfoGCSupport; +import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicReference; import com.oracle.svm.core.locks.VMCondition; import com.oracle.svm.core.locks.VMMutex; @@ -586,59 +590,59 @@ public Reference getAndClearReferencePendingList() { } @Override - public boolean printLocationInfo(Log log, UnsignedWord v) { - Pointer value = (Pointer) v; - if (imageHeapInfo.isInReadOnlyPrimitivePartition(value)) { - log.string("points into the image heap (read-only primitives)"); + public boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaHeapAccess) { + if (ImageSingletons.lookup(CompressEncoding.class).hasBase() && value.equal(KnownIntrinsics.heapBase())) { + log.string("is the heap base"); return true; } - if (imageHeapInfo.isInReadOnlyReferencePartition(value)) { - log.string("points into the image heap (read-only references)"); + Pointer ptr = (Pointer) value; + if (printLocationInfo(log, ptr)) { + if (allowJavaHeapAccess && ObjectHeaderImpl.pointsToObjectHeader(ptr)) { + DynamicHub hub = ObjectHeaderImpl.getObjectHeaderImpl().readDynamicHubFromPointer(ptr); + log.indent(true); + log.string("hub=").string(hub.getName()); + log.redent(false); + } return true; } + return false; + } - if (imageHeapInfo.isInReadOnlyRelocatablePartition(value)) { + private boolean printLocationInfo(Log log, Pointer ptr) { + if (imageHeapInfo.isInReadOnlyPrimitivePartition(ptr)) { + log.string("points into the image heap (read-only primitives)"); + return true; + } else if (imageHeapInfo.isInReadOnlyReferencePartition(ptr)) { + log.string("points into the image heap (read-only references)"); + return true; + } else if (imageHeapInfo.isInReadOnlyRelocatablePartition(ptr)) { log.string("points into the image heap (read-only relocatables)"); return true; - } - - if (imageHeapInfo.isInWritablePrimitivePartition(value)) { + } else if (imageHeapInfo.isInWritablePrimitivePartition(ptr)) { log.string("points into the image heap (writable primitives)"); return true; - } - - if (imageHeapInfo.isInWritableReferencePartition(value)) { + } else if (imageHeapInfo.isInWritableReferencePartition(ptr)) { log.string("points into the image heap (writable references)"); return true; - } - - if (imageHeapInfo.isInWritableHugePartition(value)) { + } else if (imageHeapInfo.isInWritableHugePartition(ptr)) { log.string("points into the image heap (writable huge)"); return true; - } - - if (imageHeapInfo.isInReadOnlyHugePartition(value)) { + } else if (imageHeapInfo.isInReadOnlyHugePartition(ptr)) { log.string("points into the image heap (read-only huge)"); return true; - } - - if (AuxiliaryImageHeap.isPresent() && AuxiliaryImageHeap.singleton().containsObject(value)) { + } else if (AuxiliaryImageHeap.isPresent() && AuxiliaryImageHeap.singleton().containsObject(ptr)) { log.string("points into the auxiliary image heap"); return true; - } - - if (isInYoungGen(value)) { + } else if (isInYoungGen(ptr)) { log.string("points into the young generation"); return true; - } - - if (isInOldGen(value)) { + } else if (isInOldGen(ptr)) { log.string("points into the old generation"); return true; + } else { + return printTlabInfo(log, ptr); } - - return false; } boolean isInHeap(Pointer ptr) { @@ -686,6 +690,45 @@ private static boolean findPointerInSpace(Space space, Pointer p) { return false; } + /** + * Accessing the TLAB of other threads is a highly unsafe operation and can cause crashes. So, + * this only makes sense for printing diagnostics as it is very likely that register values + * point to TLABs. + */ + private static boolean printTlabInfo(Log log, Pointer ptr) { + assert SubstrateDiagnostics.isInProgressByCurrentThread() : "can cause crashes, so it may only be used while printing diagnostics"; + for (IsolateThread thread = VMThreads.firstThreadUnsafe(); thread.isNonNull(); thread = VMThreads.nextThread(thread)) { + ThreadLocalAllocation.Descriptor tlab = getTlabUnsafe(thread); + AlignedHeader aChunk = tlab.getAlignedChunk(); + while (aChunk.isNonNull()) { + Pointer dataStart = AlignedHeapChunk.getObjectsStart(aChunk); + Pointer dataEnd = AlignedHeapChunk.getObjectsEnd(aChunk); + if (ptr.aboveOrEqual(dataStart) && ptr.belowThan(dataEnd)) { + log.string("points into an aligned TLAB chunk of thread ").zhex(thread); + return true; + } + aChunk = HeapChunk.getNext(aChunk); + } + + UnalignedHeader uChunk = tlab.getUnalignedChunk(); + while (uChunk.isNonNull()) { + Pointer dataStart = UnalignedHeapChunk.getObjectStart(uChunk); + Pointer dataEnd = UnalignedHeapChunk.getObjectEnd(uChunk); + if (ptr.aboveOrEqual(dataStart) && ptr.belowThan(dataEnd)) { + log.string("points into an unaligned TLAB chunk of thread ").zhex(thread); + return true; + } + } + } + return false; + } + + @Uninterruptible(reason = "This whole method is unsafe, so it is only uninterruptible to satisfy the checks.") + private static Descriptor getTlabUnsafe(IsolateThread thread) { + assert SubstrateDiagnostics.isInProgressByCurrentThread() : "can cause crashes, so it may only be used while printing diagnostics"; + return ThreadLocalAllocation.getTlab(thread); + } + private static class DumpHeapSettingsAndStatistics extends DiagnosticThunk { @Override public int maxInvocations() { @@ -703,6 +746,7 @@ public void printDiagnostics(Log log, int invocationCount) { log.string("Heap base: ").zhex(KnownIntrinsics.heapBase()).newline(); } log.string("Object reference size: ").signed(ConfigurationValues.getObjectLayout().getReferenceSize()).newline(); + log.string("Aligned chunk size: ").unsigned(HeapPolicy.getAlignedHeapChunkSize()).newline(); GCAccounting accounting = gc.getAccounting(); log.string("Incremental collections: ").unsigned(accounting.getIncrementalCollectionCount()).newline(); 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 22dcbca688c8..d9a0c1586a8f 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 @@ -194,7 +194,11 @@ public UnalignedHeader getFirstWritableUnalignedChunk() { return asImageHeapChunk(offsetOfFirstWritableUnalignedChunk); } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private static Word getObjectEnd(Object obj) { + if (obj == null) { + return WordFactory.nullPointer(); + } return Word.objectToUntrackedPointer(obj).add(LayoutEncoding.getSizeFromObject(obj)); } 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 5ed74754ac35..50aa8e0f710e 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 @@ -144,6 +144,27 @@ public DynamicHub dynamicHubFromObjectHeader(UnsignedWord header) { return (DynamicHub) objectValue; } + private static Pointer extractDynamicHubFromObjectHeader(UnsignedWord header) { + UnsignedWord pointerBits = clearBits(header); + if (ReferenceAccess.singleton().haveCompressedReferences()) { + UnsignedWord compressedBits = pointerBits.unsignedShiftRight(getCompressionShift()); + return KnownIntrinsics.heapBase().add(compressedBits.shiftLeft(getCompressionShift())); + } else { + return (Pointer) pointerBits; + } + } + + public static boolean pointsToObjectHeader(Pointer ptr) { + UnsignedWord potentialObjectHeader = ObjectHeaderImpl.readHeaderFromPointer(ptr); + Pointer potentialDynamicHub = ObjectHeaderImpl.extractDynamicHubFromObjectHeader(potentialObjectHeader); + if (Heap.getHeap().isInImageHeap(potentialDynamicHub)) { + UnsignedWord potentialHeaderOfDynamicHub = ObjectHeaderImpl.readHeaderFromPointer(potentialDynamicHub); + Pointer potentialHubOfDynamicHub = ObjectHeaderImpl.extractDynamicHubFromObjectHeader(potentialHeaderOfDynamicHub); + return potentialHubOfDynamicHub.equal(Word.objectToUntrackedPointer(DynamicHub.class)); + } + return false; + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public Word encodeAsUnmanagedObjectHeader(DynamicHub hub) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java index d51baef577c8..85bd719faedf 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java @@ -131,7 +131,7 @@ public static Word getTlabAddress() { } @Uninterruptible(reason = "Accesses TLAB", callerMustBe = true) - private static Descriptor getTlab(IsolateThread vmThread) { + public static Descriptor getTlab(IsolateThread vmThread) { return regularTLAB.getAddress(vmThread); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java index b7df6d07e0ee..3f6482b4cb5b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java @@ -41,6 +41,7 @@ import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader; import com.oracle.svm.core.genscavenge.remset.RememberedSet; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.util.UnsignedUtils; @@ -102,6 +103,10 @@ public static Pointer getObjectStart(UnalignedHeader that) { return HeapChunk.asPointer(that).add(getObjectStartOffset()); } + public static Pointer getObjectEnd(UnalignedHeader that) { + return HeapChunk.getEndPointer(that); + } + public static UnsignedWord getOverhead() { return getObjectStartOffset(); } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/UContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/UContextRegisterDumper.java index b2f03bc9fe90..7eee53fb5a20 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/UContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/UContextRegisterDumper.java @@ -32,7 +32,7 @@ import com.oracle.svm.core.posix.headers.Signal.ucontext_t; public interface UContextRegisterDumper extends RegisterDumper { - void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo); + void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo, boolean allowJavaHeapAccess); PointerBase getHeapBase(ucontext_t uContext); @@ -43,8 +43,8 @@ public interface UContextRegisterDumper extends RegisterDumper { PointerBase getIP(ucontext_t uContext); @Override - default void dumpRegisters(Log log, Context context, boolean printLocationInfo) { - dumpRegisters(log, (ucontext_t) context, printLocationInfo); + default void dumpRegisters(Log log, Context context, boolean printLocationInfo, boolean allowJavaHeapAccess) { + dumpRegisters(log, (ucontext_t) context, printLocationInfo, allowJavaHeapAccess); } @Override diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java index 0a97ead1766e..89ec977460e0 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java @@ -59,43 +59,43 @@ public void afterRegistration(AfterRegistrationAccess access) { class AArch64UContextRegisterDumper implements UContextRegisterDumper { @Override - public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo) { + public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo, boolean allowJavaHeapAccess) { mcontext_t sigcontext = uContext.uc_mcontext(); GregsPointer regs = sigcontext.regs(); - dumpReg(log, "R0 ", regs.read(0), printLocationInfo); - dumpReg(log, "R1 ", regs.read(1), printLocationInfo); - dumpReg(log, "R2 ", regs.read(2), printLocationInfo); - dumpReg(log, "R3 ", regs.read(3), printLocationInfo); - dumpReg(log, "R4 ", regs.read(4), printLocationInfo); - dumpReg(log, "R5 ", regs.read(5), printLocationInfo); - dumpReg(log, "R6 ", regs.read(6), printLocationInfo); - dumpReg(log, "R7 ", regs.read(7), printLocationInfo); - dumpReg(log, "R8 ", regs.read(8), printLocationInfo); - dumpReg(log, "R9 ", regs.read(9), printLocationInfo); - dumpReg(log, "R10 ", regs.read(10), printLocationInfo); - dumpReg(log, "R11 ", regs.read(11), printLocationInfo); - dumpReg(log, "R12 ", regs.read(12), printLocationInfo); - dumpReg(log, "R13 ", regs.read(13), printLocationInfo); - dumpReg(log, "R14 ", regs.read(14), printLocationInfo); - dumpReg(log, "R15 ", regs.read(15), printLocationInfo); - dumpReg(log, "R16 ", regs.read(16), printLocationInfo); - dumpReg(log, "R17 ", regs.read(17), printLocationInfo); - dumpReg(log, "R18 ", regs.read(18), printLocationInfo); - dumpReg(log, "R19 ", regs.read(19), printLocationInfo); - dumpReg(log, "R20 ", regs.read(20), printLocationInfo); - dumpReg(log, "R21 ", regs.read(21), printLocationInfo); - dumpReg(log, "R22 ", regs.read(22), printLocationInfo); - dumpReg(log, "R23 ", regs.read(23), printLocationInfo); - dumpReg(log, "R24 ", regs.read(24), printLocationInfo); - dumpReg(log, "R25 ", regs.read(25), printLocationInfo); - dumpReg(log, "R26 ", regs.read(26), printLocationInfo); - dumpReg(log, "R27 ", regs.read(27), printLocationInfo); - dumpReg(log, "R28 ", regs.read(28), printLocationInfo); - dumpReg(log, "R29 ", regs.read(29), printLocationInfo); - dumpReg(log, "R30 ", regs.read(30), printLocationInfo); - dumpReg(log, "R31 ", regs.read(31), printLocationInfo); - dumpReg(log, "SP ", sigcontext.sp(), printLocationInfo); - dumpReg(log, "PC ", sigcontext.pc(), printLocationInfo); + dumpReg(log, "R0 ", regs.read(0), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R1 ", regs.read(1), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R2 ", regs.read(2), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R3 ", regs.read(3), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R4 ", regs.read(4), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R5 ", regs.read(5), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R6 ", regs.read(6), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R7 ", regs.read(7), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R8 ", regs.read(8), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R9 ", regs.read(9), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R10 ", regs.read(10), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R11 ", regs.read(11), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R12 ", regs.read(12), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R13 ", regs.read(13), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R14 ", regs.read(14), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R15 ", regs.read(15), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R16 ", regs.read(16), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R17 ", regs.read(17), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R18 ", regs.read(18), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R19 ", regs.read(19), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R20 ", regs.read(20), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R21 ", regs.read(21), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R22 ", regs.read(22), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R23 ", regs.read(23), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R24 ", regs.read(24), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R25 ", regs.read(25), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R26 ", regs.read(26), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R27 ", regs.read(27), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R28 ", regs.read(28), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R29 ", regs.read(29), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R30 ", regs.read(30), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R31 ", regs.read(31), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "SP ", sigcontext.sp(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "PC ", sigcontext.pc(), printLocationInfo, allowJavaHeapAccess); } @Override diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java index 4ac8fdd7237d..f383405f72fb 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java @@ -59,26 +59,26 @@ public void afterRegistration(AfterRegistrationAccess access) { class AMD64UContextRegisterDumper implements UContextRegisterDumper { @Override - public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo) { + public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo, boolean allowJavaHeapAccess) { GregsPointer gregs = uContext.uc_mcontext_gregs(); - dumpReg(log, "RAX ", gregs.read(GregEnum.REG_RAX()), printLocationInfo); - dumpReg(log, "RBX ", gregs.read(GregEnum.REG_RBX()), printLocationInfo); - dumpReg(log, "RCX ", gregs.read(GregEnum.REG_RCX()), printLocationInfo); - dumpReg(log, "RDX ", gregs.read(GregEnum.REG_RDX()), printLocationInfo); - dumpReg(log, "RBP ", gregs.read(GregEnum.REG_RBP()), printLocationInfo); - dumpReg(log, "RSI ", gregs.read(GregEnum.REG_RSI()), printLocationInfo); - dumpReg(log, "RDI ", gregs.read(GregEnum.REG_RDI()), printLocationInfo); - dumpReg(log, "RSP ", gregs.read(GregEnum.REG_RSP()), printLocationInfo); - dumpReg(log, "R8 ", gregs.read(GregEnum.REG_R8()), printLocationInfo); - dumpReg(log, "R9 ", gregs.read(GregEnum.REG_R9()), printLocationInfo); - dumpReg(log, "R10 ", gregs.read(GregEnum.REG_R10()), printLocationInfo); - dumpReg(log, "R11 ", gregs.read(GregEnum.REG_R11()), printLocationInfo); - dumpReg(log, "R12 ", gregs.read(GregEnum.REG_R12()), printLocationInfo); - dumpReg(log, "R13 ", gregs.read(GregEnum.REG_R13()), printLocationInfo); - dumpReg(log, "R14 ", gregs.read(GregEnum.REG_R14()), printLocationInfo); - dumpReg(log, "R15 ", gregs.read(GregEnum.REG_R15()), printLocationInfo); - dumpReg(log, "EFL ", gregs.read(GregEnum.REG_EFL()), printLocationInfo); - dumpReg(log, "RIP ", gregs.read(GregEnum.REG_RIP()), printLocationInfo); + dumpReg(log, "RAX ", gregs.read(GregEnum.REG_RAX()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RBX ", gregs.read(GregEnum.REG_RBX()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RCX ", gregs.read(GregEnum.REG_RCX()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RDX ", gregs.read(GregEnum.REG_RDX()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RBP ", gregs.read(GregEnum.REG_RBP()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RSI ", gregs.read(GregEnum.REG_RSI()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RDI ", gregs.read(GregEnum.REG_RDI()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RSP ", gregs.read(GregEnum.REG_RSP()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R8 ", gregs.read(GregEnum.REG_R8()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R9 ", gregs.read(GregEnum.REG_R9()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R10 ", gregs.read(GregEnum.REG_R10()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R11 ", gregs.read(GregEnum.REG_R11()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R12 ", gregs.read(GregEnum.REG_R12()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R13 ", gregs.read(GregEnum.REG_R13()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R14 ", gregs.read(GregEnum.REG_R14()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R15 ", gregs.read(GregEnum.REG_R15()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "EFL ", gregs.read(GregEnum.REG_EFL()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RIP ", gregs.read(GregEnum.REG_RIP()), printLocationInfo, allowJavaHeapAccess); } @Override diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java index 27cb096d82cf..c56eb458e409 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java @@ -58,26 +58,26 @@ public void afterRegistration(AfterRegistrationAccess access) { class DarwinUContextRegisterDumper implements UContextRegisterDumper { @Override - public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo) { + public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo, boolean allowJavaHeapAccess) { Signal.MContext64 sigcontext = uContext.uc_mcontext64(); - dumpReg(log, "RAX ", ((Pointer) sigcontext).readLong(sigcontext.rax_offset()), printLocationInfo); - dumpReg(log, "RBX ", ((Pointer) sigcontext).readLong(sigcontext.rbx_offset()), printLocationInfo); - dumpReg(log, "RCX ", ((Pointer) sigcontext).readLong(sigcontext.rcx_offset()), printLocationInfo); - dumpReg(log, "RDX ", ((Pointer) sigcontext).readLong(sigcontext.rdx_offset()), printLocationInfo); - dumpReg(log, "RBP ", ((Pointer) sigcontext).readLong(sigcontext.rbp_offset()), printLocationInfo); - dumpReg(log, "RSI ", ((Pointer) sigcontext).readLong(sigcontext.rsi_offset()), printLocationInfo); - dumpReg(log, "RDI ", ((Pointer) sigcontext).readLong(sigcontext.rdi_offset()), printLocationInfo); - dumpReg(log, "RSP ", ((Pointer) sigcontext).readLong(sigcontext.rsp_offset()), printLocationInfo); - dumpReg(log, "R8 ", ((Pointer) sigcontext).readLong(sigcontext.r8_offset()), printLocationInfo); - dumpReg(log, "R9 ", ((Pointer) sigcontext).readLong(sigcontext.r9_offset()), printLocationInfo); - dumpReg(log, "R10 ", ((Pointer) sigcontext).readLong(sigcontext.r10_offset()), printLocationInfo); - dumpReg(log, "R11 ", ((Pointer) sigcontext).readLong(sigcontext.r11_offset()), printLocationInfo); - dumpReg(log, "R12 ", ((Pointer) sigcontext).readLong(sigcontext.r12_offset()), printLocationInfo); - dumpReg(log, "R13 ", ((Pointer) sigcontext).readLong(sigcontext.r13_offset()), printLocationInfo); - dumpReg(log, "R14 ", ((Pointer) sigcontext).readLong(sigcontext.r14_offset()), printLocationInfo); - dumpReg(log, "R15 ", ((Pointer) sigcontext).readLong(sigcontext.r15_offset()), printLocationInfo); - dumpReg(log, "EFL ", ((Pointer) sigcontext).readLong(sigcontext.efl_offset()), printLocationInfo); - dumpReg(log, "RIP ", ((Pointer) sigcontext).readLong(sigcontext.rip_offset()), printLocationInfo); + dumpReg(log, "RAX ", ((Pointer) sigcontext).readLong(sigcontext.rax_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RBX ", ((Pointer) sigcontext).readLong(sigcontext.rbx_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RCX ", ((Pointer) sigcontext).readLong(sigcontext.rcx_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RDX ", ((Pointer) sigcontext).readLong(sigcontext.rdx_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RBP ", ((Pointer) sigcontext).readLong(sigcontext.rbp_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RSI ", ((Pointer) sigcontext).readLong(sigcontext.rsi_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RDI ", ((Pointer) sigcontext).readLong(sigcontext.rdi_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RSP ", ((Pointer) sigcontext).readLong(sigcontext.rsp_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R8 ", ((Pointer) sigcontext).readLong(sigcontext.r8_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R9 ", ((Pointer) sigcontext).readLong(sigcontext.r9_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R10 ", ((Pointer) sigcontext).readLong(sigcontext.r10_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R11 ", ((Pointer) sigcontext).readLong(sigcontext.r11_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R12 ", ((Pointer) sigcontext).readLong(sigcontext.r12_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R13 ", ((Pointer) sigcontext).readLong(sigcontext.r13_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R14 ", ((Pointer) sigcontext).readLong(sigcontext.r14_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R15 ", ((Pointer) sigcontext).readLong(sigcontext.r15_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "EFL ", ((Pointer) sigcontext).readLong(sigcontext.efl_offset()), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RIP ", ((Pointer) sigcontext).readLong(sigcontext.rip_offset()), printLocationInfo, allowJavaHeapAccess); } @Override diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java index 9db9cd721c45..5df1ad2fa37f 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxStackOverflowSupport.java @@ -42,17 +42,15 @@ class LinuxStackOverflowSupport implements StackOverflowCheck.OSSupport { public UnsignedWord lookupStackBase() { Pthread.pthread_attr_t attr = StackValue.get(Pthread.pthread_attr_t.class); PosixUtils.checkStatusIs0(Pthread.pthread_getattr_np(Pthread.pthread_self(), attr), "LinuxStackOverflowSupport: pthread_getattr_np"); - UnsignedWord result = lookupStackStart(attr); - PosixUtils.checkStatusIs0(Pthread.pthread_attr_destroy(attr), "LinuxStackOverflowSupport: pthread_attr_destroy"); - return result; - } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - private static UnsignedWord lookupStackStart(Pthread.pthread_attr_t attr) { WordPointer stackaddrPtr = StackValue.get(WordPointer.class); WordPointer stacksizePtr = StackValue.get(WordPointer.class); PosixUtils.checkStatusIs0(Pthread.pthread_attr_getstack(attr, stackaddrPtr, stacksizePtr), "LinuxStackOverflowSupport: pthread_attr_getstack"); - return stackaddrPtr.read(); + PosixUtils.checkStatusIs0(Pthread.pthread_attr_destroy(attr), "LinuxStackOverflowSupport: pthread_attr_destroy"); + + UnsignedWord stackaddr = stackaddrPtr.read(); + UnsignedWord stacksize = stacksizePtr.read(); + return stackaddr.add(stacksize); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -61,7 +59,10 @@ public UnsignedWord lookupStackEnd() { Pthread.pthread_attr_t attr = StackValue.get(Pthread.pthread_attr_t.class); PosixUtils.checkStatusIs0(Pthread.pthread_getattr_np(Pthread.pthread_self(), attr), "LinuxStackOverflowSupport: pthread_getattr_np"); - UnsignedWord stackaddr = lookupStackStart(attr); + WordPointer stackaddrPtr = StackValue.get(WordPointer.class); + WordPointer stacksizePtr = StackValue.get(WordPointer.class); + PosixUtils.checkStatusIs0(Pthread.pthread_attr_getstack(attr, stackaddrPtr, stacksizePtr), "LinuxStackOverflowSupport: pthread_attr_getstack"); + UnsignedWord stackaddr = stackaddrPtr.read(); /* * The block of memory returned by pthread_attr_getstack() includes guard pages where diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java index 845f7800aeb2..cc24e53bf67d 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java @@ -53,29 +53,29 @@ public void afterRegistration(AfterRegistrationAccess access) { public class WindowsRegisterDumper implements RegisterDumper { @Override - public void dumpRegisters(Log log, Context context, boolean printLocationInfo) { - dumpRegisters(log, (CONTEXT) context, printLocationInfo); + public void dumpRegisters(Log log, Context context, boolean printLocationInfo, boolean allowJavaHeapAccess) { + dumpRegisters(log, (CONTEXT) context, printLocationInfo, allowJavaHeapAccess); } - private static void dumpRegisters(Log log, CONTEXT context, boolean printLocationInfo) { - dumpReg(log, "RAX ", context.Rax(), printLocationInfo); - dumpReg(log, "RBX ", context.Rbx(), printLocationInfo); - dumpReg(log, "RCX ", context.Rcx(), printLocationInfo); - dumpReg(log, "RDX ", context.Rdx(), printLocationInfo); - dumpReg(log, "RBP ", context.Rbp(), printLocationInfo); - dumpReg(log, "RSI ", context.Rsi(), printLocationInfo); - dumpReg(log, "RDI ", context.Rdi(), printLocationInfo); - dumpReg(log, "RSP ", context.Rsp(), printLocationInfo); - dumpReg(log, "R8 ", context.R8(), printLocationInfo); - dumpReg(log, "R9 ", context.R9(), printLocationInfo); - dumpReg(log, "R10 ", context.R10(), printLocationInfo); - dumpReg(log, "R11 ", context.R11(), printLocationInfo); - dumpReg(log, "R12 ", context.R12(), printLocationInfo); - dumpReg(log, "R13 ", context.R13(), printLocationInfo); - dumpReg(log, "R14 ", context.R14(), printLocationInfo); - dumpReg(log, "R15 ", context.R15(), printLocationInfo); - dumpReg(log, "EFL ", context.EFlags(), printLocationInfo); - dumpReg(log, "RIP ", context.Rip(), printLocationInfo); + private static void dumpRegisters(Log log, CONTEXT context, boolean printLocationInfo, boolean allowJavaHeapAccess) { + dumpReg(log, "RAX ", context.Rax(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RBX ", context.Rbx(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RCX ", context.Rcx(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RDX ", context.Rdx(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RBP ", context.Rbp(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RSI ", context.Rsi(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RDI ", context.Rdi(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RSP ", context.Rsp(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R8 ", context.R8(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R9 ", context.R9(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R10 ", context.R10(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R11 ", context.R11(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R12 ", context.R12(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R13 ", context.R13(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R14 ", context.R14(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "R15 ", context.R15(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "EFL ", context.EFlags(), printLocationInfo, allowJavaHeapAccess); + dumpReg(log, "RIP ", context.Rip(), printLocationInfo, allowJavaHeapAccess); } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RegisterDumper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RegisterDumper.java index cebd2cfa1eef..053ab9692857 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RegisterDumper.java @@ -41,11 +41,11 @@ static RegisterDumper singleton() { return ImageSingletons.lookup(RegisterDumper.class); } - static void dumpReg(Log log, String label, long value, boolean printLocationInfo) { + static void dumpReg(Log log, String label, long value, boolean printLocationInfo, boolean allowJavaHeapAccess) { log.string(label).zhex(value); if (printLocationInfo) { log.spaces(1); - SubstrateDiagnostics.printLocationInfo(log, WordFactory.unsigned(value)); + SubstrateDiagnostics.printLocationInfo(log, WordFactory.unsigned(value), allowJavaHeapAccess); } log.newline(); } @@ -53,7 +53,7 @@ static void dumpReg(Log log, String label, long value, boolean printLocationInfo interface Context extends PointerBase { } - void dumpRegisters(Log log, Context context, boolean printLocationInfo); + void dumpRegisters(Log log, Context context, boolean printLocationInfo, boolean allowJavaHeapAccess); PointerBase getHeapBase(Context context); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 27684f32db26..b00f80961f3e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -91,6 +91,7 @@ public static boolean isInProgress() { return state.diagnosticThread.get().isNonNull(); } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static boolean isInProgressByCurrentThread() { return state.diagnosticThread.get() == CurrentIsolate.getCurrentThread(); } @@ -111,8 +112,9 @@ public static int maxInvocations() { return result; } - public static void printLocationInfo(Log log, UnsignedWord value) { - if (value.notEqual(0) && !RuntimeCodeInfoMemory.singleton().printLocationInfo(log, value) && !VMThreads.printLocationInfo(log, value) && !Heap.getHeap().printLocationInfo(log, value)) { + public static void printLocationInfo(Log log, UnsignedWord value, boolean allowJavaHeapAccess) { + if (value.notEqual(0) && !RuntimeCodeInfoMemory.singleton().printLocationInfo(log, value, allowJavaHeapAccess) && !VMThreads.printLocationInfo(log, value, allowJavaHeapAccess) && + !Heap.getHeap().printLocationInfo(log, value, allowJavaHeapAccess)) { log.string("is an unknown value"); } } @@ -284,7 +286,7 @@ public void clear() { private static class DumpRegisters extends DiagnosticThunk { @Override public int maxInvocations() { - return 2; + return 3; } @Override @@ -293,7 +295,7 @@ public void printDiagnostics(Log log, int invocationCount) { RegisterDumper.Context context = state.context; if (context.isNonNull()) { log.string("General purpose register values:").indent(true); - RegisterDumper.singleton().dumpRegisters(log, context, invocationCount == 1); + RegisterDumper.singleton().dumpRegisters(log, context, invocationCount <= 2, invocationCount == 1); log.indent(false); } } @@ -644,9 +646,9 @@ private static void printStacktrace(Log log, IsolateThread vmThread) { public abstract static class DiagnosticThunk { /** * Prints diagnostic information. This method may be invoked multiple times if an error - * (e.g., exception or segfault) occurred while executing this method. A typical - * implementation will therefore execute different code depending on the invocation count. - * When the method is invoked for the first time, the invocation count is 1. + * (e.g., exception or segfault) occurred during execution. However, the method will only be + * invoked at most {@link #maxInvocations()} times. When the method is invoked for the first + * time, the argument invocationCount is 1. */ @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") public abstract void printDiagnostics(Log log, int invocationCount); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java index b83c1ccb6ac1..7512e34f78a4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java @@ -26,6 +26,7 @@ import java.util.EnumSet; +import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.UnmanagedMemory; import org.graalvm.nativeimage.c.function.CodePointer; @@ -201,6 +202,7 @@ public static CodeInfo allocateMethodInfo(NonmovableObjectArray objectDa return info; } + @Fold public static UnsignedWord getSizeOfCodeInfo() { return SizeOf.unsigned(CodeInfoImpl.class); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java index 86e316aa7a5f..f487f7502a1c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java @@ -308,31 +308,60 @@ public void tearDown() { } } - public boolean printLocationInfo(Log log, UnsignedWord value) { + @Uninterruptible(reason = "Must prevent the GC from freeing the CodeInfo object.") + public boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaHeapAccess) { assert SubstrateDiagnostics.isInProgressByCurrentThread() : "may only be used for printing diagnostics as the table could be freed at any time"; if (table.isNonNull()) { for (int i = 0; i < NonmovableArrays.lengthOf(table); i++) { - // TEMP (chaeubl): print the name of the code info object if javaAccess is allowed UntetheredCodeInfo info = NonmovableArrays.getWord(table, i); - if (info.equal(value)) { - log.string("is a CodeInfo object"); - return true; - } + if (info.isNonNull()) { + if (info.equal(value)) { + String name = allowJavaHeapAccess ? UntetheredCodeInfoAccess.getName(info) : null; + printIsCodeInfoObject(log, name); + return true; + } - UnsignedWord codeInfoEnd = ((UnsignedWord) info).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()); - if (value.aboveOrEqual(value) && value.belowThan(codeInfoEnd)) { - log.string("points within a CodeInfo object"); - return true; - } + UnsignedWord codeInfoEnd = ((UnsignedWord) info).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()); + if (value.aboveOrEqual((UnsignedWord) info) && value.belowThan(codeInfoEnd)) { + String name = allowJavaHeapAccess ? UntetheredCodeInfoAccess.getName(info) : null; + printInsideCodeInfo(log, info, name); + return true; + } - UnsignedWord codeStart = (UnsignedWord) UntetheredCodeInfoAccess.getCodeStart(info); - UnsignedWord codeEnd = (UnsignedWord) UntetheredCodeInfoAccess.getCodeEnd(info); - if (value.aboveOrEqual(codeStart) && value.belowOrEqual(codeEnd)) { - log.string("is at codeStart+").unsigned(value.subtract(codeStart)).string(" in CodeInfo ").zhex(info); - return true; + UnsignedWord codeStart = (UnsignedWord) UntetheredCodeInfoAccess.getCodeStart(info); + UnsignedWord codeEnd = (UnsignedWord) UntetheredCodeInfoAccess.getCodeEnd(info); + if (value.aboveOrEqual(codeStart) && value.belowOrEqual(codeEnd)) { + String name = allowJavaHeapAccess ? UntetheredCodeInfoAccess.getName(info) : null; + printInsideInstructions(log, value, info, codeStart, name); + return true; + } } } } return false; } + + @Uninterruptible(reason = "CodeInfo no longer needs to be protected from the GC.", calleeMustBe = false) + private static void printIsCodeInfoObject(Log log, String name) { + log.string("is a CodeInfo object"); + if (name != null) { + log.string(" (").string(name).string(")"); + } + } + + @Uninterruptible(reason = "CodeInfo no longer needs to be protected from the GC.", calleeMustBe = false) + private static void printInsideCodeInfo(Log log, UntetheredCodeInfo info, String name) { + log.string("points inside the CodeInfo object ").zhex(info); + if (name != null) { + log.string(" (").string(name).string(")"); + } + } + + @Uninterruptible(reason = "CodeInfo no longer needs to be protected from the GC.", calleeMustBe = false) + private static void printInsideInstructions(Log log, UnsignedWord value, UntetheredCodeInfo info, UnsignedWord codeStart, String name) { + log.string("is at codeStart+").unsigned(value.subtract(codeStart)).string(" of CodeInfo ").zhex(info); + if (name != null) { + log.string(" (").string(name).string(")"); + } + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 609ee2f8e0fd..e5b1a07d78cc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -197,5 +197,5 @@ public List> getLoadedClasses() { * If the passed value is within the Java heap, this method prints some information about that * value and returns true. Otherwise, the method returns false. */ - public abstract boolean printLocationInfo(Log log, UnsignedWord value); + public abstract boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaHeapAccess); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java index 3e64f2965d4a..978e668a922a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java @@ -203,6 +203,7 @@ public static UnsignedWord getArraySize(int encoding, int length) { return getArrayElementOffset(encoding, length).add(alignmentMask).and(~alignmentMask); } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static UnsignedWord getSizeFromObject(Object obj) { int encoding = KnownIntrinsics.readHub(obj).getLayoutEncoding(); if (isArray(encoding)) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java index d90055728da9..de67f2d2fa56 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java @@ -450,6 +450,7 @@ public Log zhex(WordBase value) { @NeverInline("Logging is always slow-path code") @Override public Log zhex(long value) { + string("0x"); int zeros = Long.numberOfLeadingZeros(value); int hexZeros = zeros / 4; for (int i = 0; i < hexZeros; i += 1) { @@ -462,6 +463,7 @@ public Log zhex(long value) { } private Log zhex(int value, int wordSizeInBytes) { + string("0x"); int zeros = Integer.numberOfLeadingZeros(value) - 32 + (wordSizeInBytes * 8); int hexZeros = zeros / 4; for (int i = 0; i < hexZeros; i += 1) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index d8ed212f3227..fbdb3de98251 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -30,7 +30,6 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.replacements.ReplacementsUtil; import org.graalvm.compiler.replacements.nodes.AssertionNode; -import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; @@ -45,7 +44,6 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.thread; import com.oracle.svm.core.annotate.NeverInline; import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.Uninterruptible; @@ -64,7 +62,6 @@ import com.oracle.svm.core.threadlocal.VMThreadLocalMTSupport; import com.oracle.svm.core.util.UnsignedUtils; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.thread.VMThreadMTFeature; /** * Utility methods for the manipulation and iteration of {@link IsolateThread}s. @@ -576,7 +573,7 @@ public static boolean ownsThreadMutex() { return THREAD_MUTEX.isOwner(); } - public static boolean printLocationInfo(Log log, UnsignedWord value) { + public static boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaHeapAccess) { for (IsolateThread thread = firstThreadUnsafe(); thread.isNonNull(); thread = nextThread(thread)) { if (thread.equal(value)) { log.string("is a thread"); From bbbf297ceb99ea8f33c0cf6f28602fda04860d60 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 6 Jul 2021 16:05:34 +0200 Subject: [PATCH 20/28] Style fixes. --- .../src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java | 1 - .../src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java | 1 - 2 files changed, 2 deletions(-) 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 16d4900d3e35..1533fb4404a8 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 @@ -37,7 +37,6 @@ import com.oracle.svm.core.annotate.AlwaysInline; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.hub.LayoutEncoding; -import com.oracle.svm.core.log.Log; import com.oracle.svm.core.os.CommittedMemoryProvider; import com.oracle.svm.core.util.UnsignedUtils; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java index 3f6482b4cb5b..1d6b7ec92734 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java @@ -41,7 +41,6 @@ import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader; import com.oracle.svm.core.genscavenge.remset.RememberedSet; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.util.UnsignedUtils; From d15cbf5bb0a1334db9fbbad6cafba70bca734e8e Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 7 Jul 2021 11:27:39 +0200 Subject: [PATCH 21/28] Further fixes. --- .../src/com/oracle/svm/core/code/RuntimeCodeCache.java | 1 + .../oracle/svm/core/code/RuntimeCodeInfoAccess.java | 1 - .../oracle/svm/core/code/RuntimeCodeInfoMemory.java | 4 ++-- .../src/com/oracle/svm/core/heap/Heap.java | 2 +- .../src/com/oracle/svm/core/locks/VMLockSupport.java | 10 +++++++--- .../src/com/oracle/svm/core/locks/VMMutex.java | 2 +- .../src/com/oracle/svm/core/log/RealLog.java | 2 +- .../com/oracle/svm/core/thread/VMOperationControl.java | 10 +++++----- .../api/SubstrateOptimizedCallTargetInstalledCode.java | 2 +- 9 files changed, 19 insertions(+), 15 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java index 1fc22ad816b5..703a1c402bb1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java @@ -238,6 +238,7 @@ private void finishInvalidation(CodeInfo info, boolean notifyGC) { NonmovableArrays.setWord(codeInfos, numCodeInfos, WordFactory.nullPointer()); RuntimeCodeInfoAccess.partialReleaseAfterInvalidate(info, notifyGC); + RuntimeCodeInfoHistory.singleton().logInvalidate(info); assert verifyTable(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java index 7512e34f78a4..bc6322ac101e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java @@ -210,7 +210,6 @@ public static UnsignedWord getSizeOfCodeInfo() { static void partialReleaseAfterInvalidate(CodeInfo info, boolean notifyGC) { InstalledCodeObserverSupport.removeObservers(RuntimeCodeInfoAccess.getCodeObserverHandles(info)); releaseMemory(info, notifyGC); - RuntimeCodeInfoHistory.singleton().logInvalidate(info); } @Uninterruptible(reason = "Prevent the GC from running - otherwise, it could accidentally visit the freed memory.") diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java index f487f7502a1c..00db3b6b3a49 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java @@ -272,7 +272,7 @@ private void printCodeInfo(Log log, int i, boolean allowJavaHeapAccess) { UntetheredCodeInfo info = NonmovableArrays.getWord(table, i); if (info.isNonNull()) { /* - * Newly created CodeInfo objects do ont have a tether yet. So, we can't use tethering + * Newly created CodeInfo objects do not have a tether yet. So, we can't use tethering * to keep the CodeInfo object alive. Instead, we read all relevant values in * uninterruptible code and pass those values to interruptible code that does the * printing. @@ -282,7 +282,7 @@ private void printCodeInfo(Log log, int i, boolean allowJavaHeapAccess) { } } - @Uninterruptible(reason = "Pass the now protected CodeInfo to interruptible code.", calleeMustBe = false) + @Uninterruptible(reason = "CodeInfo no longer needs to be protected from the GC.", calleeMustBe = false) private static void printCodeInfo0(Log log, UntetheredCodeInfo codeInfo, int state, String name, CodePointer codeStart, CodePointer codeEnd) { RuntimeCodeInfoHistory.printCodeInfo(log, codeInfo, state, name, codeStart, codeEnd); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index e5b1a07d78cc..786db141b896 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -170,7 +170,7 @@ public List> getLoadedClasses() { /** * Returns true if the object at the given address is located in the image heap. This method - * only works reliably for pointers to the start of an object. + * only works reliably for pointers that point to the start of an object. */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public abstract boolean isInImageHeap(Pointer objectPtr); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java index 95f5f2bac2d9..75db14f91c6b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java @@ -51,11 +51,15 @@ public int maxInvocations() { public void printDiagnostics(Log log, int invocationCount) { log.string("VM mutexes:").indent(true); - VMLockSupport support = ImageSingletons.lookup(VMLockSupport.class); - VMMutex[] mutexes = support.getMutexes(); - if (mutexes == null) { + VMLockSupport support = null; + if (ImageSingletons.contains(VMLockSupport.class)) { + support = ImageSingletons.lookup(VMLockSupport.class); + } + + if (support == null || support.getMutexes() == null) { log.string("No mutex information is available."); } else { + VMMutex[] mutexes = support.getMutexes(); for (int i = 0; i < mutexes.length; i++) { VMMutex mutex = mutexes[i]; IsolateThread owner = mutex.owner; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMMutex.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMMutex.java index fc3dbea34951..5a4789859ccb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMMutex.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMMutex.java @@ -57,7 +57,7 @@ public class VMMutex { @Platforms(Platform.HOSTED_ONLY.class) public VMMutex() { - this.name = "Unspecified"; + this.name = "unspecified"; } @Platforms(Platform.HOSTED_ONLY.class) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java index de67f2d2fa56..7a2dc7bd3b8c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java @@ -520,7 +520,7 @@ public Log hexdump(PointerBase from, int wordSize, int numWords) { zhex(base.readLong(offset)); break; } - if ((offset + sanitizedWordsize) % 16 == 0) { + if ((offset + sanitizedWordsize) % 16 == 0 && (offset + sanitizedWordsize) < sanitizedWordsize * numWords) { newline(); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java index 10ecf77d00f1..96a7395b7d6b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java @@ -203,14 +203,14 @@ public static void printCurrentVMOperation(Log log, boolean allowJavaHeapAccess) if (op == null) { log.string("No VMOperation in progress").newline(); } else if (allowJavaHeapAccess) { - log.string("VMOperation in progress: ").string(op.getName()).newline(); - log.string(" safepoint: ").bool(op.getCausesSafepoint()).newline(); - log.string(" queuingThread: ").zhex(control.inProgress.queueingThread.rawValue()).newline(); - log.string(" executingThread: ").zhex(control.inProgress.executingThread.rawValue()).newline(); + log.string("VMOperation in progress: ").string(op.getName()).indent(true); + log.string("Safepoint: ").bool(op.getCausesSafepoint()).newline(); + log.string("QueuingThread: ").zhex(control.inProgress.queueingThread.rawValue()).newline(); + log.string("ExecutingThread: ").zhex(control.inProgress.executingThread.rawValue()).newline(); + log.indent(false); } else { log.string("VMOperation in progress: ").zhex(Word.objectToUntrackedPointer(op)).newline(); } - log.newline(); } public static void printRecentEvents(Log log, boolean allowJavaHeapAccess) { diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java index 893de71f06c1..f5ef0afbbe1c 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java @@ -154,7 +154,7 @@ private void invalidateWithoutDeoptimization0() { } } - @Uninterruptible(reason = "Now that the CodeInfo is tether, we can call interruptible code.", calleeMustBe = false) + @Uninterruptible(reason = "Call interruptible code now that the CodeInfo is tethered.", calleeMustBe = false) private static void invalidateWithoutDeoptimization1(CodeInfo codeInfo) { CodeInfoAccess.setState(codeInfo, CodeInfo.STATE_NON_ENTRANT); RuntimeCodeInfoHistory.singleton().logMakeNonEntrant(codeInfo); From da1e6d7aa0d77df7afabba5a37440f012dc38585 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 9 Jul 2021 14:49:23 +0200 Subject: [PATCH 22/28] Various changes and refactorings. --- .../oracle/svm/core/genscavenge/HeapImpl.java | 4 ++-- .../core/genscavenge/ObjectHeaderImpl.java | 17 ++++------------ .../oracle/svm/core/SubstrateDiagnostics.java | 20 ++++++++----------- .../svm/core/SubstrateSegfaultHandler.java | 4 +--- .../svm/core/code/RuntimeCodeInfoHistory.java | 2 +- .../oracle/svm/core/heap/ObjectHeader.java | 12 +++++++++++ .../svm/core/thread/VMOperationControl.java | 2 +- .../com/oracle/svm/core/thread/VMThreads.java | 4 ++-- 8 files changed, 31 insertions(+), 34 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 a12b4c5b4f8d..c3d67cd27667 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 @@ -598,8 +598,8 @@ public boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaH Pointer ptr = (Pointer) value; if (printLocationInfo(log, ptr)) { - if (allowJavaHeapAccess && ObjectHeaderImpl.pointsToObjectHeader(ptr)) { - DynamicHub hub = ObjectHeaderImpl.getObjectHeaderImpl().readDynamicHubFromPointer(ptr); + if (allowJavaHeapAccess && objectHeaderImpl.pointsToObjectHeader(ptr)) { + DynamicHub hub = objectHeaderImpl.readDynamicHubFromPointer(ptr); log.indent(true); log.string("hub=").string(hub.getName()); log.redent(false); 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 50aa8e0f710e..41d4dcbd8e9a 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 @@ -144,8 +144,10 @@ public DynamicHub dynamicHubFromObjectHeader(UnsignedWord header) { return (DynamicHub) objectValue; } - private static Pointer extractDynamicHubFromObjectHeader(UnsignedWord header) { - UnsignedWord pointerBits = clearBits(header); + @Override + public Pointer readPotentialDynamicHubFromPointer(Pointer ptr) { + UnsignedWord potentialHeader = ObjectHeaderImpl.readHeaderFromPointer(ptr); + UnsignedWord pointerBits = clearBits(potentialHeader); if (ReferenceAccess.singleton().haveCompressedReferences()) { UnsignedWord compressedBits = pointerBits.unsignedShiftRight(getCompressionShift()); return KnownIntrinsics.heapBase().add(compressedBits.shiftLeft(getCompressionShift())); @@ -154,17 +156,6 @@ private static Pointer extractDynamicHubFromObjectHeader(UnsignedWord header) { } } - public static boolean pointsToObjectHeader(Pointer ptr) { - UnsignedWord potentialObjectHeader = ObjectHeaderImpl.readHeaderFromPointer(ptr); - Pointer potentialDynamicHub = ObjectHeaderImpl.extractDynamicHubFromObjectHeader(potentialObjectHeader); - if (Heap.getHeap().isInImageHeap(potentialDynamicHub)) { - UnsignedWord potentialHeaderOfDynamicHub = ObjectHeaderImpl.readHeaderFromPointer(potentialDynamicHub); - Pointer potentialHubOfDynamicHub = ObjectHeaderImpl.extractDynamicHubFromObjectHeader(potentialHeaderOfDynamicHub); - return potentialHubOfDynamicHub.equal(Word.objectToUntrackedPointer(DynamicHub.class)); - } - return false; - } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public Word encodeAsUnmanagedObjectHeader(DynamicHub hub) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index b00f80961f3e..2c1b308b4267 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -28,6 +28,7 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.NumUtil; +import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; @@ -96,14 +97,7 @@ public static boolean isInProgressByCurrentThread() { return state.diagnosticThread.get() == CurrentIsolate.getCurrentThread(); } - /** - * The segfault handler will invoke {@link #print} recursively if a fatal error happens while - * printing diagnostics. The value returned by this method can be used to limit the maximum - * recursion depth if necessary. - */ - @Fold public static int maxInvocations() { - // TEMP (chaeubl): test that this works int result = 0; DiagnosticThunkRegister thunks = DiagnosticThunkRegister.getSingleton(); for (int i = 0; i < thunks.size(); i++) { @@ -161,7 +155,8 @@ private static void printDiagnosticsForCurrentState() { try { thunk.printDiagnostics(log, state.invocationCount); // TEMP (chaeubl): check the max retries - throw new AssertionError(); + log.signed(GraalUnsafeAccess.getUnsafe().getInt(27L)); + continue; } catch (Throwable e) { dumpException(log, thunk, e); } @@ -171,7 +166,7 @@ private static void printDiagnosticsForCurrentState() { state.invocationCount = 0; } - // Reset the state. + // Reset the state so that another thread can print diagnostics. state.clear(); } @@ -331,7 +326,7 @@ private static void printWord(Log log) { private static void hexDump(Log log, CodePointer ip, int bytesBefore, int bytesAfter) { log.string("Printing Instructions (ip=").zhex(ip).string("):").indent(true); log.hexdump(((Pointer) ip).subtract(bytesBefore), 1, bytesBefore + bytesAfter); - log.indent(false); + log.indent(false).newline(); } } @@ -363,7 +358,7 @@ public void printDiagnostics(Log log, int invocationCount) { log.hexdump(sp, 8, bytesToPrint / 8); } - log.indent(false); + log.indent(false).newline(); } } @@ -496,6 +491,7 @@ public int maxInvocations() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { VMOperationControl.printCurrentVMOperation(log, invocationCount == 1); + log.newline(); } } @@ -639,7 +635,7 @@ public void printDiagnostics(Log log, int invocationCount) { private static void printStacktrace(Log log, IsolateThread vmThread) { log.string("Full stacktrace:").indent(true); JavaStackWalker.walkThread(vmThread, StackFramePrintVisitor.SINGLETON, log); - log.indent(false); + log.redent(false); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java index c97c9069d4bb..033b01998a40 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java @@ -147,8 +147,7 @@ protected static void dump(PointerBase signalInfo, RegisterDumper.Context contex private static void dumpInterruptibly(PointerBase signalInfo, RegisterDumper.Context context) { PointerBase callerIP = RegisterDumper.singleton().getIP(context); LogHandler logHandler = ImageSingletons.lookup(LogHandler.class); - String msg = "[ [ SubstrateSegfaultHandler caught a segfault. ] ]"; - Log log = Log.enterFatalContext(logHandler, (CodePointer) callerIP, msg, null); + Log log = Log.enterFatalContext(logHandler, (CodePointer) callerIP, "[ [ SubstrateSegfaultHandler caught a segfault. ] ]", null); if (log != null) { log.newline(); log.string("[ [ SubstrateSegfaultHandler caught a segfault in thread ").zhex(CurrentIsolate.getCurrentThread()).string(" ] ]").newline(); @@ -156,7 +155,6 @@ private static void dumpInterruptibly(PointerBase signalInfo, RegisterDumper.Con PointerBase sp = RegisterDumper.singleton().getSP(context); PointerBase ip = RegisterDumper.singleton().getIP(context); - SubstrateDiagnostics.print(log, (Pointer) sp, (CodePointer) ip, context); boolean printedDiagnostics = SubstrateDiagnostics.print(log, (Pointer) sp, (CodePointer) ip, context); if (printedDiagnostics) { log.string("Segfault detected, aborting process. Use runtime option -R:-InstallSegfaultHandler if you don't want to use SubstrateSegfaultHandler.").newline(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java index f9940210fc44..4e433d678dcc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java @@ -108,7 +108,7 @@ static void printCodeInfo(Log log, UntetheredCodeInfo codeInfo, int state, Strin } public void printRecentOperations(Log log, boolean allowJavaHeapAccess) { - log.string("Recent RuntimeCodeInfo operations (oldest first): ").indent(true); + log.string("The ").signed(recentOperations.size()).string(" most recent RuntimeCodeInfo operations (oldest first): ").indent(true); recentOperations.foreach(log, allowJavaHeapAccess ? PRINT_WITH_JAVA_HEAP_DATA : PRINT_WITHOUT_JAVA_HEAP_DATA); log.indent(false); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java index 56cb5a73cc3c..56c5aaf511d8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java @@ -70,6 +70,18 @@ public static DynamicHub readDynamicHubFromObject(Object o) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public abstract DynamicHub readDynamicHubFromPointer(Pointer ptr); + public abstract Pointer readPotentialDynamicHubFromPointer(Pointer ptr); + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public abstract void initializeHeaderOfNewObject(Pointer objectPointer, Word objectHeader); + + public boolean pointsToObjectHeader(Pointer ptr) { + Pointer potentialDynamicHub = readPotentialDynamicHubFromPointer(ptr); + if (Heap.getHeap().isInImageHeap(potentialDynamicHub)) { + Pointer potentialHubOfDynamicHub = readPotentialDynamicHubFromPointer(potentialDynamicHub); + return potentialHubOfDynamicHub.equal(Word.objectToUntrackedPointer(DynamicHub.class)); + } + return false; + } + } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java index 96a7395b7d6b..c5e77c20eab2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java @@ -207,7 +207,7 @@ public static void printCurrentVMOperation(Log log, boolean allowJavaHeapAccess) log.string("Safepoint: ").bool(op.getCausesSafepoint()).newline(); log.string("QueuingThread: ").zhex(control.inProgress.queueingThread.rawValue()).newline(); log.string("ExecutingThread: ").zhex(control.inProgress.executingThread.rawValue()).newline(); - log.indent(false); + log.redent(false); } else { log.string("VMOperation in progress: ").zhex(Word.objectToUntrackedPointer(op)).newline(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index fbdb3de98251..5043ceb337f8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -583,7 +583,7 @@ public static boolean printLocationInfo(Log log, UnsignedWord value, boolean all UnsignedWord stackBase = StackBase.get(thread); UnsignedWord stackEnd = StackEnd.get(thread); if (value.belowOrEqual(stackBase) && value.aboveOrEqual(stackEnd)) { - log.string("is pointing into the stack for thread ").zhex(thread); + log.string("points into the stack for thread ").zhex(thread); return true; } @@ -591,7 +591,7 @@ public static boolean printLocationInfo(Log log, UnsignedWord value, boolean all int sizeOfThreadLocals = ImageSingletons.lookup(VMThreadLocalMTSupport.class).vmThreadSize; UnsignedWord endOfThreadLocals = ((UnsignedWord) thread).add(sizeOfThreadLocals); if (value.aboveOrEqual((UnsignedWord) thread) && value.belowThan(endOfThreadLocals)) { - log.string("is pointing into the thread locals for thread ").zhex(thread); + log.string("points into the thread locals for thread ").zhex(thread); return true; } } From 99f9a3473169b311e9d0a3f6a70fdb0712b3bace Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 9 Jul 2021 15:35:25 +0200 Subject: [PATCH 23/28] Enable stack overflow checks on all platforms. --- .../snippets/StackOverflowCheckImpl.java | 43 +------------------ 1 file changed, 2 insertions(+), 41 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java index b1a6bb369cd8..70d5ec483e42 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java @@ -30,7 +30,6 @@ import java.util.Map; import java.util.function.Predicate; -import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; @@ -48,6 +47,7 @@ import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.UnreachableNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; @@ -74,7 +74,6 @@ import com.oracle.svm.core.graal.GraalFeature; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; -import org.graalvm.compiler.nodes.UnreachableNode; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.RestrictHeapAccessCallees; import com.oracle.svm.core.meta.SharedMethod; @@ -108,22 +107,9 @@ final class StackOverflowCheckImpl implements StackOverflowCheck { static final int STATE_UNINITIALIZED = 0; static final int STATE_YELLOW_ENABLED = 1; - /* - * Until all of our supported platforms provide the OSSupport, stack overflow checks are not - * mandatory. Eventually this check will go away, see GR-13274. - */ - @Fold - static boolean supportedByOS() { - return ImageSingletons.contains(StackOverflowCheck.OSSupport.class); - } - @Uninterruptible(reason = "Called while thread is being attached to the VM, i.e., when the thread state is not yet set up.") @Override public void initialize(IsolateThread thread) { - if (!supportedByOS()) { - return; - } - /* * Get the real physical end of the stack. Everything past this point is memory-protected. */ @@ -131,9 +117,7 @@ public void initialize(IsolateThread thread) { UnsignedWord stackBase = osSupport.lookupStackBase(); UnsignedWord stackEnd = osSupport.lookupStackEnd(); - // TEMP (chaeubl): this should be moved somewhere else... - also OSSupport should be named - // differently. - // Initialize the stack base and the stack end. + /* Initialize the stack base and the stack end thread locals. */ VMThreads.StackBase.set(thread, stackBase); VMThreads.StackEnd.set(thread, stackEnd); @@ -155,10 +139,6 @@ public void makeYellowZoneAvailable() { */ ThreadingSupportImpl.pauseRecurringCallback("Recurring callbacks are considered user code and must not run in yellow zone"); - if (!supportedByOS()) { - return; - } - int state = yellowZoneStateTL.get(); VMError.guarantee(state >= STATE_YELLOW_ENABLED, "StackOverflowSupport.disableYellowZone: Illegal state"); @@ -191,10 +171,6 @@ public boolean isYellowZoneAvailable() { public void protectYellowZone() { ThreadingSupportImpl.resumeRecurringCallbackAtNextSafepoint(); - if (!supportedByOS()) { - return; - } - int state = yellowZoneStateTL.get(); VMError.guarantee(state > STATE_YELLOW_ENABLED, "StackOverflowSupport.enableYellowZone: Illegal state"); @@ -207,10 +183,6 @@ public void protectYellowZone() { @Override public int yellowAndRedZoneSize() { - if (!supportedByOS()) { - return 0; - } - return Options.StackYellowZoneSize.getValue() + Options.StackRedZoneSize.getValue(); } @@ -449,18 +421,11 @@ public void afterRegistration(AfterRegistrationAccess access) { @Override public void registerGraalPhases(Providers providers, SnippetReflectionProvider snippetReflection, Suites suites, boolean hosted) { - if (!StackOverflowCheckImpl.supportedByOS()) { - return; - } - suites.getHighTier().prependPhase(new InsertStackOverflowCheckPhase()); } @Override public void registerForeignCalls(RuntimeConfiguration runtimeConfig, Providers providers, SnippetReflectionProvider snippetReflection, SubstrateForeignCallsProvider foreignCalls, boolean hosted) { - if (!StackOverflowCheckImpl.supportedByOS()) { - return; - } foreignCalls.register(providers, StackOverflowCheckSnippets.FOREIGN_CALLS); } @@ -468,10 +433,6 @@ public void registerForeignCalls(RuntimeConfiguration runtimeConfig, Providers p @SuppressWarnings("unused") public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues options, Iterable factories, Providers providers, SnippetReflectionProvider snippetReflection, Map, NodeLoweringProvider> lowerings, boolean hosted) { - if (!StackOverflowCheckImpl.supportedByOS()) { - return; - } - Predicate mustNotAllocatePredicate = null; if (hosted) { mustNotAllocatePredicate = method -> ImageSingletons.lookup(RestrictHeapAccessCallees.class).mustNotAllocate(method); From 6a256032cd7910dc8555345b08a565650d4a27af Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 9 Jul 2021 16:47:09 +0200 Subject: [PATCH 24/28] Enable recursive segfault handling on Posix platforms. --- .../oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java | 2 +- .../src/com/oracle/svm/core/posix/headers/Signal.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java index 86b6c51a35b7..6127d6806836 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java @@ -100,7 +100,7 @@ protected void install() { sigaction structSigAction = StackValue.get(structSigActionSize); LibC.memset(structSigAction, WordFactory.signed(0), WordFactory.unsigned(structSigActionSize)); /* Register sa_sigaction signal handler */ - structSigAction.sa_flags(Signal.SA_SIGINFO()); + structSigAction.sa_flags(Signal.SA_SIGINFO() | Signal.SA_NODEFER()); structSigAction.sa_sigaction(advancedSignalDispatcher.getFunctionPointer()); Signal.sigaction(Signal.SignalEnum.SIGSEGV, structSigAction, WordFactory.nullPointer()); Signal.sigaction(Signal.SignalEnum.SIGBUS, structSigAction, WordFactory.nullPointer()); diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java index 7afc4359a386..dfd9302d5545 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java @@ -291,6 +291,9 @@ public interface AdvancedSignalDispatcher extends CFunctionPointer { @CConstant public static native int SA_SIGINFO(); + @CConstant + public static native int SA_NODEFER(); + @CStruct(addStructKeyword = true) public interface sigaction extends PointerBase { @CField From 34bf53b1b8376e30ba93e889c5238f37dcea1556 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 9 Jul 2021 17:24:47 +0200 Subject: [PATCH 25/28] Cleanups. --- .../oracle/svm/core/SubstrateDiagnostics.java | 10 +++---- .../oracle/svm/core/code/CodeInfoAccess.java | 20 ++++++++++++++ .../svm/core/code/RuntimeCodeInfoHistory.java | 26 ++----------------- .../svm/core/code/RuntimeCodeInfoMemory.java | 11 +------- .../src/com/oracle/svm/core/heap/Heap.java | 5 ++-- .../locks/SingleThreadedVMLockSupport.java | 10 ++++++- .../oracle/svm/core/locks/VMLockSupport.java | 8 ++---- 7 files changed, 41 insertions(+), 49 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 2c1b308b4267..346d8ecf2b9e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -28,7 +28,6 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.NumUtil; -import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; @@ -142,8 +141,9 @@ private static void printDiagnosticsForCurrentState() { Log log = state.log; if (state.diagnosticThunkIndex > 0) { - log.newline(); - log.string("An error occurred while printing diagnostics. The remaining part of this section will be skipped.").resetIndentation().newline(); + // An error must have happened earlier as the code for printing diagnostics was invoked + // recursively. + log.resetIndentation(); } // Print the various sections of the diagnostics and skip all sections that were already @@ -154,9 +154,7 @@ private static void printDiagnosticsForCurrentState() { while (++state.invocationCount <= thunk.maxInvocations()) { try { thunk.printDiagnostics(log, state.invocationCount); - // TEMP (chaeubl): check the max retries - log.signed(GraalUnsafeAccess.getUnsafe().getInt(27L)); - continue; + break; } catch (Throwable e) { dumpException(log, thunk, e); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java index b88523e45be7..9fe308bc51d5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java @@ -374,4 +374,24 @@ private static CodeInfoImpl cast(UntetheredCodeInfo info) { assert isValid(info); return (CodeInfoImpl) info; } + + public static void printCodeInfo(Log log, CodeInfo info, boolean allowJavaHeapAccess) { + String name = allowJavaHeapAccess ? CodeInfoAccess.getName(info) : null; + printCodeInfo(log, info, CodeInfoAccess.getState(info), name, CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info)); + } + + public static void printCodeInfo(Log log, UntetheredCodeInfo codeInfo, int state, String name, CodePointer codeStart, CodePointer codeEnd) { + log.string("CodeInfo (").zhex(codeInfo).string(" - ").zhex(((UnsignedWord) codeInfo).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()).subtract(1)).string("), ") + .string(CodeInfoAccess.stateToString(state)); + if (name != null) { + log.string(" - ").string(name); + } + log.string(", ip: (").zhex(codeStart).string(" - ").zhex(codeEnd).string(")"); + log.newline(); + /* + * Note that we are not trying to output the InstalledCode object. It is not a pinned + * object, so when log printing (for, e.g., a fatal error) occurs during a GC, then the VM + * could segfault. + */ + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java index 4e433d678dcc..880563ed6ffe 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java @@ -29,7 +29,6 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CodePointer; -import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.log.Log; @@ -82,31 +81,10 @@ public void logFree(CodeInfo info) { private static void traceCodeCache(String kind, CodeInfo info, boolean allowJavaHeapAccess) { if (RuntimeCodeCache.Options.TraceCodeCache.getValue()) { Log.log().string(kind).string(" method: "); - printCodeInfo(Log.log(), info, allowJavaHeapAccess); + CodeInfoAccess.printCodeInfo(Log.log(), info, allowJavaHeapAccess); } } - private static void printCodeInfo(Log log, CodeInfo info, boolean allowJavaHeapAccess) { - String name = allowJavaHeapAccess ? CodeInfoAccess.getName(info) : null; - printCodeInfo(log, info, CodeInfoAccess.getState(info), name, CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info)); - } - - // TEMP (chaeubl): move this somewhere else... - static void printCodeInfo(Log log, UntetheredCodeInfo codeInfo, int state, String name, CodePointer codeStart, CodePointer codeEnd) { - log.string("CodeInfo (").zhex(codeInfo).string(" - ").zhex(((UnsignedWord) codeInfo).add(RuntimeCodeInfoAccess.getSizeOfCodeInfo()).subtract(1)).string("), ") - .string(CodeInfoAccess.stateToString(state)); - if (name != null) { - log.string(" - ").string(name); - } - log.string(", ip: (").zhex(codeStart).string(" - ").zhex(codeEnd).string(")"); - log.newline(); - /* - * Note that we are not trying to output the InstalledCode object. It is not a pinned - * object, so when log printing (for, e.g., a fatal error) occurs during a GC, then the VM - * could segfault. - */ - } - public void printRecentOperations(Log log, boolean allowJavaHeapAccess) { log.string("The ").signed(recentOperations.size()).string(" most recent RuntimeCodeInfo operations (oldest first): ").indent(true); recentOperations.foreach(log, allowJavaHeapAccess ? PRINT_WITH_JAVA_HEAP_DATA : PRINT_WITHOUT_JAVA_HEAP_DATA); @@ -154,7 +132,7 @@ public void print(Log log, boolean allowJavaHeapAccess) { if (kind != null) { log.unsigned(timestamp).string(" - ").string(kind).spaces(1); String name = allowJavaHeapAccess ? codeName : null; - printCodeInfo(log, codeInfo, codeInfoState, name, codeStart, codeEnd); + CodeInfoAccess.printCodeInfo(log, codeInfo, codeInfoState, name, codeStart, codeEnd); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java index 00db3b6b3a49..ef6d37702c6a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java @@ -27,7 +27,6 @@ import java.util.concurrent.locks.ReentrantLock; import org.graalvm.compiler.api.replacements.Fold; -import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -43,7 +42,6 @@ import com.oracle.svm.core.code.RuntimeCodeCache.CodeInfoVisitor; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.log.Log; -import com.oracle.svm.core.thread.JavaVMOperation; import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.util.VMError; @@ -85,13 +83,6 @@ public void add(CodeInfo info) { lock.lock(); try { add0(info); - - // TEMP (chaeubl): - if (count > 5) { - JavaVMOperation.enqueueBlockingSafepoint("Temp", () -> { - System.out.println(GraalUnsafeAccess.getUnsafe().getInt((long) (Math.random() * 100))); - }); - } } finally { lock.unlock(); } @@ -284,7 +275,7 @@ private void printCodeInfo(Log log, int i, boolean allowJavaHeapAccess) { @Uninterruptible(reason = "CodeInfo no longer needs to be protected from the GC.", calleeMustBe = false) private static void printCodeInfo0(Log log, UntetheredCodeInfo codeInfo, int state, String name, CodePointer codeStart, CodePointer codeEnd) { - RuntimeCodeInfoHistory.printCodeInfo(log, codeInfo, state, name, codeStart, codeEnd); + CodeInfoAccess.printCodeInfo(log, codeInfo, state, name, codeStart, codeEnd); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 786db141b896..cfd7218f1839 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -169,8 +169,9 @@ public List> getLoadedClasses() { public abstract boolean isInImageHeap(Object object); /** - * Returns true if the object at the given address is located in the image heap. This method - * only works reliably for pointers that point to the start of an object. + * Returns true if the object at the given address is located in the image heap. Depending on + * the used GC, this method may only work reliably for pointers that point to the start of an + * object. */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public abstract boolean isInImageHeap(Pointer objectPtr); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java index 67aa0d8d116a..d1f7be48987e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java @@ -39,7 +39,15 @@ * locking is necessary. */ final class SingleThreadedVMLockSupport extends VMLockSupport { - // Empty class to have the same name as the source file. + @Override + public VMMutex[] getMutexes() { + return null; + } + + @Override + public VMCondition[] getConditions() { + return null; + } } @AutomaticFeature diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java index 75db14f91c6b..dd66234a3c36 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java @@ -32,13 +32,9 @@ import com.oracle.svm.core.log.Log; public abstract class VMLockSupport { - public VMMutex[] getMutexes() { - return null; - } + public abstract VMMutex[] getMutexes(); - public VMCondition[] getConditions() { - return null; - } + public abstract VMCondition[] getConditions(); public static class DumpVMMutexes extends DiagnosticThunk { @Override From e1769eb732494e85ba95f543606b78fa02716013 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 30 Jul 2021 15:30:57 +0200 Subject: [PATCH 26/28] Various fixes. --- .../oracle/svm/core/genscavenge/HeapImpl.java | 2 +- .../WindowsSubstrateSegfaultHandler.java | 9 ++++-- .../core/windows/headers/ErrHandlingAPI.java | 3 +- .../oracle/svm/core/SubstrateDiagnostics.java | 28 ++++++++----------- .../src/com/oracle/svm/core/log/RealLog.java | 3 +- .../com/oracle/svm/core/thread/VMThreads.java | 2 +- 6 files changed, 24 insertions(+), 23 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 c3d67cd27667..140275e430f3 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 @@ -742,7 +742,7 @@ public void printDiagnostics(Log log, int invocationCount) { log.string("Heap settings and statistics:").indent(true); log.string("Supports isolates: ").bool(SubstrateOptions.SpawnIsolates.getValue()).newline(); - if (ImageSingletons.lookup(CompressEncoding.class).hasBase()) { + if (SubstrateOptions.SpawnIsolates.getValue() && ImageSingletons.lookup(CompressEncoding.class).hasBase()) { log.string("Heap base: ").zhex(KnownIntrinsics.heapBase()).newline(); } log.string("Object reference size: ").signed(ConfigurationValues.getObjectLayout().getReferenceSize()).newline(); diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java index 1db56dc1ea6d..d46aea1f7580 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java @@ -33,6 +33,7 @@ import org.graalvm.nativeimage.c.function.CEntryPoint; import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.type.CLongPointer; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.word.PointerBase; @@ -114,7 +115,8 @@ protected void printSignalInfo(Log log, PointerBase signalInfo) { int numParameters = exceptionRecord.NumberParameters(); if ((exceptionCode == EXCEPTION_ACCESS_VIOLATION() || exceptionCode == EXCEPTION_IN_PAGE_ERROR()) && numParameters >= 2) { - long exParam0 = exceptionRecord.ExceptionInformation(0).read(); + CLongPointer exInfo = exceptionRecord.ExceptionInformation(); + long exParam0 = exInfo.addressOf(0).read(); if (exParam0 == 0) { log.string(", reading address"); } else if (exParam0 == 1) { @@ -124,12 +126,13 @@ protected void printSignalInfo(Log log, PointerBase signalInfo) { } else { log.string(", ExceptionInformation=").zhex(exParam0); } - log.string(" ").zhex(exceptionRecord.ExceptionInformation(1).read()); + log.string(" ").zhex(exInfo.addressOf(1).read()); } else { if (numParameters > 0) { log.string(", ExceptionInformation="); + CLongPointer exInfo = exceptionRecord.ExceptionInformation(); for (int i = 0; i < numParameters; i++) { - log.string(" ").zhex(exceptionRecord.ExceptionInformation(i).read()); + log.string(" ").zhex(exInfo.addressOf(i).read()); } } } diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java index 9e2e319e1f13..36ab99fabd12 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java @@ -35,6 +35,7 @@ import org.graalvm.nativeimage.c.struct.CStruct; import org.graalvm.nativeimage.c.type.CLongPointer; import org.graalvm.nativeimage.c.type.VoidPointer; +import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.PointerBase; import com.oracle.svm.core.RegisterDumper; @@ -77,7 +78,7 @@ public interface EXCEPTION_RECORD extends PointerBase { int NumberParameters(); @CFieldAddress - CLongPointer ExceptionInformation(int index); + CLongPointer ExceptionInformation(); } @CConstant diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 346d8ecf2b9e..455372013865 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -28,6 +28,7 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.NumUtil; +import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; @@ -72,9 +73,6 @@ import com.oracle.svm.core.util.Counter; public class SubstrateDiagnostics { - private static final Stage0StackFramePrintVisitor[] PRINT_VISITORS = new Stage0StackFramePrintVisitor[]{Stage0StackFramePrintVisitor.SINGLETON, Stage1StackFramePrintVisitor.SINGLETON, - StackFramePrintVisitor.SINGLETON}; - private static final FastThreadLocalBytes threadOnlyAttachedForCrashHandler = FastThreadLocalFactory.createBytes(() -> 1); private static final PrintDiagnosticsState state = new PrintDiagnosticsState(); @@ -106,7 +104,7 @@ public static int maxInvocations() { } public static void printLocationInfo(Log log, UnsignedWord value, boolean allowJavaHeapAccess) { - if (value.notEqual(0) && !RuntimeCodeInfoMemory.singleton().printLocationInfo(log, value, allowJavaHeapAccess) && !VMThreads.printLocationInfo(log, value, allowJavaHeapAccess) && + if (value.notEqual(0) && !RuntimeCodeInfoMemory.singleton().printLocationInfo(log, value, allowJavaHeapAccess) && !VMThreads.printLocationInfo(log, value) && !Heap.getHeap().printLocationInfo(log, value, allowJavaHeapAccess)) { log.string("is an unknown value"); } @@ -136,6 +134,7 @@ static boolean print(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context return true; } + @SuppressFBWarnings(value = "VO_VOLATILE_INCREMENT", justification = "This method is single threaded. The fields 'diagnosticThunkIndex' and 'invocationCount' are only volatile to ensure that the updated field values are written right away.") private static void printDiagnosticsForCurrentState() { assert isInProgressByCurrentThread(); @@ -580,9 +579,12 @@ public void printDiagnostics(Log log, int invocationCount) { } private static class DumpCurrentThreadDecodedStackTrace extends DiagnosticThunk { + private static final Stage0StackFramePrintVisitor[] PRINT_VISITORS = new Stage0StackFramePrintVisitor[]{StackFramePrintVisitor.SINGLETON, Stage1StackFramePrintVisitor.SINGLETON, + Stage0StackFramePrintVisitor.SINGLETON}; + @Override public int maxInvocations() { - return 1; + return 3; } @Override @@ -590,15 +592,9 @@ public int maxInvocations() { public void printDiagnostics(Log log, int invocationCount) { Pointer sp = state.sp; CodePointer ip = state.ip; - for (int i = 0; i < PRINT_VISITORS.length; i++) { - try { - log.string("Stacktrace stage ").signed(i).string(":").indent(true); - ThreadStackPrinter.printStacktrace(sp, ip, PRINT_VISITORS[i], log); - log.indent(false); - } catch (Exception e) { - dumpException(log, this, e); - } - } + log.string("Stacktrace:").indent(true); + ThreadStackPrinter.printStacktrace(sp, ip, PRINT_VISITORS[invocationCount - 1], log); + log.indent(false); } } @@ -612,8 +608,8 @@ public int maxInvocations() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { if (VMOperation.isInProgressAtSafepoint()) { - // Iterate all threads without checking if the thread mutex is locked (it should be - // locked by this thread though because we are at a safepoint). + // Iterate all threads without checking if the thread mutex is locked (it should + // be locked by this thread though because we are at a safepoint). for (IsolateThread vmThread = VMThreads.firstThreadUnsafe(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) { if (vmThread == CurrentIsolate.getCurrentThread()) { continue; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java index 7a2dc7bd3b8c..5fd54b5afcc9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java @@ -444,7 +444,8 @@ private void rawString(char[] value) { @Override public Log zhex(WordBase value) { - return zhex(value.rawValue()); + zhex(value.rawValue()); + return this; } @NeverInline("Logging is always slow-path code") diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index 5043ceb337f8..c2a16375a720 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -573,7 +573,7 @@ public static boolean ownsThreadMutex() { return THREAD_MUTEX.isOwner(); } - public static boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaHeapAccess) { + public static boolean printLocationInfo(Log log, UnsignedWord value) { for (IsolateThread thread = firstThreadUnsafe(); thread.isNonNull(); thread = nextThread(thread)) { if (thread.equal(value)) { log.string("is a thread"); From 910c36d5917380c5e917bbe5eb7ad0315741deb6 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 30 Jul 2021 16:53:56 +0200 Subject: [PATCH 27/28] Further cleanups. Changed how stack traces are printed for the failing thread. --- .../oracle/svm/core/genscavenge/HeapImpl.java | 5 +- .../core/windows/headers/ErrHandlingAPI.java | 1 - .../oracle/svm/core/SubstrateDiagnostics.java | 46 +++++++++++-------- 3 files changed, 28 insertions(+), 24 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 140275e430f3..22c9b1ef4206 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 @@ -29,7 +29,6 @@ import java.util.List; import org.graalvm.compiler.api.replacements.Fold; -import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.nodes.gc.BarrierSet; import org.graalvm.compiler.word.Word; @@ -591,7 +590,7 @@ public Reference getAndClearReferencePendingList() { @Override public boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaHeapAccess) { - if (ImageSingletons.lookup(CompressEncoding.class).hasBase() && value.equal(KnownIntrinsics.heapBase())) { + if (SubstrateOptions.SpawnIsolates.getValue() && value.equal(KnownIntrinsics.heapBase())) { log.string("is the heap base"); return true; } @@ -742,7 +741,7 @@ public void printDiagnostics(Log log, int invocationCount) { log.string("Heap settings and statistics:").indent(true); log.string("Supports isolates: ").bool(SubstrateOptions.SpawnIsolates.getValue()).newline(); - if (SubstrateOptions.SpawnIsolates.getValue() && ImageSingletons.lookup(CompressEncoding.class).hasBase()) { + if (SubstrateOptions.SpawnIsolates.getValue()) { log.string("Heap base: ").zhex(KnownIntrinsics.heapBase()).newline(); } log.string("Object reference size: ").signed(ConfigurationValues.getObjectLayout().getReferenceSize()).newline(); diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java index 36ab99fabd12..2f819ac8123b 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/ErrHandlingAPI.java @@ -35,7 +35,6 @@ import org.graalvm.nativeimage.c.struct.CStruct; import org.graalvm.nativeimage.c.type.CLongPointer; import org.graalvm.nativeimage.c.type.VoidPointer; -import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.PointerBase; import com.oracle.svm.core.RegisterDumper; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 455372013865..087470aa568d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -224,8 +224,7 @@ private static long getTotalFrameSize0(CodePointer ip, CodeInfo codeInfo) { return CodeInfoAccess.lookupTotalFrameSize(codeInfo, CodeInfoAccess.relativeIP(codeInfo, ip)); } - private static boolean printFrameAnchors(Log log, IsolateThread thread) { - log.string("Java frame anchors:").indent(true); + private static void logFrameAnchors(Log log, IsolateThread thread) { JavaFrameAnchor anchor = JavaFrameAnchors.getFrameAnchor(thread); if (anchor.isNull()) { log.string("No anchors").newline(); @@ -234,8 +233,6 @@ private static boolean printFrameAnchors(Log log, IsolateThread thread) { log.string("Anchor ").zhex(anchor.rawValue()).string(" LastJavaSP ").zhex(anchor.getLastJavaSP().rawValue()).string(" LastJavaIP ").zhex(anchor.getLastJavaIP().rawValue()).newline(); anchor = anchor.getPreviousAnchor(); } - log.indent(false); - return true; } private static class PrintDiagnosticsState { @@ -369,7 +366,7 @@ public int maxInvocations() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { if (DeoptimizationSupport.enabled()) { - log.string("DeoptStubPointer address: ").zhex(DeoptimizationSupport.getDeoptStubPointer().rawValue()).newline().newline(); + log.string("DeoptStubPointer address: ").zhex(DeoptimizationSupport.getDeoptStubPointer()).newline().newline(); } } } @@ -388,13 +385,13 @@ public void printDiagnostics(Log log, int invocationCount) { Pointer sp = state.sp; CodePointer ip = state.ip; - log.string("TopFrame info:").indent(true); + log.string("Top frame info:").indent(true); if (sp.isNonNull() && ip.isNonNull()) { long totalFrameSize = getTotalFrameSize(sp, ip); DeoptimizedFrame deoptFrame = Deoptimizer.checkDeoptimized(sp); if (deoptFrame != null) { - log.string("RSP ").zhex(sp.rawValue()).string(" frame was deoptimized:").newline(); - log.string("SourcePC ").zhex(deoptFrame.getSourcePC().rawValue()).newline(); + log.string("RSP ").zhex(sp).string(" frame was deoptimized:").newline(); + log.string("SourcePC ").zhex(deoptFrame.getSourcePC()).newline(); log.string("SourceTotalFrameSize ").signed(totalFrameSize).newline(); } else if (totalFrameSize != -1) { log.string("TotalFrameSize in CodeInfoTable ").signed(totalFrameSize).newline(); @@ -408,11 +405,11 @@ public void printDiagnostics(Log log, int invocationCount) { } if (anchor.isNonNull()) { - log.string("Found matching Anchor:").zhex(anchor.rawValue()).newline(); + log.string("Found matching Anchor:").zhex(anchor).newline(); Pointer lastSp = anchor.getLastJavaSP(); - log.string("LastJavaSP ").zhex(lastSp.rawValue()).newline(); + log.string("LastJavaSP ").zhex(lastSp).newline(); CodePointer lastIp = anchor.getLastJavaIP(); - log.string("LastJavaIP ").zhex(lastIp.rawValue()).newline(); + log.string("LastJavaIP ").zhex(lastIp).newline(); } } } @@ -436,7 +433,7 @@ private static void dumpThreads(Log log, boolean accessThreadObject) { log.string("Threads:").indent(true); // Only used for diagnostics - iterate all threads without locking the thread mutex. for (IsolateThread thread = VMThreads.firstThreadUnsafe(); thread.isNonNull(); thread = VMThreads.nextThread(thread)) { - log.zhex(thread.rawValue()).spaces(1).string(VMThreads.StatusSupport.getStatusString(thread)); + log.zhex(thread).spaces(1).string(VMThreads.StatusSupport.getStatusString(thread)); if (accessThreadObject) { Thread threadObj = JavaThreads.fromVMThread(thread); log.string(" \"").string(threadObj.getName()).string("\" - ").object(threadObj); @@ -467,11 +464,11 @@ private static void printThreadLocals(Log log, int invocationCount) { IsolateThread currentThread = CurrentIsolate.getCurrentThread(); if (isThreadOnlyAttachedForCrashHandler(currentThread)) { if (invocationCount == 1) { - log.string("The failing thread ").zhex(currentThread.rawValue()).string(" does not have a full set of VM thread locals as it is an unattached thread.").newline(); + log.string("The failing thread ").zhex(currentThread).string(" does not have a full set of VM thread locals as it is an unattached thread.").newline(); log.newline(); } } else { - log.string("VM thread locals for the failing thread ").zhex(currentThread.rawValue()).string(":").indent(true); + log.string("VM thread locals for the failing thread ").zhex(currentThread).string(":").indent(true); VMThreadLocalInfos.dumpToLog(log, currentThread, invocationCount == 1); log.indent(false); } @@ -574,7 +571,10 @@ public int maxInvocations() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, int invocationCount) { - printFrameAnchors(log, CurrentIsolate.getCurrentThread()); + IsolateThread currentThread = CurrentIsolate.getCurrentThread(); + log.string("Java frame anchors for the failing thread ").zhex(currentThread).string(":").indent(true); + logFrameAnchors(log, currentThread); + log.indent(false); } } @@ -592,7 +592,7 @@ public int maxInvocations() { public void printDiagnostics(Log log, int invocationCount) { Pointer sp = state.sp; CodePointer ip = state.ip; - log.string("Stacktrace:").indent(true); + log.string("Stacktrace for the failing thread ").zhex(CurrentIsolate.getCurrentThread()).string(":").indent(true); ThreadStackPrinter.printStacktrace(sp, ip, PRINT_VISITORS[invocationCount - 1], log); log.indent(false); } @@ -615,9 +615,9 @@ public void printDiagnostics(Log log, int invocationCount) { continue; } try { - log.string("Thread ").zhex(vmThread.rawValue()).string(":").indent(true); + log.string("Thread ").zhex(vmThread).string(":").indent(true); printFrameAnchors(log, vmThread); - printStacktrace(log, vmThread); + printStackTrace(log, vmThread); log.indent(false); } catch (Exception e) { dumpException(log, this, e); @@ -626,8 +626,14 @@ public void printDiagnostics(Log log, int invocationCount) { } } - private static void printStacktrace(Log log, IsolateThread vmThread) { - log.string("Full stacktrace:").indent(true); + private static void printFrameAnchors(Log log, IsolateThread vmThread) { + log.string("Frame anchors:").indent(true); + logFrameAnchors(log, vmThread); + log.indent(false); + } + + private static void printStackTrace(Log log, IsolateThread vmThread) { + log.string("Stacktrace:").indent(true); JavaStackWalker.walkThread(vmThread, StackFramePrintVisitor.SINGLETON, log); log.redent(false); } From 7c55d0f474c3e6e2a2c55383018803aef75f3548 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 6 Aug 2021 15:07:40 +0200 Subject: [PATCH 28/28] Minor cleanups and documentation. --- .../windows/WindowsSubstrateSegfaultHandler.java | 14 +++++++++----- .../com/oracle/svm/core/code/CodeInfoAccess.java | 2 +- .../com/oracle/svm/core/locks/VMLockSupport.java | 8 ++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java index d46aea1f7580..b885e251fc6c 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java @@ -59,6 +59,10 @@ public void afterRegistration(AfterRegistrationAccess access) { } class WindowsSubstrateSegfaultHandler extends SubstrateSegfaultHandler { + private static final int EX_READ = 0; + private static final int EX_WRITE = 1; + private static final int EX_EXECUTE = 8; + @Override protected void install() { /* @@ -116,15 +120,15 @@ protected void printSignalInfo(Log log, PointerBase signalInfo) { int numParameters = exceptionRecord.NumberParameters(); if ((exceptionCode == EXCEPTION_ACCESS_VIOLATION() || exceptionCode == EXCEPTION_IN_PAGE_ERROR()) && numParameters >= 2) { CLongPointer exInfo = exceptionRecord.ExceptionInformation(); - long exParam0 = exInfo.addressOf(0).read(); - if (exParam0 == 0) { + long operation = exInfo.addressOf(0).read(); + if (operation == EX_READ) { log.string(", reading address"); - } else if (exParam0 == 1) { + } else if (operation == EX_WRITE) { log.string(", writing address"); - } else if (exParam0 == 8) { + } else if (operation == EX_EXECUTE) { log.string(", data execution prevention violation at address"); } else { - log.string(", ExceptionInformation=").zhex(exParam0); + log.string(", ExceptionInformation=").zhex(operation); } log.string(" ").zhex(exInfo.addressOf(1).read()); } else { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java index 9fe308bc51d5..e439cb9d6f0e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java @@ -149,7 +149,7 @@ public static String stateToString(int codeInfoState) { case CodeInfo.STATE_CODE_CONSTANTS_LIVE: return "code constants live"; case CodeInfo.STATE_NON_ENTRANT: - return "non entrant"; + return "non-entrant"; case CodeInfo.STATE_READY_FOR_INVALIDATION: return "ready for invalidation"; case CodeInfo.STATE_PARTIALLY_FREED: diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java index dd66234a3c36..ea8700d81ce5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java @@ -32,8 +32,16 @@ import com.oracle.svm.core.log.Log; public abstract class VMLockSupport { + /** + * Returns an array that contains all {@link VMMutex} objects that are present in the image or + * null if that information is not available. + */ public abstract VMMutex[] getMutexes(); + /** + * Returns an array that contains all {@link VMCondition} objects that are present in the image + * or null if that information is not available. + */ public abstract VMCondition[] getConditions(); public static class DumpVMMutexes extends DiagnosticThunk {