Skip to content

Commit 72cec96

Browse files
authored
Insert a set of known types and methods references necessary for async thunks into the mutable module (#121679)
Async thunk IL has references to methods and types that may not have MethodRef or TypeRef tokens in the assembly being crossgen'ed. There are some assertions to validate that any references in "faux il" version with the assembly, which isn't true for these types and methods. To work around this, we can inject these references into the mutable module, a synthetic module added to the assembly for things like this. When we are about to compile an async thunk method, we check to see if all the required references are already in the mutable module, and add them if not.
1 parent 139cc15 commit 72cec96

File tree

6 files changed

+458
-12
lines changed

6 files changed

+458
-12
lines changed

src/coreclr/tools/Common/Compiler/AsyncMethodVariant.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,10 @@ public static bool IsAsyncVariant(this MethodDesc method)
7878
{
7979
return method.GetTypicalMethodDefinition() is AsyncMethodVariant;
8080
}
81+
82+
public static bool IsAsyncThunk(this MethodDesc method)
83+
{
84+
return method.IsAsyncVariant() ^ method.IsAsync;
85+
}
8186
}
8287
}

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ModuleTokenResolver.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,20 @@ public void InitManifestMutableModule(MutableModule mutableModule)
5252
_manifestMutableModule = mutableModule;
5353
}
5454

55-
public ModuleToken GetModuleTokenForType(EcmaType type, bool allowDynamicallyCreatedReference, bool throwIfNotFound = true)
55+
public ModuleToken GetModuleTokenForType(TypeDesc type, bool allowDynamicallyCreatedReference, bool throwIfNotFound = true)
5656
{
57-
if (_compilationModuleGroup.VersionsWithType(type))
58-
{
59-
return new ModuleToken(type.Module, (mdToken)MetadataTokens.GetToken(type.Handle));
60-
}
61-
6257
ModuleToken token;
63-
if (_typeToRefTokens.TryGetValue(type, out token))
58+
if (type is EcmaType ecmaType)
6459
{
65-
return token;
60+
if (_compilationModuleGroup.VersionsWithType(ecmaType))
61+
{
62+
return new ModuleToken(ecmaType.Module, (mdToken)MetadataTokens.GetToken(ecmaType.Handle));
63+
}
64+
65+
if (_typeToRefTokens.TryGetValue(ecmaType, out token))
66+
{
67+
return token;
68+
}
6669
}
6770

6871
// If the token was not lazily mapped, search the input compilation set for a type reference token
@@ -178,7 +181,7 @@ private void DecodeMethodSignatureToDiscoverUsedTypeTokens(BlobHandle signatureH
178181
{
179182
MetadataReader metadataReader = token.MetadataReader;
180183
TokenResolverProvider rentedProvider = TokenResolverProvider.Rent(this, token.Module);
181-
SignatureDecoder<DummyTypeInfo, ModuleTokenResolver> sigDecoder = new (rentedProvider, metadataReader, this);
184+
SignatureDecoder<DummyTypeInfo, ModuleTokenResolver> sigDecoder = new(rentedProvider, metadataReader, this);
182185
BlobReader signature = metadataReader.GetBlobReader(signatureHandle);
183186

184187
SignatureHeader header = signature.ReadSignatureHeader();

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ public bool CanInline(MethodDesc caller, MethodDesc callee)
108108
}
109109
}
110110

111+
if (callee.IsAsyncThunk())
112+
{
113+
// Async thunks require special handling in the compiler and should not be inlined
114+
return false;
115+
}
116+
111117
_nodeFactory.DetectGenericCycles(caller, callee);
112118

113119
return NodeFactory.CompilationModuleGroup.CanInline(caller, callee);
@@ -694,6 +700,52 @@ protected override void ComputeDependencyNodeDependencies(List<DependencyNodeCor
694700
CorInfoImpl.IsMethodCompilable(this, methodCodeNodeNeedingCode.Method))
695701
_methodsWhichNeedMutableILBodies.Add(ecmaMethod);
696702
}
703+
if (method.IsAsyncThunk())
704+
{
705+
// The synthetic async thunks require references to methods/types that may not have existing methodRef entries in the version bubble.
706+
// These references need to be added to the mutable module if they don't exist.
707+
// Extract the required references by reading the IL of the thunk method.
708+
MethodIL methodIL = GetMethodIL(method);
709+
if (methodIL is null)
710+
continue;
711+
712+
_nodeFactory.ManifestMetadataTable._mutableModule.ModuleThatIsCurrentlyTheSourceOfNewReferences = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module;
713+
try
714+
{
715+
foreach (var entity in ILStubReferences.GetNecessaryReferencesFromIL(methodIL))
716+
{
717+
switch (entity)
718+
{
719+
case MethodDesc md:
720+
if (md.IsAsyncVariant())
721+
{
722+
Debug.Assert(((CompilerTypeSystemContext)md.Context).GetTargetOfAsyncVariantMethod(md.GetTypicalMethodDefinition()) == method);
723+
Debug.Assert(!_nodeFactory.Resolver.GetModuleTokenForMethod(method, allowDynamicallyCreatedReference: false, throwIfNotFound: true).IsNull);
724+
}
725+
else if (_nodeFactory.Resolver.GetModuleTokenForMethod(md, allowDynamicallyCreatedReference: true, throwIfNotFound: false).IsNull)
726+
{
727+
_nodeFactory.ManifestMetadataTable._mutableModule.TryGetEntityHandle(md);
728+
Debug.Assert(!_nodeFactory.Resolver.GetModuleTokenForMethod(md, allowDynamicallyCreatedReference: true, throwIfNotFound: true).IsNull);
729+
}
730+
break;
731+
case TypeDesc td:
732+
if (_nodeFactory.Resolver.GetModuleTokenForType(td, allowDynamicallyCreatedReference: true, throwIfNotFound: false).IsNull)
733+
{
734+
_nodeFactory.ManifestMetadataTable._mutableModule.TryGetEntityHandle(td);
735+
}
736+
Debug.Assert(!_nodeFactory.Resolver.GetModuleTokenForType(td, allowDynamicallyCreatedReference: true, throwIfNotFound: true).IsNull);
737+
break;
738+
default:
739+
throw new NotImplementedException("Unexpected entity type in Async thunk.");
740+
}
741+
}
742+
}
743+
finally
744+
{
745+
_nodeFactory.ManifestMetadataTable._mutableModule.ModuleThatIsCurrentlyTheSourceOfNewReferences = null;
746+
}
747+
}
748+
697749
if (!_nodeFactory.CompilationModuleGroup.VersionsWithMethodBody(method))
698750
{
699751
// Validate that the typedef tokens for all of the instantiation parameters of the method
@@ -977,5 +1029,6 @@ public string GetReproInstructions(MethodDesc method)
9771029
{
9781030
return _printReproInstructions(method);
9791031
}
1032+
9801033
}
9811034
}

0 commit comments

Comments
 (0)