Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6658d8b
Pass async jit flag to jit in aot tools
jtschuster Oct 15, 2025
1f917e9
Add IsRuntimeAsync override to instantiated MethodDescs
jtschuster Oct 15, 2025
431bfaa
Update src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs
jkotas Oct 15, 2025
3a4ffbc
Rename IsRuntimeAsync to IsAsync, add override in MethodDelegator
jtschuster Oct 16, 2025
1030acb
Add AsyncMethodDesc for AsyncCallConv methods
jtschuster Oct 17, 2025
4cc1f5f
Merge branch 'main' of https://github.com/dotnet/runtime into AsyncMe…
jtschuster Oct 17, 2025
7516cba
Remove comments from AsyncMethodDesc
jtschuster Oct 17, 2025
42e1157
Use MethodSignatureBuilder and assert for expected invariants
jtschuster Oct 17, 2025
429f910
Use throwing cast instead of 'as' cast
jtschuster Oct 17, 2025
4e0d53d
Fix assert
jtschuster Oct 17, 2025
c75c536
Add getter to Flags for |=
jtschuster Oct 17, 2025
e8ef453
Implement getAsyncInfo in ILCompiler
jtschuster Oct 17, 2025
5ff7bc6
Use Dictionary instead of ConcurrentDictionary for AsyncMethodDescFac…
jtschuster Oct 17, 2025
e5ea4ce
Refactor AsyncMethodDesc for clarity and efficiency
jtschuster Oct 17, 2025
0cf52dc
Update src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
jtschuster Oct 17, 2025
de10bb5
Update Signature and delete GetOtherAsyncMethod
jtschuster Oct 17, 2025
ff2712d
Remove IsAsync requirement from AsyncMethodDesc
jtschuster Oct 17, 2025
9749653
Formatting and remove unused accessor
jtschuster Oct 17, 2025
c2e3c48
Merge branch 'GetAsyncInfoR2R' into AsyncMethodDesc
jtschuster Oct 17, 2025
bada361
Delete old UnboxingMethodDescFactory, move AsyncMethodDescFactory to …
jtschuster Oct 20, 2025
2aace2c
Rename ReturnsTaskLike to IsTaskReturning
jtschuster Oct 20, 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
109 changes: 109 additions & 0 deletions src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using Internal.TypeSystem;

namespace Internal.JitInterface
{
/// <summary>
/// Represents the async-callable (CORINFO_CALLCONV_ASYNCCALL) variant of a Task/ValueTask returning method.
/// The wrapper should be short‑lived and only used while interacting with the JIT interface.
/// </summary>
internal sealed class AsyncMethodDesc : MethodDelegator, IJitHashableOnly
{
private readonly AsyncMethodDescFactory _factory;
private readonly int _jitVisibleHashCode;

public MethodDesc Target => _wrappedMethod;

public AsyncMethodDesc(MethodDesc wrappedMethod, AsyncMethodDescFactory factory)
: base(wrappedMethod)
{
Debug.Assert(wrappedMethod.IsTaskReturning());
_factory = factory;
// Salt with arbitrary constant so hash space differs from underlying method.
_jitVisibleHashCode = HashCode.Combine(wrappedMethod.GetHashCode(), 0x51C0A54);
}

public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind)
{
MethodDesc realCanonTarget = _wrappedMethod.GetCanonMethodTarget(kind);
if (realCanonTarget != _wrappedMethod)
return _factory.GetAsyncMethod(realCanonTarget);
return this;
}

public override MethodDesc GetMethodDefinition()
{
MethodDesc real = _wrappedMethod.GetMethodDefinition();
if (real != _wrappedMethod)
return _factory.GetAsyncMethod(real);
return this;
}

public override MethodDesc GetTypicalMethodDefinition()
{
MethodDesc real = _wrappedMethod.GetTypicalMethodDefinition();
if (real != _wrappedMethod)
return _factory.GetAsyncMethod(real);
return this;
}

public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation)
{
MethodDesc real = _wrappedMethod.InstantiateSignature(typeInstantiation, methodInstantiation);
if (real != _wrappedMethod)
return _factory.GetAsyncMethod(real);
return this;
}

