Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions src/coreclr/tools/Common/Compiler/AsyncMethodVariant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ private MethodSignature InitializeSignature()

public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind)
{
// We should not be calling GetCanonMethodTarget on generic definitions of anything
// and this MethodDesc is a generic definition.
Debug.Assert(!HasInstantiation && !OwningType.HasInstantiation);
return this;
}

Expand Down Expand Up @@ -77,12 +74,9 @@ protected override int CompareToImpl(MethodDesc other, TypeSystemComparer compar

public static class AsyncMethodVariantExtensions
{
/// <summary>
/// Returns true if this MethodDesc is an AsyncMethodVariant, which should not escape the jit interface.
/// </summary>
public static bool IsAsyncVariant(this MethodDesc method)
{
return method is AsyncMethodVariant;
return method.GetTypicalMethodDefinition() is AsyncMethodVariant;
}
}
}
137 changes: 137 additions & 0 deletions src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Async.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;

using Internal.IL;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
Expand All @@ -11,6 +13,141 @@ namespace ILCompiler
{
public partial class CompilerTypeSystemContext
{
private sealed class AsyncAwareVirtualMethodResolutionAlgorithm : MetadataVirtualMethodAlgorithm
{
private readonly CompilerTypeSystemContext _context;

public AsyncAwareVirtualMethodResolutionAlgorithm(CompilerTypeSystemContext context)
=> _context = context;

private MethodDesc DecomposeAsyncVariant(MethodDesc method, out bool isAsyncVariant)
{
isAsyncVariant = method.IsAsyncVariant();
return isAsyncVariant ? _context.GetTargetOfAsyncVariantMethod(method) : method;
}

public override MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, TypeDesc objectType)
{
targetMethod = DecomposeAsyncVariant(targetMethod, out bool isAsyncSlot);
MethodDesc result = base.FindVirtualFunctionTargetMethodOnObjectType(targetMethod, objectType);
if (result != null && isAsyncSlot)
result = _context.GetAsyncVariantMethod(result);

return result;
}

public override DefaultInterfaceMethodResolution ResolveInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, TypeDesc currentType, out MethodDesc impl)
{
interfaceMethod = DecomposeAsyncVariant(interfaceMethod, out bool isAsyncSlot);
DefaultInterfaceMethodResolution result = base.ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethod, currentType, out impl);
if (impl != null && isAsyncSlot)
impl = _context.GetAsyncVariantMethod(impl);

return result;
}

public override MethodDesc ResolveInterfaceMethodToStaticVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType)
{
interfaceMethod = DecomposeAsyncVariant(interfaceMethod, out bool isAsyncSlot);
MethodDesc result = base.ResolveInterfaceMethodToStaticVirtualMethodOnType(interfaceMethod, currentType);
if (result != null && isAsyncSlot)
result = _context.GetAsyncVariantMethod(result);

return result;
}
public override MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType)
{
interfaceMethod = DecomposeAsyncVariant(interfaceMethod, out bool isAsyncSlot);
MethodDesc result = base.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, currentType);
if (result != null && isAsyncSlot)
result = _context.GetAsyncVariantMethod(result);

return result;
}
public override DefaultInterfaceMethodResolution ResolveVariantInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, TypeDesc currentType, out MethodDesc impl)
{
interfaceMethod = DecomposeAsyncVariant(interfaceMethod, out bool isAsyncSlot);
DefaultInterfaceMethodResolution result = base.ResolveVariantInterfaceMethodToDefaultImplementationOnType(interfaceMethod, currentType, out impl);
if (impl != null && isAsyncSlot)
impl = _context.GetAsyncVariantMethod(impl);

return result;
}
public override MethodDesc ResolveVariantInterfaceMethodToStaticVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType)
{
interfaceMethod = DecomposeAsyncVariant(interfaceMethod, out bool isAsyncSlot);
MethodDesc result = base.ResolveVariantInterfaceMethodToStaticVirtualMethodOnType(interfaceMethod, currentType);
if (result != null && isAsyncSlot)
result = _context.GetAsyncVariantMethod(result);

return result;
}
public override MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType)
{
interfaceMethod = DecomposeAsyncVariant(interfaceMethod, out bool isAsyncSlot);
MethodDesc result = base.ResolveVariantInterfaceMethodToVirtualMethodOnType(interfaceMethod, currentType);
if (result != null && isAsyncSlot)
result = _context.GetAsyncVariantMethod(result);

return result;
}

