Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
b7bb968
Set target method desc for resumption stubs
jakobbotsch Oct 1, 2025
d5d0864
Add JIT-EE boilerplate
jakobbotsch Oct 1, 2025
d7277fb
Add debug information for runtime async information
jakobbotsch Oct 1, 2025
6addd0e
Update managed view
jakobbotsch Oct 1, 2025
6a5bf19
Remove TODOs
jakobbotsch Oct 1, 2025
262260a
Leaf transition
jakobbotsch Oct 1, 2025
4e2a829
Comment
jakobbotsch Oct 1, 2025
820afa9
Delete unused enum
jakobbotsch Oct 1, 2025
3621eae
Restore comment
jakobbotsch Oct 1, 2025
f597424
Fix osx build
jakobbotsch Oct 1, 2025
6bb6cee
Fix GCC build
jakobbotsch Oct 1, 2025
f580e3f
Change sentinel value, fix contract
jakobbotsch Oct 2, 2025
55b9522
Bump R2R
jakobbotsch Oct 2, 2025
c9c64be
Clean up
jakobbotsch Oct 2, 2025
db77446
Expose async debug info accessor APIs
jakobbotsch Oct 2, 2025
c808390
Missed bumping R2R version for naot
jakobbotsch Oct 2, 2025
3ec5160
Fix reverse mapping to IL local nums
jakobbotsch Oct 2, 2025
bb12c77
Fix monotonicity for async vars
jakobbotsch Oct 2, 2025
bf3364b
Code style
jakobbotsch Oct 2, 2025
b49f38f
Fix JIT-EE prompt tools from Egor's instructions, allow use of experi…
jakobbotsch Oct 2, 2025
d1bf49f
Address feedback, make comment less misleading
jakobbotsch Oct 3, 2025
579714e
Add AsyncContinuationVarInfo.GCIndex
jakobbotsch Oct 6, 2025
c056793
Publish NextContinuation in TLS
jakobbotsch Oct 8, 2025
9679f91
Rename ThunkTask -> RuntimeAsyncTask
jakobbotsch Oct 8, 2025
7a34475
Merge branch 'main' of github.com:dotnet/runtime into jit-async-diagn…
jakobbotsch Oct 9, 2025
e839409
Report native offsets instead
jakobbotsch Oct 9, 2025
d8ad0c1
Run jit-format
jakobbotsch Oct 9, 2025
9fdd8a7
Print reported async debug info, always report it
jakobbotsch Oct 9, 2025
69e02db
Store target IPs in AsyncResumeILStubResolver
jakobbotsch Oct 14, 2025
68c245b
Fix bug
jakobbotsch Oct 14, 2025
2031f08
Remove BBF_INTERNAL from rethrow BB to avoid broken mappings
jakobbotsch Oct 15, 2025
b7576b2
Trampolines for resumption
jakobbotsch Oct 17, 2025
03f85ec
Merge branch 'main' of github.com:dotnet/runtime into jit-async-diagn…
jakobbotsch Oct 17, 2025
06fea81
Fix after merge
jakobbotsch Oct 17, 2025
29d8998
Enable runtime async testing
jakobbotsch Oct 17, 2025
cb7a943
Undo changes
jakobbotsch Oct 17, 2025
879ec4f
Hacky late Friday GC issue fix
jakobbotsch Oct 17, 2025
0749688
Fix 32 bit build
jakobbotsch Oct 17, 2025
6bcc004
Last block no longer always results in the last IG
jakobbotsch Oct 18, 2025
286baf9
Merge branch 'main' of github.com:dotnet/runtime into jit-async-diagn…
jakobbotsch Oct 18, 2025
8cf3a72
Fix after merge
jakobbotsch Oct 18, 2025
3096aa8
Run jit-format
jakobbotsch Oct 18, 2025
9f913f3
Clean up
jakobbotsch Oct 18, 2025
85bd57a
Fix arm32
jakobbotsch Oct 18, 2025
43c5710
Revert "Store target IPs in AsyncResumeILStubResolver"
jakobbotsch Oct 20, 2025
dc9c7d8
Allocate constant resume info data and point continuations at it
jakobbotsch Oct 23, 2025
eadab40
Remove unnecessary intermediate type
jakobbotsch Oct 23, 2025
d57fc4d
Go back to not reporting async debug info unless requested
jakobbotsch Oct 23, 2025
1308e96
Insert ASYNC mappings in resume and suspension code
jakobbotsch Oct 23, 2025
bd99f2c
Fix arm arch codegen, fix LA64/RISCV64 builds
jakobbotsch Oct 23, 2025
ffa76fa
Clean up, revert unnecessary changes
jakobbotsch Oct 23, 2025
b7f2e61
Merge branch 'main' of github.com:dotnet/runtime into jit-async-diagn…
jakobbotsch Oct 23, 2025
07bf137
Update after merge
jakobbotsch Oct 23, 2025
cd0e601
Disable async testing
jakobbotsch Oct 23, 2025
e016f77
Function headers
jakobbotsch Oct 23, 2025
a9d5243
Address feedback
jakobbotsch Oct 24, 2025
d4c2b9e
Fix crossgen2 reportAsyncDebugInfo
jakobbotsch Oct 24, 2025
fabea2d
Clean up, remove paranoia code
jakobbotsch Oct 24, 2025
1762f19
Point IL offsets at await call
jakobbotsch Oct 27, 2025
ed3da47
Clean ups
jakobbotsch Oct 27, 2025
8c69bf9
Encode async continuation layouts as part of `NativeVarInfo`
jakobbotsch Oct 27, 2025
092bd67
Revert "Encode async continuation layouts as part of `NativeVarInfo`"
jakobbotsch Oct 27, 2025
96b0f88
Avoid reporting continuation parameter in debug info
jakobbotsch Oct 27, 2025
fb09144
Add `AsyncSuspensionPoint::FinalResumeNativeOffset`
jakobbotsch Oct 27, 2025
161e180
Further changes to ResumeInfo diagnostic IP
jakobbotsch Oct 29, 2025
a5a2e16
Avoid marking async mappings as label mappings
jakobbotsch Oct 29, 2025
f4f7fff
Fix comment
jakobbotsch Oct 29, 2025
7b8b9b0
Point DiagnosticIP at suspension code
jakobbotsch Oct 31, 2025
e9cef1c
Update comment
jakobbotsch Nov 3, 2025
bc2f780
Set proper IL offset ranges when splitting user code for async calls
jakobbotsch Nov 3, 2025
ea96acc
Address feedback
jakobbotsch Nov 3, 2025
959be11
Make `DispatcherInfo` have explicit layout
jakobbotsch Nov 4, 2025
4061420
Address some feedback, add a missing field
jakobbotsch Nov 4, 2025
54bab6d
Fix a comment
jakobbotsch Nov 4, 2025
c84f027
Fix r2rdump reading of bounds
jakobbotsch Nov 5, 2025
9f497bd
Bump debug info contract version
jakobbotsch Nov 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,27 @@ internal enum ContinuationFlags
ContinueOnCapturedTaskScheduler = 64,
}