public override MethodSignature Signature
{
get
{
MethodSignature wrappedSignature = _wrappedMethod.Signature;
MetadataType md = (MetadataType)wrappedSignature.ReturnType;
MethodSignatureBuilder builder = new MethodSignatureBuilder(wrappedSignature);
builder.ReturnType = md.HasInstantiation ? md.Instantiation[0] : this.Context.GetWellKnownType(WellKnownType.Void);
builder.Flags = wrappedSignature.Flags | MethodSignatureFlags.AsyncCallConv;
return builder.ToSignature();
}
}

#if !SUPPORT_JIT
// Same pattern as UnboxingMethodDesc: these should not escape JIT hashing scope.
protected override int ClassCode => throw new NotImplementedException();
protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) => throw new NotImplementedException();
protected override int ComputeHashCode() => _jitVisibleHashCode;
int IJitHashableOnly.GetJitVisibleHashCode() => _jitVisibleHashCode;
#else
int IJitHashableOnly.GetJitVisibleHashCode() => _jitVisibleHashCode;
#endif
}

internal static class AsyncMethodDescExtensions
{
/// <summary>
/// Returns true if the method returns Task, Task&lt;T&gt;, ValueTask, or ValueTask&lt;T&gt;, otherwise false.
/// </summary>
public static bool IsTaskReturning(this MethodDesc method)
{
TypeDesc ret = method.GetTypicalMethodDefinition().Signature.ReturnType;

if (ret is MetadataType md
&& md.Module == method.Context.SystemModule
&& md.Namespace.SequenceEqual("System.Threading.Tasks"u8))
{
ReadOnlySpan<byte> name = md.Name;
if (name.SequenceEqual("Task"u8) || name.SequenceEqual("Task`1"u8)
|| name.SequenceEqual("ValueTask"u8) || name.SequenceEqual("ValueTask`1"u8))
{
return true;
}
}
return false;
}
}
}
24 changes: 24 additions & 0 deletions src/coreclr/tools/Common/JitInterface/AsyncMethodDescFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Internal.TypeSystem;

namespace Internal.JitInterface
{
internal class AsyncMethodDescFactory : Dictionary<MethodDesc, AsyncMethodDesc>
{
public AsyncMethodDesc GetAsyncMethod(MethodDesc method)
{
if (!TryGetValue(method, out AsyncMethodDesc result))
{
result = new AsyncMethodDesc(method, this);
Add(method, result);
}

return result;
}
}
}
28 changes: 27 additions & 1 deletion src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3358,7 +3358,33 @@ private void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut)

private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut)
{
throw new NotImplementedException();
DefType continuation = MethodBeingCompiled.Context.SystemModule.GetType("System.Runtime.CompilerServices"u8, "Continuation"u8);
pAsyncInfoOut.continuationClsHnd = ObjectToHandle(continuation);
// 'Next' field
pAsyncInfoOut.continuationNextFldHnd = ObjectToHandle(continuation.GetField("Next"u8));
// 'Resume' field
pAsyncInfoOut.continuationResumeFldHnd = ObjectToHandle(continuation.GetField("Resume"u8));
// 'State' field
pAsyncInfoOut.continuationStateFldHnd = ObjectToHandle(continuation.GetField("State"u8));
// 'Flags' field
pAsyncInfoOut.continuationFlagsFldHnd = ObjectToHandle(continuation.GetField("Flags"u8));
// 'Data' field
pAsyncInfoOut.continuationDataFldHnd = ObjectToHandle(continuation.GetField("Data"u8));
// 'GCData' field
pAsyncInfoOut.continuationGCDataFldHnd = ObjectToHandle(continuation.GetField("GCData"u8));
// Whether or not the continuation needs to be allocated through the
// helper that also takes a method handle
pAsyncInfoOut.continuationsNeedMethodHandle = false;
DefType asyncHelpers = MethodBeingCompiled.Context.SystemModule.GetType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8);
DefType executionContext = MethodBeingCompiled.Context.SystemModule.GetType("System.Threading"u8, "ExecutionContext"u8);
DefType @void = MethodBeingCompiled.Context.GetWellKnownType(WellKnownType.Void);
// Method handle for AsyncHelpers.CaptureExecutionContext
pAsyncInfoOut.captureExecutionContextMethHnd = ObjectToHandle(asyncHelpers.GetMethod("CaptureExecutionContext"u8, null));
// Method handle for AsyncHelpers.RestoreExecutionContext
pAsyncInfoOut.restoreExecutionContextMethHnd = ObjectToHandle(asyncHelpers.GetMethod("RestoreExecutionContext"u8, null));
pAsyncInfoOut.captureContinuationContextMethHnd = ObjectToHandle(asyncHelpers.GetMethod("CaptureContinuationContext"u8, null));
pAsyncInfoOut.captureContextsMethHnd = ObjectToHandle(asyncHelpers.GetMethod("CaptureContexts"u8, null));
pAsyncInfoOut.restoreContextsMethHnd = ObjectToHandle(asyncHelpers.GetMethod("RestoreContexts"u8, null));
}