public override IEnumerable<MethodDesc> ComputeAllVirtualSlots(TypeDesc type)
{
foreach (MethodDesc method in base.ComputeAllVirtualSlots(type))
{
yield return method;

// We create an async variant slot for any Task-returning method, not just runtime-async.
// This is not a problem in practice because the slot is still subject to dependency
// analysis and if not used, will not be generated.
//
// The reason why we need it is this:
//
// interface IFoo
// {
// [RuntimeAsyncMethodGeneration(true)]
// Task Method();
// }
//
// class Base
// {
// [RuntimeAsyncMethodGeneration(false)]
// public virtual Task Method();
// }
//
// class Derived : Base, IFoo
// {
// // Q: The runtime-async implementation for IFoo.Method
// // comes from Base. However Base was not runtime-async and we
// // didn't know about IFoo in Base either. Who has the slot?
// // A: Base has the runtime-async slot, despite the method not being runtime-async.
// }
if (method.GetTypicalMethodDefinition().Signature.ReturnsTaskOrValueTask())
yield return _context.GetAsyncVariantMethod(method);
}
}
}

public MethodDesc GetTargetOfAsyncVariantMethod(MethodDesc asyncVariantMethod)
{
var asyncMethodVariantDefinition = (AsyncMethodVariant)asyncVariantMethod.GetTypicalMethodDefinition();
MethodDesc result = asyncMethodVariantDefinition.Target;

// If there are generics involved, we need to specialize
if (asyncVariantMethod != asyncMethodVariantDefinition)
{
TypeDesc owningType = asyncVariantMethod.OwningType;
if (owningType != asyncMethodVariantDefinition.OwningType)
result = GetMethodForInstantiatedType(result, (InstantiatedType)owningType);

if (asyncVariantMethod.HasInstantiation && !asyncVariantMethod.IsMethodDefinition)
result = GetInstantiatedMethod(result, asyncVariantMethod.Instantiation);
}

return result;
}

public MethodDesc GetAsyncVariantMethod(MethodDesc taskReturningMethod)
{
Debug.Assert(taskReturningMethod.Signature.ReturnsTaskOrValueTask());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ namespace ILCompiler
public partial class CompilerTypeSystemContext : MetadataTypeSystemContext, IMetadataStringDecoderProvider
{
private readonly MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm();
private readonly MetadataVirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm();

private MetadataStringDecoder _metadataStringDecoder;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,7 @@ public override MethodIL GetMethodIL(MethodDesc method)
}
else
{
// TODO: Emit thunk with async calling convention
throw new NotImplementedException();
return AsyncThunkILEmitter.EmitAsyncMethodThunk(asyncVariantImpl, asyncVariantImpl.Target);
}
}
else
Expand Down
14 changes: 14 additions & 0 deletions src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,19 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me

return emitter.Link(taskReturningMethod);
}

public static MethodIL EmitAsyncMethodThunk(MethodDesc asyncMethod, MethodDesc taskReturningMethod)
{
TypeSystemContext context = asyncMethod.Context;

var emitter = new ILEmitter();
var codestream = emitter.NewCodeStream();

// TODO: match EmitAsyncMethodThunk in CoreCLR VM

codestream.EmitCallThrowHelper(emitter, context.GetHelperEntryPoint("ThrowHelpers"u8, "ThrowNotSupportedException"u8));

return emitter.Link(asyncMethod);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public SharedGenericsConfiguration GenericsConfig
private readonly Int128FieldLayoutAlgorithm _int128FieldLayoutAlgorithm;
private readonly TypeWithRepeatedFieldsFieldLayoutAlgorithm _typeWithRepeatedFieldsFieldLayoutAlgorithm;

private readonly AsyncAwareVirtualMethodResolutionAlgorithm _virtualMethodAlgorithm;

private TypeDesc[] _arrayOfTInterfaces;
private TypeDesc[] _arrayEnumeratorOfTInterfaces;
private ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm;
Expand All @@ -53,6 +55,8 @@ public CompilerTypeSystemContext(TargetDetails details, SharedGenericsMode gener
{
_genericsMode = genericsMode;

_virtualMethodAlgorithm = new AsyncAwareVirtualMethodResolutionAlgorithm(this);

_vectorOfTFieldLayoutAlgorithm = new VectorOfTFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
_vectorFieldLayoutAlgorithm = new VectorFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
_int128FieldLayoutAlgorithm = new Int128FieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace ILCompiler
{
partial class CompilerTypeSystemContext
{
private readonly MetadataVirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm();

public CompilerTypeSystemContext(TargetDetails details, SharedGenericsMode genericsMode)
: base(details)
{
Expand Down
Loading