From 88a98a3310327d6167b21641de9db8261a926936 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 17 May 2023 11:34:30 +0200 Subject: [PATCH 01/16] svm: add static FrameInfoQueryResult#getSourceReference --- .../src/com/oracle/svm/core/code/FrameInfoQueryResult.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java index bb375834d5a2..bc187e6ed7c4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java @@ -353,6 +353,10 @@ public int getSourceLineNumber() { * Returns the name and source code location of the method. */ public StackTraceElement getSourceReference() { + return getSourceReference(sourceClass, sourceMethodName, sourceLineNumber); + } + + public static StackTraceElement getSourceReference(Class sourceClass, String sourceMethodName, int sourceLineNumber) { if (sourceClass == null) { return new StackTraceElement("", sourceMethodName, null, sourceLineNumber); } From 25c4cf269cf517c2ff99b8d47cea92ea2aea842a Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 17 May 2023 15:58:58 +0200 Subject: [PATCH 02/16] svm: no longer pass FrameInfoQueryResult to BacktraceDecoder#processSourceReference --- .../src/com/oracle/svm/core/jdk/BacktraceDecoder.java | 6 +++--- .../src/com/oracle/svm/core/jdk/StackTraceUtils.java | 4 ++-- .../src/com/oracle/svm/core/log/RealLog.java | 8 +++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java index 91cffd6f4f88..4ca5a16a0115 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java @@ -44,7 +44,7 @@ public abstract class BacktraceDecoder { * * @param backtrace internal backtrace stored in {@link Target_java_lang_Throwable#backtrace} * @param maxFramesProcessed the maximum number of frames that should be - * {@linkplain #processFrameInfo processed} + * {@linkplain #processSourceReference processed} * @param maxFramesDecode the maximum number of frames that should be decoded (0 means all) * @return the number of decoded frames */ @@ -106,7 +106,7 @@ private int visitFrame(CodePointer ip, CodeInfo tetheredCodeInfo, int oldFramesD continue; } if (framesDecoded < maxFramesProcessed) { - processFrameInfo(frameInfo); + processSourceReference(frameInfo.getSourceClass(), frameInfo.getSourceMethodName(), frameInfo.getSourceLineNumber()); } framesDecoded++; if (framesDecoded == maxFramesDecode) { @@ -117,5 +117,5 @@ private int visitFrame(CodePointer ip, CodeInfo tetheredCodeInfo, int oldFramesD } @RestrictHeapAccess(access = RestrictHeapAccess.Access.UNRESTRICTED, reason = "Some implementations allocate.") - protected abstract void processFrameInfo(FrameInfoQueryResult frameInfo); + protected abstract void processSourceReference(Class sourceClass, String sourceMethodName, int sourceLineNumber); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index 051107df4cf6..11dbfed59b65 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -369,8 +369,8 @@ static StackTraceElement[] build(Object backtrace) { private final ArrayList trace = new ArrayList<>(); @Override - protected void processFrameInfo(FrameInfoQueryResult frameInfo) { - StackTraceElement sourceReference = frameInfo.getSourceReference(); + protected void processSourceReference(Class sourceClass, String sourceMethodName, int sourceLineNumber) { + StackTraceElement sourceReference = FrameInfoQueryResult.getSourceReference(sourceClass, sourceMethodName, sourceLineNumber); trace.add(sourceReference); } } 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 b99fce5d4e8f..8bd06abc4601 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 @@ -42,10 +42,10 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.c.NonmovableArrays; -import com.oracle.svm.core.code.FrameInfoQueryResult; import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.jdk.BacktraceDecoder; import com.oracle.svm.core.jdk.JDKUtils; import com.oracle.svm.core.locks.VMMutex; @@ -701,8 +701,10 @@ protected final int printBacktrace(Object backtrace, int maxFramesProcessed) { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") - protected void processFrameInfo(FrameInfoQueryResult frameInfo) { - printJavaFrame(frameInfo.getSourceClassName(), frameInfo.getSourceMethodName(), frameInfo.getSourceFileName(), frameInfo.getSourceLineNumber()); + protected void processSourceReference(Class sourceClass, String sourceMethodName, int sourceLineNumber) { + String sourceClassName = sourceClass != null ? sourceClass.getName() : ""; + String sourceFileName = sourceClass != null ? DynamicHub.fromClass(sourceClass).getSourceFileName() : null; + printJavaFrame(sourceClassName, sourceMethodName, sourceFileName, sourceLineNumber); } } } From ee38749424c90c1c75a5d31759ef191ffac3accc Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 17 May 2023 17:49:03 +0200 Subject: [PATCH 03/16] svm: support storing encoded source reference Throwable#backtrace --- .../oracle/svm/core/jdk/BacktraceDecoder.java | 33 ++- .../oracle/svm/core/jdk/StackTraceUtils.java | 228 +++++++++++++++--- 2 files changed, 225 insertions(+), 36 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java index 4ca5a16a0115..20fec016f433 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java @@ -37,6 +37,10 @@ import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.util.VMError; +/** + * Decoder for backtraces computed by {@link BacktraceVisitor} and stored in + * {@link Target_java_lang_Throwable#backtrace}. + */ public abstract class BacktraceDecoder { /** @@ -53,12 +57,20 @@ protected final int visitBacktrace(Object backtrace, int maxFramesProcessed, int int framesDecoded = 0; if (backtrace != null) { final long[] trace = (long[]) backtrace; - for (long address : trace) { - if (address == 0) { - break; + int backtraceIndex = 0; + while (backtraceIndex < trace.length && trace[backtraceIndex] != 0) { + long entry = trace[backtraceIndex]; + if (BacktraceVisitor.isSourceReference(entry)) { + /* Entry is an encoded source reference. */ + VMError.guarantee(backtraceIndex + BacktraceVisitor.MAX_ENTRIES_PER_FRAME <= trace.length, "Truncated backtrace array"); + backtraceIndex += visitSourceReference(maxFramesProcessed, framesDecoded, trace, backtraceIndex); + framesDecoded++; + } else { + /* Entry is a raw code pointer. */ + CodePointer ip = WordFactory.pointer(entry); + framesDecoded = visitCodePointer(ip, framesDecoded, maxFramesProcessed, maxFramesDecodeLimit); + backtraceIndex++; } - CodePointer ip = WordFactory.pointer(address); - framesDecoded = visitCodePointer(ip, framesDecoded, maxFramesProcessed, maxFramesDecodeLimit); if (framesDecoded == maxFramesDecodeLimit) { break; } @@ -67,6 +79,17 @@ protected final int visitBacktrace(Object backtrace, int maxFramesProcessed, int return framesDecoded - maxFramesProcessed; } + private int visitSourceReference(int maxFramesProcessed, int framesDecoded, long[] trace, int backtraceIndex) { + int sourceLineNumber = BacktraceVisitor.readSourceLineNumber(trace, backtraceIndex); + Class sourceClass = BacktraceVisitor.readSourceClass(trace, backtraceIndex); + String sourceMethodName = BacktraceVisitor.readSourceMethodName(trace, backtraceIndex); + + if (framesDecoded < maxFramesProcessed) { + processSourceReference(sourceClass, sourceMethodName, sourceLineNumber); + } + return BacktraceVisitor.MAX_ENTRIES_PER_FRAME; + } + @Uninterruptible(reason = "Prevent the GC from freeing the CodeInfo object.") private int visitCodePointer(CodePointer ip, int oldFramesDecoded, int maxFramesProcessed, int maxFramesDecode) { int framesDecoded = oldFramesDecoded; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index 11dbfed59b65..902bb396b675 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -32,22 +32,26 @@ import java.util.ArrayList; import java.util.Arrays; +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.word.Pointer; +import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.code.CodeInfo; import com.oracle.svm.core.code.CodeInfoAccess; +import com.oracle.svm.core.code.CodeInfoQueryResult; import com.oracle.svm.core.code.CodeInfoTable; import com.oracle.svm.core.code.FrameInfoQueryResult; -import com.oracle.svm.core.code.UntetheredCodeInfo; import com.oracle.svm.core.deopt.DeoptimizedFrame; +import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.heap.VMOperationInfos; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.snippets.KnownIntrinsics; @@ -259,7 +263,16 @@ protected void operate() { */ final class BacktraceVisitor extends StackFrameVisitor { + /** + * Index into {@link #trace} + */ private int index = 0; + + /** + * Number of frames stored (native or Java frames). Because Java frames take up more than one + * entry in {@link #trace} this number might be different to {@link #index}. + */ + private int numFrames = 0; private final int limit = computeNativeLimit(); /* @@ -270,6 +283,7 @@ final class BacktraceVisitor extends StackFrameVisitor { private long[] trace = new long[INITIAL_TRACE_SIZE]; public static final int NATIVE_FRAME_LIMIT_MARGIN = 10; + static final int MAX_ENTRIES_PER_FRAME = useCompressedReferences() ? 2 : 3; /** * Gets the number of native frames to collect. Native frames and Java frames do not directly @@ -293,45 +307,197 @@ private static int computeNativeLimit() { return maxJavaStackTraceDepthExtended > maxJavaStackTraceDepth ? maxJavaStackTraceDepthExtended : Integer.MAX_VALUE; } - @Uninterruptible(reason = "Prevent the GC from freeing the CodeInfo object.") - private static boolean decodeCodePointer(BuildStackTraceVisitor visitor, CodePointer ip) { - UntetheredCodeInfo untetheredInfo = CodeInfoTable.lookupCodeInfo(ip); - if (untetheredInfo.isNull()) { - /* Unknown frame. Must not happen for AOT-compiled code. */ - throw VMError.shouldNotReachHere("Stack walk must walk only frames of known code."); + @Override + protected boolean visitFrame(Pointer sp, CodePointer ip, CodeInfo codeInfo, DeoptimizedFrame deoptimizedFrame) { + if (deoptimizedFrame != null) { + for (DeoptimizedFrame.VirtualFrame frame = deoptimizedFrame.getTopFrame(); frame != null; frame = frame.getCaller()) { + FrameInfoQueryResult frameInfo = frame.getFrameInfo(); + if (!visitFrameInfo(frameInfo)) { + return false; + } + } + } else if (!isAOTCodePointer(ip)) { + CodeInfoQueryResult queryResult = CodeInfoTable.lookupCodeInfoQueryResult(codeInfo, ip); + for (FrameInfoQueryResult frameInfo = queryResult.getFrameInfo(); frameInfo != null; frameInfo = frameInfo.getCaller()) { + if (!visitFrameInfo(frameInfo)) { + return false; + } + } + } else { + visitAOTFrame(ip); } + return numFrames != limit; + } - Object tether = CodeInfoAccess.acquireTether(untetheredInfo); - try { - CodeInfo tetheredCodeInfo = CodeInfoAccess.convert(untetheredInfo, tether); - if (!visitFrame(visitor, ip, tetheredCodeInfo)) { - return true; - } - } finally { - CodeInfoAccess.releaseTether(untetheredInfo, tether); + private void visitAOTFrame(CodePointer ip) { + long rawValue = ip.rawValue(); + VMError.guarantee(rawValue != 0, "Unexpected code pointer: 0"); + VMError.guarantee(!isSourceReference(rawValue), "Not a code pointer: 0x%x", rawValue); + ensureSize(index + 1); + trace[index++] = rawValue; + numFrames++; + } + + private boolean visitFrameInfo(FrameInfoQueryResult frameInfo) { + if (!StackTraceUtils.shouldShowFrame(frameInfo, false, true, false)) { + /* Always ignore the frame. It is an internal frame of the VM. */ + return true; + + } else if (index == 0 && Throwable.class.isAssignableFrom(frameInfo.getSourceClass())) { + /* + * We are still in the constructor invocation chain at the beginning of the stack trace, + * which is also filtered by the Java HotSpot VM. + */ + return true; } - return false; + int sourceLineNumber = frameInfo.getSourceLineNumber(); + Class sourceClass = frameInfo.getSourceClass(); + String sourceMethodName = frameInfo.getSourceMethodName(); + + VMError.guarantee(Heap.getHeap().isInImageHeap(sourceClass), "Source class must be in the image heap"); + VMError.guarantee(Heap.getHeap().isInImageHeap(sourceMethodName), "Source method name string must be in the image heap"); + + ensureSize(index + MAX_ENTRIES_PER_FRAME); + index += writeSourceReference(trace, index, sourceLineNumber, sourceClass, sourceMethodName); + numFrames++; + return numFrames != limit; } - @Uninterruptible(reason = "Wraps the now safe call to the possibly interruptible visitor.", callerMustBe = true, calleeMustBe = false) - private static boolean visitFrame(BuildStackTraceVisitor visitor, CodePointer ip, CodeInfo tetheredCodeInfo) { - return visitor.visitFrame(WordFactory.nullPointer(), ip, tetheredCodeInfo, null); + /** + * Determines whether a {@link CodePointer} refers to AOT compiled code that is stored in the + * image heap and therefore cannot be garbage collected. + */ + public static boolean isAOTCodePointer(CodePointer ip) { + return CodeInfoAccess.contains(CodeInfoTable.getImageCodeInfo(), ip); } - @Override - protected boolean visitFrame(Pointer sp, CodePointer ip, CodeInfo codeInfo, DeoptimizedFrame deoptimizedFrame) { - VMError.guarantee(deoptimizedFrame == null, "Deoptimization not supported"); - long rawValue = ip.rawValue(); - VMError.guarantee(rawValue != 0, "Unexpected code pointer: 0"); - add(rawValue); - return index != limit; + /** + * Determines whether an entry in the {@link Target_java_lang_Throwable#backtrace} array is a + * source reference, as written by {@link #writeSourceReference}. + * + * @implNote A source reference entry has their high bit set, i.e., it is a negative number in + * the tows complement representation (see {@link #encodeLineNumber}). + * @see #writeSourceReference + * @see #encodeLineNumber + */ + public static boolean isSourceReference(long entry) { + return entry < 0; + } + + /** + * Encodes line number information of a source reference to be stored in the + * {@link Target_java_lang_Throwable#backtrace} array. Line numbers can be positive for regular + * line number, or zero or negative for to mark special source references. + * + * @implNote A line number ({@code int}) is stored as a negative {@code long} value to + * distinguish it from an ordinary {@link CodePointer}. + * + * @see #isSourceReference + */ + public static long encodeLineNumber(int lineNumber) { + return 0xffffffff_00000000L | lineNumber; + } + + /** + * Decodes a line number previously encoded by {@link #encodeLineNumber}. + */ + public static int decodeLineNumber(long entry) { + return (int) entry; } - private void add(long value) { - if (index == trace.length) { - trace = Arrays.copyOf(trace, Math.min(trace.length * 2, limit)); + /** + * Writes source reference to a backtrace array. + * + * @return the numbers of elements written + */ + static int writeSourceReference(long[] backtrace, int pos, int sourceLineNumber, Class sourceClass, String sourceMethodName) { + long encodedLineNumber = encodeLineNumber(sourceLineNumber); + VMError.guarantee(isSourceReference(encodedLineNumber), "Encoded line number looks like a code pointer: %s", encodedLineNumber); + backtrace[pos] = encodedLineNumber; + if (useCompressedReferences()) { + long sourceClassOop = assertNonZero(ReferenceAccess.singleton().getCompressedRepresentation(sourceClass).rawValue()); + long sourceMethodNameOop = assertNonZero(ReferenceAccess.singleton().getCompressedRepresentation(sourceMethodName).rawValue()); + backtrace[pos + 1] = (sourceClassOop << 32) | (0xfffffffL & sourceMethodNameOop); + } else { + backtrace[pos + 1] = assertNonZero(Word.objectToUntrackedPointer(sourceClass).rawValue()); + backtrace[pos + 2] = assertNonZero(Word.objectToUntrackedPointer(sourceMethodName).rawValue()); + } + return MAX_ENTRIES_PER_FRAME; + } + + /** + * Return the source line number of a source reference entry created by + * {@link #writeSourceReference}. + * + * @param backtrace the backtrace array + * @param pos the start position of the source reference entry + * @return the source line number + */ + static int readSourceLineNumber(long[] backtrace, int pos) { + return BacktraceVisitor.decodeLineNumber(backtrace[pos]); + } + + /** + * Return the source class of a source reference entry created by {@link #writeSourceReference}. + * + * @param backtrace the backtrace array + * @param pos the start position of the source reference entry + * @return the source class + */ + static Class readSourceClass(long[] backtrace, int pos) { + if (useCompressedReferences()) { + UnsignedWord ref = WordFactory.unsigned(backtrace[pos + 1]).unsignedShiftRight(32); + return (Class) ReferenceAccess.singleton().uncompressReference(ref); + } else { + Word sourceClassPtr = WordFactory.pointer(backtrace[pos + 1]); + return sourceClassPtr.toObject(Class.class, true); + } + } + + /** + * Return the source method name of a source reference entry created by + * {@link #writeSourceReference}. + * + * @param backtrace the backtrace array + * @param pos the start position of the source reference entry + * @return the source method name + */ + static String readSourceMethodName(long[] backtrace, int pos) { + if (useCompressedReferences()) { + UnsignedWord ref = WordFactory.unsigned(backtrace[pos + 1]).and(WordFactory.unsigned(0xffffffffL)); + return (String) ReferenceAccess.singleton().uncompressReference(ref); + } else { + Word sourceMethodNamePtr = WordFactory.pointer(backtrace[pos + 2]); + return sourceMethodNamePtr.toObject(String.class, true); + } + } + + /** + * Determines whether compressed references are enabled. If so, two references can be packed in + * a single {@code long} entry. + */ + @Fold + static boolean useCompressedReferences() { + return ReferenceAccess.singleton().getCompressEncoding().hasShift(); + } + + private static long assertNonZero(long rawValue) { + VMError.guarantee(rawValue != 0, "Must not write 0 values to backtrace"); + return rawValue; + } + + private void ensureSize(int minLength) { + if (minLength > trace.length) { + trace = Arrays.copyOf(trace, saturatedMultiply(trace.length, 2)); + } + } + + static int saturatedMultiply(int a, int b) { + long r = (long) a * (long) b; + if ((int) r != r) { + return Integer.MAX_VALUE; } - trace[index++] = value; + return (int) r; } /** From 5230eed715b3ae102ba3e062614defc688290869 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 23 May 2023 15:30:08 +0200 Subject: [PATCH 04/16] svm: avoid VMError.guarantee with format string --- .../src/com/oracle/svm/core/jdk/StackTraceUtils.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index 902bb396b675..61ae6460a8a5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -332,7 +332,9 @@ protected boolean visitFrame(Pointer sp, CodePointer ip, CodeInfo codeInfo, Deop private void visitAOTFrame(CodePointer ip) { long rawValue = ip.rawValue(); VMError.guarantee(rawValue != 0, "Unexpected code pointer: 0"); - VMError.guarantee(!isSourceReference(rawValue), "Not a code pointer: 0x%x", rawValue); + if (isSourceReference(rawValue)) { + throw VMError.shouldNotReachHere("Not a code pointer: 0x" + Long.toHexString(rawValue)); + } ensureSize(index + 1); trace[index++] = rawValue; numFrames++; @@ -412,7 +414,9 @@ public static int decodeLineNumber(long entry) { */ static int writeSourceReference(long[] backtrace, int pos, int sourceLineNumber, Class sourceClass, String sourceMethodName) { long encodedLineNumber = encodeLineNumber(sourceLineNumber); - VMError.guarantee(isSourceReference(encodedLineNumber), "Encoded line number looks like a code pointer: %s", encodedLineNumber); + if (!isSourceReference(encodedLineNumber)) { + throw VMError.shouldNotReachHere("Encoded line number looks like a code pointer: " + encodedLineNumber); + } backtrace[pos] = encodedLineNumber; if (useCompressedReferences()) { long sourceClassOop = assertNonZero(ReferenceAccess.singleton().getCompressedRepresentation(sourceClass).rawValue()); From eff75a1c4fb8ae583e8ed33fcf923b0df2de7a73 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 31 May 2023 11:50:13 +0200 Subject: [PATCH 05/16] svm: make BacktraceDecoder more readable --- .../src/com/oracle/svm/core/jdk/BacktraceDecoder.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java index 20fec016f433..38a28bccbb51 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java @@ -63,11 +63,14 @@ protected final int visitBacktrace(Object backtrace, int maxFramesProcessed, int if (BacktraceVisitor.isSourceReference(entry)) { /* Entry is an encoded source reference. */ VMError.guarantee(backtraceIndex + BacktraceVisitor.MAX_ENTRIES_PER_FRAME <= trace.length, "Truncated backtrace array"); - backtraceIndex += visitSourceReference(maxFramesProcessed, framesDecoded, trace, backtraceIndex); + visitSourceReference(maxFramesProcessed, framesDecoded, trace, backtraceIndex); + /* Always a single frame. */ framesDecoded++; + backtraceIndex += BacktraceVisitor.MAX_ENTRIES_PER_FRAME; } else { /* Entry is a raw code pointer. */ CodePointer ip = WordFactory.pointer(entry); + /* Arbitrary number of Java frames for a single native frame (inlining). */ framesDecoded = visitCodePointer(ip, framesDecoded, maxFramesProcessed, maxFramesDecodeLimit); backtraceIndex++; } @@ -79,7 +82,7 @@ protected final int visitBacktrace(Object backtrace, int maxFramesProcessed, int return framesDecoded - maxFramesProcessed; } - private int visitSourceReference(int maxFramesProcessed, int framesDecoded, long[] trace, int backtraceIndex) { + private void visitSourceReference(int maxFramesProcessed, int framesDecoded, long[] trace, int backtraceIndex) { int sourceLineNumber = BacktraceVisitor.readSourceLineNumber(trace, backtraceIndex); Class sourceClass = BacktraceVisitor.readSourceClass(trace, backtraceIndex); String sourceMethodName = BacktraceVisitor.readSourceMethodName(trace, backtraceIndex); @@ -87,7 +90,6 @@ private int visitSourceReference(int maxFramesProcessed, int framesDecoded, long if (framesDecoded < maxFramesProcessed) { processSourceReference(sourceClass, sourceMethodName, sourceLineNumber); } - return BacktraceVisitor.MAX_ENTRIES_PER_FRAME; } @Uninterruptible(reason = "Prevent the GC from freeing the CodeInfo object.") From 936b7bff953979c568a0142ff43b7fbd7e925886 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 31 May 2023 13:56:06 +0200 Subject: [PATCH 06/16] svm: make BacktraceVisitor more readable --- .../oracle/svm/core/jdk/StackTraceUtils.java | 78 +++++++++++++++++-- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index 61ae6460a8a5..8fa39d10d11e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -260,6 +260,67 @@ protected void operate() { /** * Visits the stack frames and collects a backtrace in an internal format to be stored in * {@link Target_java_lang_Throwable#backtrace}. + * + * The {@link Target_java_lang_Throwable#backtrace} is a {@code long} array that either stores a + * native instruction pointer (for AOT compiled methods) or an encoded Java source reference + * containing a source line number, a source class and a source method name (for JIT compiled + * methods). A native instruction pointer is always a single {@code long} element, while an encoded + * Java source reference takes {@linkplain #MAX_ENTRIES_PER_FRAME 2 elements} if references are + * {@link #useCompressedReferences() compressed}, or 3 otherwise. Native instruction pointers and + * source references can be mixed. The source line number of the source reference is + * {@linkplain #encodeLineNumber encoded} in a way that it can be distinguished from a native + * instruction pointer. + * + *

