Skip to content

Commit 79e8a8d

Browse files
Rebased
1 parent 0769ce2 commit 79e8a8d

File tree

7 files changed

+132
-6
lines changed

7 files changed

+132
-6
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using Internal.TypeSystem;
6+
7+
using Debug = System.Diagnostics.Debug;
8+
9+
namespace ILCompiler
10+
{
11+
public partial class AsyncMethodVariant : MethodDelegator, IPrefixMangledMethod
12+
{
13+
MethodDesc IPrefixMangledMethod.BaseMethod => _wrappedMethod;
14+
15+
string IPrefixMangledMethod.Prefix => "AsyncCallable";
16+
}
17+
}

src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,11 +1828,6 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken)
18281828

18291829
if (result is MethodDesc method)
18301830
{
1831-
pResolvedToken.hMethod = ObjectToHandle(method);
1832-
1833-
TypeDesc owningClass = method.OwningType;
1834-
pResolvedToken.hClass = ObjectToHandle(owningClass);
1835-
18361831
#if !SUPPORT_JIT
18371832
_compilation.TypeSystemContext.EnsureLoadableMethod(method);
18381833
#endif
@@ -1848,6 +1843,27 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken)
18481843
#else
18491844
_compilation.NodeFactory.MetadataManager.GetDependenciesDueToAccess(ref _additionalDependencies, _compilation.NodeFactory, (MethodIL)methodIL, method);
18501845
#endif
1846+
1847+
if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Await)
1848+
{
1849+
// in rare cases a method that returns Task is not actually TaskReturning (i.e. returns T).
1850+
// we cannot resolve to an Async variant in such case.
1851+
// return NULL, so that caller would re-resolve as a regular method call
1852+
method = method.IsAsync && method.GetMethodDefinition().Signature.ReturnsTaskOrValueTask()
1853+
? _compilation.TypeSystemContext.GetAsyncVariantMethod(method)
1854+
: null;
1855+
}
1856+
1857+
if (method != null)
1858+
{
1859+
pResolvedToken.hMethod = ObjectToHandle(method);
1860+
pResolvedToken.hClass = ObjectToHandle(method.OwningType);
1861+
}
1862+
else
1863+
{
1864+
pResolvedToken.hMethod = null;
1865+
pResolvedToken.hClass = null;
1866+
}
18511867
}
18521868
else
18531869
if (result is FieldDesc)
@@ -4316,7 +4332,7 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes)
43164332
flags.Set(CorJitFlag.CORJIT_FLAG_SOFTFP_ABI);
43174333
}
43184334

4319-
if (this.MethodBeingCompiled.IsAsync)
4335+
if (this.MethodBeingCompiled.Signature.IsAsyncCall)
43204336
{
43214337
flags.Set(CorJitFlag.CORJIT_FLAG_ASYNC);
43224338
}

src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,9 @@ public enum CorInfoTokenKind
13661366

13671367
// token comes from resolved static virtual method
13681368
CORINFO_TOKENKIND_ResolvedStaticVirtualMethod = 0x1000 | CORINFO_TOKENKIND_Method,
1369+
1370+
// token comes from runtime async awaiting pattern
1371+
CORINFO_TOKENKIND_Await = 0x2000 | CORINFO_TOKENKIND_Method,
13691372
};
13701373

13711374
// These are error codes returned by CompileMethod

src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
using System;
55

6+
using ILCompiler;
7+
68
using Internal.TypeSystem;
79
using Internal.TypeSystem.Ecma;
810

@@ -309,6 +311,20 @@ public override MethodIL GetMethodIL(MethodDesc method)
309311
return result;
310312
}
311313

