2424 */
2525package com .oracle .svm .core .jdk ;
2626
27+ import static com .oracle .svm .core .snippets .KnownIntrinsics .readCallerStackPointer ;
28+
2729import java .security .AccessControlContext ;
2830import java .security .AccessController ;
2931import java .security .ProtectionDomain ;
3032import java .util .ArrayList ;
3133
3234import org .graalvm .nativeimage .IsolateThread ;
35+ import org .graalvm .nativeimage .c .function .CodePointer ;
3336import org .graalvm .word .Pointer ;
3437
3538import com .oracle .svm .core .SubstrateOptions ;
3639import com .oracle .svm .core .SubstrateUtil ;
3740import com .oracle .svm .core .annotate .NeverInline ;
3841import com .oracle .svm .core .code .FrameInfoQueryResult ;
42+ import com .oracle .svm .core .heap .VMOperationInfos ;
3943import com .oracle .svm .core .snippets .KnownIntrinsics ;
4044import com .oracle .svm .core .stack .JavaStackFrameVisitor ;
4145import com .oracle .svm .core .stack .JavaStackWalker ;
46+ import com .oracle .svm .core .thread .JavaThreads ;
47+ import com .oracle .svm .core .thread .JavaVMOperation ;
4248import com .oracle .svm .core .thread .LoomSupport ;
49+ import com .oracle .svm .core .thread .PlatformThreads ;
50+ import com .oracle .svm .core .thread .Target_java_lang_Thread ;
4351import com .oracle .svm .core .thread .Target_jdk_internal_vm_Continuation ;
52+ import com .oracle .svm .core .thread .VMOperation ;
53+ import com .oracle .svm .core .thread .VirtualThreads ;
4454import com .oracle .svm .util .DirectAnnotationAccess ;
4555
4656import jdk .vm .ci .meta .MetaAccessProvider ;
@@ -53,28 +63,45 @@ public class StackTraceUtils {
5363 private static final StackTraceElement [] NO_ELEMENTS = new StackTraceElement [0 ];
5464
5565 /**
56- * Captures the stack trace of the current thread. Used by {@link Throwable#fillInStackTrace()},
57- * {@link Thread #getStackTrace()}, and {@link Thread#getAllStackTraces ()}.
66+ * Captures the stack trace of the current thread. In almost any context, calling
67+ * {@link JavaThreads #getStackTrace} for {@link Thread#currentThread ()} is preferable .
5868 *
5969 * Captures at most {@link SubstrateOptions#MaxJavaStackTraceDepth} stack trace elements if max
6070 * depth > 0, or all if max depth <= 0.
6171 */
62- public static StackTraceElement [] getStackTrace (boolean filterExceptions , Pointer startSP ) {
72+ public static StackTraceElement [] getStackTrace (boolean filterExceptions , Pointer startSP , Pointer endSP ) {
6373 BuildStackTraceVisitor visitor = new BuildStackTraceVisitor (filterExceptions , SubstrateOptions .MaxJavaStackTraceDepth .getValue ());
64- JavaStackWalker .walkCurrentThread (startSP , visitor );
74+ JavaStackWalker .walkCurrentThread (startSP , endSP , visitor );
6575 return visitor .trace .toArray (NO_ELEMENTS );
6676 }
6777
6878 /**
69- * Captures the stack trace of another thread. Used by {@link Thread#getStackTrace()} and
70- * {@link Thread#getAllStackTraces()}.
79+ * Captures the stack trace of a thread (potentially the current thread) while stopped at a
80+ * safepoint. Used by {@link Thread#getStackTrace()} and {@link Thread#getAllStackTraces()}.
7181 *
7282 * Captures at most {@link SubstrateOptions#MaxJavaStackTraceDepth} stack trace elements if max
7383 * depth > 0, or all if max depth <= 0.
7484 */
75- public static StackTraceElement [] getStackTrace (boolean filterExceptions , IsolateThread thread ) {
76- BuildStackTraceVisitor visitor = new BuildStackTraceVisitor (filterExceptions , SubstrateOptions .MaxJavaStackTraceDepth .getValue ());
77- JavaStackWalker .walkThread (thread , visitor );
85+ @ NeverInline ("Potentially starting a stack walk in the caller frame" )
86+ public static StackTraceElement [] getStackTraceAtSafepoint (Thread thread ) {
87+ assert VMOperation .isInProgressAtSafepoint ();
88+ if (VirtualThreads .isSupported ()) { // NOTE: also for platform threads!
89+ return VirtualThreads .singleton ().getVirtualOrPlatformThreadStackTraceAtSafepoint (thread , readCallerStackPointer ());
90+ }
91+ return PlatformThreads .getStackTraceAtSafepoint (thread , readCallerStackPointer ());
92+ }
93+
94+ public static StackTraceElement [] getThreadStackTraceAtSafepoint (IsolateThread isolateThread , Pointer endSP ) {
95+ assert VMOperation .isInProgressAtSafepoint ();
96+ BuildStackTraceVisitor visitor = new BuildStackTraceVisitor (false , SubstrateOptions .MaxJavaStackTraceDepth .getValue ());
97+ JavaStackWalker .walkThread (isolateThread , endSP , visitor );
98+ return visitor .trace .toArray (NO_ELEMENTS );
99+ }
100+
101+ public static StackTraceElement [] getThreadStackTraceAtSafepoint (Pointer startSP , Pointer endSP , CodePointer startIP ) {
102+ assert VMOperation .isInProgressAtSafepoint ();
103+ BuildStackTraceVisitor visitor = new BuildStackTraceVisitor (false , SubstrateOptions .MaxJavaStackTraceDepth .getValue ());
104+ JavaStackWalker .walkThreadAtSafepoint (startSP , endSP , startIP , visitor );
78105 return visitor .trace .toArray (NO_ELEMENTS );
79106 }
80107
@@ -183,6 +210,31 @@ public static ClassLoader latestUserDefinedClassLoader(Pointer startSP) {
183210 JavaStackWalker .walkCurrentThread (startSP , visitor );
184211 return visitor .result ;
185212 }
213+
214+ public static StackTraceElement [] asyncGetStackTrace (Thread thread ) {
215+ GetStackTraceOperation vmOp = new GetStackTraceOperation (thread );
216+ vmOp .enqueue ();
217+ return vmOp .result ;
218+ }
219+
220+ private static class GetStackTraceOperation extends JavaVMOperation {
221+ private final Thread thread ;
222+ StackTraceElement [] result ;
223+
224+ GetStackTraceOperation (Thread thread ) {
225+ super (VMOperationInfos .get (GetStackTraceOperation .class , "Get stack trace" , SystemEffect .SAFEPOINT ));
226+ this .thread = thread ;
227+ }
228+
229+ @ Override
230+ protected void operate () {
231+ if (thread .isAlive ()) {
232+ result = getStackTraceAtSafepoint (thread );
233+ } else {
234+ result = Target_java_lang_Thread .EMPTY_STACK_TRACE ;
235+ }
236+ }
237+ }
186238}
187239
188240class BuildStackTraceVisitor extends JavaStackFrameVisitor {
0 commit comments