// Keep in sync with dataAsyncResumeInfo in the JIT
internal unsafe struct ResumeInfo
{
public delegate*<Continuation, ref byte, Continuation?> Resume;
// IP to use for diagnostics. Points into the jitted suspension code.
// For debug codegen the IP resolves via an ASYNC native->IL mapping to
// the IL AsyncHelpers.Await (or other async function) call which
// caused the suspension.
// For optimized codegen the mapping into the root method may be more
// approximate (e.g. because of inlining).
// For all codegens the offset of DiagnosticsIP matches
// DiagnosticNativeOffset for the corresponding AsyncSuspensionPoint in
// the debug info.
public void* DiagnosticIP;
}

#pragma warning disable CA1852 // "Type can be sealed" -- no it cannot because the runtime constructs subtypes dynamically
internal unsafe class Continuation
{
public Continuation? Next;
public delegate*<Continuation, ref byte, Continuation?> Resume;
public ResumeInfo* ResumeInfo;
public ContinuationFlags Flags;
public int State;

Expand Down Expand Up @@ -195,9 +211,8 @@ private interface IRuntimeAsyncTaskOps<T>
static abstract ref byte GetResultStorage(T task);
}

/// <summary>
/// Represents a wrapped runtime async operation.
/// </summary>
// Represents execution of a chain of suspended and resuming runtime
// async functions.
private sealed class RuntimeAsyncTask<T> : Task<T>, ITaskCompletionAction
{
public RuntimeAsyncTask()
Expand Down Expand Up @@ -261,9 +276,8 @@ public static void PostToSyncContext(RuntimeAsyncTask<T> task, SynchronizationCo
}
}

