diff --git a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs
index 623422b7aef992..8cb62bd656e099 100644
--- a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs
+++ b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs
@@ -41,7 +41,7 @@ public enum ReadyToRunImportSectionFlags : ushort
/// Constants for method and field encoding
///
[Flags]
- public enum ReadyToRunMethodSigFlags : byte
+ public enum ReadyToRunMethodSigFlags : ushort
{
READYTORUN_METHOD_SIG_None = 0x00,
READYTORUN_METHOD_SIG_UnboxingStub = 0x01,
@@ -52,6 +52,7 @@ public enum ReadyToRunMethodSigFlags : byte
READYTORUN_METHOD_SIG_Constrained = 0x20,
READYTORUN_METHOD_SIG_OwnerType = 0x40,
READYTORUN_METHOD_SIG_UpdateContext = 0x80,
+ READYTORUN_METHOD_SIG_AsyncThunkVariant = 0x100,
}
[Flags]
diff --git a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs
deleted file mode 100644
index b6584b5588eafb..00000000000000
--- a/src/coreclr/tools/Common/JitInterface/AsyncMethodDesc.cs
+++ /dev/null
@@ -1,109 +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.Diagnostics;
-using Internal.TypeSystem;
-
-namespace Internal.JitInterface
-{
- ///
- /// 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.
- ///
- 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
- {
- ///
- /// 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;
-
- if (ret is MetadataType md
- && md.Module == method.Context.SystemModule
- && 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/AsyncMethodDescFactory.cs b/src/coreclr/tools/Common/JitInterface/AsyncMethodDescFactory.cs
deleted file mode 100644
index 5494807192e078..00000000000000
--- a/src/coreclr/tools/Common/JitInterface/AsyncMethodDescFactory.cs
+++ /dev/null
@@ -1,24 +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.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/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 4e574ed7641083..86677b0f548c3d 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -614,7 +614,11 @@ private MethodDesc MethodBeingCompiled
{
get
{
+#if READYTORUN
+ return _methodCodeNode.GetJitMethod(_asyncMethodFactory);
+#else
return _methodCodeNode.Method;
+#endif
}
}
@@ -877,6 +881,7 @@ private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* s
if (!signature.IsStatic) sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_HASTHIS;
if (signature.IsExplicitThis) sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_EXPLICITTHIS;
+ if (signature.IsAsyncCallConv) sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_ASYNCCALL;
TypeDesc returnType = signature.ReturnType;
@@ -1395,7 +1400,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
if (info->pResolvedTokenVirtualMethod != null)
{
- methodWithTokenDecl = ComputeMethodWithToken(decl, ref *info->pResolvedTokenVirtualMethod, null, false);
+ methodWithTokenDecl = ComputeMethodWithToken(decl, ref *info->pResolvedTokenVirtualMethod, null, false, asyncVariant: false);
}
else
{
@@ -1410,7 +1415,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DECL_NOT_REPRESENTABLE;
return false;
}
- methodWithTokenDecl = new MethodWithToken(decl, declToken, null, false, null, devirtualizedMethodOwner: decl.OwningType);
+ methodWithTokenDecl = new MethodWithToken(decl, declToken, null, false, asyncVariant: false, null, devirtualizedMethodOwner: decl.OwningType);
}
MethodWithToken methodWithTokenImpl;
#endif
@@ -1436,7 +1441,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
else
{
#if READYTORUN
- methodWithTokenImpl = new MethodWithToken(nonUnboxingImpl, resolver.GetModuleTokenForMethod(nonUnboxingImpl.GetTypicalMethodDefinition(), allowDynamicallyCreatedReference: false, throwIfNotFound: true), null, unboxingStub, null, devirtualizedMethodOwner: impl.OwningType);
+ methodWithTokenImpl = new MethodWithToken(nonUnboxingImpl, resolver.GetModuleTokenForMethod(nonUnboxingImpl.GetTypicalMethodDefinition(), allowDynamicallyCreatedReference: false, throwIfNotFound: true), null, unboxingStub, asyncVariant: false, null, devirtualizedMethodOwner: impl.OwningType);
#endif
info->resolvedTokenDevirtualizedMethod = CreateResolvedTokenFromMethod(this, impl
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
index ff37fc2f9bc60b..5a20a9dffcd3ab 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
@@ -119,6 +119,7 @@ public unsafe struct CORINFO_SIG_INFO
private uint totalILArgs() { return (uint)(numArgs + (hasImplicitThis() ? 1 : 0)); }
private bool isVarArg() { return ((getCallConv() == CorInfoCallConv.CORINFO_CALLCONV_VARARG) || (getCallConv() == CorInfoCallConv.CORINFO_CALLCONV_NATIVEVARARG)); }
internal bool hasTypeArg() { return ((callConv & CorInfoCallConv.CORINFO_CALLCONV_PARAMTYPE) != 0); }
+ private bool isAsyncCallConv() { return ((callConv & CorInfoCallConv.CORINFO_CALLCONV_ASYNCCALL) != 0); }
};
//----------------------------------------------------------------------------
@@ -377,6 +378,7 @@ public enum CorInfoCallConv
CORINFO_CALLCONV_HASTHIS = 0x20,
CORINFO_CALLCONV_EXPLICITTHIS = 0x40,
CORINFO_CALLCONV_PARAMTYPE = 0x80, // Passed last. Same as CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG
+ CORINFO_CALLCONV_ASYNCCALL = 0x100, // Is this a call to an async function?
}
// Represents the calling conventions supported with the extensible calling convention syntax
diff --git a/src/coreclr/tools/Common/JitInterface/UnboxingMethodDesc.cs b/src/coreclr/tools/Common/JitInterface/UnboxingMethodDesc.cs
index eb1ba8a9d3bfc9..0d106949ae56bb 100644
--- a/src/coreclr/tools/Common/JitInterface/UnboxingMethodDesc.cs
+++ b/src/coreclr/tools/Common/JitInterface/UnboxingMethodDesc.cs
@@ -64,6 +64,14 @@ public override MethodDesc InstantiateSignature(Instantiation typeInstantiation,
return this;
}
+ public override AsyncMethodKind AsyncMethodKind
+ {
+ get
+ {
+ return _wrappedMethod.AsyncMethodKind;
+ }
+ }
+
public override string ToString()
{
return "Unboxing MethodDesc: " + _wrappedMethod.ToString();
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/AsyncMethodVariant.cs b/src/coreclr/tools/Common/TypeSystem/Common/AsyncMethodVariant.cs
new file mode 100644
index 00000000000000..c15c138dffe87f
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/Common/AsyncMethodVariant.cs
@@ -0,0 +1,138 @@
+// 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.JitInterface;
+
+
+namespace Internal.TypeSystem
+{
+ ///
+ /// Either the AsyncMethodImplVariant or AsyncMethodThunkVariant of a method marked .IsAsync.
+ ///
+ public partial class AsyncMethodVariant : MethodDelegator, IJitHashableOnly
+ {
+ private readonly AsyncMethodVariantFactory _factory;
+ private readonly AsyncMethodKind _asyncMethodKind;
+ private readonly int _jitVisibleHashCode;
+ private MethodSignature _asyncSignature;
+
+ public AsyncMethodVariant(MethodDesc wrappedMethod, AsyncMethodVariantFactory factory, AsyncMethodKind kind)
+ : base(wrappedMethod)
+ {
+ Debug.Assert(wrappedMethod.IsTaskReturning);
+ Debug.Assert(kind switch
+ {
+ AsyncMethodKind.AsyncVariantThunk => !wrappedMethod.IsAsync,
+ AsyncMethodKind.AsyncVariantImpl => wrappedMethod.IsAsync,
+ _ => false,
+ });
+ _factory = factory;
+ _asyncMethodKind = kind;
+ _jitVisibleHashCode = HashCode.Combine(wrappedMethod.GetHashCode(), 0x310bb74f);
+ }
+
+ public MethodDesc Target => _wrappedMethod;
+
+ public override AsyncMethodKind AsyncMethodKind => _asyncMethodKind;
+
+ public override MethodSignature Signature
+ {
+ get
+ {
+ return _asyncSignature ??= _wrappedMethod.Signature.CreateAsyncSignature();
+ }
+ }
+
+ public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind)
+ {
+ return _factory.GetOrCreateAsyncMethodImplVariant(_wrappedMethod.GetCanonMethodTarget(kind), _asyncMethodKind);
+ }
+
+ public override MethodDesc GetMethodDefinition()
+ {
+ var real = _wrappedMethod.GetMethodDefinition();
+ if (real == _wrappedMethod)
+ return this;
+
+ return _factory.GetOrCreateAsyncMethodImplVariant(real, _asyncMethodKind);
+ }
+
+ public override MethodDesc GetTypicalMethodDefinition()
+ {
+ var real = _wrappedMethod.GetTypicalMethodDefinition();
+ if (real == _wrappedMethod)
+ return this;
+ return _factory.GetOrCreateAsyncMethodImplVariant(real, _asyncMethodKind);
+ }
+
+ public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation)
+ {
+ var real = _wrappedMethod.InstantiateSignature(typeInstantiation, methodInstantiation);
+ if (real == _wrappedMethod)
+ return this;
+ return _factory.GetOrCreateAsyncMethodImplVariant(real, _asyncMethodKind);
+ }
+
+ public override string ToString() => $"Async variant ({_asyncMethodKind}): " + _wrappedMethod.ToString();
+
+ protected override int ClassCode => throw new NotImplementedException();
+
+ protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override int ComputeHashCode()
+ {
+ throw new NotSupportedException("This method may not be stored as it is expected to only be used transiently in the JIT");
+ }
+
+ int IJitHashableOnly.GetJitVisibleHashCode() => _jitVisibleHashCode;
+ }
+
+ public sealed class AsyncMethodVariantFactory : Dictionary<(MethodDesc, AsyncMethodKind), AsyncMethodVariant>
+ {
+ public AsyncMethodVariant GetOrCreateAsyncMethodImplVariant(MethodDesc wrappedMethod, AsyncMethodKind kind)
+ {
+ Debug.Assert(wrappedMethod.IsAsync);
+ if (!TryGetValue((wrappedMethod, kind), out AsyncMethodVariant variant))
+ {
+ variant = new AsyncMethodVariant(wrappedMethod, this, kind);
+ this[(wrappedMethod, kind)] = variant;
+ }
+ return variant;
+ }
+
+ public AsyncMethodVariant GetOrCreateAsyncThunk(MethodDesc wrappedMethod)
+ {
+ return GetOrCreateAsyncMethodImplVariant(wrappedMethod, AsyncMethodKind.AsyncVariantThunk);
+ }
+
+ public AsyncMethodVariant GetOrCreateAsyncImpl(MethodDesc wrappedMethod)
+ {
+ return GetOrCreateAsyncMethodImplVariant(wrappedMethod, AsyncMethodKind.AsyncVariantImpl);
+ }
+ }
+
+ public static class AsyncMethodVariantExtensions
+ {
+ ///
+ /// Returns true if this MethodDesc is an AsyncMethodVariant, which should not escape the jit interface.
+ ///
+ public static bool IsAsyncVariant(this MethodDesc method)
+ {
+ return method is AsyncMethodVariant;
+ }
+
+ ///
+ /// Gets the wrapped method of the AsyncMethodVariant. This method is Task-returning.
+ ///
+ public static MethodDesc GetAsyncVariantDefinition(this MethodDesc method)
+ {
+ return ((AsyncMethodVariant)method).Target;
+ }
+ }
+}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.Async.cs b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.Async.cs
new file mode 100644
index 00000000000000..2a1f28b36b138b
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.Async.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Threading;
+
+namespace Internal.TypeSystem
+{
+ public sealed partial class InstantiatedMethod
+ {
+ public override AsyncMethodKind AsyncMethodKind
+ {
+ get
+ {
+ return _methodDef.AsyncMethodKind;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs
index 6024dcc6cc335d..fb5694f92fbd62 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedMethod.cs
@@ -3,6 +3,7 @@
using System;
using System.Diagnostics;
+using System.Threading;
using Internal.NativeFormat;
namespace Internal.TypeSystem
@@ -58,21 +59,27 @@ private TypeDesc Instantiate(TypeDesc type)
return type.InstantiateSignature(default(Instantiation), _instantiation);
}
+ private void InitializeSignature()
+ {
+ var template = _methodDef.Signature;
+ _signature = InstantiateSignature(template);
+ }
+
+ private MethodSignature InstantiateSignature(MethodSignature template)
+ {
+ var builder = new MethodSignatureBuilder(template);
+ builder.ReturnType = Instantiate(template.ReturnType);
+ for (int i = 0; i < template.Length; i++)
+ builder[i] = Instantiate(template[i]);
+ return builder.ToSignature();
+ }
+
public override MethodSignature Signature
{
get
{
if (_signature == null)
- {
- MethodSignature template = _methodDef.Signature;
- MethodSignatureBuilder builder = new MethodSignatureBuilder(template);
-
- builder.ReturnType = Instantiate(template.ReturnType);
- for (int i = 0; i < template.Length; i++)
- builder[i] = Instantiate(template[i]);
-
- _signature = builder.ToSignature();
- }
+ InitializeSignature();
return _signature;
}
@@ -134,7 +141,6 @@ public override bool IsAsync
}
}
-
public override bool HasCustomAttribute(string attributeNamespace, string attributeName)
{
return _methodDef.HasCustomAttribute(attributeNamespace, attributeName);
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodDelegator.Async.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodDelegator.Async.cs
new file mode 100644
index 00000000000000..58f780c8a3aa6e
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodDelegator.Async.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace Internal.TypeSystem
+{
+ ///
+ /// Wraps a object and delegates methods to that .
+ ///
+ public abstract partial class MethodDelegator : MethodDesc
+ {
+ public abstract override AsyncMethodKind AsyncMethodKind { get; }
+ }
+}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.Async.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.Async.cs
new file mode 100644
index 00000000000000..3d3356147cb6af
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.Async.cs
@@ -0,0 +1,183 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System;
+
+namespace Internal.TypeSystem
+{
+ public sealed partial class MethodSignature
+ {
+ // Flags that extend MethodSignatureFlags.
+ // These are not in metadata, just cached values.
+ // They must not conflict with MethodSignatureFlags.
+ private static class MethodSignatureFlagsExtensions
+ {
+ public const MethodSignatureFlags ReturnsTaskOrValueTask = (MethodSignatureFlags)(1 << 30); // Not a real flag, just a cached value
+ public const MethodSignatureFlags ReturnsTaskOrValueTaskMask = (MethodSignatureFlags)(1 << 31); // Not a real flag, just a cached value
+ }
+
+ public bool ReturnsTaskOrValueTask
+ {
+ get
+ {
+ if ((_flags & MethodSignatureFlagsExtensions.ReturnsTaskOrValueTaskMask) == 0)
+ {
+ // Compute and cache the value
+ if (ReturnsTaskOrValueTaskCore())
+ {
+ _flags |= MethodSignatureFlagsExtensions.ReturnsTaskOrValueTask;
+ }
+ _flags |= MethodSignatureFlagsExtensions.ReturnsTaskOrValueTaskMask;
+ }
+ return (_flags & MethodSignatureFlagsExtensions.ReturnsTaskOrValueTask) != 0;
+ }
+ }
+
+ public MethodSignature CreateAsyncSignature()
+ {
+ Debug.Assert(!IsAsyncCallConv);
+ Debug.Assert(ReturnsTaskOrValueTask);
+ TypeDesc md = this.ReturnType;
+ MethodSignatureBuilder builder = new MethodSignatureBuilder(this);
+ builder.ReturnType = md.HasInstantiation ? md.Instantiation[0] : this.Context.GetWellKnownType(WellKnownType.Void);
+ builder.Flags = this.Flags | MethodSignatureFlags.AsyncCallingConvention;
+ return builder.ToSignature();
+ }
+
+ private bool ReturnsTaskOrValueTaskCore()
+ {
+ TypeDesc ret = this.ReturnType;
+
+ if (ret is MetadataType md
+ && md.Module == this.Context.SystemModule
+ && 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;
+ }
+ }
+
+ public enum AsyncMethodKind
+ {
+ // Regular methods not returning tasks
+ // These are "normal" methods that do not get other variants.
+ // Note: Generic T-returning methods are NotAsync, even if T could be a Task.
+ NotAsync,
+
+ // Regular methods that return Task/ValueTask
+ // Such method has its actual IL body and there also a synthetic variant that is an
+ // Async-callable thunk. (AsyncVariantThunk)
+ TaskReturning,
+
+ // Task-returning methods marked as MethodImpl::Async in metadata.
+ // Such method has a body that is a thunk that forwards to an Async implementation variant
+ // which owns the original IL. (AsyncVariantImpl)
+ RuntimeAsync,
+
+ //=============================================================
+ // On {TaskReturning, AsyncVariantThunk} and {RuntimeAsync, AsyncVariantImpl} pairs:
+ //
+ // When we see a Task-returning method we create 2 method variants that logically match the same method definition.
+ // One variant has the same signature/callconv as the defining method and another is a matching Async variant.
+ // Depending on whether the definition was a runtime async method or an ordinary Task-returning method,
+ // the IL body belongs to one of the variants and another variant is a synthetic thunk.
+ //
+ // The signature of the Async variant is derived from the original signature by replacing Task return type with
+ // modreq'd element type:
+ // Example: "Task Foo();" ===> "modreq(Task`) int Foo();"
+ // Example: "ValueTask Bar();" ===> "modreq(ValueTask) void Bar();"
+ //
+ // The reason for this encoding is that:
+ // - it uses parts of original signature, as-is, thus does not need to look for or construct anything
+ // - it "unwraps" the element type.
+ // - it is reversible. In particular nonconflicting signatures will map to nonconflicting ones.
+ //
+ // Async methods are called with CORINFO_CALLCONV_ASYNCCALL call convention.
+ //
+ // It is possible to get from one variant to another via GetAsyncOtherVariant.
+ //
+ // NOTE: not all Async methods are "variants" from a pair, see AsyncExplicitImpl below.
+ //=============================================================
+
+ // The following methods use special calling convention (CORINFO_CALLCONV_ASYNCCALL)
+ // These methods are emitted by the JIT as resumable state machines and also take an extra
+ // parameter and extra return - the continuation object.
+
+ // Async methods with actual IL implementation of a MethodImpl::Async method.
+ AsyncVariantImpl,
+
+ // Async methods with synthetic bodies that forward to a TaskReturning method.
+ AsyncVariantThunk,
+
+ // Methods that are explicitly declared as Async in metadata while not Task returning.
+ // This is a special case used in a few infrastructure methods like `Await`.
+ // Such methods do not get non-Async variants/thunks and can only be called from another Async method.
+ // NOTE: These methods have the original signature and it is not possible to tell if the method is Async
+ // from the signature alone, thus all these methods are also JIT intrinsics.
+ AsyncExplicitImpl,
+ }
+
+ public abstract partial class MethodDesc : TypeSystemEntity
+ {
+ public virtual AsyncMethodKind AsyncMethodKind
+ {
+ get
+ {
+ return AsyncMethodKind.NotAsync;
+ }
+ }
+
+ public bool IsTaskReturning
+ {
+ get
+ {
+ return Signature.ReturnsTaskOrValueTask;
+ }
+ }
+
+ public bool IsAsyncVariant
+ {
+ get
+ {
+ return AsyncMethodKind is
+ AsyncMethodKind.AsyncVariantImpl or
+ AsyncMethodKind.AsyncVariantThunk;
+ }
+ }
+
+ ///
+ /// Is this synthetic Task/async adapter to an async/Task implementation?
+ /// If yes, the method has another variant, which has the actual user-defined method body.
+ ///
+ public bool IsAsyncThunk
+ {
+ get
+ {
+ return AsyncMethodKind is
+ AsyncMethodKind.AsyncVariantThunk or
+ AsyncMethodKind.RuntimeAsync;
+ }
+ }
+
+ ///
+ /// Is this method callable as an async method? (i.e. uses Async calling convention)
+ ///
+ public bool IsAsyncCallConv
+ {
+ get
+ {
+ return AsyncMethodKind is
+ AsyncMethodKind.AsyncVariantImpl or
+ AsyncMethodKind.AsyncVariantThunk or
+ AsyncMethodKind.AsyncExplicitImpl;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs
index 3f53e780d435e5..656f7b0c905bd9 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs
@@ -20,10 +20,10 @@ public enum MethodSignatureFlags
UnmanagedCallingConventionThisCall = 0x0003,
CallingConventionVarargs = 0x0005,
UnmanagedCallingConvention = 0x0009,
+ AsyncCallingConvention = 0x0100,
Static = 0x0010,
ExplicitThis = 0x0020,
- AsyncCallConv = 0x0040,
}
public enum EmbeddedSignatureDataKind
@@ -143,7 +143,7 @@ public bool IsAsyncCallConv
{
get
{
- return (_flags & MethodSignatureFlags.AsyncCallConv) != 0;
+ return (_flags & MethodSignatureFlags.AsyncCallingConvention) != 0;
}
}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.Async.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.Async.cs
new file mode 100644
index 00000000000000..cfe736142b9075
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.Async.cs
@@ -0,0 +1,20 @@
+// 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.Threading;
+using Debug = System.Diagnostics.Debug;
+
+namespace Internal.TypeSystem
+{
+ public sealed partial class MethodForInstantiatedType
+ {
+ public override AsyncMethodKind AsyncMethodKind
+ {
+ get
+ {
+ return _typicalMethodDef.AsyncMethodKind;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs b/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs
index b5c7195b483e14..2c93bbcdfd0bf0 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MethodForInstantiatedType.cs
@@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-
+using System.Threading;
using Debug = System.Diagnostics.Debug;
namespace Internal.TypeSystem
@@ -51,21 +51,29 @@ private TypeDesc Instantiate(TypeDesc type)
return type.InstantiateSignature(_instantiatedType.Instantiation, default(Instantiation));
}
+ private MethodSignature InstantiateSignature(MethodSignature template)
+ {
+ MethodSignatureBuilder builder = new MethodSignatureBuilder(template);
+ builder.ReturnType = Instantiate(template.ReturnType);
+ for (int i = 0; i < template.Length; i++)
+ builder[i] = Instantiate(template[i]);
+
+ return builder.ToSignature();
+ }
+
+ private void InitializeSignature()
+ {
+ MethodSignature template = _typicalMethodDef.Signature;
+ _signature = InstantiateSignature(template);
+
+ }
+
public override MethodSignature Signature
{
get
{
if (_signature == null)
- {
- MethodSignature template = _typicalMethodDef.Signature;
- MethodSignatureBuilder builder = new MethodSignatureBuilder(template);
-
- builder.ReturnType = Instantiate(template.ReturnType);
- for (int i = 0; i < template.Length; i++)
- builder[i] = Instantiate(template[i]);
-
- _signature = builder.ToSignature();
- }
+ InitializeSignature();
return _signature;
}
diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.Async.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.Async.cs
new file mode 100644
index 00000000000000..a4ad0234e388d4
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.Async.cs
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Threading;
+
+namespace Internal.TypeSystem.Ecma
+{
+ public sealed partial class EcmaMethod
+ {
+ public override AsyncMethodKind AsyncMethodKind
+ {
+ get
+ {
+ // EcmaMethod always represents the Task-returning variant for Task-returning methods
+ // in order to match the signature, even though the IL in metadata may not match.
+ // Other MethodDescs represent the async variant.
+ bool returnsTask = Signature.ReturnsTaskOrValueTask;
+ if (returnsTask)
+ {
+ return IsAsync
+ ? AsyncMethodKind.RuntimeAsync
+ : AsyncMethodKind.TaskReturning;
+ }
+ else
+ {
+ return IsAsync
+ ? AsyncMethodKind.AsyncExplicitImpl
+ : AsyncMethodKind.NotAsync;
+ }
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs
index 09fb19a982fd79..facce63d99e8d4 100644
--- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs
@@ -15,6 +15,7 @@ public sealed partial class EcmaMethod : MethodDesc, EcmaModule.IEntityHandleObj
{
private static class MethodFlags
{
+#pragma warning disable IDE0055 // Disable formatting to keep aligned
public const int BasicMetadataCache = 0x00001;
public const int Virtual = 0x00002;
public const int NewSlot = 0x00004;
@@ -28,11 +29,12 @@ private static class MethodFlags
public const int AggressiveOptimization = 0x00400;
public const int NoOptimization = 0x00800;
public const int RequireSecObject = 0x01000;
+ public const int Async = 0x02000;
- public const int AttributeMetadataCache = 0x02000;
- public const int Intrinsic = 0x04000;
- public const int UnmanagedCallersOnly = 0x08000;
- public const int Async = 0x10000;
+ public const int AttributeMetadataCache = 0x04000;
+ public const int Intrinsic = 0x08000;
+ public const int UnmanagedCallersOnly = 0x10000;
+#pragma warning restore IDE0055
};
private EcmaType _type;
@@ -75,14 +77,13 @@ public override EcmaType OwningType
}
}
- private MethodSignature InitializeSignature()
+ private void InitializeSignature()
{
var metadataReader = MetadataReader;
BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetMethodDefinition(_handle).Signature);
-
EcmaSignatureParser parser = new EcmaSignatureParser(Module, signatureReader, NotFoundBehavior.Throw);
var signature = parser.ParseMethodSignature();
- return (_signature = signature);
+ _signature = signature;
}
public override MethodSignature Signature
@@ -90,7 +91,8 @@ public override MethodSignature Signature
get
{
if (_signature == null)
- return InitializeSignature();
+ InitializeSignature();
+
return _signature;
}
}
diff --git a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.cs b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.cs
index 5f97f7645ea76e..e9ff95f1d0e9e8 100644
--- a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.cs
+++ b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.cs
@@ -39,6 +39,8 @@ internal MethodForRuntimeDeterminedType(MethodDesc typicalMethodDef, RuntimeDete
public override ReadOnlySpan Name => _typicalMethodDef.Name;
public override MethodDesc GetTypicalMethodDefinition() => _typicalMethodDef;
public override Instantiation Instantiation => _typicalMethodDef.Instantiation;
+ public override bool IsAsync => _typicalMethodDef.IsAsync;
+ public override AsyncMethodKind AsyncMethodKind => _typicalMethodDef.AsyncMethodKind;
public override bool HasCustomAttribute(string attributeNamespace, string attributeName)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs
index a89a3115cb102a..e96fb8036844c4 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs
@@ -43,7 +43,10 @@ public override IEnumerable GetStaticDependencies(NodeFacto
try
{
context.DetectGenericCycles(Type, method);
- dependencies.Add(context.CompiledMethodNode(method), $"Method on type {Type.ToString()}");
+ dependencies.Add(context.CompiledMethodNode(method, false), $"Method on type {Type.ToString()}");
+ if (method.IsTaskReturning)
+ dependencies.Add(context.CompiledMethodNode(method, true), $"Async Method on type {Type.ToString()}");
+
}
catch (TypeSystemException)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs
index 4c73a0ab08bcab..f8e7b2c6dd242d 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs
@@ -59,7 +59,7 @@ public override IEnumerable GetStaticDependencies(NodeFacto
}
if (useDependency)
{
- ISymbolNode canonMethodNode = factory.CompiledMethodNode(canonMethod);
+ ISymbolNode canonMethodNode = factory.CompiledMethodNode(canonMethod, _method.AsyncVariant);
yield return new DependencyListEntry(canonMethodNode, "Canonical method for instantiating stub");
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ILBodyFixupSignature.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ILBodyFixupSignature.cs
index 45b39e8de77d72..f43dfd6dc73924 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ILBodyFixupSignature.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ILBodyFixupSignature.cs
@@ -77,7 +77,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
dataBuilder.EmitTypeSignature(typeRef, innerContext);
}
- MethodWithToken method = new MethodWithToken(_method, moduleToken, null, unboxing: false, context: null);
+ MethodWithToken method = new MethodWithToken(_method, moduleToken, null, unboxing: false, asyncVariant: false, context: null);
dataBuilder.EmitMethodSignature(method, enforceDefEncoding: false, enforceOwningType: false, innerContext, false);
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs
index db63a30fae67a5..c49afd4fb7fc67 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs
@@ -51,7 +51,7 @@ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilde
sb.Append("__ReadyToRunInstanceEntryPointTable"u8);
}
- public static byte[] BuildSignatureForMethodDefinedInModule(MethodDesc method, NodeFactory factory)
+ public static byte[] BuildSignatureForMethodDefinedInModule(MethodDesc method, NodeFactory factory, bool asyncVariant = false)
{
EcmaMethod typicalMethod = (EcmaMethod)method.GetTypicalMethodDefinition();
@@ -70,7 +70,7 @@ public static byte[] BuildSignatureForMethodDefinedInModule(MethodDesc method, N
ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder();
signatureBuilder.EmitMethodSignature(
- new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, context: null),
+ new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, asyncVariant: asyncVariant, context: null),
enforceDefEncoding: true,
enforceOwningType: moduleToken.Module is EcmaModule ? factory.CompilationModuleGroup.EnforceOwningType((EcmaModule)moduleToken.Module) : true,
factory.SignatureContext,
@@ -81,7 +81,7 @@ public static byte[] BuildSignatureForMethodDefinedInModule(MethodDesc method, N
private byte[] BuildSignatureForMethod(MethodWithGCInfo method, NodeFactory factory)
{
- return BuildSignatureForMethodDefinedInModule(method.Method, factory);
+ return BuildSignatureForMethodDefinedInModule(method.Method, factory, method.AsyncVariant);
}
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstrumentationDataTableNode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstrumentationDataTableNode.cs
index 323661407e311d..8290efe54bc7e1 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstrumentationDataTableNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstrumentationDataTableNode.cs
@@ -147,7 +147,7 @@ private int MethodToInt(TypeSystemEntityOrUnknown handle)
EcmaMethod typicalMethod = (EcmaMethod)handle.AsMethod.GetTypicalMethodDefinition();
ModuleToken moduleToken = new ModuleToken(typicalMethod.Module, typicalMethod.Handle);
- MethodWithToken tok = new MethodWithToken(handle.AsMethod, moduleToken, constrainedType: null, unboxing: false, context: null);
+ MethodWithToken tok = new MethodWithToken(handle.AsMethod, moduleToken, constrainedType: null, unboxing: false, asyncVariant:false, context: null);
Import methodHandleImport = (Import)_symbolFactory.CreateReadyToRunHelper(ReadyToRunHelperId.MethodHandle, tok);
_imports.Add(methodHandleImport);
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs
index c3f3324e0c6ba4..9bbc5f1ffe0a53 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs
@@ -65,7 +65,7 @@ protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFact
try
{
factory.DetectGenericCycles(_method.Method, canonMethod);
- list.Add(factory.CompiledMethodNode(canonMethod), "Virtual function dependency on cross module inlineable method");
+ list.Add(factory.CompiledMethodNode(canonMethod, _method.AsyncVariant), "Virtual function dependency on cross module inlineable method");
}
catch (TypeSystemException)
{
@@ -89,7 +89,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
// Optimize some of the fixups into a more compact form
ReadyToRunFixupKind fixupKind = _fixupKind;
bool optimized = false;
- if (!_method.Unboxing && !IsInstantiatingStub && _method.ConstrainedType == null &&
+ if (!_method.Unboxing && !IsInstantiatingStub && !_method.AsyncVariant && _method.ConstrainedType == null &&
fixupKind == ReadyToRunFixupKind.MethodEntry)
{
if (!_method.Method.HasInstantiation && !_method.Method.OwningType.HasInstantiation && !_method.Method.OwningType.IsArray)
@@ -116,13 +116,13 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
if (method.Token.TokenType == CorTokenType.mdtMethodSpec)
{
- method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method), method.ConstrainedType, unboxing: _method.Unboxing, null);
+ method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method), method.ConstrainedType, unboxing: _method.Unboxing, asyncVariant: _method.AsyncVariant, null);
}
else if (!optimized && (method.Token.TokenType == CorTokenType.mdtMemberRef))
{
if (method.Method.OwningType.GetTypeDefinition() is EcmaType)
{
- method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method), method.ConstrainedType, unboxing: _method.Unboxing, null);
+ method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method), method.ConstrainedType, unboxing: _method.Unboxing, asyncVariant: _method.AsyncVariant, null);
}
}
}
@@ -154,6 +154,10 @@ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilde
{
sb.Append(" [INST]"u8);
}
+ if (_method.AsyncVariant)
+ {
+ sb.Append(" [ASYNC]"u8);
+ }
sb.Append(": "u8);
_method.AppendMangledName(nameMangler, sb);
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs
index 4b5f00c661c678..6162beef9387e5 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs
@@ -31,12 +31,17 @@ public class MethodWithGCInfo : ObjectNode, IMethodBodyNode, ISymbolDefinitionNo
private MethodDesc[] _inlinedMethods;
private bool _lateTriggeredCompilation;
private DependencyList _nonRelocationDependencies;
+ private bool _isAsyncVariant;
- public MethodWithGCInfo(MethodDesc methodDesc)
+ public MethodWithGCInfo(MethodDesc methodDesc, bool isAsyncVariant)
{
+ Debug.Assert(!methodDesc.IsAsyncVariant());
+ Debug.Assert(!methodDesc.IsUnboxingThunk());
GCInfoNode = new MethodGCInfoNode(this);
_fixups = new List();
_method = methodDesc;
+ _isAsyncVariant = isAsyncVariant;
+ Debug.Assert(_isAsyncVariant ? methodDesc.IsTaskReturning : true);
}
protected override void OnMarked(NodeFactory context)
@@ -91,6 +96,15 @@ public void SetCode(ObjectData data)
public MethodDesc Method => _method;
+ public MethodDesc GetJitMethod(AsyncMethodVariantFactory factory)
+ {
+ if (!_isAsyncVariant)
+ return _method;
+ return _method.IsAsync ?
+ factory.GetOrCreateAsyncImpl(_method)
+ : factory.GetOrCreateAsyncThunk(_method);
+ }
+
public List Fixups => _fixups;
public int Size => _methodCode.Data.Length;
@@ -323,7 +337,7 @@ public void InitializeFrameInfos(FrameInfo[] frameInfos)
else
{
// On x86, fake a single frame info representing the entire method
- _frameInfos = new FrameInfo[]
+ _frameInfos = new FrameInfo[]
{
new FrameInfo((FrameInfoFlags)0, startOffset: 0, endOffset: 0, blobData: Array.Empty())
};
@@ -378,7 +392,13 @@ public void InitializeDebugEHClauseInfos(DebugEHClauseInfo[] debugEHClauseInfos)
public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
{
MethodWithGCInfo otherNode = (MethodWithGCInfo)other;
- return comparer.Compare(_method, otherNode._method);
+
+ var result = comparer.Compare(_method, otherNode._method);
+ if (result != 0)
+ return result;
+ if (_isAsyncVariant == otherNode._isAsyncVariant)
+ return 0;
+ return _isAsyncVariant ? -1 : 1;
}
public void InitializeInliningInfo(MethodDesc[] inlinedMethods, NodeFactory factory)
@@ -396,6 +416,9 @@ public void InitializeNonRelocationDependencies(DependencyList dependencies)
public int Offset => 0;
public override bool IsShareable => throw new NotImplementedException();
+
+ public bool AsyncVariant => _isAsyncVariant;
+
public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => IsEmpty;
public override string ToString() => _method.ToString();
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs
index 2c4ca7cd004702..b259ae6d822b00 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs
@@ -436,6 +436,10 @@ public void EmitMethodSignature(
{
flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType;
}
+ if (method.AsyncVariant)
+ {
+ flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_AsyncThunkVariant;
+ }
EmitMethodSpecificationSignature(method, flags, enforceDefEncoding, enforceOwningType, context);
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs
index 4a45d024afcf89..31f0c40d409652 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs
@@ -185,7 +185,7 @@ public static void AddDependenciesForAsyncStateMachineBox(ref DependencyList dep
try
{
factory.DetectGenericCycles(type, method);
- dependencies.Add(factory.CompiledMethodNode(method), $"AsyncStateMachineBox Method on type {type.ToString()}");
+ dependencies.Add(factory.CompiledMethodNode(method, false), $"AsyncStateMachineBox Method on type {type.ToString()}");
}
catch (TypeSystemException)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs
index e1c1e9a2448b10..fd3a079152fd70 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs
@@ -112,13 +112,13 @@ public void AddMarkedILBodyFixupSignature(ILBodyFixupSignature sig)
_markedILBodyFixupSignatures.Add(sig);
}
- private NodeCache _localMethodCache;
+ private NodeCache<(MethodDesc, bool), MethodWithGCInfo> _localMethodCache;
- public MethodWithGCInfo CompiledMethodNode(MethodDesc method)
+ public MethodWithGCInfo CompiledMethodNode(MethodDesc method, bool asyncVariant)
{
Debug.Assert(CompilationModuleGroup.ContainsMethodBody(method, false));
Debug.Assert(method == method.GetCanonMethodTarget(CanonicalFormKind.Specific));
- return _localMethodCache.GetOrAdd(method);
+ return _localMethodCache.GetOrAdd((method, asyncVariant));
}
private NodeCache _allMethodsOnType;
@@ -281,9 +281,9 @@ private void CreateNodeCaches()
_importMethods = new NodeCache(CreateMethodEntrypoint);
- _localMethodCache = new NodeCache(key =>
+ _localMethodCache = new NodeCache<(MethodDesc, bool), MethodWithGCInfo>(key =>
{
- return new MethodWithGCInfo(key);
+ return new MethodWithGCInfo(key.Item1, key.Item2);
});
_methodSignatures = new NodeCache(key =>
@@ -430,7 +430,7 @@ private IMethodNode CreateMethodEntrypoint(TypeAndMethod key)
if (CompilationModuleGroup.ContainsMethodBody(compilableMethod, false))
{
- methodWithGCInfo = CompiledMethodNode(compilableMethod);
+ methodWithGCInfo = CompiledMethodNode(compilableMethod, method.AsyncVariant);
}
if (isPrecodeImportRequired)
@@ -479,7 +479,7 @@ public IEnumerable EnumerateCompiledMethods(EcmaModule moduleT
EcmaModule module = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module;
ModuleToken moduleToken = Resolver.GetModuleTokenForMethod(method, allowDynamicallyCreatedReference: true, throwIfNotFound: true);
- IMethodNode methodNodeDebug = MethodEntrypoint(new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, context: null), false, false, false);
+ IMethodNode methodNodeDebug = MethodEntrypoint(new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, asyncVariant: methodCodeNode.AsyncVariant, context: null), false, false, false);
MethodWithGCInfo methodCodeNodeDebug = methodNodeDebug as MethodWithGCInfo;
if (methodCodeNodeDebug == null && methodNodeDebug is DelayLoadMethodImport DelayLoadMethodImport)
{
@@ -778,7 +778,7 @@ public void AttachToDependencyGraph(DependencyAnalyzerBase graph, I
}
}
- InliningInfoNode crossModuleInliningInfoTable = new InliningInfoNode(null,
+ InliningInfoNode crossModuleInliningInfoTable = new InliningInfoNode(null,
CompilationModuleGroup.IsCompositeBuildMode ? InliningInfoNode.InfoType.CrossModuleInliningForCrossModuleDataOnly : InliningInfoNode.InfoType.CrossModuleAllMethods);
Header.Add(Internal.Runtime.ReadyToRunSectionType.CrossModuleInlineInfo, crossModuleInliningInfoTable, crossModuleInliningInfoTable);
this.CrossModuleInlningInfo = crossModuleInliningInfoTable;
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs
index e7e4039f95071f..4a6c947af022b9 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs
@@ -247,7 +247,7 @@ public void AddCompilationRoot(MethodDesc method, bool rootMinimalDependencies,
MethodDesc canonMethod = method.GetCanonMethodTarget(CanonicalFormKind.Specific);
if (_factory.CompilationModuleGroup.ContainsMethodBody(canonMethod, false))
{
- IMethodNode methodEntryPoint = _factory.CompiledMethodNode(canonMethod);
+ IMethodNode methodEntryPoint = _factory.CompiledMethodNode(canonMethod, false);
if (rootMinimalDependencies)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs
index 93e3f3605cb03d..ddf005b8a7e6b7 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs
@@ -85,7 +85,7 @@ protected virtual void Graph_NewMarkedNode(DependencyNodeCore obj)
perModuleData = new PerModuleMethodsGenerated(module);
_methodsGenerated[module] = perModuleData;
}
- if (method.HasInstantiation || method.OwningType.HasInstantiation)
+ if (method.HasInstantiation || method.OwningType.HasInstantiation || method.IsAsyncThunk)
{
perModuleData.GenericMethodsGenerated.Add(methodNode);
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/ReadyToRunILProvider.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/ReadyToRunILProvider.cs
index 6ea7cb2638fedf..bf97d6721ac908 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/ReadyToRunILProvider.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/ReadyToRunILProvider.cs
@@ -165,6 +165,14 @@ public override MethodIL GetMethodIL(MethodDesc method)
return result;
}
+ if (method.IsAsync)
+ {
+ // We should not be creating any AsyncMethodVariants yet.
+ // This hasn't been implemented.
+ Debug.Assert(method.AsyncMethodKind is AsyncMethodKind.RuntimeAsync or AsyncMethodKind.AsyncExplicitImpl);
+ return null;
+ }
+
// Check to see if there is an override for the EcmaMethodIL. If there is not
// then simply return the EcmaMethodIL. In theory this could call
// CreateCrossModuleInlineableTokensForILBody, but we explicitly do not want
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
index 5139e35de8b69d..444533b810b62f 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
@@ -354,11 +354,8 @@
JitInterface\UnboxingMethodDescFactory.cs
-
- JitInterface\AsyncMethodDesc.cs
-
-
- JitInterface\AsyncMethodDesc.cs
+
+ TypeSystem\Common\AsyncMethodVariant.cs
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
index 2bde41e031f496..b23f695bb6443e 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
@@ -130,16 +130,19 @@ public class MethodWithToken
public readonly TypeDesc ConstrainedType;
public readonly bool Unboxing;
public readonly bool OwningTypeNotDerivedFromToken;
+ public readonly bool AsyncVariant;
public readonly TypeDesc OwningType;
- public MethodWithToken(MethodDesc method, ModuleToken token, TypeDesc constrainedType, bool unboxing, object context, TypeDesc devirtualizedMethodOwner = null)
+ public MethodWithToken(MethodDesc method, ModuleToken token, TypeDesc constrainedType, bool unboxing, bool asyncVariant, object context, TypeDesc devirtualizedMethodOwner = null)
{
Debug.Assert(!method.IsUnboxingThunk());
+ Debug.Assert(!method.IsAsyncVariant());
Method = method;
Token = token;
ConstrainedType = constrainedType;
Unboxing = unboxing;
+ AsyncVariant = asyncVariant;
OwningType = GetMethodTokenOwningType(this, constrainedType, context, devirtualizedMethodOwner, out OwningTypeNotDerivedFromToken);
}
@@ -349,6 +352,8 @@ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
}
if (Unboxing)
sb.Append("; UNBOXING"u8);
+ if (AsyncVariant)
+ sb.Append("; ASYNC"u8);
}
public override string ToString()
@@ -365,6 +370,8 @@ public override string ToString()
debuggingName.Append(Token.ToString());
if (Unboxing)
debuggingName.Append("; UNBOXING");
+ if (AsyncVariant)
+ debuggingName.Append("; ASYNC");
return debuggingName.ToString();
}
@@ -396,6 +403,10 @@ public int CompareTo(MethodWithToken other, TypeSystemComparer comparer)
if (result != 0)
return result;
+ result = AsyncVariant.CompareTo(other.AsyncVariant);
+ if (result != 0)
+ return result;
+
// The OwningType/OwningTypeNotDerivedFromToken should be equivalent if the above conditions are equal.
Debug.Assert(OwningTypeNotDerivedFromToken == other.OwningTypeNotDerivedFromToken);
Debug.Assert(OwningTypeNotDerivedFromToken || (OwningType == other.OwningType));
@@ -465,6 +476,7 @@ unsafe partial class CorInfoImpl
private NativeVarInfo[] _debugVarInfos;
private HashSet _inlinedMethods;
private UnboxingMethodDescFactory _unboxingThunkFactory = new UnboxingMethodDescFactory();
+ private AsyncMethodVariantFactory _asyncMethodFactory = new AsyncMethodVariantFactory();
private List _precodeFixups;
private List _ilBodiesNeeded;
private Dictionary _preInitedTypes = new Dictionary();
@@ -906,7 +918,7 @@ private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref
var methodIL = HandleToObject(pResolvedToken.tokenScope);
MethodDesc sharedMethod = methodIL.OwningMethod.GetSharedRuntimeFormMethodTarget();
_compilation.NodeFactory.DetectGenericCycles(MethodBeingCompiled, sharedMethod);
- helperArg = new MethodWithToken(methodDesc, HandleToModuleToken(ref pResolvedToken), constrainedType, unboxing: false, context: sharedMethod);
+ helperArg = new MethodWithToken(methodDesc, HandleToModuleToken(ref pResolvedToken), constrainedType, unboxing: false, asyncVariant: false, context: sharedMethod);
}
else if (helperArg is FieldDesc fieldDesc)
{
@@ -956,6 +968,7 @@ private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetM
HandleToModuleToken(ref pTargetMethod),
constrainedType: constrainedType,
unboxing: false,
+ asyncVariant: false,
context: typeOrMethodContext);
// runtime lookup is not needed, callerHandle is unused
@@ -1329,7 +1342,7 @@ private FieldWithToken ComputeFieldWithToken(FieldDesc field, ref CORINFO_RESOLV
return new FieldWithToken(field, token);
}
- private MethodWithToken ComputeMethodWithToken(MethodDesc method, ref CORINFO_RESOLVED_TOKEN pResolvedToken, TypeDesc constrainedType, bool unboxing)
+ private MethodWithToken ComputeMethodWithToken(MethodDesc method, ref CORINFO_RESOLVED_TOKEN pResolvedToken, TypeDesc constrainedType, bool unboxing, bool asyncVariant)
{
ModuleToken token = HandleToModuleToken(ref pResolvedToken, method, out object context, ref constrainedType);
@@ -1339,7 +1352,7 @@ private MethodWithToken ComputeMethodWithToken(MethodDesc method, ref CORINFO_RE
devirtualizedMethodOwner = HandleToObject(pResolvedToken.hClass);
}
- return new MethodWithToken(method, token, constrainedType: constrainedType, unboxing: unboxing, context: context, devirtualizedMethodOwner: devirtualizedMethodOwner);
+ return new MethodWithToken(method, token, constrainedType: constrainedType, unboxing: unboxing, asyncVariant: asyncVariant, context: context, devirtualizedMethodOwner: devirtualizedMethodOwner);
}
private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken, MethodDesc methodDesc, out object context, ref TypeDesc constrainedType)
@@ -2444,7 +2457,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO
pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(
_compilation.SymbolNodeFactory.InterfaceDispatchCell(
- ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: null, unboxing: false),
+ ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: null, unboxing: false, asyncVariant: false),
MethodBeingCompiled));
// If the abi of the method isn't stable, this will cause a usage of the RequiresRuntimeJitSymbol, which will trigger a RequiresRuntimeJitException
@@ -2489,7 +2502,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO
// READYTORUN: FUTURE: Direct calls if possible
pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(
_compilation.NodeFactory.MethodEntrypoint(
- ComputeMethodWithToken(nonUnboxingMethod, ref pResolvedToken, constrainedType, unboxing: isUnboxingStub),
+ ComputeMethodWithToken(nonUnboxingMethod, ref pResolvedToken, constrainedType, unboxing: isUnboxingStub, asyncVariant: false),
isInstantiatingStub: useInstantiatingStub,
isPrecodeImportRequired: (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0,
isJumpableImportRequired: false));
@@ -2513,7 +2526,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO
{
pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(
_compilation.NodeFactory.DynamicHelperCell(
- ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: null, unboxing: false),
+ ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: null, unboxing: false, asyncVariant: false),
useInstantiatingStub));
Debug.Assert(!pResult->sig.hasTypeArg());
@@ -2540,7 +2553,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO
{
pResult->instParamLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(
ReadyToRunHelperId.MethodDictionary,
- ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: constrainedType, unboxing: false)));
+ ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: constrainedType, unboxing: false, asyncVariant: false)));
}
else
{
@@ -2791,7 +2804,7 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool
symbolNode = _compilation.SymbolNodeFactory.CreateReadyToRunHelper(
ReadyToRunHelperId.MethodHandle,
- ComputeMethodWithToken(md, ref pResolvedToken, constrainedType: null, unboxing: unboxingStub));
+ ComputeMethodWithToken(md, ref pResolvedToken, constrainedType: null, unboxing: unboxingStub, asyncVariant: false /* ?? */));
}
break;
@@ -3033,7 +3046,7 @@ private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORIN
Debug.Assert(_compilation.CompilationModuleGroup.VersionsWithMethodBody(methodDesc));
EcmaMethod ecmaMethod = (EcmaMethod)methodDesc;
ModuleToken moduleToken = new ModuleToken(ecmaMethod.Module, ecmaMethod.Handle);
- MethodWithToken methodWithToken = new MethodWithToken(ecmaMethod, moduleToken, constrainedType: null, unboxing: false, context: null);
+ MethodWithToken methodWithToken = new MethodWithToken(ecmaMethod, moduleToken, constrainedType: null, unboxing: false, asyncVariant: false, context: null);
if ((ecmaMethod.GetPInvokeMethodCallingConventions() & UnmanagedCallingConventions.IsSuppressGcTransition) != 0)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj
index d8c363424d831a..04a075b74820db 100644
--- a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj
@@ -264,6 +264,9 @@
TypeSystem\Common\InstantiatedMethod.cs
+
+ TypeSystem\Common\InstantiatedMethod.cs
+
TypeSystem\Common\InstantiatedMethod.Diagnostic.cs
@@ -312,6 +315,9 @@
TypeSystem\Common\MethodForInstantiatedType.cs
+
+ TypeSystem\Common\MethodForInstantiatedType.Async.cs
+
TypeSystem\Common\MethodForInstantiatedType.Diagnostic.cs
@@ -378,12 +384,18 @@
TypeSystem\Common\MethodDelegator.cs
+
+ TypeSystem\Common\MethodDelegator.Async.cs
+
TypeSystem\Common\MethodDelegator.Diagnostic.cs
TypeSystem\Common\MethodDesc.cs
+
+ TypeSystem\Common\MethodDesc.Async.cs
+
TypeSystem\Common\MethodDesc.Diagnostic.cs
@@ -480,6 +492,9 @@
Ecma\EcmaMethod.cs
+
+ Ecma\EcmaMethod.Async.cs
+
Ecma\EcmaMethod.cs