private mdToken getMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod)
Expand Down
16 changes: 16 additions & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -878,10 +878,26 @@ public unsafe struct CORINFO_ASYNC_INFO
public CORINFO_CLASS_STRUCT_* continuationClsHnd;
// 'Next' field
public CORINFO_FIELD_STRUCT_* continuationNextFldHnd;
// 'Resume' field
public CORINFO_FIELD_STRUCT_* continuationResumeFldHnd;
// 'State' field
public CORINFO_FIELD_STRUCT_* continuationStateFldHnd;
// 'Flags' field
public CORINFO_FIELD_STRUCT_* continuationFlagsFldHnd;
// 'Data' field
public CORINFO_FIELD_STRUCT_* continuationDataFldHnd;
// 'GCData' field
public CORINFO_FIELD_STRUCT_* continuationGCDataFldHnd;
// Whether or not the continuation needs to be allocated through the
// helper that also takes a method handle
public bool continuationsNeedMethodHandle; // byte?
// Method handle for AsyncHelpers.CaptureExecutionContext
public CORINFO_METHOD_STRUCT_* captureExecutionContextMethHnd;
// Method handle for AsyncHelpers.RestoreExecutionContext
public CORINFO_METHOD_STRUCT_* restoreExecutionContextMethHnd;
public CORINFO_METHOD_STRUCT_* captureContinuationContextMethHnd;
public CORINFO_METHOD_STRUCT_* captureContextsMethHnd;
public CORINFO_METHOD_STRUCT_* restoreContextsMethHnd;
}

// Flags passed from JIT to runtime.
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public enum MethodSignatureFlags

Static = 0x0010,
ExplicitThis = 0x0020,
AsyncCallConv = 0x0040,
}

public enum EmbeddedSignatureDataKind
Expand Down Expand Up @@ -138,6 +139,14 @@ public bool IsExplicitThis
}
}

public bool IsAsyncCallConv
{
get
{
return (_flags & MethodSignatureFlags.AsyncCallConv) != 0;
}
}

public int GenericParameterCount
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@
<Compile Include="Compiler\SystemObjectFieldLayoutAlgorithm.cs" />
<Compile Include="IL\ReadyToRunILProvider.cs" />
<Compile Include="JitInterface\CorInfoImpl.ReadyToRun.cs" />
<Compile Include="JitInterface\UnboxingMethodDescFactory.cs" />
<Compile Include="ObjectWriter\SectionBuilder.cs" />
<Compile Include="ObjectWriter\R2RPEBuilder.cs" />
<Compile Include="ObjectWriter\RelocationHelper.cs" />
Expand Down Expand Up @@ -337,5 +336,14 @@
<Compile Include="..\..\Common\JitInterface\UnboxingMethodDesc.cs">
<Link>JitInterface\UnboxingMethodDesc.cs</Link>
</Compile>
<Compile Include="..\..\Common\JitInterface\UnboxingMethodDescFactory.cs">
<Link>JitInterface\UnboxingMethodDescFactory.cs</Link>
</Compile>
<Compile Include="..\..\Common\JitInterface\AsyncMethodDesc.cs">
<Link>JitInterface\AsyncMethodDesc.cs</Link>
</Compile>
<Compile Include="..\..\Common\JitInterface\AsyncMethodDescFactory.cs">
<Link>JitInterface\AsyncMethodDesc.cs</Link>
</Compile>
</ItemGroup>
</Project>

This file was deleted.

Loading