- 
                Notifications
    
You must be signed in to change notification settings  - Fork 5.2k
 
Rename AsyncMethodDesc to AsyncMethodVariant, add "AsyncVariant" flag to MethodWithToken and MethodWithGCInfo #121218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
27bef54
              f54a832
              f072d09
              3ff1a3c
              f22ed2d
              c4523a0
              442b6eb
              eee7c72
              3c6854a
              d574847
              62b9652
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| 
          
            
          
           | 
    @@ -614,7 +614,11 @@ private MethodDesc MethodBeingCompiled | |
| { | ||
| get | ||
| { | ||
| #if READYTORUN | ||
| return _methodCodeNode.GetJitMethod(_asyncMethodFactory); | ||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be better to inline the contents of   | 
||
| #else | ||
| return _methodCodeNode.Method; | ||
| #endif | ||
| } | ||
| } | ||
| 
     | 
||
| 
          
            
          
           | 
    @@ -877,6 +881,7 @@ private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* s | |
| 
     | 
||
| if (!signature.IsStatic) sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_HASTHIS; | ||
| if (signature.IsExplicitThis) sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_EXPLICITTHIS; | ||
| if (signature.IsAsyncCallConv) sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_ASYNCCALL; | ||
| 
     | 
||
| TypeDesc returnType = signature.ReturnType; | ||
| 
     | 
||
| 
          
            
          
           | 
    @@ -1395,7 +1400,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) | |
| 
     | 
||
| if (info->pResolvedTokenVirtualMethod != null) | ||
| { | ||
| methodWithTokenDecl = ComputeMethodWithToken(decl, ref *info->pResolvedTokenVirtualMethod, null, false); | ||
| methodWithTokenDecl = ComputeMethodWithToken(decl, ref *info->pResolvedTokenVirtualMethod, null, false, asyncVariant: false); | ||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the  I would make this throw RequiresRuntimeJitException if   | 
||
| } | ||
| else | ||
| { | ||
| 
        
          
        
         | 
    @@ -1410,7 +1415,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) | |
| info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DECL_NOT_REPRESENTABLE; | ||
| return false; | ||
| } | ||
| methodWithTokenDecl = new MethodWithToken(decl, declToken, null, false, null, devirtualizedMethodOwner: decl.OwningType); | ||
| methodWithTokenDecl = new MethodWithToken(decl, declToken, null, false, asyncVariant: false, null, devirtualizedMethodOwner: decl.OwningType); | ||
| } | ||
| MethodWithToken methodWithTokenImpl; | ||
| #endif | ||
| 
        
          
        
         | 
    @@ -1436,7 +1441,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) | |
| else | ||
| { | ||
| #if READYTORUN | ||
| methodWithTokenImpl = new MethodWithToken(nonUnboxingImpl, resolver.GetModuleTokenForMethod(nonUnboxingImpl.GetTypicalMethodDefinition(), allowDynamicallyCreatedReference: false, throwIfNotFound: true), null, unboxingStub, null, devirtualizedMethodOwner: impl.OwningType); | ||
| methodWithTokenImpl = new MethodWithToken(nonUnboxingImpl, resolver.GetModuleTokenForMethod(nonUnboxingImpl.GetTypicalMethodDefinition(), allowDynamicallyCreatedReference: false, throwIfNotFound: true), null, unboxingStub, asyncVariant: false, null, devirtualizedMethodOwner: impl.OwningType); | ||
| #endif | ||
| 
     | 
||
| info->resolvedTokenDevirtualizedMethod = CreateResolvedTokenFromMethod(this, impl | ||
| 
          
            
          
           | 
    ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| // 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 System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using Internal.JitInterface; | ||
| 
     | 
||
| 
     | 
||
| namespace Internal.TypeSystem | ||
| { | ||
| /// <summary> | ||
| /// Either the AsyncMethodImplVariant or AsyncMethodThunkVariant of a method marked .IsAsync. | ||
| /// </summary> | ||
| public partial class AsyncMethodVariant : MethodDelegator, IJitHashableOnly | ||
| { | ||
| private readonly AsyncMethodVariantFactory _factory; | ||
| private readonly AsyncMethodKind _asyncMethodKind; | ||
| private readonly int _jitVisibleHashCode; | ||
| private MethodSignature _asyncSignature; | ||
| 
     | 
||
| public AsyncMethodVariant(MethodDesc wrappedMethod, AsyncMethodVariantFactory factory, AsyncMethodKind kind) | ||
| : base(wrappedMethod) | ||
| { | ||
| Debug.Assert(wrappedMethod.IsTaskReturning); | ||
| Debug.Assert(kind switch | ||
| { | ||
| AsyncMethodKind.AsyncVariantThunk => !wrappedMethod.IsAsync, | ||
| AsyncMethodKind.AsyncVariantImpl => wrappedMethod.IsAsync, | ||
| _ => false, | ||
| }); | ||
| 
         
      Comment on lines
    
      +26
     to 
      +31
    
   
  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need the   | 
||
| _factory = factory; | ||
| _asyncMethodKind = kind; | ||
| _jitVisibleHashCode = HashCode.Combine(wrappedMethod.GetHashCode(), 0x310bb74f); | ||
| } | ||
| 
     | 
||
| public MethodDesc Target => _wrappedMethod; | ||
| 
     | 
||
| public override AsyncMethodKind AsyncMethodKind => _asyncMethodKind; | ||
| 
     | 
||
| public override MethodSignature Signature | ||
| { | ||
| get | ||
| { | ||
| return _asyncSignature ??= _wrappedMethod.Signature.CreateAsyncSignature(); | ||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inline   | 
||
| } | ||
| } | ||
| 
     | 
||
| public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) | ||
| { | ||
| return _factory.GetOrCreateAsyncMethodImplVariant(_wrappedMethod.GetCanonMethodTarget(kind), _asyncMethodKind); | ||
| } | ||
| 
     | 
||
| public override MethodDesc GetMethodDefinition() | ||
| { | ||
| var real = _wrappedMethod.GetMethodDefinition(); | ||
| if (real == _wrappedMethod) | ||
| return this; | ||
| 
     | 
||
| return _factory.GetOrCreateAsyncMethodImplVariant(real, _asyncMethodKind); | ||
| } | ||
| 
     | 
||
| public override MethodDesc GetTypicalMethodDefinition() | ||
| { | ||
| var real = _wrappedMethod.GetTypicalMethodDefinition(); | ||
| if (real == _wrappedMethod) | ||
| return this; | ||
| return _factory.GetOrCreateAsyncMethodImplVariant(real, _asyncMethodKind); | ||
| } | ||
| 
     | 
||
| public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) | ||
| { | ||
| var real = _wrappedMethod.InstantiateSignature(typeInstantiation, methodInstantiation); | ||
| if (real == _wrappedMethod) | ||
| return this; | ||
| return _factory.GetOrCreateAsyncMethodImplVariant(real, _asyncMethodKind); | ||
| } | ||
| 
     | 
||
| public override string ToString() => $"Async variant ({_asyncMethodKind}): " + _wrappedMethod.ToString(); | ||
| 
     | 
||
| protected override int ClassCode => throw new NotImplementedException(); | ||
| 
     | 
||
| protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) | ||
| { | ||
| throw new NotImplementedException(); | ||
| } | ||
| 
     | 
||
| protected override int ComputeHashCode() | ||
| { | ||
| throw new NotSupportedException("This method may not be stored as it is expected to only be used transiently in the JIT"); | ||
| } | ||
| 
     | 
||
| int IJitHashableOnly.GetJitVisibleHashCode() => _jitVisibleHashCode; | ||
| } | ||
| 
     | 