/// <summary>
/// Represents a wrapped runtime async operation.
/// </summary>
// Represents execution of a chain of suspended and resuming runtime
// async functions.
private sealed class RuntimeAsyncTask : Task, ITaskCompletionAction
{
public RuntimeAsyncTask()
Expand Down Expand Up @@ -329,35 +343,63 @@ public static void PostToSyncContext(RuntimeAsyncTask task, SynchronizationConte

private static class RuntimeAsyncTaskCore
{
[StructLayout(LayoutKind.Explicit)]
private unsafe ref struct DispatcherInfo
{
// Dispatcher info for next dispatcher present on stack, or
// null if none.
[FieldOffset(0)]
public DispatcherInfo* Next;

// Next continuation the dispatcher will process.
#if TARGET_64BIT
[FieldOffset(8)]
#else
[FieldOffset(4)]
#endif
public Continuation? NextContinuation;
}

// Information about current task dispatching, to be used for async
// stackwalking.
[ThreadStatic]
private static unsafe DispatcherInfo* t_dispatcherInfo;

public static unsafe void DispatchContinuations<T, TOps>(T task) where T : Task, ITaskCompletionAction where TOps : IRuntimeAsyncTaskOps<T>
{
ExecutionAndSyncBlockStore contexts = default;
contexts.Push();
Continuation? continuation = TOps.GetContinuationState(task);

DispatcherInfo dispatcherInfo;
dispatcherInfo.Next = t_dispatcherInfo;
dispatcherInfo.NextContinuation = TOps.GetContinuationState(task);
t_dispatcherInfo = &dispatcherInfo;

while (true)
{
Debug.Assert(continuation != null);
Debug.Assert(dispatcherInfo.NextContinuation != null);
try
{
ref byte resultLoc = ref continuation.Next != null ? ref continuation.Next.GetResultStorageOrNull() : ref TOps.GetResultStorage(task);
Continuation? newContinuation = continuation.Resume(continuation, ref resultLoc);
Continuation curContinuation = dispatcherInfo.NextContinuation;
Continuation? nextContinuation = curContinuation.Next;
dispatcherInfo.NextContinuation = nextContinuation;

ref byte resultLoc = ref nextContinuation != null ? ref nextContinuation.GetResultStorageOrNull() : ref TOps.GetResultStorage(task);
Continuation? newContinuation = curContinuation.ResumeInfo->Resume(curContinuation, ref resultLoc);

if (newContinuation != null)
{
newContinuation.Next = continuation.Next;
newContinuation.Next = nextContinuation;
HandleSuspended<T, TOps>(task);
contexts.Pop();
t_dispatcherInfo = dispatcherInfo.Next;
return;
}

continuation = continuation.Next;
}
catch (Exception ex)
{
Debug.Assert(continuation != null);
Continuation? nextContinuation = UnwindToPossibleHandler(continuation);
if (nextContinuation == null)
Continuation? handlerContinuation = UnwindToPossibleHandler(dispatcherInfo.NextContinuation);
if (handlerContinuation == null)
{
// Tail of AsyncTaskMethodBuilderT.SetException
bool successfullySet = ex is OperationCanceledException oce ?
Expand All @@ -366,6 +408,8 @@ public static unsafe void DispatchContinuations<T, TOps>(T task) where T : Task,

contexts.Pop();

t_dispatcherInfo = dispatcherInfo.Next;

if (!successfullySet)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted);
Expand All @@ -374,17 +418,18 @@ public static unsafe void DispatchContinuations<T, TOps>(T task) where T : Task,
return;
}

nextContinuation.SetException(ex);

continuation = nextContinuation;
handlerContinuation.SetException(ex);
dispatcherInfo.NextContinuation = handlerContinuation;
}

if (continuation == null)
if (dispatcherInfo.NextContinuation == null)
{
bool successfullySet = TOps.SetCompleted(task);

contexts.Pop();

t_dispatcherInfo = dispatcherInfo.Next;

if (!successfullySet)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted);
Expand All @@ -393,26 +438,23 @@ public static unsafe void DispatchContinuations<T, TOps>(T task) where T : Task,
return;
}

if (QueueContinuationFollowUpActionIfNecessary<T, TOps>(task, continuation))
if (QueueContinuationFollowUpActionIfNecessary<T, TOps>(task, dispatcherInfo.NextContinuation))
{
contexts.Pop();
t_dispatcherInfo = dispatcherInfo.Next;
return;
}
}
}

private static Continuation? UnwindToPossibleHandler(Continuation continuation)
private static Continuation? UnwindToPossibleHandler(Continuation? continuation)
{
while (true)
{
Continuation? nextContinuation = continuation.Next;
if (nextContinuation == null)
return null;

if ((nextContinuation.Flags & ContinuationFlags.HasException) != 0)
return nextContinuation;
if (continuation == null || (continuation.Flags & ContinuationFlags.HasException) != 0)
return continuation;

continuation = nextContinuation;
continuation = continuation.Next;
}
}

Expand Down
29 changes: 28 additions & 1 deletion src/coreclr/inc/cordebuginfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class ICorDebugInfo
STACK_EMPTY = 0x02, // The stack is empty here
CALL_SITE = 0x04, // This is a call site.
NATIVE_END_OFFSET_UNKNOWN = 0x08, // Indicates a epilog endpoint
CALL_INSTRUCTION = 0x10 // The actual instruction of a call.
CALL_INSTRUCTION = 0x10, // The actual instruction of a call.
ASYNC = 0x20, // Indicates suspension/resumption for an async call

};

