707 lines
28 KiB
C#
707 lines
28 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
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 abstract class MethodToStateMachineRewriter : MethodToClassRewriter
|
|
{
|
|
internal readonly MethodSymbol OriginalMethod;
|
|
|
|
protected readonly SyntheticBoundNodeFactory F;
|
|
|
|
protected readonly FieldSymbol stateField;
|
|
|
|
protected readonly LocalSymbol cachedState;
|
|
|
|
protected readonly LocalSymbol? cachedThis;
|
|
|
|
protected readonly FieldSymbol? instanceIdField;
|
|
|
|
private readonly ResumableStateMachineStateAllocator _resumableStateAllocator;
|
|
|
|
private Dictionary<LabelSymbol, List<StateMachineState>> _dispatches = new Dictionary<LabelSymbol, List<StateMachineState>>();
|
|
|
|
private Dictionary<TypeSymbol, ArrayBuilder<StateMachineFieldSymbol>>? _lazyAvailableReusableHoistedFields;
|
|
|
|
private int _nextHoistedFieldId = 1;
|
|
|
|
private readonly EmptyStructTypeCache _emptyStructTypeCache = EmptyStructTypeCache.CreateNeverEmpty();
|
|
|
|
private readonly IReadOnlySet<Symbol> _hoistedVariables;
|
|
|
|
private readonly SynthesizedLocalOrdinalsDispenser _synthesizedLocalOrdinals;
|
|
|
|
private int _nextFreeHoistedLocalSlot;
|
|
|
|
private readonly ArrayBuilder<StateMachineStateDebugInfo> _stateDebugInfoBuilder;
|
|
|
|
protected BoundBlockInstrumentation? instrumentation;
|
|
|
|
protected abstract StateMachineState FirstIncreasingResumableState { get; }
|
|
|
|
protected abstract string EncMissingStateMessage { get; }
|
|
|
|
protected override TypeMap TypeMap => ((SynthesizedContainer)F.CurrentType).TypeMap;
|
|
|
|
protected override MethodSymbol CurrentMethod => F.CurrentFunction;
|
|
|
|
protected override NamedTypeSymbol ContainingType => OriginalMethod.ContainingType;
|
|
|
|
internal IReadOnlySet<Symbol> HoistedVariables => _hoistedVariables;
|
|
|
|
public MethodToStateMachineRewriter(SyntheticBoundNodeFactory F, MethodSymbol originalMethod, FieldSymbol state, FieldSymbol? instanceIdField, IReadOnlySet<Symbol> hoistedVariables, IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, ArrayBuilder<StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder, VariableSlotAllocator? slotAllocatorOpt, int nextFreeHoistedLocalSlot, BindingDiagnosticBag diagnostics)
|
|
: base(slotAllocatorOpt, F.CompilationState, diagnostics)
|
|
{
|
|
//IL_0178: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0123: Invalid comparison between Unknown and I4
|
|
this.F = F;
|
|
stateField = state;
|
|
this.instanceIdField = instanceIdField;
|
|
cachedState = F.SynthesizedLocal(F.SpecialType((SpecialType)13), F.Syntax, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)27);
|
|
OriginalMethod = originalMethod;
|
|
_hoistedVariables = hoistedVariables;
|
|
_synthesizedLocalOrdinals = synthesizedLocalOrdinals;
|
|
_nextFreeHoistedLocalSlot = nextFreeHoistedLocalSlot;
|
|
foreach (KeyValuePair<Symbol, CapturedSymbolReplacement> nonReusableLocalProxy in nonReusableLocalProxies)
|
|
{
|
|
proxies.Add(nonReusableLocalProxy.Key, nonReusableLocalProxy.Value);
|
|
}
|
|
ParameterSymbol thisParameter = originalMethod.ThisParameter;
|
|
if ((object)thisParameter != null && thisParameter.Type.IsReferenceType && proxies.TryGetValue(thisParameter, out CapturedSymbolReplacement value) && (int)((CompilationOptions)F.Compilation.Options).OptimizationLevel == 1)
|
|
{
|
|
BoundExpression boundExpression = value.Replacement(F.Syntax, (NamedTypeSymbol frameType) => F.This());
|
|
cachedThis = F.SynthesizedLocal(boundExpression.Type, F.Syntax, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-5));
|
|
}
|
|
_stateDebugInfoBuilder = stateMachineStateDebugInfoBuilder;
|
|
_resumableStateAllocator = new ResumableStateMachineStateAllocator(slotAllocatorOpt, FirstIncreasingResumableState, increasing: true);
|
|
}
|
|
|
|
protected abstract BoundStatement GenerateReturn(bool finished);
|
|
|
|
protected override bool NeedsProxy(Symbol localOrParameter)
|
|
{
|
|
return _hoistedVariables.Contains(localOrParameter);
|
|
}
|
|
|
|
protected override BoundExpression FramePointer(SyntaxNode syntax, NamedTypeSymbol frameClass)
|
|
{
|
|
SyntaxNode syntax2 = F.Syntax;
|
|
F.Syntax = syntax;
|
|
BoundThisReference result = F.This();
|
|
F.Syntax = syntax2;
|
|
return result;
|
|
}
|
|
|
|
protected void AddResumableState(SyntaxNode awaitOrYieldReturnSyntax, AwaitDebugId awaitId, out StateMachineState state, out GeneratedLabelSymbol resumeLabel)
|
|
{
|
|
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
|
|
AddResumableState(_resumableStateAllocator, awaitOrYieldReturnSyntax, awaitId, out state, out resumeLabel);
|
|
}
|
|
|
|
protected void AddResumableState(ResumableStateMachineStateAllocator allocator, SyntaxNode awaitOrYieldReturnSyntax, AwaitDebugId awaitId, out StateMachineState stateNumber, out GeneratedLabelSymbol resumeLabel)
|
|
{
|
|
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000b: Expected I4, but got Unknown
|
|
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
|
|
stateNumber = (StateMachineState)(int)allocator.AllocateState(awaitOrYieldReturnSyntax, awaitId);
|
|
AddStateDebugInfo(awaitOrYieldReturnSyntax, awaitId, stateNumber);
|
|
AddState(stateNumber, out resumeLabel);
|
|
}
|
|
|
|
protected void AddStateDebugInfo(SyntaxNode node, AwaitDebugId awaitId, StateMachineState state)
|
|
{
|
|
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0020: 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)
|
|
int num = CurrentMethod.CalculateLocalSyntaxOffset(node.SpanStart, node.SyntaxTree);
|
|
_stateDebugInfoBuilder.Add(new StateMachineStateDebugInfo(num, awaitId, state));
|
|
}
|
|
|
|
protected void AddState(StateMachineState stateNumber, out GeneratedLabelSymbol resumeLabel)
|
|
{
|
|
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
|
|
if (_dispatches == null)
|
|
{
|
|
_dispatches = new Dictionary<LabelSymbol, List<StateMachineState>>();
|
|
}
|
|
resumeLabel = F.GenerateLabel("stateMachine");
|
|
_dispatches.Add(resumeLabel, new List<StateMachineState> { stateNumber });
|
|
}
|
|
|
|
protected BoundStatement Dispatch(bool isOutermost)
|
|
{
|
|
IEnumerable<SyntheticBoundNodeFactory.SyntheticSwitchSection> items = _dispatches.OrderBy<KeyValuePair<LabelSymbol, List<StateMachineState>>, StateMachineState>(delegate(KeyValuePair<LabelSymbol, List<StateMachineState>> kv)
|
|
{
|
|
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
|
|
KeyValuePair<LabelSymbol, List<StateMachineState>> keyValuePair = kv;
|
|
return keyValuePair.Value[0];
|
|
}).Select(delegate(KeyValuePair<LabelSymbol, List<StateMachineState>> kv)
|
|
{
|
|
SyntheticBoundNodeFactory f = F;
|
|
KeyValuePair<LabelSymbol, List<StateMachineState>> keyValuePair = kv;
|
|
ImmutableArray<int> values = EnumerableExtensions.SelectAsArray<StateMachineState, int>((IReadOnlyCollection<StateMachineState>)keyValuePair.Value, (Func<StateMachineState, int>)((StateMachineState state) => (int)state));
|
|
BoundStatement[] array = new BoundStatement[1];
|
|
SyntheticBoundNodeFactory f2 = F;
|
|
keyValuePair = kv;
|
|
array[0] = f2.Goto(keyValuePair.Key);
|
|
return f.SwitchSection(values, array);
|
|
});
|
|
BoundStatement boundStatement = F.Switch(F.Local(cachedState), items.ToImmutableArray());
|
|
if (isOutermost)
|
|
{
|
|
BoundStatement boundStatement2 = GenerateMissingStateDispatch();
|
|
if (boundStatement2 != null)
|
|
{
|
|
boundStatement = F.Block(boundStatement, boundStatement2);
|
|
}
|
|
}
|
|
return boundStatement;
|
|
}
|
|
|
|
protected virtual BoundStatement? GenerateMissingStateDispatch()
|
|
{
|
|
return _resumableStateAllocator.GenerateThrowMissingStateDispatch(F, F.Local(cachedState), EncMissingStateMessage);
|
|
}
|
|
|
|
private BoundStatement PossibleIteratorScope(ImmutableArray<LocalSymbol> locals, Func<BoundStatement> wrapped)
|
|
{
|
|
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00c6: Invalid comparison between Unknown and I4
|
|
if (locals.IsDefaultOrEmpty)
|
|
{
|
|
return wrapped();
|
|
}
|
|
ArrayBuilder<StateMachineFieldSymbol> instance = ArrayBuilder<StateMachineFieldSymbol>.GetInstance();
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
if (!NeedsProxy(current) || (int)current.RefKind != 0)
|
|
{
|
|
continue;
|
|
}
|
|
bool reused = false;
|
|
if (!proxies.TryGetValue(current, out CapturedSymbolReplacement value))
|
|
{
|
|
value = new CapturedToStateMachineFieldReplacement(GetOrAllocateReusableHoistedField(TypeMap.SubstituteType(current.Type).Type, out reused, current), isReusable: true);
|
|
proxies.Add(current, value);
|
|
}
|
|
if ((int)current.SynthesizedKind == 0)
|
|
{
|
|
SyntaxNode scopeDesignatorOpt = current.ScopeDesignatorOpt;
|
|
if (scopeDesignatorOpt == null || scopeDesignatorOpt.Kind() != SyntaxKind.SwitchSection)
|
|
{
|
|
goto IL_00c8;
|
|
}
|
|
}
|
|
if ((int)current.SynthesizedKind != 30)
|
|
{
|
|
continue;
|
|
}
|
|
goto IL_00c8;
|
|
IL_00c8:
|
|
if (!reused)
|
|
{
|
|
instance.Add(((CapturedToStateMachineFieldReplacement)value).HoistedField);
|
|
}
|
|
}
|
|
BoundStatement boundStatement = wrapped();
|
|
ArrayBuilder<BoundExpression> instance2 = ArrayBuilder<BoundExpression>.GetInstance();
|
|
enumerator = locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current2 = enumerator.Current;
|
|
if (!proxies.TryGetValue(current2, out CapturedSymbolReplacement value2))
|
|
{
|
|
continue;
|
|
}
|
|
if (value2 is CapturedToStateMachineFieldReplacement capturedToStateMachineFieldReplacement)
|
|
{
|
|
AddVariableCleanup(instance2, capturedToStateMachineFieldReplacement.HoistedField);
|
|
if (value2.IsReusable)
|
|
{
|
|
FreeReusableHoistedField(capturedToStateMachineFieldReplacement.HoistedField);
|
|
}
|
|
continue;
|
|
}
|
|
ImmutableArray<StateMachineFieldSymbol>.Enumerator enumerator2 = ((CapturedToExpressionSymbolReplacement)value2).HoistedFields.GetEnumerator();
|
|
while (enumerator2.MoveNext())
|
|
{
|
|
StateMachineFieldSymbol current3 = enumerator2.Current;
|
|
AddVariableCleanup(instance2, current3);
|
|
if (value2.IsReusable)
|
|
{
|
|
FreeReusableHoistedField(current3);
|
|
}
|
|
}
|
|
}
|
|
if (instance2.Count != 0)
|
|
{
|
|
boundStatement = F.Block(boundStatement, F.Block(ArrayBuilderExtensions.SelectAsArray<BoundExpression, SyntheticBoundNodeFactory, BoundStatement>(instance2, (Func<BoundExpression, SyntheticBoundNodeFactory, BoundStatement>)((BoundExpression e, SyntheticBoundNodeFactory f) => f.ExpressionStatement(e)), F)));
|
|
}
|
|
instance2.Free();
|
|
if (instance.Count != 0)
|
|
{
|
|
boundStatement = MakeStateMachineScope(instance.ToImmutable(), boundStatement);
|
|
}
|
|
instance.Free();
|
|
return boundStatement;
|
|
}
|
|
|
|
internal BoundBlock MakeStateMachineScope(ImmutableArray<StateMachineFieldSymbol> hoistedLocals, BoundStatement statement)
|
|
{
|
|
return F.Block(new BoundStateMachineScope(F.Syntax, hoistedLocals, statement));
|
|
}
|
|
|
|
internal static bool TryUnwrapBoundStateMachineScope(ref BoundStatement statement, out ImmutableArray<StateMachineFieldSymbol> hoistedLocals)
|
|
{
|
|
if (statement.Kind == BoundKind.Block)
|
|
{
|
|
ImmutableArray<BoundStatement> statements = ((BoundBlock)statement).Statements;
|
|
if (statements.Length == 1 && statements[0].Kind == BoundKind.StateMachineScope)
|
|
{
|
|
BoundStateMachineScope boundStateMachineScope = (BoundStateMachineScope)statements[0];
|
|
statement = boundStateMachineScope.Statement;
|
|
hoistedLocals = boundStateMachineScope.Fields;
|
|
return true;
|
|
}
|
|
}
|
|
hoistedLocals = ImmutableArray<StateMachineFieldSymbol>.Empty;
|
|
return false;
|
|
}
|
|
|
|
private void AddVariableCleanup(ArrayBuilder<BoundExpression> cleanup, FieldSymbol field)
|
|
{
|
|
if (MightContainReferences(field.Type))
|
|
{
|
|
cleanup.Add(F.AssignmentExpression(F.Field(F.This(), field), F.NullOrDefault(field.Type)));
|
|
}
|
|
}
|
|
|
|
private bool MightContainReferences(TypeSymbol type)
|
|
{
|
|
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0010: Invalid comparison between Unknown and I4
|
|
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001c: Invalid comparison between Unknown and I4
|
|
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0028: Invalid comparison between Unknown and I4
|
|
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
|
|
if (type.IsReferenceType || (int)type.TypeKind == 11)
|
|
{
|
|
return true;
|
|
}
|
|
if ((int)type.TypeKind != 10)
|
|
{
|
|
return false;
|
|
}
|
|
if ((int)type.SpecialType == 36)
|
|
{
|
|
return true;
|
|
}
|
|
if ((int)type.SpecialType != 0)
|
|
{
|
|
return false;
|
|
}
|
|
if (!type.IsFromCompilation(((PEModuleBuilder<CSharpCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, EmbeddedTypesManager, ModuleCompilationState>)CompilationState.ModuleBuilderOpt).Compilation))
|
|
{
|
|
return true;
|
|
}
|
|
foreach (FieldSymbol structInstanceField in _emptyStructTypeCache.GetStructInstanceFields(type))
|
|
{
|
|
if (MightContainReferences(structInstanceField.Type))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private StateMachineFieldSymbol GetOrAllocateReusableHoistedField(TypeSymbol type, out bool reused, LocalSymbol local = null)
|
|
{
|
|
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
|
|
if (_lazyAvailableReusableHoistedFields != null && _lazyAvailableReusableHoistedFields.TryGetValue(type, out ArrayBuilder<StateMachineFieldSymbol> value) && value.Count > 0)
|
|
{
|
|
StateMachineFieldSymbol result = value.Last();
|
|
value.RemoveLast();
|
|
reused = true;
|
|
return result;
|
|
}
|
|
reused = false;
|
|
int num = _nextHoistedFieldId++;
|
|
if ((object)local != null && (int)local.SynthesizedKind == 0)
|
|
{
|
|
string name = GeneratedNames.MakeHoistedLocalFieldName((SynthesizedLocalKind)0, num, local.Name);
|
|
return F.StateMachineField(type, name, (SynthesizedLocalKind)0, num);
|
|
}
|
|
return F.StateMachineField(type, GeneratedNames.ReusableHoistedLocalFieldName(num));
|
|
}
|
|
|
|
private void FreeReusableHoistedField(StateMachineFieldSymbol field)
|
|
{
|
|
if (_lazyAvailableReusableHoistedFields == null || !_lazyAvailableReusableHoistedFields.TryGetValue(field.Type, out ArrayBuilder<StateMachineFieldSymbol> value))
|
|
{
|
|
if (_lazyAvailableReusableHoistedFields == null)
|
|
{
|
|
_lazyAvailableReusableHoistedFields = new Dictionary<TypeSymbol, ArrayBuilder<StateMachineFieldSymbol>>(SymbolEqualityComparer.IgnoringDynamicTupleNamesAndNullability);
|
|
}
|
|
_lazyAvailableReusableHoistedFields.Add(field.Type, value = new ArrayBuilder<StateMachineFieldSymbol>());
|
|
}
|
|
value.Add(field);
|
|
}
|
|
|
|
private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssignmentOperator node)
|
|
{
|
|
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
|
|
BoundExpression expr = (BoundExpression)Visit(node.Right);
|
|
ArrayBuilder<BoundExpression> instance = ArrayBuilder<BoundExpression>.GetInstance();
|
|
bool needsSacrificialEvaluation = false;
|
|
ArrayBuilder<StateMachineFieldSymbol> instance2 = ArrayBuilder<StateMachineFieldSymbol>.GetInstance();
|
|
SyntaxNode val;
|
|
int syntaxOffset;
|
|
if ((int)((CompilationOptions)F.Compilation.Options).OptimizationLevel == 0)
|
|
{
|
|
val = local.GetDeclaratorSyntax();
|
|
syntaxOffset = OriginalMethod.CalculateLocalSyntaxOffset(LambdaUtilities.GetDeclaratorPosition(val), val.SyntaxTree);
|
|
}
|
|
else
|
|
{
|
|
val = null;
|
|
syntaxOffset = -1;
|
|
}
|
|
BoundExpression boundExpression = HoistExpression(expr, val, syntaxOffset, local.RefKind, instance, instance2, ref needsSacrificialEvaluation);
|
|
proxies.Add(local, new CapturedToExpressionSymbolReplacement(boundExpression, instance2.ToImmutableAndFree(), isReusable: true));
|
|
if (needsSacrificialEvaluation)
|
|
{
|
|
TypeSymbol type = TypeMap.SubstituteType(local.Type).Type;
|
|
LocalSymbol localSymbol = F.SynthesizedLocal(type, null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)1, (SynthesizedLocalKind)(-2));
|
|
return F.Sequence(ImmutableArray.Create(localSymbol), instance.ToImmutableAndFree(), F.AssignmentExpression(F.Local(localSymbol), boundExpression, isRef: true));
|
|
}
|
|
if (instance.Count == 0)
|
|
{
|
|
instance.Free();
|
|
return null;
|
|
}
|
|
BoundExpression result = instance.Last();
|
|
instance.RemoveLast();
|
|
return F.Sequence(ImmutableArray<LocalSymbol>.Empty, instance.ToImmutableAndFree(), result);
|
|
}
|
|
|
|
private BoundExpression HoistExpression(BoundExpression expr, SyntaxNode awaitSyntaxOpt, int syntaxOffset, RefKind refKind, ArrayBuilder<BoundExpression> sideEffects, ArrayBuilder<StateMachineFieldSymbol> hoistedFields, ref bool needsSacrificialEvaluation)
|
|
{
|
|
//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0181: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01d2: Invalid comparison between Unknown and I4
|
|
//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0188: Invalid comparison between Unknown and I4
|
|
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_020d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0239: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_028b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
|
|
switch (expr.Kind)
|
|
{
|
|
case BoundKind.ArrayAccess:
|
|
{
|
|
BoundArrayAccess boundArrayAccess = (BoundArrayAccess)expr;
|
|
BoundExpression expression = HoistExpression(boundArrayAccess.Expression, awaitSyntaxOpt, syntaxOffset, (RefKind)0, sideEffects, hoistedFields, ref needsSacrificialEvaluation);
|
|
ArrayBuilder<BoundExpression> instance = ArrayBuilder<BoundExpression>.GetInstance();
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = boundArrayAccess.Indices.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
instance.Add(HoistExpression(current, awaitSyntaxOpt, syntaxOffset, (RefKind)0, sideEffects, hoistedFields, ref needsSacrificialEvaluation));
|
|
}
|
|
needsSacrificialEvaluation = true;
|
|
return boundArrayAccess.Update(expression, instance.ToImmutableAndFree(), boundArrayAccess.Type);
|
|
}
|
|
case BoundKind.FieldAccess:
|
|
{
|
|
BoundFieldAccess boundFieldAccess = (BoundFieldAccess)expr;
|
|
if (boundFieldAccess.FieldSymbol.IsStatic)
|
|
{
|
|
if ((int)refKind != 0 || boundFieldAccess.FieldSymbol.IsReadOnly)
|
|
{
|
|
return expr;
|
|
}
|
|
}
|
|
else if ((int)refKind != 0)
|
|
{
|
|
bool flag = !boundFieldAccess.FieldSymbol.ContainingType.IsReferenceType;
|
|
BoundExpression boundExpression = HoistExpression(boundFieldAccess.ReceiverOpt, awaitSyntaxOpt, syntaxOffset, (RefKind)(flag ? ((int)refKind) : 0), sideEffects, hoistedFields, ref needsSacrificialEvaluation);
|
|
if (boundExpression.Kind != BoundKind.ThisReference && !flag)
|
|
{
|
|
needsSacrificialEvaluation = true;
|
|
}
|
|
return F.Field(boundExpression, boundFieldAccess.FieldSymbol);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.DefaultExpression:
|
|
case BoundKind.ThisReference:
|
|
case BoundKind.BaseReference:
|
|
return expr;
|
|
case BoundKind.Call:
|
|
{
|
|
BoundCall boundCall = (BoundCall)expr;
|
|
if ((int)refKind != 0 && (int)refKind != 3)
|
|
{
|
|
F.Diagnostics.Add(ErrorCode.ERR_RefReturningCallAndAwait, F.Syntax.Location, boundCall.Method);
|
|
}
|
|
refKind = (RefKind)0;
|
|
break;
|
|
}
|
|
case BoundKind.ConditionalOperator:
|
|
_ = (BoundConditionalOperator)expr;
|
|
if ((int)refKind != 0 && (int)refKind != 3)
|
|
{
|
|
F.Diagnostics.Add(ErrorCode.ERR_RefConditionalAndAwait, F.Syntax.Location);
|
|
}
|
|
refKind = (RefKind)0;
|
|
break;
|
|
}
|
|
if (expr.ConstantValueOpt != (ConstantValue)null)
|
|
{
|
|
return expr;
|
|
}
|
|
if ((int)refKind != 0)
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)expr.Kind);
|
|
}
|
|
TypeSymbol type = expr.Type;
|
|
StateMachineFieldSymbol stateMachineFieldSymbol;
|
|
if ((int)((CompilationOptions)F.Compilation.Options).OptimizationLevel == 0)
|
|
{
|
|
int num = _synthesizedLocalOrdinals.AssignLocalOrdinal((SynthesizedLocalKind)29, syntaxOffset);
|
|
LocalDebugId val = default(LocalDebugId);
|
|
((LocalDebugId)(ref val))._002Ector(syntaxOffset, num);
|
|
int slotIndex = default(int);
|
|
if (slotAllocatorOpt == null || !slotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(awaitSyntaxOpt, ((PEModuleBuilder<CSharpCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, EmbeddedTypesManager, ModuleCompilationState>)F.ModuleBuilderOpt).Translate(type, awaitSyntaxOpt, ((BindingDiagnosticBag)Diagnostics).DiagnosticBag), (SynthesizedLocalKind)29, val, ((BindingDiagnosticBag)Diagnostics).DiagnosticBag, ref slotIndex))
|
|
{
|
|
slotIndex = _nextFreeHoistedLocalSlot++;
|
|
}
|
|
string name = GeneratedNames.MakeHoistedLocalFieldName((SynthesizedLocalKind)29, slotIndex);
|
|
stateMachineFieldSymbol = F.StateMachineField(expr.Type, name, new LocalSlotDebugInfo((SynthesizedLocalKind)29, val), slotIndex);
|
|
}
|
|
else
|
|
{
|
|
stateMachineFieldSymbol = GetOrAllocateReusableHoistedField(type, out var _);
|
|
}
|
|
hoistedFields.Add(stateMachineFieldSymbol);
|
|
BoundFieldAccess boundFieldAccess2 = F.Field(F.This(), stateMachineFieldSymbol);
|
|
sideEffects.Add(F.AssignmentExpression(boundFieldAccess2, expr));
|
|
return boundFieldAccess2;
|
|
}
|
|
|
|
public override BoundNode Visit(BoundNode node)
|
|
{
|
|
if (node == null)
|
|
{
|
|
return node;
|
|
}
|
|
SyntaxNode syntax = F.Syntax;
|
|
F.Syntax = node.Syntax;
|
|
BoundNode? result = base.Visit(node);
|
|
F.Syntax = syntax;
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitBlock(BoundBlock node)
|
|
{
|
|
if (node.Instrumentation != null)
|
|
{
|
|
instrumentation = (BoundBlockInstrumentation)Visit(node.Instrumentation);
|
|
}
|
|
return PossibleIteratorScope(node.Locals, () => VisitBlock(node, removeInstrumentation: true));
|
|
}
|
|
|
|
public override BoundNode VisitStateMachineInstanceId(BoundStateMachineInstanceId node)
|
|
{
|
|
return F.Field(F.This(), instanceIdField);
|
|
}
|
|
|
|
public override BoundNode VisitScope(BoundScope node)
|
|
{
|
|
ArrayBuilder<LocalSymbol> instance = ArrayBuilder<LocalSymbol>.GetInstance();
|
|
ArrayBuilder<StateMachineFieldSymbol> instance2 = ArrayBuilder<StateMachineFieldSymbol>.GetInstance();
|
|
bool flag = false;
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = node.Locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
if (TryRewriteLocal(current, out LocalSymbol newLocal))
|
|
{
|
|
instance.Add(newLocal);
|
|
flag = flag || (object)current != newLocal;
|
|
}
|
|
else
|
|
{
|
|
instance2.Add(((CapturedToStateMachineFieldReplacement)proxies[current]).HoistedField);
|
|
}
|
|
}
|
|
ImmutableArray<BoundStatement> statements = VisitList(node.Statements);
|
|
if (instance2.Count != 0)
|
|
{
|
|
BoundStatement statement;
|
|
if (instance.Count == 0)
|
|
{
|
|
instance.Free();
|
|
statement = new BoundStatementList(node.Syntax, statements);
|
|
}
|
|
else
|
|
{
|
|
statement = node.Update(instance.ToImmutableAndFree(), statements);
|
|
}
|
|
return MakeStateMachineScope(instance2.ToImmutable(), statement);
|
|
}
|
|
instance2.Free();
|
|
ImmutableArray<LocalSymbol> locals;
|
|
if (flag)
|
|
{
|
|
locals = instance.ToImmutableAndFree();
|
|
}
|
|
else
|
|
{
|
|
instance.Free();
|
|
locals = node.Locals;
|
|
}
|
|
return node.Update(locals, statements);
|
|
}
|
|
|
|
public override BoundNode VisitForStatement(BoundForStatement node)
|
|
{
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs", 793);
|
|
}
|
|
|
|
public override BoundNode VisitUsingStatement(BoundUsingStatement node)
|
|
{
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs", 798);
|
|
}
|
|
|
|
public override BoundNode VisitExpressionStatement(BoundExpressionStatement node)
|
|
{
|
|
BoundExpression boundExpression = (BoundExpression)Visit(node.Expression);
|
|
if (boundExpression != null)
|
|
{
|
|
return node.Update(boundExpression);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
|
|
{
|
|
if (node.Left.Kind != BoundKind.Local)
|
|
{
|
|
return base.VisitAssignmentOperator(node);
|
|
}
|
|
LocalSymbol localSymbol = ((BoundLocal)node.Left).LocalSymbol;
|
|
if (!NeedsProxy(localSymbol))
|
|
{
|
|
return base.VisitAssignmentOperator(node);
|
|
}
|
|
if (proxies.ContainsKey(localSymbol))
|
|
{
|
|
return base.VisitAssignmentOperator(node);
|
|
}
|
|
return HoistRefInitialization((SynthesizedLocal)localSymbol, node);
|
|
}
|
|
|
|
public override BoundNode VisitTryStatement(BoundTryStatement node)
|
|
{
|
|
Dictionary<LabelSymbol, List<StateMachineState>> dictionary = _dispatches;
|
|
_dispatches = null;
|
|
BoundBlock boundBlock = F.Block((BoundStatement)Visit(node.TryBlock));
|
|
GeneratedLabelSymbol generatedLabelSymbol = null;
|
|
if (_dispatches != null)
|
|
{
|
|
generatedLabelSymbol = F.GenerateLabel("tryDispatch");
|
|
boundBlock = F.Block(F.HiddenSequencePoint(), Dispatch(isOutermost: false), boundBlock);
|
|
if (dictionary == null)
|
|
{
|
|
dictionary = new Dictionary<LabelSymbol, List<StateMachineState>>();
|
|
}
|
|
dictionary.Add(generatedLabelSymbol, new List<StateMachineState>(from kv in _dispatches.Values
|
|
from n in kv
|
|
orderby n
|
|
select n));
|
|
}
|
|
_dispatches = dictionary;
|
|
ImmutableArray<BoundCatchBlock> catchBlocks = VisitList(node.CatchBlocks);
|
|
BoundBlock finallyBlockOpt = ((node.FinallyBlockOpt == null) ? null : F.Block(F.HiddenSequencePoint(), F.If(ShouldEnterFinallyBlock(), VisitFinally(node.FinallyBlockOpt)), F.HiddenSequencePoint()));
|
|
BoundStatement boundStatement = node.Update(boundBlock, catchBlocks, finallyBlockOpt, node.FinallyLabelOpt, node.PreferFaultHandler);
|
|
if ((object)generatedLabelSymbol != null)
|
|
{
|
|
boundStatement = F.Block(F.HiddenSequencePoint(), F.Label(generatedLabelSymbol), boundStatement);
|
|
}
|
|
return boundStatement;
|
|
}
|
|
|
|
protected virtual BoundBlock VisitFinally(BoundBlock finallyBlock)
|
|
{
|
|
return (BoundBlock)Visit(finallyBlock);
|
|
}
|
|
|
|
protected virtual BoundBinaryOperator ShouldEnterFinallyBlock()
|
|
{
|
|
return F.IntLessThan(F.Local(cachedState), F.Literal((StateMachineState)0));
|
|
}
|
|
|
|
protected BoundExpressionStatement GenerateSetBothStates(StateMachineState stateNumber)
|
|
{
|
|
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
|
|
return F.Assignment(F.Field(F.This(), stateField), F.AssignmentExpression(F.Local(cachedState), F.Literal(stateNumber)));
|
|
}
|
|
|
|
protected BoundStatement CacheThisIfNeeded()
|
|
{
|
|
if ((object)cachedThis != null)
|
|
{
|
|
BoundExpression right = proxies[OriginalMethod.ThisParameter].Replacement(F.Syntax, (NamedTypeSymbol frameType) => F.This());
|
|
return F.Assignment(F.Local(cachedThis), right);
|
|
}
|
|
return F.StatementList();
|
|
}
|
|
|
|
public sealed override BoundNode VisitThisReference(BoundThisReference node)
|
|
{
|
|
if ((object)cachedThis != null)
|
|
{
|
|
return F.Local(cachedThis);
|
|
}
|
|
ParameterSymbol thisParameter = OriginalMethod.ThisParameter;
|
|
if ((object)thisParameter == null || !proxies.TryGetValue(thisParameter, out CapturedSymbolReplacement value))
|
|
{
|
|
return node.Update(VisitType(node.Type));
|
|
}
|
|
return value.Replacement(F.Syntax, (NamedTypeSymbol frameType) => F.This());
|
|
}
|
|
|
|
public override BoundNode VisitBaseReference(BoundBaseReference node)
|
|
{
|
|
if ((object)cachedThis != null)
|
|
{
|
|
return F.Local(cachedThis);
|
|
}
|
|
return proxies[OriginalMethod.ThisParameter].Replacement(F.Syntax, (NamedTypeSymbol frameType) => F.This());
|
|
}
|
|
}
|