||
| public sealed class AsyncMethodVariantFactory : Dictionary<(MethodDesc, AsyncMethodKind), AsyncMethodVariant> | ||
| { | ||
| public AsyncMethodVariant GetOrCreateAsyncMethodImplVariant(MethodDesc wrappedMethod, AsyncMethodKind kind) | ||
| { | ||
| Debug.Assert(wrappedMethod.IsAsync); | ||
| if (!TryGetValue((wrappedMethod, kind), out AsyncMethodVariant variant)) | ||
| { | ||
| variant = new AsyncMethodVariant(wrappedMethod, this, kind); | ||
| this[(wrappedMethod, kind)] = variant; | ||
| } | ||
| return variant; | ||
| } | ||
| 
     | 
||
| public AsyncMethodVariant GetOrCreateAsyncThunk(MethodDesc wrappedMethod) | ||
| { | ||
| return GetOrCreateAsyncMethodImplVariant(wrappedMethod, AsyncMethodKind.AsyncVariantThunk); | ||
| } | ||
| 
     | 
||
| public AsyncMethodVariant GetOrCreateAsyncImpl(MethodDesc wrappedMethod) | ||
| { | ||
| return GetOrCreateAsyncMethodImplVariant(wrappedMethod, AsyncMethodKind.AsyncVariantImpl); | ||
| } | ||
| } | ||
| 
     | 
||
| public static class AsyncMethodVariantExtensions | ||
| { | ||
| /// <summary> | ||
| /// Returns true if this MethodDesc is an AsyncMethodVariant, which should not escape the jit interface. | ||
| /// </summary> | ||
| public static bool IsAsyncVariant(this MethodDesc method) | ||
| { | ||
| return method is AsyncMethodVariant; | ||
| } | ||
| 
     | 
||
| /// <summary> | ||
| /// Gets the wrapped method of the AsyncMethodVariant. This method is Task-returning. | ||
| /// </summary> | ||
| public static MethodDesc GetAsyncVariantDefinition(this MethodDesc method) | ||
| { | ||
| return ((AsyncMethodVariant)method).Target; | ||
| } | ||
| 
         
      Comment on lines
    
      +130
     to 
      +136
    
   
  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this used?  | 
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| 
     | 
||
| using System.Diagnostics; | ||
                
      
                  MichalStrehovsky marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| using System.Threading; | ||
| 
     | 
||
| namespace Internal.TypeSystem | ||
| { | ||
| public sealed partial class InstantiatedMethod | ||
| { | ||
| public override AsyncMethodKind AsyncMethodKind | ||
| { | ||
| get | ||
| { | ||
| return _methodDef.AsyncMethodKind; | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be just
AsyncVariant(ie cover both Thunk or impl)?This enum is part of R2R file format. It is used to encode references to methods in other assemblies. This encoding should be resilient to compatible changes in the implementation of other assemblies. If we encode
AsyncThunkVarianthere, it does not sound like we will be resilient to the implementations in other assemblies changing between async v1 and async v2.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is
READYTORUN_METHOD_SIG_SlotInsteadOfTokenused? Could we reuse it (bumping the R2R version of course)?