Expand Down Expand Up @@ -431,4 +432,30 @@ class ICorDebugInfo
// Source information about the IL instruction in the inlinee
SourceTypes Source;
};

struct AsyncContinuationVarInfo
{
// IL number of variable (or one of the special IL numbers, like TYPECTXT_ILNUM)
uint32_t VarNumber;
// Offset in continuation object where this variable is stored
uint32_t Offset;
};

struct AsyncSuspensionPoint
{
// Offset of IP stored in ResumeInfo.DiagnosticIP. This offset maps to
// the IL call that resulted in the suspension point through an ASYNC
// mapping. Also used as a unique key for debug information about the
// suspension point. See ResumeInfo.DiagnosticIP in SPC for more info.
uint32_t DiagnosticNativeOffset;
// Count of AsyncContinuationVarInfo in array of locals starting where
// the previous suspension point's locals end.
uint32_t NumContinuationVars;
};

struct AsyncInfo
{
// Number of suspension points in the method.
uint32_t NumSuspensionPoints;
};
};
16 changes: 13 additions & 3 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1734,8 +1734,8 @@ struct CORINFO_ASYNC_INFO
CORINFO_CLASS_HANDLE continuationClsHnd;
// 'Next' field
CORINFO_FIELD_HANDLE continuationNextFldHnd;
// 'Resume' field
CORINFO_FIELD_HANDLE continuationResumeFldHnd;
// 'ResumeInfo' field
CORINFO_FIELD_HANDLE continuationResumeInfoFldHnd;
// 'State' field
CORINFO_FIELD_HANDLE continuationStateFldHnd;
// 'Flags' field
Expand Down Expand Up @@ -2912,6 +2912,16 @@ class ICorStaticInfo
uint32_t numMappings // [IN] Number of rich mappings
) = 0;

// Report async debug information to EE.
// The arrays are expected to be allocated with allocateArray
// and ownership is transferred to the EE with this call.
virtual void reportAsyncDebugInfo(
ICorDebugInfo::AsyncInfo* asyncInfo, // [IN] Async method information
ICorDebugInfo::AsyncSuspensionPoint* suspensionPoints, // [IN] Array of async suspension points, indexed by state number
ICorDebugInfo::AsyncContinuationVarInfo* vars, // [IN] Array of async continuation variable info
uint32_t numVars // [IN] Number of entries in the async vars array
) = 0;

// Report back some metadata about the compilation to the EE -- for
// example, metrics about the compilation.
virtual void reportMetadata(
Expand Down Expand Up @@ -3340,7 +3350,7 @@ class ICorDynamicInfo : public ICorStaticInfo
CORINFO_TAILCALL_HELPERS* pResult
) = 0;

virtual CORINFO_METHOD_HANDLE getAsyncResumptionStub() = 0;
virtual CORINFO_METHOD_HANDLE getAsyncResumptionStub(void** entryPoint) = 0;