Uncompressed References

+ * + *
+ *                      backtrace content      |   Number of Java frames
+ *                    ---------------------------------------------------
+ * backtrace[pos + 0] | native inst. pointer   |   X Java frames
+ *                    --------------------------
+ * backtrace[pos + 1] | native inst. pointer   |   Y Java frames
+ *                    --------------------------
+ * backtrace[pos + 2] | encoded src line nr    |   1 Java frame
+ * backtrace[pos + 3] | source class ref       |
+ * backtrace[pos + 4] | source method name ref |
+ *                    --------------------------
+ * backtrace[pos + 5] | encoded src line nr    |   1 Java frame
+ * backtrace[pos + 6] | source class ref       |
+ * backtrace[pos + 7] | source method name ref |
+ *                    --------------------------
+ * backtrace[pos + 8] | native inst. pointer   |   Z Java frames
+ *                    --------------------------
+ *                    | ... remaining          |
+ *                    --------------------------
+ *                    | 0                      |   0 terminated if not all elements are used
+ * 
+ * + *

Compressed References

+ * + *
+ *                      backtrace content                                   |   Number of Java frames
+ *                    --------------------------------------------------------------------------------
+ * backtrace[pos + 0] | native inst. pointer                                |   X Java frames
+ *                    -------------------------------------------------------
+ * backtrace[pos + 1] | native inst. pointer                                |   Y Java frames
+ *                    -------------------------------------------------------
+ * backtrace[pos + 2] | encoded src line nr                                 |   1 Java frame
+ * backtrace[pos + 3] | (source class ref) << 32 | (source method name ref) |
+ *                    -------------------------------------------------------
+ * backtrace[pos + 4] | encoded src line nr                                 |   1 Java frame
+ * backtrace[pos + 5] | (source class ref) << 32 | (source method name ref) |
+ *                    -------------------------------------------------------
+ * backtrace[pos + 5] | native inst. pointer                                |   Z Java frames
+ *                    -------------------------------------------------------
+ *                    | ... remaining                                       |
+ *                    -------------------------------------------------------
+ *                    | 0                                                   |   0 terminated if not all elements are used
+ * 
+ * + * @see #writeSourceReference writes the source references into the backtrace array + * @see #visitAOTFrame writes a native instruction pointer into the backtrace array + * @see BacktraceDecoder decodes the backtrace array + * */ final class BacktraceVisitor extends StackFrameVisitor { @@ -360,7 +421,8 @@ private boolean visitFrameInfo(FrameInfoQueryResult frameInfo) { VMError.guarantee(Heap.getHeap().isInImageHeap(sourceMethodName), "Source method name string must be in the image heap"); ensureSize(index + MAX_ENTRIES_PER_FRAME); - index += writeSourceReference(trace, index, sourceLineNumber, sourceClass, sourceMethodName); + writeSourceReference(trace, index, sourceLineNumber, sourceClass, sourceMethodName); + index += MAX_ENTRIES_PER_FRAME; numFrames++; return numFrames != limit; } @@ -410,9 +472,12 @@ public static int decodeLineNumber(long entry) { /** * Writes source reference to a backtrace array. * - * @return the numbers of elements written + * @see #readSourceLineNumber + * @see #readSourceClass + * @see #readSourceMethodName */ - static int writeSourceReference(long[] backtrace, int pos, int sourceLineNumber, Class sourceClass, String sourceMethodName) { + static void writeSourceReference(long[] backtrace, int pos, int sourceLineNumber, Class sourceClass, String sourceMethodName) { + // TODO document frame format long encodedLineNumber = encodeLineNumber(sourceLineNumber); if (!isSourceReference(encodedLineNumber)) { throw VMError.shouldNotReachHere("Encoded line number looks like a code pointer: " + encodedLineNumber); @@ -421,12 +486,13 @@ static int writeSourceReference(long[] backtrace, int pos, int sourceLineNumber, if (useCompressedReferences()) { long sourceClassOop = assertNonZero(ReferenceAccess.singleton().getCompressedRepresentation(sourceClass).rawValue()); long sourceMethodNameOop = assertNonZero(ReferenceAccess.singleton().getCompressedRepresentation(sourceMethodName).rawValue()); - backtrace[pos + 1] = (sourceClassOop << 32) | (0xfffffffL & sourceMethodNameOop); + VMError.guarantee((0xffffffff_00000000L & sourceClassOop) == 0L, "Compressed source class reference with high bits"); + VMError.guarantee((0xffffffff_00000000L & sourceMethodNameOop) == 0L, "Compressed source methode name reference with high bits"); + backtrace[pos + 1] = (sourceClassOop << 32) | sourceMethodNameOop; } else { backtrace[pos + 1] = assertNonZero(Word.objectToUntrackedPointer(sourceClass).rawValue()); backtrace[pos + 2] = assertNonZero(Word.objectToUntrackedPointer(sourceMethodName).rawValue()); } - return MAX_ENTRIES_PER_FRAME; } /** @@ -436,6 +502,8 @@ static int writeSourceReference(long[] backtrace, int pos, int sourceLineNumber, * @param backtrace the backtrace array * @param pos the start position of the source reference entry * @return the source line number + * + * @see #writeSourceReference */ static int readSourceLineNumber(long[] backtrace, int pos) { return BacktraceVisitor.decodeLineNumber(backtrace[pos]); From 1ef3ab58fe05e9dbe91ef54e8e94c377c962c1f1 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 31 May 2023 14:02:08 +0200 Subject: [PATCH 07/16] svm: eliminate dead code in fillInStackTrace if deoptimization is disabled --- .../src/com/oracle/svm/core/jdk/BacktraceDecoder.java | 4 +++- .../src/com/oracle/svm/core/jdk/StackTraceUtils.java | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java index 38a28bccbb51..804dd0388732 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java @@ -34,6 +34,7 @@ import com.oracle.svm.core.code.CodeInfoTable; import com.oracle.svm.core.code.FrameInfoQueryResult; import com.oracle.svm.core.code.UntetheredCodeInfo; +import com.oracle.svm.core.deopt.DeoptimizationSupport; import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.util.VMError; @@ -60,7 +61,7 @@ protected final int visitBacktrace(Object backtrace, int maxFramesProcessed, int int backtraceIndex = 0; while (backtraceIndex < trace.length && trace[backtraceIndex] != 0) { long entry = trace[backtraceIndex]; - if (BacktraceVisitor.isSourceReference(entry)) { + if (DeoptimizationSupport.enabled() && BacktraceVisitor.isSourceReference(entry)) { /* Entry is an encoded source reference. */ VMError.guarantee(backtraceIndex + BacktraceVisitor.MAX_ENTRIES_PER_FRAME <= trace.length, "Truncated backtrace array"); visitSourceReference(maxFramesProcessed, framesDecoded, trace, backtraceIndex); @@ -68,6 +69,7 @@ protected final int visitBacktrace(Object backtrace, int maxFramesProcessed, int framesDecoded++; backtraceIndex += BacktraceVisitor.MAX_ENTRIES_PER_FRAME; } else { + VMError.guarantee(!BacktraceVisitor.isSourceReference(entry), "Unexpected source reference"); /* Entry is a raw code pointer. */ CodePointer ip = WordFactory.pointer(entry); /* Arbitrary number of Java frames for a single native frame (inlining). */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index 8fa39d10d11e..96579995ff68 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -49,7 +49,9 @@ import com.oracle.svm.core.code.CodeInfoQueryResult; import com.oracle.svm.core.code.CodeInfoTable; import com.oracle.svm.core.code.FrameInfoQueryResult; +import com.oracle.svm.core.deopt.DeoptimizationSupport; import com.oracle.svm.core.deopt.DeoptimizedFrame; +import com.oracle.svm.core.graal.RuntimeCompilation; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.heap.VMOperationInfos; @@ -370,14 +372,14 @@ private static int computeNativeLimit() { @Override protected boolean visitFrame(Pointer sp, CodePointer ip, CodeInfo codeInfo, DeoptimizedFrame deoptimizedFrame) { - if (deoptimizedFrame != null) { + if (DeoptimizationSupport.enabled() && deoptimizedFrame != null) { for (DeoptimizedFrame.VirtualFrame frame = deoptimizedFrame.getTopFrame(); frame != null; frame = frame.getCaller()) { FrameInfoQueryResult frameInfo = frame.getFrameInfo(); if (!visitFrameInfo(frameInfo)) { return false; } } - } else if (!isAOTCodePointer(ip)) { + } else if (RuntimeCompilation.isEnabled() && !isAOTCodePointer(ip)) { CodeInfoQueryResult queryResult = CodeInfoTable.lookupCodeInfoQueryResult(codeInfo, ip); for (FrameInfoQueryResult frameInfo = queryResult.getFrameInfo(); frameInfo != null; frameInfo = frameInfo.getCaller()) { if (!visitFrameInfo(frameInfo)) { @@ -385,6 +387,8 @@ protected boolean visitFrame(Pointer sp, CodePointer ip, CodeInfo codeInfo, Deop } } } else { + VMError.guarantee(deoptimizedFrame == null, "deoptimizedFrame non-null"); + VMError.guarantee(isAOTCodePointer(ip), "Trying to store native instruction pointer of a JIT method"); visitAOTFrame(ip); } return numFrames != limit; From 27a1cc8648b5e358ce25b2581acea314853c0222 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 31 May 2023 14:06:35 +0200 Subject: [PATCH 08/16] svm: disable Throwable#getOurStackTrace in TruffleFeature --- .../src/com/oracle/svm/truffle/TruffleFeature.java | 1 + 1 file changed, 1 insertion(+) diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java index 70ef4882f9a2..a9feffc28088 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java @@ -583,6 +583,7 @@ private void initializeMethodBlocklist(MetaAccessProvider metaAccess, FeatureAcc blocklistMethod(metaAccess, Throwable.class, "fillInStackTrace"); // Implementations which don't call Throwable.fillInStackTrace are allowed implementationOnlyBlocklist(metaAccess, Throwable.class, "fillInStackTrace"); + blocklistMethod(metaAccess, Throwable.class, "getOurStackTrace"); blocklistMethod(metaAccess, Throwable.class, "initCause", Throwable.class); blocklistMethod(metaAccess, Throwable.class, "addSuppressed", Throwable.class); blocklistMethod(metaAccess, System.class, "getProperty", String.class); From 6cd7b7a6e7cbe9981c6182a65f7d602512b79ee0 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 31 May 2023 14:26:10 +0200 Subject: [PATCH 09/16] svm: fix style issues --- .../src/com/oracle/svm/core/jdk/StackTraceUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index 96579995ff68..4c888498c4b6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -327,7 +327,7 @@ protected void operate() { final class BacktraceVisitor extends StackFrameVisitor { /** - * Index into {@link #trace} + * Index into {@link #trace}. */ private int index = 0; From 6b4862c74e2be0200f353bcfde9fb8ee962c6cc3 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 2 Jun 2023 06:15:12 +0000 Subject: [PATCH 10/16] svm: remove left-over TODO from StackTraceUtils.java --- .../src/com/oracle/svm/core/jdk/StackTraceUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index 4c888498c4b6..d0e316870f3b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -481,7 +481,6 @@ public static int decodeLineNumber(long entry) { * @see #readSourceMethodName */ static void writeSourceReference(long[] backtrace, int pos, int sourceLineNumber, Class sourceClass, String sourceMethodName) { - // TODO document frame format long encodedLineNumber = encodeLineNumber(sourceLineNumber); if (!isSourceReference(encodedLineNumber)) { throw VMError.shouldNotReachHere("Encoded line number looks like a code pointer: " + encodedLineNumber); From aad71dd26729651e0ae82e201a8a35526a66bf03 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Mon, 5 Jun 2023 07:51:41 +0200 Subject: [PATCH 11/16] svm: update Javadoc in fillInStackTrace code --- .../oracle/svm/core/jdk/StackTraceUtils.java | 36 ++++++------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index d0e316870f3b..62c59246d3b3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -278,19 +278,11 @@ protected void operate() { *
  *                      backtrace content      |   Number of Java frames
  *                    ---------------------------------------------------
