From 90a68c401fc58df07e0bff7c4b7fd171179af219 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 23 Jun 2026 15:23:30 +0200 Subject: [PATCH 1/4] Check for ComInterop case for async variants in crossgen2 --- .../tools/Common/JitInterface/CorInfoImpl.cs | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index d21377ed7d80da..6e22f4570a361c 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1546,7 +1546,7 @@ static CORINFO_RESOLVED_TOKEN CreateResolvedTokenFromMethod(CorInfoImpl jitInter { method = method.GetTargetOfAsyncVariant(); } - else if (method.Signature.ReturnsTaskOrValueTask()) + else if (HasCallableAsyncVariant(method)) { method = method.GetAsyncVariant(); } @@ -1874,15 +1874,7 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) if (pResolvedToken.tokenType is 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 - bool allowAsyncVariant = method.GetTypicalMethodDefinition().Signature.ReturnsTaskOrValueTask(); - - // Don't get async variant of Delegate.Invoke method; the pointed to method is not an async variant either. - allowAsyncVariant = allowAsyncVariant && !method.OwningType.IsDelegate; - - method = allowAsyncVariant + method = HasCallableAsyncVariant(method) ? _compilation.TypeSystemContext.GetAsyncVariantMethod(method) : null; } @@ -1955,6 +1947,22 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) pResolvedToken.cbMethodSpec = 0; } + private bool HasCallableAsyncVariant(MethodDesc method) + { + // 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 + bool allowAsyncVariant = method.GetTypicalMethodDefinition().Signature.ReturnsTaskOrValueTask(); + + // Don't get async variant of Delegate.Invoke method; the pointed to method is not an async variant either. + allowAsyncVariant = allowAsyncVariant && !method.OwningType.IsDelegate; + + // Don't get async variant of ComImport methods since we do not generate any runtime async entry points for them. + allowAsyncVariant = allowAsyncVariant && !method.OwningType.IsComImport; + + return allowAsyncVariant; + } + private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) { var methodIL = HandleToObject(module); From 1a686126d68ba44a19df9c1ed022d303423184c9 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 23 Jun 2026 15:34:53 +0200 Subject: [PATCH 2/4] Feedback --- .../tools/Common/JitInterface/CorInfoImpl.cs | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 6e22f4570a361c..8d215dc400d298 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1949,18 +1949,29 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) private bool HasCallableAsyncVariant(MethodDesc method) { - // 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 - bool allowAsyncVariant = method.GetTypicalMethodDefinition().Signature.ReturnsTaskOrValueTask(); + // In some cases a method that returns Task is not actually + // TaskReturning (i.e. it might return T). We cannot resolve to an + // async variant in such case. + if (!method.GetTypicalMethodDefinition().Signature.ReturnsTaskOrValueTask()) + { + return false; + } - // Don't get async variant of Delegate.Invoke method; the pointed to method is not an async variant either. - allowAsyncVariant = allowAsyncVariant && !method.OwningType.IsDelegate; + // Don't get async variant of Delegate.Invoke method; the pointed + // to method is not an async variant either. + if (method.OwningType.IsDelegate) + { + return false; + } - // Don't get async variant of ComImport methods since we do not generate any runtime async entry points for them. - allowAsyncVariant = allowAsyncVariant && !method.OwningType.IsComImport; + // Don't get async variant of ComImport methods since we do not + // generate any runtime async entry points for them. + if (!method.OwningType.IsComImport) + { + return false; + } - return allowAsyncVariant; + return true; } private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) From 024802317e89482a5711871443c6414169a421fd Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 23 Jun 2026 15:52:43 +0200 Subject: [PATCH 3/4] Whoops --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 8d215dc400d298..ef1e3ec835b646 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1966,7 +1966,7 @@ private bool HasCallableAsyncVariant(MethodDesc method) // Don't get async variant of ComImport methods since we do not // generate any runtime async entry points for them. - if (!method.OwningType.IsComImport) + if (method.OwningType.IsComImport) { return false; } From 68d5a0c9568d24a3d97a51f8789e889885416b70 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 23 Jun 2026 16:36:04 +0200 Subject: [PATCH 4/4] Make static --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index ef1e3ec835b646..e3dea4bbdc585a 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1947,7 +1947,7 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) pResolvedToken.cbMethodSpec = 0; } - private bool HasCallableAsyncVariant(MethodDesc method) + private static bool HasCallableAsyncVariant(MethodDesc method) { // In some cases a method that returns Task is not actually // TaskReturning (i.e. it might return T). We cannot resolve to an