Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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 Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler
{
public partial class AsyncMethodVariant : MethodDelegator, IPrefixMangledMethod
{
MethodDesc IPrefixMangledMethod.BaseMethod => _wrappedMethod;

string IPrefixMangledMethod.Prefix => "AsyncCallable";
}
}
28 changes: 22 additions & 6 deletions src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1828,11 +1828,6 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken)

if (result is MethodDesc method)
{
pResolvedToken.hMethod = ObjectToHandle(method);

TypeDesc owningClass = method.OwningType;
pResolvedToken.hClass = ObjectToHandle(owningClass);

#if !SUPPORT_JIT
_compilation.TypeSystemContext.EnsureLoadableMethod(method);
#endif
Expand All @@ -1848,6 +1843,27 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken)
#else
_compilation.NodeFactory.MetadataManager.GetDependenciesDueToAccess(ref _additionalDependencies, _compilation.NodeFactory, (MethodIL)methodIL, method);
#endif

if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Await)
{
// in rare cases a method that returns Task is not actually TaskReturning (i.e. returns T).
// we cannot resolve to an Async variant in such case.
// return NULL, so that caller would re-resolve as a regular method call
method = method.IsAsync && method.GetMethodDefinition().Signature.ReturnsTaskOrValueTask()
? _compilation.TypeSystemContext.GetAsyncVariantMethod(method)
: null;
}

if (method != null)
{
pResolvedToken.hMethod = ObjectToHandle(method);
pResolvedToken.hClass = ObjectToHandle(method.OwningType);
}
else
{
pResolvedToken.hMethod = null;
pResolvedToken.hClass = null;
}
}
else
if (result is FieldDesc)
Expand Down Expand Up @@ -4316,7 +4332,7 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes)
flags.Set(CorJitFlag.CORJIT_FLAG_SOFTFP_ABI);
}

if (this.MethodBeingCompiled.IsAsync)
if (this.MethodBeingCompiled.Signature.IsAsyncCall)
{
flags.Set(CorJitFlag.CORJIT_FLAG_ASYNC);
}
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,9 @@ public enum CorInfoTokenKind

// token comes from resolved static virtual method
CORINFO_TOKENKIND_ResolvedStaticVirtualMethod = 0x1000 | CORINFO_TOKENKIND_Method,

// token comes from runtime async awaiting pattern
CORINFO_TOKENKIND_Await = 0x2000 | CORINFO_TOKENKIND_Method,
};

// These are error codes returned by CompileMethod
Expand Down
21 changes: 21 additions & 0 deletions src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

using System;

using ILCompiler;

using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;

Expand Down Expand Up @@ -309,6 +311,20 @@ public override MethodIL GetMethodIL(MethodDesc method)
return result;
}

if (ecmaMethod.IsAsync)
{
if (ecmaMethod.Signature.ReturnsTaskOrValueTask())
{
return AsyncThunkILEmitter.EmitTaskReturningThunk(ecmaMethod, ((CompilerTypeSystemContext)ecmaMethod.Context).GetAsyncVariantMethod(ecmaMethod));
}
else
{
// We only allow non-Task returning runtime async methods in CoreLib
if (ecmaMethod.OwningType.Module != ecmaMethod.Context.SystemModule)
ThrowHelper.ThrowBadImageFormatException();
}
}

