Files
2026-08-27 10:56:38 -06:00

359 lines
19 KiB
C#

using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.Cci;
using Microsoft.CodeAnalysis.CSharp.Emit.NoPia;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.PooledObjects;
namespace Microsoft.CodeAnalysis.CSharp;
internal abstract class StateMachineRewriter
{
protected readonly BoundStatement body;
protected readonly MethodSymbol method;
protected readonly BindingDiagnosticBag diagnostics;
protected readonly SyntheticBoundNodeFactory F;
protected readonly SynthesizedContainer stateMachineType;
protected readonly VariableSlotAllocator? slotAllocatorOpt;
protected readonly SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals;
protected readonly ArrayBuilder<StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder;
protected FieldSymbol? stateField;
protected FieldSymbol? instanceIdField;
protected IReadOnlyDictionary<Symbol, CapturedSymbolReplacement>? nonReusableLocalProxies;
protected int nextFreeHoistedLocalSlot;
protected IOrderedReadOnlySet<Symbol>? hoistedVariables;
protected Dictionary<Symbol, CapturedSymbolReplacement>? initialParameters;
protected FieldSymbol? initialThreadIdField;
protected abstract bool PreserveInitialParameterValuesAndThreadId { get; }
protected StateMachineRewriter(BoundStatement body, MethodSymbol method, SynthesizedContainer stateMachineType, ArrayBuilder<StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder, VariableSlotAllocator? slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Expected O, but got Unknown
this.body = body;
this.method = method;
this.stateMachineType = stateMachineType;
this.stateMachineStateDebugInfoBuilder = stateMachineStateDebugInfoBuilder;
this.slotAllocatorOpt = slotAllocatorOpt;
synthesizedLocalOrdinals = new SynthesizedLocalOrdinalsDispenser();
this.diagnostics = diagnostics;
F = new SyntheticBoundNodeFactory(method, body.Syntax, compilationState, diagnostics);
}
protected abstract void GenerateControlFields();
protected abstract void InitializeStateMachine(ArrayBuilder<BoundStatement> bodyBuilder, NamedTypeSymbol frameType, LocalSymbol stateMachineLocal);
protected abstract BoundStatement GenerateStateMachineCreation(LocalSymbol stateMachineVariable, NamedTypeSymbol frameType, IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> proxies);
protected abstract void GenerateMethodImplementations();
protected BoundStatement Rewrite()
{
if (body.HasErrors)
{
return body;
}
F.OpenNestedType(stateMachineType);
GenerateControlFields();
if (PreserveInitialParameterValuesAndThreadId && CanGetThreadId())
{
initialThreadIdField = F.StateMachineField(F.SpecialType((SpecialType)13), GeneratedNames.MakeIteratorCurrentThreadIdFieldName());
}
if (PreserveInitialParameterValuesAndThreadId)
{
initialParameters = new Dictionary<Symbol, CapturedSymbolReplacement>();
}
OrderedSet<Symbol> variablesToHoist = IteratorAndAsyncCaptureWalker.Analyze(F.Compilation, method, body, ((BindingDiagnosticBag)diagnostics).DiagnosticBag);
if (((BindingDiagnosticBag)diagnostics).HasAnyErrors())
{
return new BoundBadStatement(F.Syntax, ImmutableArray<BoundNode>.Empty, hasErrors: true);
}
CreateNonReusableLocalProxies((IEnumerable<Symbol>)variablesToHoist, out nonReusableLocalProxies, out nextFreeHoistedLocalSlot);
hoistedVariables = (IOrderedReadOnlySet<Symbol>?)(object)variablesToHoist;
GenerateMethodImplementations();
return GenerateKickoffMethodBody();
}
private void CreateNonReusableLocalProxies(IEnumerable<Symbol> variablesToHoist, out IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> proxies, out int nextFreeHoistedLocalSlot)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Invalid comparison between Unknown and I4
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Invalid comparison between Unknown and I4
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_017a: Unknown result type (might be due to invalid IL or missing references)
//IL_0196: Unknown result type (might be due to invalid IL or missing references)
//IL_0198: Unknown result type (might be due to invalid IL or missing references)
//IL_019a: Unknown result type (might be due to invalid IL or missing references)
Dictionary<Symbol, CapturedSymbolReplacement> dictionary = new Dictionary<Symbol, CapturedSymbolReplacement>();
TypeMap typeMap = stateMachineType.TypeMap;
bool flag = (int)((CompilationOptions)F.Compilation.Options).OptimizationLevel == 0;
bool flag2 = flag && slotAllocatorOpt != null;
nextFreeHoistedLocalSlot = (flag2 ? slotAllocatorOpt.PreviousHoistedLocalSlotCount : 0);
LocalDebugId none = default(LocalDebugId);
int num4 = default(int);
foreach (Symbol item in variablesToHoist)
{
if ((int)item.Kind == 8)
{
LocalSymbol localSymbol = (LocalSymbol)item;
SynthesizedLocalKind synthesizedKind = localSymbol.SynthesizedKind;
if (!SynthesizedLocalKindExtensions.MustSurviveStateMachineSuspension(synthesizedKind) || localSymbol.IsConst || (int)localSymbol.RefKind != 0)
{
continue;
}
StateMachineFieldSymbol stateMachineFieldSymbol = null;
if (ShouldPreallocateNonReusableProxy(localSymbol))
{
TypeSymbol type = typeMap.SubstituteType(localSymbol.Type).Type;
int num = -1;
if (flag)
{
SyntaxNode declaratorSyntax = localSymbol.GetDeclaratorSyntax();
int num2 = method.CalculateLocalSyntaxOffset(LambdaUtilities.GetDeclaratorPosition(declaratorSyntax), declaratorSyntax.SyntaxTree);
int num3 = synthesizedLocalOrdinals.AssignLocalOrdinal(synthesizedKind, num2);
((LocalDebugId)(ref none))._002Ector(num2, num3);
if (flag2 && slotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(declaratorSyntax, ((PEModuleBuilder<CSharpCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, EmbeddedTypesManager, ModuleCompilationState>)F.ModuleBuilderOpt).Translate(type, declaratorSyntax, ((BindingDiagnosticBag)diagnostics).DiagnosticBag), synthesizedKind, none, ((BindingDiagnosticBag)diagnostics).DiagnosticBag, ref num4))
{
num = num4;
}
}
else
{
none = LocalDebugId.None;
}
if (num == -1)
{
num = nextFreeHoistedLocalSlot++;
}
string name = GeneratedNames.MakeHoistedLocalFieldName(synthesizedKind, num, localSymbol.Name);
stateMachineFieldSymbol = F.StateMachineField(type, name, new LocalSlotDebugInfo(synthesizedKind, none), num);
}
if (stateMachineFieldSymbol != null)
{
dictionary.Add(localSymbol, new CapturedToStateMachineFieldReplacement(stateMachineFieldSymbol, isReusable: false));
}
continue;
}
ParameterSymbol parameterSymbol = (ParameterSymbol)item;
if (parameterSymbol.IsThis)
{
NamedTypeSymbol containingType = method.ContainingType;
StateMachineFieldSymbol stateMachineFieldSymbol2 = F.StateMachineField(containingType, GeneratedNames.ThisProxyFieldName(), isPublic: true, isThis: true);
dictionary.Add(parameterSymbol, new CapturedToStateMachineFieldReplacement(stateMachineFieldSymbol2, isReusable: false));
if (PreserveInitialParameterValuesAndThreadId)
{
StateMachineFieldSymbol hoistedField = (containingType.IsStructType() ? F.StateMachineField(containingType, GeneratedNames.StateMachineThisParameterProxyName(), isPublic: true, isThis: true) : stateMachineFieldSymbol2);
initialParameters.Add(parameterSymbol, new CapturedToStateMachineFieldReplacement(hoistedField, isReusable: false));
}
}
else
{
StateMachineFieldSymbol hoistedField2 = F.StateMachineField(typeMap.SubstituteType(parameterSymbol.Type).Type, parameterSymbol.Name, !PreserveInitialParameterValuesAndThreadId);
dictionary.Add(parameterSymbol, new CapturedToStateMachineFieldReplacement(hoistedField2, isReusable: false));
if (PreserveInitialParameterValuesAndThreadId)
{
StateMachineFieldSymbol hoistedField3 = F.StateMachineField(typeMap.SubstituteType(parameterSymbol.Type).Type, GeneratedNames.StateMachineParameterProxyFieldName(parameterSymbol.Name), isPublic: true);
initialParameters.Add(parameterSymbol, new CapturedToStateMachineFieldReplacement(hoistedField3, isReusable: false));
}
}
}
proxies = dictionary;
}
private bool ShouldPreallocateNonReusableProxy(LocalSymbol local)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Invalid comparison between Unknown and I4
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
SynthesizedLocalKind synthesizedKind = local.SynthesizedKind;
OptimizationLevel optimizationLevel = ((CompilationOptions)F.Compilation.Options).OptimizationLevel;
if ((int)optimizationLevel == 1 && (int)synthesizedKind == 0)
{
return false;
}
return !SynthesizedLocalKindExtensions.IsSlotReusable(synthesizedKind, optimizationLevel);
}
private BoundStatement GenerateKickoffMethodBody()
{
F.CurrentFunction = method;
ArrayBuilder<BoundStatement> instance = ArrayBuilder<BoundStatement>.GetInstance();
NamedTypeSymbol namedTypeSymbol = (method.IsGenericMethod ? stateMachineType.Construct(method.TypeArgumentsWithAnnotations, unbound: false) : stateMachineType);
LocalSymbol localSymbol = F.SynthesizedLocal(namedTypeSymbol, null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-2));
InitializeStateMachine(instance, namedTypeSymbol, localSymbol);
IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> readOnlyDictionary;
if (!PreserveInitialParameterValuesAndThreadId)
{
readOnlyDictionary = nonReusableLocalProxies;
}
else
{
IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> readOnlyDictionary2 = initialParameters;
readOnlyDictionary = readOnlyDictionary2;
}
IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> proxies = readOnlyDictionary;
instance.Add(GenerateStateMachineCreation(localSymbol, namedTypeSymbol, proxies));
return F.Block(ImmutableArray.Create(localSymbol), instance.ToImmutableAndFree());
}
protected BoundStatement GenerateParameterStorage(LocalSymbol stateMachineVariable, IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> proxies)
{
ArrayBuilder<BoundStatement> instance = ArrayBuilder<BoundStatement>.GetInstance();
if (!method.IsStatic && proxies.TryGetValue(method.ThisParameter, out var value))
{
instance.Add((BoundStatement)F.Assignment(value.Replacement(F.Syntax, (NamedTypeSymbol frameType1) => F.Local(stateMachineVariable)), F.This()));
}
ImmutableArray<ParameterSymbol>.Enumerator enumerator = method.Parameters.GetEnumerator();
while (enumerator.MoveNext())
{
ParameterSymbol current = enumerator.Current;
if (proxies.TryGetValue(current, out var value2))
{
instance.Add((BoundStatement)F.Assignment(value2.Replacement(F.Syntax, (NamedTypeSymbol frameType1) => F.Local(stateMachineVariable)), F.Parameter(current)));
}
}
ImmutableArray<BoundStatement> statements = instance.ToImmutableAndFree();
return F.Block(statements);
}
protected SynthesizedImplementationMethod OpenMethodImplementation(MethodSymbol methodToImplement, string methodName = null, bool hasMethodBodyDependency = false)
{
SynthesizedStateMachineDebuggerHiddenMethod synthesizedStateMachineDebuggerHiddenMethod = new SynthesizedStateMachineDebuggerHiddenMethod(methodName, methodToImplement, (StateMachineTypeSymbol)F.CurrentType, null, hasMethodBodyDependency);
((PEModuleBuilder<CSharpCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, EmbeddedTypesManager, ModuleCompilationState>)F.ModuleBuilderOpt).AddSynthesizedDefinition(F.CurrentType, (IMethodDefinition)(object)synthesizedStateMachineDebuggerHiddenMethod.GetCciAdapter());
F.CurrentFunction = synthesizedStateMachineDebuggerHiddenMethod;
return synthesizedStateMachineDebuggerHiddenMethod;
}
protected MethodSymbol OpenPropertyImplementation(MethodSymbol getterToImplement)
{
SynthesizedStateMachineProperty synthesizedStateMachineProperty = new SynthesizedStateMachineProperty(getterToImplement, (StateMachineTypeSymbol)F.CurrentType);
((PEModuleBuilder<CSharpCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, EmbeddedTypesManager, ModuleCompilationState>)F.ModuleBuilderOpt).AddSynthesizedDefinition(F.CurrentType, (IPropertyDefinition)(object)synthesizedStateMachineProperty.GetCciAdapter());
MethodSymbol getMethod = synthesizedStateMachineProperty.GetMethod;
((PEModuleBuilder<CSharpCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, EmbeddedTypesManager, ModuleCompilationState>)F.ModuleBuilderOpt).AddSynthesizedDefinition(F.CurrentType, (IMethodDefinition)(object)getMethod.GetCciAdapter());
F.CurrentFunction = getMethod;
return getMethod;
}
protected SynthesizedImplementationMethod OpenMoveNextMethodImplementation(MethodSymbol methodToImplement)
{
SynthesizedStateMachineMoveNextMethod synthesizedStateMachineMoveNextMethod = new SynthesizedStateMachineMoveNextMethod(methodToImplement, (StateMachineTypeSymbol)F.CurrentType);
((PEModuleBuilder<CSharpCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, EmbeddedTypesManager, ModuleCompilationState>)F.ModuleBuilderOpt).AddSynthesizedDefinition(F.CurrentType, (IMethodDefinition)(object)synthesizedStateMachineMoveNextMethod.GetCciAdapter());
F.CurrentFunction = synthesizedStateMachineMoveNextMethod;
return synthesizedStateMachineMoveNextMethod;
}
protected BoundExpression MakeCurrentThreadId()
{
PropertySymbol propertySymbol = (PropertySymbol)F.WellKnownMember((WellKnownMember)305, isOptional: true);
if ((object)propertySymbol != null)
{
MethodSymbol getMethod = propertySymbol.GetMethod;
if ((object)getMethod != null)
{
return F.Call(null, getMethod);
}
}
return F.Property(F.Property((WellKnownMember)145), (WellKnownMember)146);
}
protected SynthesizedImplementationMethod GenerateIteratorGetEnumerator(MethodSymbol getEnumeratorMethod, ref BoundExpression managedThreadId, StateMachineState initialState)
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
SynthesizedImplementationMethod result = OpenMethodImplementation(getEnumeratorMethod);
ArrayBuilder<BoundStatement> instance = ArrayBuilder<BoundStatement>.GetInstance();
LocalSymbol resultVariable = F.SynthesizedLocal(stateMachineType, null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-2));
BoundStatement boundStatement = F.Assignment(F.Local(resultVariable), F.New(stateMachineType.Constructor, F.Literal(initialState)));
GeneratedLabelSymbol label = F.GenerateLabel("thisInitialized");
if ((object)initialThreadIdField != null)
{
managedThreadId = MakeCurrentThreadId();
ArrayBuilder<BoundStatement> instance2 = ArrayBuilder<BoundStatement>.GetInstance(4);
GenerateResetInstance(instance2, initialState);
instance2.Add((BoundStatement)F.Assignment(F.Local(resultVariable), F.This()));
if (method.IsStatic || method.ThisParameter.Type.IsReferenceType)
{
instance2.Add((BoundStatement)F.Goto(label));
}
boundStatement = F.If(F.LogicalAnd(F.IntEqual(F.Field(F.This(), stateField), F.Literal((StateMachineState)(-2))), F.IntEqual(F.Field(F.This(), initialThreadIdField), managedThreadId)), F.Block(instance2.ToImmutableAndFree()), boundStatement);
}
instance.Add(boundStatement);
Dictionary<Symbol, CapturedSymbolReplacement> dictionary = initialParameters;
IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> readOnlyDictionary = nonReusableLocalProxies;
if (!method.IsStatic && readOnlyDictionary.TryGetValue(method.ThisParameter, out var value))
{
instance.Add((BoundStatement)F.Assignment(value.Replacement(F.Syntax, (NamedTypeSymbol stateMachineType) => F.Local(resultVariable)), dictionary[method.ThisParameter].Replacement(F.Syntax, (NamedTypeSymbol stateMachineType) => F.This())));
}
instance.Add((BoundStatement)F.Label(label));
ImmutableArray<ParameterSymbol>.Enumerator enumerator = method.Parameters.GetEnumerator();
while (enumerator.MoveNext())
{
ParameterSymbol current = enumerator.Current;
if (readOnlyDictionary.TryGetValue(current, out var value2))
{
BoundExpression resultParameter = value2.Replacement(F.Syntax, (NamedTypeSymbol stateMachineType) => F.Local(resultVariable));
BoundExpression parameterProxy = dictionary[current].Replacement(F.Syntax, (NamedTypeSymbol stateMachineType) => F.This());
BoundStatement boundStatement2 = InitializeParameterField(getEnumeratorMethod, current, resultParameter, parameterProxy);
instance.Add(boundStatement2);
}
}
instance.Add((BoundStatement)F.Return(F.Local(resultVariable)));
F.CloseMethod(F.Block(ImmutableArray.Create(resultVariable), instance.ToImmutableAndFree()));
return result;
}
protected virtual void GenerateResetInstance(ArrayBuilder<BoundStatement> builder, StateMachineState initialState)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
builder.Add((BoundStatement)F.Assignment(F.Field(F.This(), stateField), F.Literal(initialState)));
}
protected virtual BoundStatement InitializeParameterField(MethodSymbol getEnumeratorMethod, ParameterSymbol parameter, BoundExpression resultParameter, BoundExpression parameterProxy)
{
return F.Assignment(resultParameter, parameterProxy);
}
protected bool CanGetThreadId()
{
if ((object)F.WellKnownMember((WellKnownMember)146, isOptional: true) == null)
{
return (object)F.WellKnownMember((WellKnownMember)305, isOptional: true) != null;
}
return true;
}
}