From 6658d8b6653e7fd0554397b939438ceda3a1416c Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 15 Oct 2025 14:05:40 -0700 Subject: [PATCH 01/19] Pass async jit flag to jit in aot tools --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 7 ++++++- .../tools/Common/JitInterface/CorInfoTypes.cs | 1 + .../tools/Common/TypeSystem/Common/MethodDesc.cs | 8 ++++++++ .../tools/Common/TypeSystem/Ecma/EcmaMethod.cs | 12 ++++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 7538a26ef002ff..2d994466e0bb97 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3713,7 +3713,7 @@ private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SI private CORINFO_METHOD_STRUCT_* getAsyncResumptionStub() #pragma warning restore CA1822 // Mark members as static { - return null; + throw new NotImplementedException("Crossgen2 does not support runtime-async yet"); } private byte[] _code; @@ -4297,6 +4297,11 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) flags.Set(CorJitFlag.CORJIT_FLAG_SOFTFP_ABI); } + if (this.MethodBeingCompiled.IsRuntimeAsync) + { + flags.Set(CorJitFlag.CORJIT_FLAG_ASYNC); + } + return (uint)sizeof(CORJIT_FLAGS); } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 797ae1c7d3061e..f2688c585b0e52 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1414,6 +1414,7 @@ public enum CorJitFlag : uint // ARM only CORJIT_FLAG_RELATIVE_CODE_RELOCS = 29, // JIT should generate PC-relative address computations instead of EE relocation records CORJIT_FLAG_SOFTFP_ABI = 30, // Enable armel calling convention + CORJIT_FLAG_ASYNC = 31, // Generate code for use as an async function } public struct CORJIT_FLAGS diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs index 2075c60ea21713..20fd7f40299e54 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs @@ -658,6 +658,14 @@ public virtual bool IsPublic } } + public virtual bool IsRuntimeAsync + { + get + { + return false; + } + } + public abstract bool HasCustomAttribute(string attributeNamespace, string attributeName); /// diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs index 28cb1192ea4889..a37c8ba0f90503 100644 --- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs +++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs @@ -32,6 +32,7 @@ private static class MethodFlags public const int AttributeMetadataCache = 0x02000; public const int Intrinsic = 0x04000; public const int UnmanagedCallersOnly = 0x08000; + public const int Async = 0x10000; }; private EcmaType _type; @@ -167,6 +168,9 @@ private int InitializeMethodFlags(int mask) if ((methodImplAttributes & MethodImplAttributes.Synchronized) != 0) flags |= MethodFlags.Synchronized; + if ((methodImplAttributes & MethodImplAttributes.Async) != 0) + flags |= MethodFlags.Async; + flags |= MethodFlags.BasicMetadataCache; } @@ -367,6 +371,14 @@ public override bool IsStaticConstructor } } + public override bool IsRuntimeAsync + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Async) & MethodFlags.Async) != 0; + } + } + public MethodAttributes Attributes { get From 1f917e9a94c6965dec13d9218c13be9378f86581 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 15 Oct 2025 15:47:00 -0700 Subject: [PATCH 02/19] Add IsRuntimeAsync override to instantiated MethodDescs --- .../tools/Common/TypeSystem/Common/InstantiatedMethod.cs | 9 +++++++++ .../TypeSystem/Common/MethodForInstantiatedType.cs | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs index 0fd68eef059f82..1b9ffbc3e5bd45 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs @@ -126,6 +126,15 @@ public override bool IsPublic } } + public override bool IRuntimeAsync + { + get + { + return _methodDef.IsRuntimeAsync; + } + } + + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) { return _methodDef.HasCustomAttribute(attributeNamespace, attributeName); diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs index 4a1cf836e17466..d22179aeb3934e 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs @@ -119,6 +119,14 @@ public override bool IsPublic } } + public override bool IsRuntimeAsync + { + get + { + return _typicalMethodDef.IsRuntimeAsync; + } + } + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) { return _typicalMethodDef.HasCustomAttribute(attributeNamespace, attributeName); From 431bfaaeb25e59f225b98d1fc01a646a4aad4650 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 15 Oct 2025 15:48:11 -0700 Subject: [PATCH 03/19] Update src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs --- .../tools/Common/TypeSystem/Common/InstantiatedMethod.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs index 1b9ffbc3e5bd45..7609855b3b0e96 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs @@ -126,7 +126,7 @@ public override bool IsPublic } } - public override bool IRuntimeAsync + public override bool IsRuntimeAsync { get { From 3a4ffbc68beaf430679a3157dc5ba5cdb8474343 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 16 Oct 2025 09:23:22 -0700 Subject: [PATCH 04/19] Rename IsRuntimeAsync to IsAsync, add override in MethodDelegator --- .../tools/Common/TypeSystem/Common/InstantiatedMethod.cs | 4 ++-- src/coreclr/tools/Common/TypeSystem/Common/MethodDelegator.cs | 2 ++ src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs | 2 +- .../Common/TypeSystem/Common/MethodForInstantiatedType.cs | 4 ++-- src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs index 7609855b3b0e96..6024dcc6cc335d 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs @@ -126,11 +126,11 @@ public override bool IsPublic } } - public override bool IsRuntimeAsync + public override bool IsAsync { get { - return _methodDef.IsRuntimeAsync; + return _methodDef.IsAsync; } } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodDelegator.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodDelegator.cs index 918bb5e62a88a8..55dba7ed9cead9 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MethodDelegator.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodDelegator.cs @@ -38,6 +38,8 @@ public MethodDelegator(MethodDesc wrappedMethod) public override bool IsFinal => _wrappedMethod.IsFinal; + public override bool IsAsync => _wrappedMethod.IsAsync; + public override bool HasCustomAttribute(string attributeNamespace, string attributeName) { return _wrappedMethod.HasCustomAttribute(attributeNamespace, attributeName); diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs index 20fd7f40299e54..96d4c0b163507e 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs @@ -658,7 +658,7 @@ public virtual bool IsPublic } } - public virtual bool IsRuntimeAsync + public virtual bool IsAsync { get { diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs index d22179aeb3934e..b5c7195b483e14 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs @@ -119,11 +119,11 @@ public override bool IsPublic } } - public override bool IsRuntimeAsync + public override bool IsAsync { get { - return _typicalMethodDef.IsRuntimeAsync; + return _typicalMethodDef.IsAsync; } } diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs index a37c8ba0f90503..09fb19a982fd79 100644 --- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs +++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs @@ -371,7 +371,7 @@ public override bool IsStaticConstructor } } - public override bool IsRuntimeAsync + public override bool IsAsync { get { From 1030acb67393f2afe228eb38683fe972ff5f3250 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:23:56 -0700 Subject: [PATCH 05/19] Add AsyncMethodDesc for AsyncCallConv methods --- .../Common/JitInterface/AsyncMethodDesc.cs | 156 ++++++++++++++++++ .../tools/Common/JitInterface/CorInfoImpl.cs | 2 +- .../Common/TypeSystem/Common/MethodDesc.cs | 9 + .../ILCompiler.ReadyToRun.csproj | 4 + .../JitInterface/AsyncMethodDescFactory.cs | 30 ++++ 5 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs new file mode 100644 index 00000000000000..85e107c290e30a --- /dev/null +++ b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs @@ -0,0 +1,156 @@ +// 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 +{ + /// + /// Represents the async-callable (CORINFO_CALLCONV_ASYNCCALL) variant of a Task/ValueTask returning method. + /// Mirrors the structure and usage pattern of . + /// The wrapper should be short‑lived and only used while interacting with the JIT interface. + /// + 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 is not null); + Debug.Assert(wrappedMethod.IsAsync && wrappedMethod.ReturnsTaskLike()); + _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 + { + var wrappedSignature = _wrappedMethod.Signature; + var ret = wrappedSignature.ReturnType; + if (ret is MetadataType md) + { + if (md.Namespace.SequenceEqual("System.Threading.Tasks"u8)) + { + ReadOnlySpan name = md.Name; + TypeDesc returnType = null; + if (name.SequenceEqual("Task"u8) || name.SequenceEqual("ValueTask"u8)) + { + returnType = this.Context.GetWellKnownType(WellKnownType.Void); + } + else if (name.SequenceEqual("Task`1"u8) || name.SequenceEqual("ValueTask`1"u8)) + { + returnType = md.Instantiation[0]; + } + else + { + throw new UnreachableException("AsyncMethodDesc should not wrap a non-Task-like-returning method"); + } + TypeDesc[] parameters = new TypeDesc[wrappedSignature.Length]; + for (int i = 0; i < wrappedSignature.Length; i++) + { + parameters[i] = wrappedSignature[i]; + } + + return new MethodSignature( + // Do we need to mask other call convs here? + wrappedSignature.Flags | MethodSignatureFlags.AsyncCallConv, + wrappedSignature.GenericParameterCount, + returnType, + parameters, + wrappedSignature.GetEmbeddedSignatureData()); + } + } + throw new UnreachableException("AsyncMethodDesc should not wrap a non-Task-like-returning method"); + } + } + +#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 + { + //public static bool IsAsyncCallConvMethod(this MethodDesc method) => method is AsyncMethodDesc; + + /// + /// Returns the other async variant. If the supplied method is an async-callconv wrapper, returns the wrapped (Task-returning) method. + /// If it is a Task/ValueTask returning method, returns (and possibly creates) the async-callconv variant via the factory; otherwise null. + /// + public static MethodDesc GetOtherAsyncMethod(this MethodDesc method, AsyncMethodDescFactory factory) + { + if (method is null) return null; + if (method is AsyncMethodDesc amd) + return amd.Target; // unwrap + + if (method.IsAsync && ReturnsTaskLike(method)) + return factory.GetAsyncMethod(method); + + return null; + } + + public static bool ReturnsTaskLike(this MethodDesc method) + { + TypeDesc ret = method.GetTypicalMethodDefinition().Signature.ReturnType; + if (ret == null) return false; + + if (ret is MetadataType md) + { + if (md.Namespace.SequenceEqual("System.Threading.Tasks"u8)) + { + ReadOnlySpan 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; + } + } +} diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 2d994466e0bb97..ab43b57640a4a5 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -4297,7 +4297,7 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) flags.Set(CorJitFlag.CORJIT_FLAG_SOFTFP_ABI); } - if (this.MethodBeingCompiled.IsRuntimeAsync) + if (this.MethodBeingCompiled.IsAsync) { flags.Set(CorJitFlag.CORJIT_FLAG_ASYNC); } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs index 96d4c0b163507e..3f53e780d435e5 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs @@ -23,6 +23,7 @@ public enum MethodSignatureFlags Static = 0x0010, ExplicitThis = 0x0020, + AsyncCallConv = 0x0040, } public enum EmbeddedSignatureDataKind @@ -138,6 +139,14 @@ public bool IsExplicitThis } } + public bool IsAsyncCallConv + { + get + { + return (_flags & MethodSignatureFlags.AsyncCallConv) != 0; + } + } + public int GenericParameterCount { get diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 3251ff2660ebe3..fdb3a928b2b49b 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -162,6 +162,7 @@ + @@ -337,5 +338,8 @@ JitInterface\UnboxingMethodDesc.cs + + JitInterface\AsyncMethodDesc.cs + diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs new file mode 100644 index 00000000000000..18caf3b9e50057 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs @@ -0,0 +1,30 @@ +// 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.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using Internal.TypeSystem; + +namespace Internal.JitInterface +{ + internal class AsyncMethodDescFactory : ConcurrentDictionary + { + private Func _factoryDelegate; + private AsyncMethodDesc CreateAsyncMethod(MethodDesc method) + { + return new AsyncMethodDesc(method, this); + } + + public AsyncMethodDescFactory() + { + _factoryDelegate = CreateAsyncMethod; + } + + public AsyncMethodDesc GetAsyncMethod(MethodDesc method) + { + return GetOrAdd(method, _factoryDelegate); + } + } +} From 7516cba5e2801575a50012f7e708bf29c5cdf4ed Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:31:39 -0700 Subject: [PATCH 06/19] Remove comments from AsyncMethodDesc --- src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs index 85e107c290e30a..d5504ac6fec37b 100644 --- a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs +++ b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs @@ -92,7 +92,6 @@ public override MethodSignature Signature } return new MethodSignature( - // Do we need to mask other call convs here? wrappedSignature.Flags | MethodSignatureFlags.AsyncCallConv, wrappedSignature.GenericParameterCount, returnType, @@ -117,8 +116,6 @@ public override MethodSignature Signature internal static class AsyncMethodDescExtensions { - //public static bool IsAsyncCallConvMethod(this MethodDesc method) => method is AsyncMethodDesc; - /// /// Returns the other async variant. If the supplied method is an async-callconv wrapper, returns the wrapped (Task-returning) method. /// If it is a Task/ValueTask returning method, returns (and possibly creates) the async-callconv variant via the factory; otherwise null. From 42e11571dd3ac98e13304f18d47ab542e3b28882 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:43:33 -0700 Subject: [PATCH 07/19] Use MethodSignatureBuilder and assert for expected invariants --- .../Common/JitInterface/AsyncMethodDesc.cs | 51 ++++++++----------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs index d5504ac6fec37b..b0fcc7c6fa0ceb 100644 --- a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs +++ b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs @@ -67,39 +67,28 @@ public override MethodSignature Signature { var wrappedSignature = _wrappedMethod.Signature; var ret = wrappedSignature.ReturnType; - if (ret is MetadataType md) + var md = ret as MetadataType; + Debug.Assert(md.Namespace.SequenceEqual("System.Threading.Tasks"u8)); + ReadOnlySpan name = md.Name; + TypeDesc returnType = null; + if (name.SequenceEqual("Task"u8) || name.SequenceEqual("ValueTask"u8)) { - if (md.Namespace.SequenceEqual("System.Threading.Tasks"u8)) - { - ReadOnlySpan name = md.Name; - TypeDesc returnType = null; - if (name.SequenceEqual("Task"u8) || name.SequenceEqual("ValueTask"u8)) - { - returnType = this.Context.GetWellKnownType(WellKnownType.Void); - } - else if (name.SequenceEqual("Task`1"u8) || name.SequenceEqual("ValueTask`1"u8)) - { - returnType = md.Instantiation[0]; - } - else - { - throw new UnreachableException("AsyncMethodDesc should not wrap a non-Task-like-returning method"); - } - TypeDesc[] parameters = new TypeDesc[wrappedSignature.Length]; - for (int i = 0; i < wrappedSignature.Length; i++) - { - parameters[i] = wrappedSignature[i]; - } - - return new MethodSignature( - wrappedSignature.Flags | MethodSignatureFlags.AsyncCallConv, - wrappedSignature.GenericParameterCount, - returnType, - parameters, - wrappedSignature.GetEmbeddedSignatureData()); - } + returnType = this.Context.GetWellKnownType(WellKnownType.Void); } - throw new UnreachableException("AsyncMethodDesc should not wrap a non-Task-like-returning method"); + else if (name.SequenceEqual("Task`1"u8) || name.SequenceEqual("ValueTask`1"u8)) + { + Debug.Assert(returnType.HasInstantiation); + returnType = md.Instantiation[0]; + } + else + { + throw new UnreachableException("AsyncMethodDesc should not wrap a non-Task-like-returning method"); + } + + var builder = new MethodSignatureBuilder(_wrappedMethod.Signature); + builder.ReturnType = returnType; + builder.Flags |= MethodSignatureFlags.AsyncCallConv; + return builder.ToSignature(); } } From 429f9104ee4c8a746ad88627fd5db6ae3dcf30dc Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:45:44 -0700 Subject: [PATCH 08/19] Use throwing cast instead of 'as' cast --- src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs index b0fcc7c6fa0ceb..dd6c401f6a1314 100644 --- a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs +++ b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs @@ -67,7 +67,7 @@ public override MethodSignature Signature { var wrappedSignature = _wrappedMethod.Signature; var ret = wrappedSignature.ReturnType; - var md = ret as MetadataType; + var md = (MetadataType)ret; Debug.Assert(md.Namespace.SequenceEqual("System.Threading.Tasks"u8)); ReadOnlySpan name = md.Name; TypeDesc returnType = null; From 4e0d53deddf32b650f104448dcf2fc0caac1cebe Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:44:49 -0700 Subject: [PATCH 09/19] Fix assert --- src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs index dd6c401f6a1314..6ec597a35b500d 100644 --- a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs +++ b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs @@ -77,7 +77,7 @@ public override MethodSignature Signature } else if (name.SequenceEqual("Task`1"u8) || name.SequenceEqual("ValueTask`1"u8)) { - Debug.Assert(returnType.HasInstantiation); + Debug.Assert(md.HasInstantiation); returnType = md.Instantiation[0]; } else From c75c5367260d002408dca2e5acd9ca33d7543b87 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:47:14 -0700 Subject: [PATCH 10/19] Add getter to Flags for |= --- src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs index 3f53e780d435e5..b50b2eb222a73c 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs @@ -395,6 +395,10 @@ public MethodSignatureBuilder(MethodSignature template) public MethodSignatureFlags Flags { + get + { + return _flags; + } set { _flags = value; From e8ef453f9b1fa8c9ce3b15eb9266308cffac2be6 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:48:38 -0700 Subject: [PATCH 11/19] Implement getAsyncInfo in ILCompiler --- .../tools/Common/JitInterface/CorInfoImpl.cs | 28 ++++++++++++++++++- .../tools/Common/JitInterface/CorInfoTypes.cs | 16 +++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index ab43b57640a4a5..af5ac763cc4cb6 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -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("Data"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) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index f2688c585b0e52..d8dd7e9685e460 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -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. From 5ff7bc6e7c691f4c6b83226f5d2e594571b7a3d3 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:53:31 -0700 Subject: [PATCH 12/19] Use Dictionary instead of ConcurrentDictionary for AsyncMethodDescFactory --- .../JitInterface/AsyncMethodDescFactory.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs index 18caf3b9e50057..d8eabfdd1357fb 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs @@ -2,14 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using Internal.TypeSystem; namespace Internal.JitInterface { - internal class AsyncMethodDescFactory : ConcurrentDictionary + internal class AsyncMethodDescFactory : Dictionary { private Func _factoryDelegate; private AsyncMethodDesc CreateAsyncMethod(MethodDesc method) From e5ea4cedc561e67577b767ac3561a4f01f8a35d2 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:25:11 -0700 Subject: [PATCH 13/19] Refactor AsyncMethodDesc for clarity and efficiency --- .../Common/JitInterface/AsyncMethodDesc.cs | 39 +++++-------------- .../JitInterface/AsyncMethodDescFactory.cs | 5 ++- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs index 6ec597a35b500d..d0d8556b4b2965 100644 --- a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs +++ b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs @@ -9,7 +9,6 @@ namespace Internal.JitInterface { /// /// Represents the async-callable (CORINFO_CALLCONV_ASYNCCALL) variant of a Task/ValueTask returning method. - /// Mirrors the structure and usage pattern of . /// The wrapper should be short‑lived and only used while interacting with the JIT interface. /// internal sealed class AsyncMethodDesc : MethodDelegator, IJitHashableOnly @@ -65,28 +64,9 @@ public override MethodSignature Signature { get { - var wrappedSignature = _wrappedMethod.Signature; - var ret = wrappedSignature.ReturnType; - var md = (MetadataType)ret; - Debug.Assert(md.Namespace.SequenceEqual("System.Threading.Tasks"u8)); - ReadOnlySpan name = md.Name; - TypeDesc returnType = null; - if (name.SequenceEqual("Task"u8) || name.SequenceEqual("ValueTask"u8)) - { - returnType = this.Context.GetWellKnownType(WellKnownType.Void); - } - else if (name.SequenceEqual("Task`1"u8) || name.SequenceEqual("ValueTask`1"u8)) - { - Debug.Assert(md.HasInstantiation); - returnType = md.Instantiation[0]; - } - else - { - throw new UnreachableException("AsyncMethodDesc should not wrap a non-Task-like-returning method"); - } - + var md = (MetadataType)_wrappedMethod.Signature.ReturnType; var builder = new MethodSignatureBuilder(_wrappedMethod.Signature); - builder.ReturnType = returnType; + builder.ReturnType = md.HasInstantiation ? md.Instantiation[0] : this.Context.GetWellKnownType(WellKnownType.Void); builder.Flags |= MethodSignatureFlags.AsyncCallConv; return builder.ToSignature(); } @@ -111,7 +91,6 @@ internal static class AsyncMethodDescExtensions /// public static MethodDesc GetOtherAsyncMethod(this MethodDesc method, AsyncMethodDescFactory factory) { - if (method is null) return null; if (method is AsyncMethodDesc amd) return amd.Target; // unwrap @@ -124,16 +103,16 @@ public static MethodDesc GetOtherAsyncMethod(this MethodDesc method, AsyncMethod public static bool ReturnsTaskLike(this MethodDesc method) { TypeDesc ret = method.GetTypicalMethodDefinition().Signature.ReturnType; - if (ret == null) return false; - if (ret is MetadataType md) + if (ret is MetadataType md + && md.Module == method.Context.SystemModule + && md.Namespace.SequenceEqual("System.Threading.Tasks"u8)) { - if (md.Namespace.SequenceEqual("System.Threading.Tasks"u8)) + ReadOnlySpan name = md.Name; + if (name.SequenceEqual("Task"u8) || name.SequenceEqual("Task`1"u8) + || name.SequenceEqual("ValueTask"u8) || name.SequenceEqual("ValueTask`1"u8)) { - ReadOnlySpan 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 true; } } return false; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs index d8eabfdd1357fb..bde2419eb85d12 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs @@ -2,13 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; +using System.Collections.Concurrent; using System.Diagnostics; using Internal.TypeSystem; namespace Internal.JitInterface { - internal class AsyncMethodDescFactory : Dictionary + internal class AsyncMethodDescFactory : ConcurrentDictionary { private Func _factoryDelegate; private AsyncMethodDesc CreateAsyncMethod(MethodDesc method) @@ -23,6 +23,7 @@ public AsyncMethodDescFactory() public AsyncMethodDesc GetAsyncMethod(MethodDesc method) { + return GetOrAdd(method, _factoryDelegate); } } From 0cf52dcbf140897696341e9b9313e6177c8d15a0 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:52:04 -0700 Subject: [PATCH 14/19] Update src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index af5ac763cc4cb6..3df47ba887b672 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3371,7 +3371,7 @@ private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut) // 'Data' field pAsyncInfoOut.continuationDataFldHnd = ObjectToHandle(continuation.GetField("Data"u8)); // 'GCData' field - pAsyncInfoOut.continuationGCDataFldHnd = ObjectToHandle(continuation.GetField("Data"u8)); + 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; From de10bb5508f8c55a914cf93e038fb9e46d1869ee Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:54:48 -0700 Subject: [PATCH 15/19] Update Signature and delete GetOtherAsyncMethod --- .../Common/JitInterface/AsyncMethodDesc.cs | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs index d0d8556b4b2965..5e53635f2fc6ea 100644 --- a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs +++ b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs @@ -64,10 +64,11 @@ public override MethodSignature Signature { get { - var md = (MetadataType)_wrappedMethod.Signature.ReturnType; - var builder = new MethodSignatureBuilder(_wrappedMethod.Signature); + 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 |= MethodSignatureFlags.AsyncCallConv; + builder.Flags = wrappedSignature.Flags | MethodSignatureFlags.AsyncCallConv; return builder.ToSignature(); } } @@ -85,21 +86,6 @@ public override MethodSignature Signature internal static class AsyncMethodDescExtensions { - /// - /// Returns the other async variant. If the supplied method is an async-callconv wrapper, returns the wrapped (Task-returning) method. - /// If it is a Task/ValueTask returning method, returns (and possibly creates) the async-callconv variant via the factory; otherwise null. - /// - public static MethodDesc GetOtherAsyncMethod(this MethodDesc method, AsyncMethodDescFactory factory) - { - if (method is AsyncMethodDesc amd) - return amd.Target; // unwrap - - if (method.IsAsync && ReturnsTaskLike(method)) - return factory.GetAsyncMethod(method); - - return null; - } - public static bool ReturnsTaskLike(this MethodDesc method) { TypeDesc ret = method.GetTypicalMethodDefinition().Signature.ReturnType; From ff2712d75f9b0916c40c7b75184a6bf2acebfbba Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:57:43 -0700 Subject: [PATCH 16/19] Remove IsAsync requirement from AsyncMethodDesc --- src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs index 5e53635f2fc6ea..ed1fb69b6bead6 100644 --- a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs +++ b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs @@ -21,8 +21,7 @@ internal sealed class AsyncMethodDesc : MethodDelegator, IJitHashableOnly public AsyncMethodDesc(MethodDesc wrappedMethod, AsyncMethodDescFactory factory) : base(wrappedMethod) { - Debug.Assert(wrappedMethod is not null); - Debug.Assert(wrappedMethod.IsAsync && wrappedMethod.ReturnsTaskLike()); + Debug.Assert(wrappedMethod.ReturnsTaskLike()); _factory = factory; // Salt with arbitrary constant so hash space differs from underlying method. _jitVisibleHashCode = HashCode.Combine(wrappedMethod.GetHashCode(), 0x51C0A54); From 9749653dbdb52194d1bcb0c51be81f11f616d78b Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:16:57 -0700 Subject: [PATCH 17/19] Formatting and remove unused accessor --- src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs | 4 ---- .../JitInterface/AsyncMethodDescFactory.cs | 1 - 2 files changed, 5 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs index b50b2eb222a73c..3f53e780d435e5 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs @@ -395,10 +395,6 @@ public MethodSignatureBuilder(MethodSignature template) public MethodSignatureFlags Flags { - get - { - return _flags; - } set { _flags = value; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs index bde2419eb85d12..fa6d386ede77dc 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs @@ -23,7 +23,6 @@ public AsyncMethodDescFactory() public AsyncMethodDesc GetAsyncMethod(MethodDesc method) { - return GetOrAdd(method, _factoryDelegate); } } From bada361cb780b6c149e21fb7f6cdf4e37a61fa60 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 20 Oct 2025 09:53:44 -0700 Subject: [PATCH 18/19] Delete old UnboxingMethodDescFactory, move AsyncMethodDescFactory to Common --- .../JitInterface/AsyncMethodDescFactory.cs | 24 +++++++++++++++ .../ILCompiler.ReadyToRun.csproj | 8 +++-- .../JitInterface/AsyncMethodDescFactory.cs | 29 ------------------ .../JitInterface/UnboxingMethodDescFactory.cs | 30 ------------------- 4 files changed, 30 insertions(+), 61 deletions(-) create mode 100644 src/coreclr/tools/Common/JitInterface/AsyncMethodDescFactory.cs delete mode 100644 src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs delete mode 100644 src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/UnboxingMethodDescFactory.cs diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDescFactory.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDescFactory.cs new file mode 100644 index 00000000000000..5494807192e078 --- /dev/null +++ b/src/coreclr/tools/Common/JitInterface/AsyncMethodDescFactory.cs @@ -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 + { + public AsyncMethodDesc GetAsyncMethod(MethodDesc method) + { + if (!TryGetValue(method, out AsyncMethodDesc result)) + { + result = new AsyncMethodDesc(method, this); + Add(method, result); + } + + return result; + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index fdb3a928b2b49b..5b141cfdd059bf 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -162,7 +162,6 @@ - @@ -285,7 +284,6 @@ - @@ -338,8 +336,14 @@ JitInterface\UnboxingMethodDesc.cs + + JitInterface\UnboxingMethodDescFactory.cs + JitInterface\AsyncMethodDesc.cs + + JitInterface\AsyncMethodDesc.cs + diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs deleted file mode 100644 index fa6d386ede77dc..00000000000000 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/AsyncMethodDescFactory.cs +++ /dev/null @@ -1,29 +0,0 @@ -// 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.Concurrent; -using System.Diagnostics; -using Internal.TypeSystem; - -namespace Internal.JitInterface -{ - internal class AsyncMethodDescFactory : ConcurrentDictionary - { - private Func _factoryDelegate; - private AsyncMethodDesc CreateAsyncMethod(MethodDesc method) - { - return new AsyncMethodDesc(method, this); - } - - public AsyncMethodDescFactory() - { - _factoryDelegate = CreateAsyncMethod; - } - - public AsyncMethodDesc GetAsyncMethod(MethodDesc method) - { - return GetOrAdd(method, _factoryDelegate); - } - } -} diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/UnboxingMethodDescFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/UnboxingMethodDescFactory.cs deleted file mode 100644 index 42f4a648fbaaef..00000000000000 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/UnboxingMethodDescFactory.cs +++ /dev/null @@ -1,30 +0,0 @@ -// 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.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using Internal.TypeSystem; - -namespace Internal.JitInterface -{ - internal class UnboxingMethodDescFactory : ConcurrentDictionary - { - private Func _factoryDelegate; - private UnboxingMethodDesc CreateUnboxingMethod(MethodDesc method) - { - return new UnboxingMethodDesc(method, this); - } - - public UnboxingMethodDescFactory() - { - _factoryDelegate = CreateUnboxingMethod; - } - - public UnboxingMethodDesc GetUnboxingMethod(MethodDesc method) - { - return GetOrAdd(method, _factoryDelegate); - } - } -} From 2aace2c5fbdcc4dc2af5e7b8a38e905d6e0ef51a Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 20 Oct 2025 10:56:13 -0700 Subject: [PATCH 19/19] Rename ReturnsTaskLike to IsTaskReturning --- src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs index ed1fb69b6bead6..b6584b5588eafb 100644 --- a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs +++ b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs @@ -21,7 +21,7 @@ internal sealed class AsyncMethodDesc : MethodDelegator, IJitHashableOnly public AsyncMethodDesc(MethodDesc wrappedMethod, AsyncMethodDescFactory factory) : base(wrappedMethod) { - Debug.Assert(wrappedMethod.ReturnsTaskLike()); + Debug.Assert(wrappedMethod.IsTaskReturning()); _factory = factory; // Salt with arbitrary constant so hash space differs from underlying method. _jitVisibleHashCode = HashCode.Combine(wrappedMethod.GetHashCode(), 0x51C0A54); @@ -85,7 +85,10 @@ public override MethodSignature Signature internal static class AsyncMethodDescExtensions { - public static bool ReturnsTaskLike(this MethodDesc method) + /// + /// Returns true if the method returns Task, Task<T>, ValueTask, or ValueTask<T>, otherwise false. + /// + public static bool IsTaskReturning(this MethodDesc method) { TypeDesc ret = method.GetTypicalMethodDefinition().Signature.ReturnType;