virtual CORINFO_CLASS_HANDLE getContinuationType(
size_t dataSize,
Expand Down
9 changes: 8 additions & 1 deletion src/coreclr/inc/icorjitinfoimpl_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,12 @@ void reportRichMappings(
ICorDebugInfo::RichOffsetMapping* mappings,
uint32_t numMappings) override;

void reportAsyncDebugInfo(
ICorDebugInfo::AsyncInfo* asyncInfo,
ICorDebugInfo::AsyncSuspensionPoint* suspensionPoints,
ICorDebugInfo::AsyncContinuationVarInfo* vars,
uint32_t numVars) override;

void reportMetadata(
const char* key,
const void* value,
Expand Down Expand Up @@ -660,7 +666,8 @@ CORINFO_CLASS_HANDLE getContinuationType(
bool* objRefs,
size_t objRefsSize) override;

CORINFO_METHOD_HANDLE getAsyncResumptionStub() override;
CORINFO_METHOD_HANDLE getAsyncResumptionStub(
void** entryPoint) override;

bool convertPInvokeCalliToCall(
CORINFO_RESOLVED_TOKEN* pResolvedToken,
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@

#include <minipal/guid.h>

constexpr GUID JITEEVersionIdentifier = { /* 68e93e9d-dd28-49ca-9ebc-a01a54532bb3 */
0x68e93e9d,
0xdd28,
0x49ca,
{0x9e, 0xbc, 0xa0, 0x1a, 0x54, 0x53, 0x2b, 0xb3}
constexpr GUID JITEEVersionIdentifier = { /* a802fbbf-3e14-4b34-a348-5fba9fd756d4 */
0xa802fbbf,
0x3e14,
0x4b34,
{0xa3, 0x48, 0x5f, 0xba, 0x9f, 0xd7, 0x56, 0xd4}
};

#endif // JIT_EE_VERSIONING_GUID_H
5 changes: 3 additions & 2 deletions src/coreclr/inc/readytorun.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
// src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h
// If you update this, ensure you run `git grep MINIMUM_READYTORUN_MAJOR_VERSION`
// and handle pending work.
#define READYTORUN_MAJOR_VERSION 16
#define READYTORUN_MAJOR_VERSION 17
#define READYTORUN_MINOR_VERSION 0x0000

#define MINIMUM_READYTORUN_MAJOR_VERSION 16
#define MINIMUM_READYTORUN_MAJOR_VERSION 17

// R2R Version 2.1 adds the InliningInfo section
// R2R Version 2.2 adds the ProfileDataInfo section
Expand All @@ -47,6 +47,7 @@
// R2R Version 14 changed x86 code generation to use funclets
// R2R Version 15 removes double to int/uint helper calls
// R2R Version 16 replaces the compression format for debug boundaries with a new format that is smaller and more efficient to parse
// R2R Version 17 adds support for producing "fat" debug information (that e.g. can include async debug info)

struct READYTORUN_CORE_HEADER
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/ICorJitInfo_names_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ DEF_CLR_API(setBoundaries)
DEF_CLR_API(getVars)
DEF_CLR_API(setVars)
DEF_CLR_API(reportRichMappings)
DEF_CLR_API(reportAsyncDebugInfo)
DEF_CLR_API(reportMetadata)
DEF_CLR_API(allocateArray)
DEF_CLR_API(freeArray)
Expand Down
16 changes: 14 additions & 2 deletions src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,17 @@ void WrapICorJitInfo::reportRichMappings(
API_LEAVE(reportRichMappings);
}

void WrapICorJitInfo::reportAsyncDebugInfo(
ICorDebugInfo::AsyncInfo* asyncInfo,
ICorDebugInfo::AsyncSuspensionPoint* suspensionPoints,
ICorDebugInfo::AsyncContinuationVarInfo* vars,
uint32_t numVars)
{
API_ENTER(reportAsyncDebugInfo);
wrapHnd->reportAsyncDebugInfo(asyncInfo, suspensionPoints, vars, numVars);
API_LEAVE(reportAsyncDebugInfo);
}

void WrapICorJitInfo::reportMetadata(
const char* key,
const void* value,
Expand Down Expand Up @@ -1547,10 +1558,11 @@ CORINFO_CLASS_HANDLE WrapICorJitInfo::getContinuationType(
return temp;
}

CORINFO_METHOD_HANDLE WrapICorJitInfo::getAsyncResumptionStub()
CORINFO_METHOD_HANDLE WrapICorJitInfo::getAsyncResumptionStub(
void** entryPoint)
{
API_ENTER(getAsyncResumptionStub);
CORINFO_METHOD_HANDLE temp = wrapHnd->getAsyncResumptionStub();
CORINFO_METHOD_HANDLE temp = wrapHnd->getAsyncResumptionStub(entryPoint);
API_LEAVE(getAsyncResumptionStub);
return temp;
}
Expand Down
Loading
Loading