|
// 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 Internal.IL;
using Internal.TypeSystem;
using Debug = System.Diagnostics.Debug;
namespace ILCompiler.Dataflow
{
/// <summary>
/// Removes the concept of async variants from <see cref="MethodIL"/> by reporting
/// <see cref="MethodILScope.OwningMethod"/> how it's generated in the metadata.
/// Dataflow infrastructure doesn't expect async variant method signatures.
/// </summary>
internal sealed class AsyncMaskingILProvider : ILProvider
{
private readonly ILProvider _wrappedProvider;
public AsyncMaskingILProvider(ILProvider wrappedProvider)
{
Debug.Assert(wrappedProvider is not AsyncMaskingILProvider);
_wrappedProvider = wrappedProvider;
}
public override MethodIL GetMethodIL(MethodDesc method)
{
Debug.Assert(!method.IsAsyncVariant());
MethodDesc methodForIL;
if (method.IsAsync && method.GetTypicalMethodDefinition().Signature.ReturnsTaskOrValueTask())
methodForIL = ((CompilerTypeSystemContext)method.Context).GetAsyncVariantMethod(method);
else
methodForIL = method;
MethodIL methodIL = _wrappedProvider.GetMethodIL(methodForIL);
return methodForIL == method ? methodIL : new AsyncMaskedMethodIL(method, methodIL);
}
public static MethodIL WrapIL(MethodIL methodIL)
{
MethodDesc owningMethod = methodIL.OwningMethod;
if (owningMethod.IsAsync && owningMethod.IsAsyncVariant())
{
return new AsyncMaskedMethodIL(((CompilerTypeSystemContext)owningMethod.Context).GetTargetOfAsyncVariantMethod(owningMethod), methodIL);
}
return methodIL;
}
private sealed class AsyncMaskedMethodIL : MethodIL
{
private readonly MethodDesc _owner;
private readonly MethodIL _wrappedIL;
public AsyncMaskedMethodIL(MethodDesc owner, MethodIL wrappedIL)
=> (_owner, _wrappedIL) = (owner, wrappedIL);
// Change the owner
public override MethodDesc OwningMethod => _owner;
// Everything else dispatches to the wrapper MethodIL
public override MethodDebugInformation GetDebugInfo() => _wrappedIL.GetDebugInfo();
public override ILExceptionRegion[] GetExceptionRegions() => _wrappedIL.GetExceptionRegions();
public override byte[] GetILBytes() => _wrappedIL.GetILBytes();
public override LocalVariableDefinition[] GetLocals() => _wrappedIL.GetLocals();
public override object GetObject(int token, NotFoundBehavior notFoundBehavior = NotFoundBehavior.Throw) => _wrappedIL.GetObject(token, notFoundBehavior);
public override bool IsInitLocals => _wrappedIL.IsInitLocals;
public override int MaxStack => _wrappedIL.MaxStack;
public override MethodIL GetMethodILDefinition()
{
Debug.Assert(_wrappedIL.GetMethodILDefinition() == _wrappedIL);
return this;
}
}
}
}
|