314+
if (ecmaMethod.IsAsync)
315+
{
316+
if (ecmaMethod.Signature.ReturnsTaskOrValueTask())
317+
{
318+
return AsyncThunkILEmitter.EmitTaskReturningThunk(ecmaMethod, ((CompilerTypeSystemContext)ecmaMethod.Context).GetAsyncVariantMethod(ecmaMethod));
319+
}
320+
else
321+
{
322+
// We only allow non-Task returning runtime async methods in CoreLib
323+
if (ecmaMethod.OwningType.Module != ecmaMethod.Context.SystemModule)
324+
ThrowHelper.ThrowBadImageFormatException();
325+
}
326+
}
327+
312328
MethodIL methodIL = EcmaMethodIL.Create(ecmaMethod);
313329
if (methodIL != null)
314330
return methodIL;
@@ -354,6 +370,11 @@ public override MethodIL GetMethodIL(MethodDesc method)
354370
return ArrayMethodILEmitter.EmitIL((ArrayMethod)method);
355371
}
356372
else
373+
if (method is AsyncMethodVariant asyncVariantImpl)
374+
{
375+
return EcmaMethodIL.Create(asyncVariantImpl.Target);
376+
}
377+
else
357378
{
358379
Debug.Assert(!(method is PInvokeTargetNativeMethod), "Who is asking for IL of PInvokeTargetNativeMethod?");
359380
return null;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Internal.TypeSystem;
5+
6+
namespace Internal.IL.Stubs
7+
{
8+
public static class AsyncThunkILEmitter
9+
{
10+
public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, MethodDesc asyncMethod)
11+
{
12+
TypeSystemContext context = taskReturningMethod.Context;
13+
14+
var emitter = new ILEmitter();
15+
var codestream = emitter.NewCodeStream();
16+
17+
// TODO: match EmitTaskReturningThunk in CoreCLR VM
18+
19+
MethodSignature sig = asyncMethod.Signature;
20+
int numParams = (sig.IsStatic || sig.IsExplicitThis) ? sig.Length : sig.Length + 1;
21+
for (int i = 0; i < numParams; i++)
22+
codestream.EmitLdArg(i);
23+
24+
codestream.Emit(ILOpcode.call, emitter.NewToken(asyncMethod));
25+
26+
if (sig.ReturnType.IsVoid)
27+
{
28+
codestream.Emit(ILOpcode.call, emitter.NewToken(context.SystemModule.GetKnownType("System.Threading.Tasks"u8, "Task"u8).GetKnownMethod("get_CompletedTask"u8, null)));
29+
}
30+
else
31+
{
32+
codestream.Emit(ILOpcode.call, emitter.NewToken(context.SystemModule.GetKnownType("System.Threading.Tasks"u8, "Task"u8).GetKnownMethod("FromResult"u8, null).MakeInstantiatedMethod(sig.ReturnType)));
33+
}
34+
35+
codestream.Emit(ILOpcode.ret);
36+
37+
return emitter.Link(taskReturningMethod);
38+
}
39+
}
40+
}

src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
</ItemGroup>
3434

3535
<ItemGroup>
36+
<Compile Include="..\..\Common\Compiler\AsyncMethodVariant.cs" Link="Compiler\AsyncMethodVariant.cs" />
37+
<Compile Include="..\..\Common\Compiler\AsyncMethodVariant.Mangling.cs" Link="Compiler\AsyncMethodVariant.Mangling.cs" />
38+
<Compile Include="..\..\Common\Compiler\CompilerTypeSystemContext.Async.cs" Link="Compiler\CompilerTypeSystemContext.Async.cs" />
3639
<Compile Include="..\..\Common\Compiler\Win32Resources\ResourceData.cs" Link="Compiler\Win32Resources\ResourceData.cs" />
3740
<Compile Include="..\..\Common\Compiler\Win32Resources\ResourceData.Reader.cs" Link="Compiler\Win32Resources\ResourceData.Reader.cs" />
3841
<Compile Include="..\..\Common\Compiler\Win32Resources\ResourceData.ResourcesDataModel.cs" Link="Compiler\Win32Resources\ResourceData.ResourcesDataModel.cs" />
@@ -42,6 +45,7 @@
4245
<Compile Include="..\..\Common\TypeSystem\IL\DelegateInfo.cs">
4346
<Link>IL\DelegateInfo.cs</Link>
4447
</Compile>
48+
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\AsyncThunks.cs" Link="IL\Stubs\AsyncThunks.cs" />
4549
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\DelegateThunks.Sorting.cs">
4650
<Link>IL\Stubs\DelegateThunks.Sorting.cs</Link>
4751
</Compile>

src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,35 @@ public static T Await<T>(ConfiguredValueTaskAwaitable<T> configuredAwaitable)
220220
public static void UnsafeAwaitAwaiter<TAwaiter>(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion { throw new NotImplementedException(); }
221221
[RequiresPreviewFeatures]
222222
public static void AwaitAwaiter<TAwaiter>(TAwaiter awaiter) where TAwaiter : INotifyCompletion { throw new NotImplementedException(); }
223+
#if NATIVEAOT
224+
[RequiresPreviewFeatures]
225+
public static void Await(System.Threading.Tasks.Task task)
226+
{
227+
TaskAwaiter awaiter = task.GetAwaiter();
228+
if (!awaiter.IsCompleted)
229+
{
230+
throw new NotImplementedException();
231+
}
232+
233+
awaiter.GetResult();
234+
}
235+
[RequiresPreviewFeatures]
236+
public static T Await<T>(System.Threading.Tasks.Task<T> task)
237+
{
238+
TaskAwaiter<T> awaiter = task.GetAwaiter();
239+
if (!awaiter.IsCompleted)
240+
{
241+
throw new NotImplementedException();
242+
}
243+
244+
return awaiter.GetResult();
245+
}
246+
#else
223247
[RequiresPreviewFeatures]
224248
public static void Await(System.Threading.Tasks.Task task) { throw new NotImplementedException(); }
225249
[RequiresPreviewFeatures]
226250
public static T Await<T>(System.Threading.Tasks.Task<T> task) { throw new NotImplementedException(); }
251+
#endif
227252
[RequiresPreviewFeatures]
228253
public static void Await(System.Threading.Tasks.ValueTask task) { throw new NotImplementedException(); }
229254
[RequiresPreviewFeatures]

0 commit comments

Comments
 (0)