Task-returning thunk methods on generic types need support for resolving MethodDesc's to MethodSpec or at least MemberRef tokens. MethodWithToken expects a valid ModuleToken for a given method, which exists for methods on generic types and generic methods if the method is in an assembly. In generated IL, we don't have these tokens available. We emit TypeRefs and MemberRefs in the mutable module that point to TypeDefs and MethodDefs in referenced assemblies. We expect to be able to emit any types and methods we need to reference as a signature, only needing tokens that point to required TypeDefs. However, this internal use of a single token that represents a generic method that we may not already have a valid ModuleToken for. If we have a scheme to go from GenericMethod to MethodSpec / MemberRef in the MutableModule, we should be able to work around this issue. However, the ModuleToken resolver and mutable module only resolve or create ModuleTokens that resolve to Definitions. At the very least, we need a MemberRef to the method on the instantiated type.
The relevant code is in HandleToModuleToken:
|
MethodILScope methodILDef = methodIL.GetMethodILScopeDefinition(); |
|
bool isFauxMethodIL = !(methodILDef is IEcmaMethodIL); |
|
if (isFauxMethodIL) |
|
{ |
|
// It's okay to strip the instantiation away because we don't need a MethodSpec |
|
// token - SignatureBuilder will generate the generic method signature |
|
// using instantiation parameters from the MethodDesc entity. |
|
resultMethod = resultMethod.GetTypicalMethodDefinition(); |
Repro program (requires #122651 and reenabling generic async methods):
public class Program
{
public static async Task Main()
{
await GenericType<int>.AsyncMethod()
}
public class GenericType<T>
{
public static async Task AsyncMethod()
{
Task.Delay(100);
}
}
}
IIRC the call stack with issues is:
|
// READYTORUN: FUTURE: Direct calls if possible |
|
pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol( |
|
_compilation.NodeFactory.MethodEntrypoint( |
|
ComputeMethodWithToken(nonUnboxingMethod, ref pResolvedToken, constrainedType, unboxing: isUnboxingStub), |
|
isInstantiatingStub: useInstantiatingStub, |
|
isPrecodeImportRequired: (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0, |
|
isJumpableImportRequired: false)); |
|
private MethodWithToken ComputeMethodWithToken(MethodDesc method, ref CORINFO_RESOLVED_TOKEN pResolvedToken, TypeDesc constrainedType, bool unboxing) |
|
{ |
|
ModuleToken token = HandleToModuleToken(ref pResolvedToken, method, out object context, ref constrainedType); |
|
|
|
TypeDesc devirtualizedMethodOwner = null; |
|
if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_DevirtualizedMethod) |
|
{ |
|
devirtualizedMethodOwner = HandleToObject(pResolvedToken.hClass); |
|
} |
|
|
|
return new MethodWithToken(method, token, constrainedType: constrainedType, unboxing: unboxing, context: context, devirtualizedMethodOwner: devirtualizedMethodOwner); |
|
} |
|
private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) |
In HandleToModuleToken, the instantiation is stripped. Then it comes back to
new MethodWithToken()
|
return new MethodWithToken(method, token, constrainedType: constrainedType, unboxing: unboxing, context: context, devirtualizedMethodOwner: devirtualizedMethodOwner); |
Which calculates the OwningType from the ModuleToken for the method
|
public MethodWithToken(MethodDesc method, ModuleToken token, TypeDesc constrainedType, bool unboxing, object context, TypeDesc devirtualizedMethodOwner = null) |
|
{ |
|
Debug.Assert(!method.IsUnboxingThunk()); |
|
Debug.Assert(!method.IsAsyncVariant()); |
|
Method = method; |
|
Token = token; |
|
ConstrainedType = constrainedType; |
|
Unboxing = unboxing; |
|
OwningType = GetMethodTokenOwningType(this, constrainedType, context, devirtualizedMethodOwner, out OwningTypeNotDerivedFromToken); |
|
} |
Task-returning thunk methods on generic types need support for resolving MethodDesc's to MethodSpec or at least MemberRef tokens. MethodWithToken expects a valid ModuleToken for a given method, which exists for methods on generic types and generic methods if the method is in an assembly. In generated IL, we don't have these tokens available. We emit TypeRefs and MemberRefs in the mutable module that point to TypeDefs and MethodDefs in referenced assemblies. We expect to be able to emit any types and methods we need to reference as a signature, only needing tokens that point to required TypeDefs. However, this internal use of a single token that represents a generic method that we may not already have a valid ModuleToken for. If we have a scheme to go from GenericMethod to MethodSpec / MemberRef in the MutableModule, we should be able to work around this issue. However, the ModuleToken resolver and mutable module only resolve or create ModuleTokens that resolve to Definitions. At the very least, we need a MemberRef to the method on the instantiated type.
The relevant code is in HandleToModuleToken:
runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
Lines 1405 to 1408 in 91d0ef7
runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
Lines 1418 to 1421 in 91d0ef7
Repro program (requires #122651 and reenabling generic async methods):
IIRC the call stack with issues is:
runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
Lines 2511 to 2517 in 91d0ef7
runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
Lines 1344 to 1355 in 91d0ef7
runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
Line 1389 in 91d0ef7
In HandleToModuleToken, the instantiation is stripped. Then it comes back to
new MethodWithToken()runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
Line 1354 in 91d0ef7
Which calculates the OwningType from the ModuleToken for the method
runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
Lines 136 to 145 in 91d0ef7