- * backtrace[pos + 0] | native inst. pointer   |   X Java frames
+ * backtrace[pos + 0] | native inst. pointer   |   0..n Java frames
  *                    --------------------------
- * backtrace[pos + 1] | native inst. pointer   |   Y Java frames
- *                    --------------------------
- * backtrace[pos + 2] | encoded src line nr    |   1 Java frame
- * backtrace[pos + 3] | source class ref       |
- * backtrace[pos + 4] | source method name ref |
- *                    --------------------------
- * backtrace[pos + 5] | encoded src line nr    |   1 Java frame
- * backtrace[pos + 6] | source class ref       |
- * backtrace[pos + 7] | source method name ref |
- *                    --------------------------
- * backtrace[pos + 8] | native inst. pointer   |   Z Java frames
+ * backtrace[pos + 1] | encoded src line nr    |   1 Java frame
+ * backtrace[pos + 2] | source class ref       |
+ * backtrace[pos + 3] | source method name ref |
  *                    --------------------------
  *                    | ... remaining          |
  *                    --------------------------
@@ -302,17 +294,10 @@ protected void operate() {
  * 
  *                      backtrace content                                   |   Number of Java frames
  *                    --------------------------------------------------------------------------------
- * backtrace[pos + 0] | native inst. pointer                                |   X Java frames
- *                    -------------------------------------------------------
- * backtrace[pos + 1] | native inst. pointer                                |   Y Java frames
- *                    -------------------------------------------------------
- * backtrace[pos + 2] | encoded src line nr                                 |   1 Java frame
- * backtrace[pos + 3] | (source class ref) << 32 | (source method name ref) |
- *                    -------------------------------------------------------
- * backtrace[pos + 4] | encoded src line nr                                 |   1 Java frame
- * backtrace[pos + 5] | (source class ref) << 32 | (source method name ref) |
+ * backtrace[pos + 0] | native inst. pointer                                |   0..n Java frames
  *                    -------------------------------------------------------
- * backtrace[pos + 5] | native inst. pointer                                |   Z Java frames
+ * backtrace[pos + 1] | encoded src line nr                                 |   1 Java frame
+ * backtrace[pos + 2] | (source class ref) << 32 | (source method name ref) |
  *                    -------------------------------------------------------
  *                    | ... remaining                                       |
  *                    -------------------------------------------------------
@@ -332,8 +317,9 @@ final class BacktraceVisitor extends StackFrameVisitor {
     private int index = 0;
 
     /**
-     * Number of frames stored (native or Java frames). Because Java frames take up more than one
-     * entry in {@link #trace} this number might be different to {@link #index}.
+     * Number of frames stored (native instruction pointers or encoded Java source reference).
+     * Because Java frames take up more than one entry in {@link #trace} this number might be
+     * different to {@link #index}.
      */
     private int numFrames = 0;
     private final int limit = computeNativeLimit();
@@ -444,7 +430,7 @@ public static boolean isAOTCodePointer(CodePointer ip) {
      * source reference, as written by {@link #writeSourceReference}.
      *
      * @implNote A source reference entry has their high bit set, i.e., it is a negative number in
-     *           the tows complement representation (see {@link #encodeLineNumber}).
+     *           the two's complement representation (see {@link #encodeLineNumber}).
      * @see #writeSourceReference
      * @see #encodeLineNumber
      */

From 66f2e8f502399db35daf930c0a23de932f7496d3 Mon Sep 17 00:00:00 2001
From: Josef Eisl 
Date: Tue, 6 Jun 2023 14:11:27 +0200
Subject: [PATCH 12/16] svm: use getReferenceSize to check for compressed
 reference

---
 .../src/com/oracle/svm/core/jdk/StackTraceUtils.java           | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
index 62c59246d3b3..4cea1c5c0ec0 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
@@ -49,6 +49,7 @@
 import com.oracle.svm.core.code.CodeInfoQueryResult;
 import com.oracle.svm.core.code.CodeInfoTable;
 import com.oracle.svm.core.code.FrameInfoQueryResult;
+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.graal.RuntimeCompilation;
@@ -539,7 +540,7 @@ static String readSourceMethodName(long[] backtrace, int pos) {
      */
     @Fold
     static boolean useCompressedReferences() {
-        return ReferenceAccess.singleton().getCompressEncoding().hasShift();
+        return ConfigurationValues.getObjectLayout().getReferenceSize() == 4;
     }
 
     private static long assertNonZero(long rawValue) {

From f41d2963a51619b9cf4e5340b13b5f63052ca65f Mon Sep 17 00:00:00 2001
From: Josef Eisl 
Date: Tue, 6 Jun 2023 14:12:31 +0200
Subject: [PATCH 13/16] svm: rename MAX_ENTRIES_PER_FRAME to
 ENTRIES_PER_SOURCE_REFERENCE

---
 .../com/oracle/svm/core/jdk/BacktraceDecoder.java    |  4 ++--
 .../src/com/oracle/svm/core/jdk/StackTraceUtils.java | 12 ++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java
index 804dd0388732..e585c257ceb9 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java
@@ -63,11 +63,11 @@ protected final int visitBacktrace(Object backtrace, int maxFramesProcessed, int
                 long entry = trace[backtraceIndex];
                 if (DeoptimizationSupport.enabled() && BacktraceVisitor.isSourceReference(entry)) {
                     /* Entry is an encoded source reference. */
-                    VMError.guarantee(backtraceIndex + BacktraceVisitor.MAX_ENTRIES_PER_FRAME <= trace.length, "Truncated backtrace array");
+                    VMError.guarantee(backtraceIndex + BacktraceVisitor.ENTRIES_PER_SOURCE_REFERENCE <= trace.length, "Truncated backtrace array");
                     visitSourceReference(maxFramesProcessed, framesDecoded, trace, backtraceIndex);
                     /* Always a single frame. */
                     framesDecoded++;
-                    backtraceIndex += BacktraceVisitor.MAX_ENTRIES_PER_FRAME;
+                    backtraceIndex += BacktraceVisitor.ENTRIES_PER_SOURCE_REFERENCE;
                 } else {
                     VMError.guarantee(!BacktraceVisitor.isSourceReference(entry), "Unexpected source reference");
                     /* Entry is a raw code pointer. */
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
index 4cea1c5c0ec0..b42ac77a91d3 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
@@ -268,9 +268,9 @@ protected void operate() {
  * native instruction pointer (for AOT compiled methods) or an encoded Java source reference
  * containing a source line number, a source class and a source method name (for JIT compiled
  * methods). A native instruction pointer is always a single {@code long} element, while an encoded
- * Java source reference takes {@linkplain #MAX_ENTRIES_PER_FRAME 2 elements} if references are
- * {@link #useCompressedReferences() compressed}, or 3 otherwise. Native instruction pointers and
- * source references can be mixed. The source line number of the source reference is
+ * Java source reference takes {@linkplain #ENTRIES_PER_SOURCE_REFERENCE 2 elements} if references
+ * are {@link #useCompressedReferences() compressed}, or 3 otherwise. Native instruction pointers
+ * and source references can be mixed. The source line number of the source reference is
  * {@linkplain #encodeLineNumber encoded} in a way that it can be distinguished from a native
  * instruction pointer.
  *
@@ -333,7 +333,7 @@ final class BacktraceVisitor extends StackFrameVisitor {
     private long[] trace = new long[INITIAL_TRACE_SIZE];
 
     public static final int NATIVE_FRAME_LIMIT_MARGIN = 10;
-    static final int MAX_ENTRIES_PER_FRAME = useCompressedReferences() ? 2 : 3;
+    static final int ENTRIES_PER_SOURCE_REFERENCE = useCompressedReferences() ? 2 : 3;
 
     /**
      * Gets the number of native frames to collect. Native frames and Java frames do not directly
@@ -411,9 +411,9 @@ private boolean visitFrameInfo(FrameInfoQueryResult frameInfo) {
         VMError.guarantee(Heap.getHeap().isInImageHeap(sourceClass), "Source class must be in the image heap");
         VMError.guarantee(Heap.getHeap().isInImageHeap(sourceMethodName), "Source method name string must be in the image heap");
 
-        ensureSize(index + MAX_ENTRIES_PER_FRAME);
+        ensureSize(index + ENTRIES_PER_SOURCE_REFERENCE);
         writeSourceReference(trace, index, sourceLineNumber, sourceClass, sourceMethodName);
-        index += MAX_ENTRIES_PER_FRAME;
+        index += ENTRIES_PER_SOURCE_REFERENCE;
         numFrames++;
         return numFrames != limit;
     }

From c4c79089af503a9837a1481d25240d82f2ba9929 Mon Sep 17 00:00:00 2001
From: Josef Eisl 
Date: Tue, 6 Jun 2023 14:19:18 +0200
Subject: [PATCH 14/16] svm: replace ENTRIES_PER_SOURCE_REFERENCE with
 entriesPerSourceReference()

---
 .../com/oracle/svm/core/jdk/BacktraceDecoder.java    |  4 ++--
 .../src/com/oracle/svm/core/jdk/StackTraceUtils.java | 12 ++++++++----
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java
index e585c257ceb9..e1f286775694 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java
@@ -63,11 +63,11 @@ protected final int visitBacktrace(Object backtrace, int maxFramesProcessed, int
                 long entry = trace[backtraceIndex];
                 if (DeoptimizationSupport.enabled() && BacktraceVisitor.isSourceReference(entry)) {
                     /* Entry is an encoded source reference. */
-                    VMError.guarantee(backtraceIndex + BacktraceVisitor.ENTRIES_PER_SOURCE_REFERENCE <= trace.length, "Truncated backtrace array");
+                    VMError.guarantee(backtraceIndex + BacktraceVisitor.entriesPerSourceReference() <= trace.length, "Truncated backtrace array");
                     visitSourceReference(maxFramesProcessed, framesDecoded, trace, backtraceIndex);
                     /* Always a single frame. */
                     framesDecoded++;
-                    backtraceIndex += BacktraceVisitor.ENTRIES_PER_SOURCE_REFERENCE;
+                    backtraceIndex += BacktraceVisitor.entriesPerSourceReference();
                 } else {
                     VMError.guarantee(!BacktraceVisitor.isSourceReference(entry), "Unexpected source reference");
                     /* Entry is a raw code pointer. */
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
index b42ac77a91d3..0314054aac24 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
@@ -268,7 +268,7 @@ protected void operate() {
  * native instruction pointer (for AOT compiled methods) or an encoded Java source reference
  * containing a source line number, a source class and a source method name (for JIT compiled
  * methods). A native instruction pointer is always a single {@code long} element, while an encoded
- * Java source reference takes {@linkplain #ENTRIES_PER_SOURCE_REFERENCE 2 elements} if references
+ * Java source reference takes {@linkplain #entriesPerSourceReference() 2 elements} if references
  * are {@link #useCompressedReferences() compressed}, or 3 otherwise. Native instruction pointers
  * and source references can be mixed. The source line number of the source reference is
  * {@linkplain #encodeLineNumber encoded} in a way that it can be distinguished from a native
@@ -333,7 +333,11 @@ final class BacktraceVisitor extends StackFrameVisitor {
     private long[] trace = new long[INITIAL_TRACE_SIZE];
 
     public static final int NATIVE_FRAME_LIMIT_MARGIN = 10;
-    static final int ENTRIES_PER_SOURCE_REFERENCE = useCompressedReferences() ? 2 : 3;
+
+    @Fold
+    static int entriesPerSourceReference() {
+        return useCompressedReferences() ? 2 : 3;
+    }
 
     /**
      * Gets the number of native frames to collect. Native frames and Java frames do not directly
@@ -411,9 +415,9 @@ private boolean visitFrameInfo(FrameInfoQueryResult frameInfo) {
         VMError.guarantee(Heap.getHeap().isInImageHeap(sourceClass), "Source class must be in the image heap");
         VMError.guarantee(Heap.getHeap().isInImageHeap(sourceMethodName), "Source method name string must be in the image heap");
 
-        ensureSize(index + ENTRIES_PER_SOURCE_REFERENCE);
+        ensureSize(index + entriesPerSourceReference());
         writeSourceReference(trace, index, sourceLineNumber, sourceClass, sourceMethodName);
-        index += ENTRIES_PER_SOURCE_REFERENCE;
+        index += entriesPerSourceReference();
         numFrames++;
         return numFrames != limit;
     }

From bfb06115637c96a524aebddafd70ef9a68626671 Mon Sep 17 00:00:00 2001
From: Josef Eisl 
Date: Fri, 9 Jun 2023 07:46:39 +0200
Subject: [PATCH 15/16] Revert "svm: eliminate dead code in fillInStackTrace if
 deoptimization is disabled"

This reverts commit 1ef3ab58fe05e9dbe91ef54e8e94c377c962c1f1.
---
 .../src/com/oracle/svm/core/jdk/BacktraceDecoder.java     | 4 +---
 .../src/com/oracle/svm/core/jdk/StackTraceUtils.java      | 8 ++------
 2 files changed, 3 insertions(+), 9 deletions(-)

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java
index e1f286775694..ba2e2f4849f0 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java
@@ -34,7 +34,6 @@
 import com.oracle.svm.core.code.CodeInfoTable;
 import com.oracle.svm.core.code.FrameInfoQueryResult;
 import com.oracle.svm.core.code.UntetheredCodeInfo;
-import com.oracle.svm.core.deopt.DeoptimizationSupport;
 import com.oracle.svm.core.heap.RestrictHeapAccess;
 import com.oracle.svm.core.util.VMError;
 
@@ -61,7 +60,7 @@ protected final int visitBacktrace(Object backtrace, int maxFramesProcessed, int
             int backtraceIndex = 0;
             while (backtraceIndex < trace.length && trace[backtraceIndex] != 0) {
                 long entry = trace[backtraceIndex];
-                if (DeoptimizationSupport.enabled() && BacktraceVisitor.isSourceReference(entry)) {
+                if (BacktraceVisitor.isSourceReference(entry)) {
                     /* Entry is an encoded source reference. */
                     VMError.guarantee(backtraceIndex + BacktraceVisitor.entriesPerSourceReference() <= trace.length, "Truncated backtrace array");
                     visitSourceReference(maxFramesProcessed, framesDecoded, trace, backtraceIndex);
@@ -69,7 +68,6 @@ protected final int visitBacktrace(Object backtrace, int maxFramesProcessed, int
                     framesDecoded++;
                     backtraceIndex += BacktraceVisitor.entriesPerSourceReference();
                 } else {
-                    VMError.guarantee(!BacktraceVisitor.isSourceReference(entry), "Unexpected source reference");
                     /* Entry is a raw code pointer. */
                     CodePointer ip = WordFactory.pointer(entry);
                     /* Arbitrary number of Java frames for a single native frame (inlining). */
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
index 0314054aac24..73e22630509d 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java
@@ -50,9 +50,7 @@
 import com.oracle.svm.core.code.CodeInfoTable;
 import com.oracle.svm.core.code.FrameInfoQueryResult;
 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.graal.RuntimeCompilation;
 import com.oracle.svm.core.heap.Heap;
 import com.oracle.svm.core.heap.ReferenceAccess;
 import com.oracle.svm.core.heap.VMOperationInfos;
@@ -363,14 +361,14 @@ private static int computeNativeLimit() {
 
     @Override
     protected boolean visitFrame(Pointer sp, CodePointer ip, CodeInfo codeInfo, DeoptimizedFrame deoptimizedFrame) {
-        if (DeoptimizationSupport.enabled() && deoptimizedFrame != null) {
+        if (deoptimizedFrame != null) {
             for (DeoptimizedFrame.VirtualFrame frame = deoptimizedFrame.getTopFrame(); frame != null; frame = frame.getCaller()) {
                 FrameInfoQueryResult frameInfo = frame.getFrameInfo();
                 if (!visitFrameInfo(frameInfo)) {
                     return false;
                 }
             }
-        } else if (RuntimeCompilation.isEnabled() && !isAOTCodePointer(ip)) {
+        } else if (!isAOTCodePointer(ip)) {
             CodeInfoQueryResult queryResult = CodeInfoTable.lookupCodeInfoQueryResult(codeInfo, ip);
             for (FrameInfoQueryResult frameInfo = queryResult.getFrameInfo(); frameInfo != null; frameInfo = frameInfo.getCaller()) {
                 if (!visitFrameInfo(frameInfo)) {
@@ -378,8 +376,6 @@ protected boolean visitFrame(Pointer sp, CodePointer ip, CodeInfo codeInfo, Deop
                 }
             }
         } else {
-            VMError.guarantee(deoptimizedFrame == null, "deoptimizedFrame non-null");
-            VMError.guarantee(isAOTCodePointer(ip), "Trying to store native instruction pointer of a JIT method");
             visitAOTFrame(ip);
         }
         return numFrames != limit;

From e7f30465de199d54a8d1c07a29063e4ec35fc5dc Mon Sep 17 00:00:00 2001
From: Josef Eisl 
Date: Fri, 9 Jun 2023 13:50:09 +0200
Subject: [PATCH 16/16] Revert "svm: disable Throwable#getOurStackTrace in
 TruffleFeature"

This reverts commit 27a1cc8648b5e358ce25b2581acea314853c0222.
---
 .../src/com/oracle/svm/truffle/TruffleFeature.java               | 1 -
 1 file changed, 1 deletion(-)

diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java
index a9feffc28088..70ef4882f9a2 100644
--- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java
+++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java
@@ -583,7 +583,6 @@ private void initializeMethodBlocklist(MetaAccessProvider metaAccess, FeatureAcc
         blocklistMethod(metaAccess, Throwable.class, "fillInStackTrace");
         // Implementations which don't call Throwable.fillInStackTrace are allowed
         implementationOnlyBlocklist(metaAccess, Throwable.class, "fillInStackTrace");
-        blocklistMethod(metaAccess, Throwable.class, "getOurStackTrace");
         blocklistMethod(metaAccess, Throwable.class, "initCause", Throwable.class);
         blocklistMethod(metaAccess, Throwable.class, "addSuppressed", Throwable.class);
         blocklistMethod(metaAccess, System.class, "getProperty", String.class);