238 lines
11 KiB
C#
238 lines
11 KiB
C#
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using Microsoft.CodeAnalysis.CSharp.Emit.NoPia;
|
|
using Microsoft.CodeAnalysis.CSharp.Symbols;
|
|
using Microsoft.CodeAnalysis.CodeGen;
|
|
using Microsoft.CodeAnalysis.Emit;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp;
|
|
|
|
internal class IteratorRewriter : StateMachineRewriter
|
|
{
|
|
private readonly TypeWithAnnotations _elementType;
|
|
|
|
private readonly bool _isEnumerable;
|
|
|
|
private FieldSymbol _currentField;
|
|
|
|
protected override bool PreserveInitialParameterValuesAndThreadId => _isEnumerable;
|
|
|
|
private IteratorRewriter(BoundStatement body, MethodSymbol method, bool isEnumerable, IteratorStateMachine stateMachineType, ArrayBuilder<StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics)
|
|
: base(body, method, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics)
|
|
{
|
|
_elementType = stateMachineType.ElementType;
|
|
_isEnumerable = isEnumerable;
|
|
}
|
|
|
|
internal static BoundStatement Rewrite(BoundStatement body, MethodSymbol method, int methodOrdinal, ArrayBuilder<StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics, out IteratorStateMachine stateMachineType)
|
|
{
|
|
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0034: Invalid comparison between Unknown and I4
|
|
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_003b: Invalid comparison between Unknown and I4
|
|
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
|
|
TypeWithAnnotations iteratorElementTypeWithAnnotations = method.IteratorElementTypeWithAnnotations;
|
|
if (iteratorElementTypeWithAnnotations.IsDefault || method.IsAsync)
|
|
{
|
|
stateMachineType = null;
|
|
return body;
|
|
}
|
|
SpecialType specialType = method.ReturnType.OriginalDefinition.SpecialType;
|
|
bool isEnumerable;
|
|
if (specialType - 24 > 1)
|
|
{
|
|
if (specialType - 28 > 1)
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)method.ReturnType.OriginalDefinition.SpecialType);
|
|
}
|
|
isEnumerable = false;
|
|
}
|
|
else
|
|
{
|
|
isEnumerable = true;
|
|
}
|
|
stateMachineType = new IteratorStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, isEnumerable, iteratorElementTypeWithAnnotations);
|
|
((ModuleCompilationState<NamedTypeSymbol, MethodSymbol>)((PEModuleBuilder<CSharpCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, EmbeddedTypesManager, ModuleCompilationState>)compilationState.ModuleBuilderOpt).CompilationState).SetStateMachineType(method, (NamedTypeSymbol)stateMachineType);
|
|
IteratorRewriter iteratorRewriter = new IteratorRewriter(body, method, isEnumerable, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics);
|
|
if (!iteratorRewriter.VerifyPresenceOfRequiredAPIs())
|
|
{
|
|
return body;
|
|
}
|
|
return iteratorRewriter.Rewrite();
|
|
}
|
|
|
|
protected bool VerifyPresenceOfRequiredAPIs()
|
|
{
|
|
BindingDiagnosticBag instance = BindingDiagnosticBag.GetInstance(withDiagnostics: true, ((BindingDiagnosticBag<AssemblySymbol>)(object)diagnostics).AccumulatesDependencies);
|
|
EnsureSpecialType((SpecialType)13, instance);
|
|
EnsureSpecialType((SpecialType)35, instance);
|
|
EnsureSpecialMember((SpecialMember)92, instance);
|
|
EnsureSpecialType((SpecialType)28, instance);
|
|
EnsureSpecialPropertyGetter((SpecialMember)85, instance);
|
|
EnsureSpecialMember((SpecialMember)87, instance);
|
|
EnsureSpecialMember((SpecialMember)88, instance);
|
|
EnsureSpecialType((SpecialType)29, instance);
|
|
EnsureSpecialPropertyGetter((SpecialMember)90, instance);
|
|
if (_isEnumerable)
|
|
{
|
|
EnsureSpecialType((SpecialType)24, instance);
|
|
EnsureSpecialMember((SpecialMember)84, instance);
|
|
EnsureSpecialType((SpecialType)25, instance);
|
|
EnsureSpecialMember((SpecialMember)89, instance);
|
|
}
|
|
bool num = ((BindingDiagnosticBag)instance).HasAnyErrors();
|
|
if (!num)
|
|
{
|
|
((BindingDiagnosticBag<AssemblySymbol>)(object)diagnostics).AddDependencies((BindingDiagnosticBag<AssemblySymbol>)(object)instance, false);
|
|
}
|
|
else
|
|
{
|
|
((BindingDiagnosticBag<AssemblySymbol>)(object)diagnostics).AddRange((BindingDiagnosticBag<AssemblySymbol>)(object)instance, false);
|
|
}
|
|
((BindingDiagnosticBag<AssemblySymbol>)(object)instance).Free();
|
|
return !num;
|
|
}
|
|
|
|
private Symbol EnsureSpecialMember(SpecialMember member, BindingDiagnosticBag bag)
|
|
{
|
|
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
|
|
Binder.TryGetSpecialTypeMember<Symbol>(F.Compilation, member, body.Syntax, bag, out var symbol);
|
|
return symbol;
|
|
}
|
|
|
|
private void EnsureSpecialType(SpecialType type, BindingDiagnosticBag bag)
|
|
{
|
|
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
|
|
Binder.GetSpecialType(F.Compilation, type, body.Syntax, bag);
|
|
}
|
|
|
|
private void EnsureSpecialPropertyGetter(SpecialMember member, BindingDiagnosticBag bag)
|
|
{
|
|
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
|
|
PropertySymbol propertySymbol = (PropertySymbol)EnsureSpecialMember(member, bag);
|
|
if ((object)propertySymbol != null)
|
|
{
|
|
MethodSymbol getMethod = propertySymbol.GetMethod;
|
|
if ((object)getMethod == null)
|
|
{
|
|
Binder.Error(bag, ErrorCode.ERR_PropertyLacksGet, SyntaxNodeOrToken.op_Implicit(body.Syntax), propertySymbol);
|
|
}
|
|
else
|
|
{
|
|
bag.ReportUseSite(getMethod, body.Syntax.Location);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void GenerateControlFields()
|
|
{
|
|
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
|
|
stateField = F.StateMachineField(F.SpecialType((SpecialType)13), GeneratedNames.MakeStateMachineStateFieldName());
|
|
MethodInstrumentation methodBodyInstrumentations = F.ModuleBuilderOpt.GetMethodBodyInstrumentations(method);
|
|
if (((MethodInstrumentation)(ref methodBodyInstrumentations)).Kinds.Contains((InstrumentationKind)(-1)))
|
|
{
|
|
instanceIdField = F.StateMachineField(F.SpecialType((SpecialType)16), GeneratedNames.MakeStateMachineStateIdFieldName());
|
|
}
|
|
_currentField = F.StateMachineField(_elementType, GeneratedNames.MakeIteratorCurrentFieldName());
|
|
}
|
|
|
|
protected override void GenerateMethodImplementations()
|
|
{
|
|
try
|
|
{
|
|
BoundExpression managedThreadId = null;
|
|
GenerateEnumeratorImplementation();
|
|
if (_isEnumerable)
|
|
{
|
|
GenerateEnumerableImplementation(ref managedThreadId);
|
|
}
|
|
GenerateConstructor(managedThreadId);
|
|
}
|
|
catch (SyntheticBoundNodeFactory.MissingPredefinedMember missingPredefinedMember)
|
|
{
|
|
((BindingDiagnosticBag)diagnostics).Add(missingPredefinedMember.Diagnostic);
|
|
}
|
|
}
|
|
|
|
private void GenerateEnumeratorImplementation()
|
|
{
|
|
MethodSymbol methodToImplement = F.SpecialMethod((SpecialMember)92);
|
|
MethodSymbol methodToImplement2 = F.SpecialMethod((SpecialMember)87);
|
|
MethodSymbol methodToImplement3 = F.SpecialMethod((SpecialMember)88);
|
|
MethodSymbol getMethod = F.SpecialProperty((SpecialMember)85).GetMethod;
|
|
NamedTypeSymbol newOwner = F.SpecialType((SpecialType)29).Construct(ImmutableArray.Create(_elementType));
|
|
MethodSymbol getterToImplement = F.SpecialProperty((SpecialMember)90).GetMethod.AsMember(newOwner);
|
|
SynthesizedImplementationMethod disposeMethod = OpenMethodImplementation(methodToImplement, null, hasMethodBodyDependency: true);
|
|
SynthesizedImplementationMethod moveNextMethod = OpenMoveNextMethodImplementation(methodToImplement2);
|
|
GenerateMoveNextAndDispose(moveNextMethod, disposeMethod);
|
|
OpenPropertyImplementation(getterToImplement);
|
|
F.CloseMethod(F.Return(F.Field(F.This(), _currentField)));
|
|
OpenMethodImplementation(methodToImplement3);
|
|
F.CloseMethod(F.Throw(F.New(F.WellKnownType((WellKnownType)240))));
|
|
OpenPropertyImplementation(getMethod);
|
|
F.CloseMethod(F.Return(F.Field(F.This(), _currentField)));
|
|
}
|
|
|
|
private void GenerateEnumerableImplementation(ref BoundExpression managedThreadId)
|
|
{
|
|
MethodSymbol methodToImplement = F.SpecialMethod((SpecialMember)84);
|
|
NamedTypeSymbol newOwner = F.SpecialType((SpecialType)25).Construct(_elementType.Type);
|
|
MethodSymbol getEnumeratorMethod = F.SpecialMethod((SpecialMember)89).AsMember(newOwner);
|
|
SynthesizedImplementationMethod synthesizedImplementationMethod = GenerateIteratorGetEnumerator(getEnumeratorMethod, ref managedThreadId, (StateMachineState)0);
|
|
OpenMethodImplementation(methodToImplement);
|
|
F.CloseMethod(F.Return(F.Call(F.This(), synthesizedImplementationMethod)));
|
|
}
|
|
|
|
private void GenerateConstructor(BoundExpression managedThreadId)
|
|
{
|
|
F.CurrentFunction = stateMachineType.Constructor;
|
|
ArrayBuilder<BoundStatement> instance = ArrayBuilder<BoundStatement>.GetInstance();
|
|
instance.Add(F.BaseInitialization());
|
|
instance.Add((BoundStatement)F.Assignment(F.Field(F.This(), stateField), F.Parameter(F.CurrentFunction.Parameters[0])));
|
|
if (managedThreadId != null)
|
|
{
|
|
instance.Add((BoundStatement)F.Assignment(F.Field(F.This(), initialThreadIdField), managedThreadId));
|
|
}
|
|
if ((object)instanceIdField != null)
|
|
{
|
|
MethodSymbol methodSymbol = F.WellKnownMethod((WellKnownMember)361);
|
|
if ((object)methodSymbol != null)
|
|
{
|
|
instance.Add((BoundStatement)F.Assignment(F.InstanceField(instanceIdField), F.Call(null, methodSymbol)));
|
|
}
|
|
}
|
|
instance.Add((BoundStatement)F.Return());
|
|
F.CloseMethod(F.Block(instance.ToImmutableAndFree()));
|
|
instance = null;
|
|
}
|
|
|
|
protected override void InitializeStateMachine(ArrayBuilder<BoundStatement> bodyBuilder, NamedTypeSymbol frameType, LocalSymbol stateMachineLocal)
|
|
{
|
|
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
|
|
StateMachineState value = (StateMachineState)(_isEnumerable ? (-2) : 0);
|
|
bodyBuilder.Add((BoundStatement)F.Assignment(F.Local(stateMachineLocal), F.New(stateMachineType.Constructor.AsMember(frameType), F.Literal(value))));
|
|
}
|
|
|
|
protected override BoundStatement GenerateStateMachineCreation(LocalSymbol stateMachineVariable, NamedTypeSymbol frameType, IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> proxies)
|
|
{
|
|
ArrayBuilder<BoundStatement> instance = ArrayBuilder<BoundStatement>.GetInstance();
|
|
instance.Add(GenerateParameterStorage(stateMachineVariable, proxies));
|
|
instance.Add((BoundStatement)F.Return(F.Local(stateMachineVariable)));
|
|
return F.Block(instance.ToImmutableAndFree());
|
|
}
|
|
|
|
private void GenerateMoveNextAndDispose(SynthesizedImplementationMethod moveNextMethod, SynthesizedImplementationMethod disposeMethod)
|
|
{
|
|
new IteratorMethodToStateMachineRewriter(F, method, stateField, _currentField, instanceIdField, (IReadOnlySet<Symbol>)(object)hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics).GenerateMoveNextAndDispose(body, moveNextMethod, disposeMethod);
|
|
}
|
|
}
|