MethodIL methodIL = EcmaMethodIL.Create(ecmaMethod);
if (methodIL != null)
return methodIL;
Expand Down Expand Up @@ -354,6 +370,11 @@ public override MethodIL GetMethodIL(MethodDesc method)
return ArrayMethodILEmitter.EmitIL((ArrayMethod)method);
}
else
if (method is AsyncMethodVariant asyncVariantImpl)
{
return EcmaMethodIL.Create(asyncVariantImpl.Target);
}
else
{
Debug.Assert(!(method is PInvokeTargetNativeMethod), "Who is asking for IL of PInvokeTargetNativeMethod?");
return null;
Expand Down
40 changes: 40 additions & 0 deletions src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Internal.TypeSystem;

namespace Internal.IL.Stubs
{
public static class AsyncThunkILEmitter
{
public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, MethodDesc asyncMethod)
{
TypeSystemContext context = taskReturningMethod.Context;

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

// TODO: match EmitTaskReturningThunk in CoreCLR VM

MethodSignature sig = asyncMethod.Signature;
int numParams = (sig.IsStatic || sig.IsExplicitThis) ? sig.Length : sig.Length + 1;
for (int i = 0; i < numParams; i++)
codestream.EmitLdArg(i);

codestream.Emit(ILOpcode.call, emitter.NewToken(asyncMethod));

if (sig.ReturnType.IsVoid)
{
codestream.Emit(ILOpcode.call, emitter.NewToken(context.SystemModule.GetKnownType("System.Threading.Tasks"u8, "Task"u8).GetKnownMethod("get_CompletedTask"u8, null)));
}
else
{
codestream.Emit(ILOpcode.call, emitter.NewToken(context.SystemModule.GetKnownType("System.Threading.Tasks"u8, "Task"u8).GetKnownMethod("FromResult"u8, null).MakeInstantiatedMethod(sig.ReturnType)));
}

codestream.Emit(ILOpcode.ret);

return emitter.Link(taskReturningMethod);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
</ItemGroup>

<ItemGroup>
<Compile Include="..\..\Common\Compiler\AsyncMethodVariant.cs" Link="Compiler\AsyncMethodVariant.cs" />
<Compile Include="..\..\Common\Compiler\AsyncMethodVariant.Mangling.cs" Link="Compiler\AsyncMethodVariant.Mangling.cs" />
<Compile Include="..\..\Common\Compiler\CompilerTypeSystemContext.Async.cs" Link="Compiler\CompilerTypeSystemContext.Async.cs" />
<Compile Include="..\..\Common\Compiler\Win32Resources\ResourceData.cs" Link="Compiler\Win32Resources\ResourceData.cs" />
<Compile Include="..\..\Common\Compiler\Win32Resources\ResourceData.Reader.cs" Link="Compiler\Win32Resources\ResourceData.Reader.cs" />
<Compile Include="..\..\Common\Compiler\Win32Resources\ResourceData.ResourcesDataModel.cs" Link="Compiler\Win32Resources\ResourceData.ResourcesDataModel.cs" />
Expand All @@ -42,6 +45,7 @@
<Compile Include="..\..\Common\TypeSystem\IL\DelegateInfo.cs">
<Link>IL\DelegateInfo.cs</Link>
</Compile>
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\AsyncThunks.cs" Link="IL\Stubs\AsyncThunks.cs" />
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\DelegateThunks.Sorting.cs">
<Link>IL\Stubs\DelegateThunks.Sorting.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,35 @@ public static T Await<T>(ConfiguredValueTaskAwaitable<T> configuredAwaitable)
public static void UnsafeAwaitAwaiter<TAwaiter>(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion { throw new NotImplementedException(); }
[RequiresPreviewFeatures]
public static void AwaitAwaiter<TAwaiter>(TAwaiter awaiter) where TAwaiter : INotifyCompletion { throw new NotImplementedException(); }
#if NATIVEAOT
[RequiresPreviewFeatures]
public static void Await(System.Threading.Tasks.Task task)
{
TaskAwaiter awaiter = task.GetAwaiter();
if (!awaiter.IsCompleted)
{
throw new NotImplementedException();
}

awaiter.GetResult();
}
[RequiresPreviewFeatures]
public static T Await<T>(System.Threading.Tasks.Task<T> task)
{
TaskAwaiter<T> awaiter = task.GetAwaiter();
if (!awaiter.IsCompleted)
{
throw new NotImplementedException();
}

return awaiter.GetResult();
}
#else
[RequiresPreviewFeatures]
public static void Await(System.Threading.Tasks.Task task) { throw new NotImplementedException(); }
[RequiresPreviewFeatures]
public static T Await<T>(System.Threading.Tasks.Task<T> task) { throw new NotImplementedException(); }
#endif
[RequiresPreviewFeatures]
public static void Await(System.Threading.Tasks.ValueTask task) { throw new NotImplementedException(); }
[RequiresPreviewFeatures]
Expand Down
Loading