1142 lines
36 KiB
C#
1142 lines
36 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using Microsoft.CodeAnalysis.CSharp.Symbols;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp.CodeGen;
|
|
|
|
internal sealed class StackOptimizerPass1 : BoundTreeRewriter
|
|
{
|
|
private sealed class LocalUsedWalker : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
|
|
{
|
|
private readonly LocalSymbol _local;
|
|
|
|
private bool _found;
|
|
|
|
internal LocalUsedWalker(LocalSymbol local, int recursionDepth)
|
|
: base(recursionDepth)
|
|
{
|
|
_local = local;
|
|
}
|
|
|
|
public bool IsLocalUsedIn(BoundNode node)
|
|
{
|
|
_found = false;
|
|
Visit(node);
|
|
return _found;
|
|
}
|
|
|
|
public override BoundNode Visit(BoundNode node)
|
|
{
|
|
if (!_found)
|
|
{
|
|
return base.Visit(node);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitLocal(BoundLocal node)
|
|
{
|
|
if (node.LocalSymbol == _local)
|
|
{
|
|
_found = true;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private readonly bool _debugFriendly;
|
|
|
|
private readonly ArrayBuilder<(BoundExpression, ExprContext)> _evalStack;
|
|
|
|
private int _counter;
|
|
|
|
private ExprContext _context;
|
|
|
|
private BoundLocal _assignmentLocal;
|
|
|
|
private readonly Dictionary<LocalSymbol, LocalDefUseInfo> _locals;
|
|
|
|
private readonly SmallDictionary<object, DummyLocal> _dummyVariables = new SmallDictionary<object, DummyLocal>((IEqualityComparer<object>)ReferenceEqualityComparer.Instance);
|
|
|
|
public static readonly DummyLocal empty = new DummyLocal();
|
|
|
|
private int _recursionDepth;
|
|
|
|
private StackOptimizerPass1(Dictionary<LocalSymbol, LocalDefUseInfo> locals, ArrayBuilder<(BoundExpression, ExprContext)> evalStack, bool debugFriendly)
|
|
{
|
|
_locals = locals;
|
|
_evalStack = evalStack;
|
|
_debugFriendly = debugFriendly;
|
|
DeclareLocal(empty, 0);
|
|
RecordDummyWrite(empty);
|
|
}
|
|
|
|
public static BoundNode Analyze(BoundNode node, Dictionary<LocalSymbol, LocalDefUseInfo> locals, bool debugFriendly)
|
|
{
|
|
ArrayBuilder<(BoundExpression, ExprContext)> instance = ArrayBuilder<(BoundExpression, ExprContext)>.GetInstance();
|
|
BoundNode result = new StackOptimizerPass1(locals, instance, debugFriendly).Visit(node);
|
|
instance.Free();
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode Visit(BoundNode node)
|
|
{
|
|
if (node is BoundExpression node2)
|
|
{
|
|
return VisitExpression(node2, ExprContext.Value);
|
|
}
|
|
return VisitStatement(node);
|
|
}
|
|
|
|
private BoundExpression VisitExpressionCore(BoundExpression node, ExprContext context)
|
|
{
|
|
ExprContext context2 = _context;
|
|
int stackDepth = StackDepth();
|
|
_context = context;
|
|
BoundExpression result = ((!(node.ConstantValueOpt == (ConstantValue)null)) ? node : (node = (BoundExpression)base.Visit(node)));
|
|
_context = context2;
|
|
_counter++;
|
|
switch (context)
|
|
{
|
|
case ExprContext.Sideeffects:
|
|
SetStackDepth(stackDepth);
|
|
break;
|
|
case ExprContext.Value:
|
|
case ExprContext.Address:
|
|
case ExprContext.Box:
|
|
SetStackDepth(stackDepth);
|
|
PushEvalStack(node, context);
|
|
break;
|
|
default:
|
|
throw ExceptionUtilities.UnexpectedValue((object)context);
|
|
case ExprContext.AssignmentTarget:
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private BoundExpression VisitExpression(BoundExpression node, ExprContext context)
|
|
{
|
|
_recursionDepth++;
|
|
BoundExpression result;
|
|
if (_recursionDepth > 1)
|
|
{
|
|
StackGuard.EnsureSufficientExecutionStack(_recursionDepth);
|
|
result = VisitExpressionCore(node, context);
|
|
}
|
|
else
|
|
{
|
|
result = VisitExpressionCoreWithStackGuard(node, context);
|
|
}
|
|
_recursionDepth--;
|
|
return result;
|
|
}
|
|
|
|
private BoundExpression VisitExpressionCoreWithStackGuard(BoundExpression node, ExprContext context)
|
|
{
|
|
try
|
|
{
|
|
return VisitExpressionCore(node, context);
|
|
}
|
|
catch (InsufficientExecutionStackException inner)
|
|
{
|
|
throw new CancelledByStackGuardException(inner, node);
|
|
}
|
|
}
|
|
|
|
protected override BoundExpression VisitExpressionWithoutStackGuard(BoundExpression node)
|
|
{
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs", 537);
|
|
}
|
|
|
|
private void PushEvalStack(BoundExpression result, ExprContext context)
|
|
{
|
|
_evalStack.Add((result, context));
|
|
}
|
|
|
|
private int StackDepth()
|
|
{
|
|
return _evalStack.Count;
|
|
}
|
|
|
|
private bool EvalStackIsEmpty()
|
|
{
|
|
return StackDepth() == 0;
|
|
}
|
|
|
|
private void SetStackDepth(int depth)
|
|
{
|
|
_evalStack.Clip(depth);
|
|
}
|
|
|
|
private void PopEvalStack()
|
|
{
|
|
SetStackDepth(_evalStack.Count - 1);
|
|
}
|
|
|
|
public BoundNode VisitStatement(BoundNode node)
|
|
{
|
|
return VisitSideEffect(node);
|
|
}
|
|
|
|
public BoundNode VisitSideEffect(BoundNode node)
|
|
{
|
|
int stackDepth = StackDepth();
|
|
ExprContext context = _context;
|
|
BoundNode result = base.Visit(node);
|
|
if (_debugFriendly)
|
|
{
|
|
EnsureOnlyEvalStack();
|
|
}
|
|
_context = context;
|
|
SetStackDepth(stackDepth);
|
|
_counter++;
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitConversion(BoundConversion node)
|
|
{
|
|
ExprContext context = ((_context == ExprContext.Sideeffects && !node.ConversionHasSideEffects()) ? ExprContext.Sideeffects : ExprContext.Value);
|
|
return node.UpdateOperand(VisitExpression(node.Operand, context));
|
|
}
|
|
|
|
public override BoundNode VisitPassByCopy(BoundPassByCopy node)
|
|
{
|
|
ExprContext context = ((_context == ExprContext.Sideeffects) ? ExprContext.Sideeffects : ExprContext.Value);
|
|
return node.Update(VisitExpression(node.Expression, context), node.Type);
|
|
}
|
|
|
|
public override BoundNode VisitBlock(BoundBlock node)
|
|
{
|
|
if (node.Instrumentation != null)
|
|
{
|
|
DeclareLocal(node.Instrumentation.Local, 0);
|
|
}
|
|
DeclareLocals(node.Locals, 0);
|
|
return base.VisitBlock(node);
|
|
}
|
|
|
|
public override BoundNode VisitSequence(BoundSequence node)
|
|
{
|
|
int num = StackDepth();
|
|
ImmutableArray<LocalSymbol> locals = node.Locals;
|
|
if (!locals.IsDefaultOrEmpty)
|
|
{
|
|
if (_context == ExprContext.Sideeffects)
|
|
{
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
if (IsNestedLocalOfCompoundOperator(current, node))
|
|
{
|
|
DeclareLocal(current, num + 1);
|
|
}
|
|
else
|
|
{
|
|
DeclareLocal(current, num);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DeclareLocals(locals, num);
|
|
}
|
|
}
|
|
ExprContext context = _context;
|
|
ImmutableArray<BoundExpression> sideEffects = node.SideEffects;
|
|
ArrayBuilder<BoundExpression> val = null;
|
|
if (!sideEffects.IsDefault)
|
|
{
|
|
for (int i = 0; i < sideEffects.Length; i++)
|
|
{
|
|
BoundExpression boundExpression = sideEffects[i];
|
|
BoundExpression boundExpression2 = VisitExpression(boundExpression, ExprContext.Sideeffects);
|
|
if (val == null && boundExpression2 != boundExpression)
|
|
{
|
|
val = ArrayBuilder<BoundExpression>.GetInstance();
|
|
val.AddRange(sideEffects, i);
|
|
}
|
|
val?.Add(boundExpression2);
|
|
}
|
|
}
|
|
BoundExpression value = VisitExpression(node.Value, context);
|
|
return node.Update(node.Locals, val?.ToImmutableAndFree() ?? sideEffects, value, node.Type);
|
|
}
|
|
|
|
private bool IsNestedLocalOfCompoundOperator(LocalSymbol local, BoundSequence node)
|
|
{
|
|
BoundExpression value = node.Value;
|
|
if (value != null && value.Kind == BoundKind.Local && ((BoundLocal)value).LocalSymbol == local)
|
|
{
|
|
ImmutableArray<BoundExpression> sideEffects = node.SideEffects;
|
|
BoundExpression boundExpression = sideEffects.LastOrDefault();
|
|
if (boundExpression != null && boundExpression.Kind == BoundKind.AssignmentOperator)
|
|
{
|
|
BoundAssignmentOperator boundAssignmentOperator = (BoundAssignmentOperator)boundExpression;
|
|
if (IsIndirectOrInstanceFieldAssignment(boundAssignmentOperator) && boundAssignmentOperator.Right.Kind == BoundKind.Sequence)
|
|
{
|
|
LocalUsedWalker localUsedWalker = new LocalUsedWalker(local, _recursionDepth);
|
|
for (int i = 0; i < sideEffects.Length - 1; i++)
|
|
{
|
|
if (localUsedWalker.IsLocalUsedIn(sideEffects[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if (localUsedWalker.IsLocalUsedIn(boundAssignmentOperator.Left))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override BoundNode VisitExpressionStatement(BoundExpressionStatement node)
|
|
{
|
|
return node.Update(VisitExpression(node.Expression, ExprContext.Sideeffects));
|
|
}
|
|
|
|
public override BoundNode VisitLocal(BoundLocal node)
|
|
{
|
|
//IL_006b: 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)
|
|
if (node.ConstantValueOpt == (ConstantValue)null)
|
|
{
|
|
switch (_context)
|
|
{
|
|
case ExprContext.Address:
|
|
if ((int)node.LocalSymbol.RefKind != 0)
|
|
{
|
|
RecordVarRead(node.LocalSymbol);
|
|
}
|
|
else
|
|
{
|
|
RecordVarRef(node.LocalSymbol);
|
|
}
|
|
break;
|
|
case ExprContext.AssignmentTarget:
|
|
_assignmentLocal = node;
|
|
break;
|
|
case ExprContext.Sideeffects:
|
|
if ((int)node.LocalSymbol.RefKind != 0)
|
|
{
|
|
RecordVarRead(node.LocalSymbol);
|
|
}
|
|
break;
|
|
case ExprContext.Value:
|
|
case ExprContext.Box:
|
|
RecordVarRead(node.LocalSymbol);
|
|
break;
|
|
}
|
|
}
|
|
return base.VisitLocal(node);
|
|
}
|
|
|
|
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
|
|
{
|
|
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0121: Invalid comparison between Unknown and I4
|
|
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0126: Invalid comparison between Unknown and I4
|
|
if (node.Left is BoundSequence boundSequence)
|
|
{
|
|
BoundExpression node2 = boundSequence.Update(boundSequence.Locals, boundSequence.SideEffects, node.Update(boundSequence.Value, node.Right, node.IsRef, node.Type), boundSequence.Type);
|
|
node2 = (BoundExpression)Visit(node2);
|
|
_counter--;
|
|
return node2;
|
|
}
|
|
bool flag = IsIndirectAssignment(node);
|
|
BoundExpression left = VisitExpression(node.Left, flag ? ExprContext.Address : ExprContext.AssignmentTarget);
|
|
BoundLocal assignmentLocal = _assignmentLocal;
|
|
_assignmentLocal = null;
|
|
ExprContext context = ((!node.IsRef && _context != ExprContext.Address) ? ExprContext.Value : ExprContext.Address);
|
|
BoundExpression right = node.Right;
|
|
int num;
|
|
if (right.Kind == BoundKind.ObjectCreationExpression && right.Type.IsVerifierValue())
|
|
{
|
|
num = ((((BoundObjectCreationExpression)right).Constructor.ParameterCount != 0) ? 1 : 0);
|
|
if (num != 0)
|
|
{
|
|
PushEvalStack(null, ExprContext.None);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
num = 0;
|
|
}
|
|
right = VisitExpression(node.Right, context);
|
|
if (num != 0)
|
|
{
|
|
PopEvalStack();
|
|
}
|
|
if (assignmentLocal != null)
|
|
{
|
|
LocalSymbol localSymbol = assignmentLocal.LocalSymbol;
|
|
RefKind refKind = localSymbol.RefKind;
|
|
bool flag2 = (((int)refKind == 3 || (int)refKind == 5) ? true : false);
|
|
if (flag2 && (_context == ExprContext.Address || _context == ExprContext.Value))
|
|
{
|
|
ShouldNotSchedule(localSymbol);
|
|
}
|
|
if (CanScheduleToStack(localSymbol) && assignmentLocal.Type.IsPointerOrFunctionPointer() && right.Kind == BoundKind.Conversion && ((BoundConversion)right).ConversionKind.IsPointerConversion())
|
|
{
|
|
ShouldNotSchedule(localSymbol);
|
|
}
|
|
RecordVarWrite(localSymbol);
|
|
assignmentLocal = null;
|
|
}
|
|
return node.Update(left, right, node.IsRef, node.Type);
|
|
}
|
|
|
|
internal static bool IsFixedBufferAssignmentToRefLocal(BoundExpression left, BoundExpression right, bool isRef)
|
|
{
|
|
if (isRef && right is BoundFieldAccess boundFieldAccess && boundFieldAccess.FieldSymbol.IsFixedSizeBuffer)
|
|
{
|
|
return left.Type.Equals(((PointerTypeSymbol)right.Type).PointedAtType, (TypeCompareKind)63);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static bool IsIndirectAssignment(BoundAssignmentOperator node)
|
|
{
|
|
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
|
|
BoundExpression left = node.Left;
|
|
switch (left.Kind)
|
|
{
|
|
case BoundKind.ThisReference:
|
|
return true;
|
|
case BoundKind.Parameter:
|
|
if ((int)((BoundParameter)left).ParameterSymbol.RefKind != 0)
|
|
{
|
|
return !node.IsRef;
|
|
}
|
|
return false;
|
|
case BoundKind.Local:
|
|
if ((int)((BoundLocal)left).LocalSymbol.RefKind != 0)
|
|
{
|
|
return !node.IsRef;
|
|
}
|
|
return false;
|
|
case BoundKind.Call:
|
|
return true;
|
|
case BoundKind.FunctionPointerInvocation:
|
|
return true;
|
|
case BoundKind.ConditionalOperator:
|
|
return true;
|
|
case BoundKind.AssignmentOperator:
|
|
return true;
|
|
case BoundKind.Sequence:
|
|
return false;
|
|
case BoundKind.PointerIndirectionOperator:
|
|
case BoundKind.RefValueOperator:
|
|
case BoundKind.PseudoVariable:
|
|
return true;
|
|
case BoundKind.ArrayAccess:
|
|
case BoundKind.InstrumentationPayloadRoot:
|
|
case BoundKind.ModuleVersionId:
|
|
case BoundKind.FieldAccess:
|
|
return false;
|
|
default:
|
|
throw ExceptionUtilities.UnexpectedValue((object)left.Kind);
|
|
}
|
|
}
|
|
|
|
private static bool IsIndirectOrInstanceFieldAssignment(BoundAssignmentOperator node)
|
|
{
|
|
BoundExpression left = node.Left;
|
|
if (left.Kind == BoundKind.FieldAccess)
|
|
{
|
|
return !((BoundFieldAccess)left).FieldSymbol.IsStatic;
|
|
}
|
|
return IsIndirectAssignment(node);
|
|
}
|
|
|
|
public override BoundNode VisitCall(BoundCall node)
|
|
{
|
|
if (node.ReceiverOpt is BoundCall boundCall)
|
|
{
|
|
int stackDepth = StackDepth();
|
|
ArrayBuilder<BoundCall> instance = ArrayBuilder<BoundCall>.GetInstance();
|
|
ArrayBuilderExtensions.Push<BoundCall>(instance, node);
|
|
node = boundCall;
|
|
while (node.ReceiverOpt is BoundCall boundCall2)
|
|
{
|
|
ArrayBuilderExtensions.Push<BoundCall>(instance, node);
|
|
node = boundCall2;
|
|
}
|
|
BoundExpression boundExpression = visitReceiver(node);
|
|
while (true)
|
|
{
|
|
boundExpression = visitArgumentsAndUpdateCall(node, boundExpression);
|
|
BoundCall boundCall3 = node;
|
|
if (!ArrayBuilderExtensions.TryPop<BoundCall>(instance, ref node))
|
|
{
|
|
break;
|
|
}
|
|
CheckCallReceiver(boundCall3, node);
|
|
_counter++;
|
|
SetStackDepth(stackDepth);
|
|
PushEvalStack(boundCall3, GetReceiverContext(boundCall3));
|
|
}
|
|
instance.Free();
|
|
return boundExpression;
|
|
}
|
|
BoundExpression receiver = visitReceiver(node);
|
|
return visitArgumentsAndUpdateCall(node, receiver);
|
|
BoundCall visitArgumentsAndUpdateCall(BoundCall boundCall4, BoundExpression receiverOpt)
|
|
{
|
|
ImmutableArray<BoundExpression> arguments = VisitArguments(boundCall4.Arguments, boundCall4.Method.Parameters, boundCall4.ArgumentRefKindsOpt);
|
|
return boundCall4.Update(receiverOpt, (ThreeState)0, boundCall4.Method, arguments);
|
|
}
|
|
BoundExpression visitReceiver(BoundCall boundCall4)
|
|
{
|
|
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_005b: Invalid comparison between Unknown and I4
|
|
BoundExpression receiverOpt = boundCall4.ReceiverOpt;
|
|
MethodSymbol method = boundCall4.Method;
|
|
if (method.RequiresInstanceReceiver)
|
|
{
|
|
return VisitCallOrConditionalAccessReceiver(receiverOpt, boundCall4);
|
|
}
|
|
_counter++;
|
|
if ((method.IsAbstract || method.IsVirtual) && receiverOpt is BoundTypeExpression boundTypeExpression)
|
|
{
|
|
TypeSymbol type = boundTypeExpression.Type;
|
|
if ((object)type != null && (int)type.TypeKind == 11)
|
|
{
|
|
return boundTypeExpression.Update(null, null, ImmutableArray<BoundExpression>.Empty, boundTypeExpression.TypeWithAnnotations, VisitType(boundTypeExpression.Type));
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private BoundExpression VisitCallOrConditionalAccessReceiver(BoundExpression receiver, BoundCall callOpt)
|
|
{
|
|
_ = receiver.Type;
|
|
if (callOpt != null)
|
|
{
|
|
CheckCallReceiver(receiver, callOpt);
|
|
}
|
|
ExprContext receiverContext = GetReceiverContext(receiver);
|
|
receiver = VisitExpression(receiver, receiverContext);
|
|
return receiver;
|
|
}
|
|
|
|
private void CheckCallReceiver(BoundExpression receiver, BoundCall call)
|
|
{
|
|
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_004d: Invalid comparison between Unknown and I4
|
|
if (!CodeGenerator.IsRef(receiver) || !CodeGenerator.IsPossibleReferenceTypeReceiverOfConstrainedCall(receiver) || CodeGenerator.IsSafeToDereferenceReceiverRefAfterEvaluatingArguments(call.Arguments))
|
|
{
|
|
return;
|
|
}
|
|
BoundExpression boundExpression;
|
|
for (boundExpression = receiver; boundExpression is BoundSequence boundSequence; boundExpression = boundSequence.Value)
|
|
{
|
|
}
|
|
if (boundExpression is BoundLocal boundLocal)
|
|
{
|
|
LocalSymbol localSymbol = boundLocal.LocalSymbol;
|
|
if ((object)localSymbol != null && (int)localSymbol.RefKind != 0)
|
|
{
|
|
ShouldNotSchedule(localSymbol);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static ExprContext GetReceiverContext(BoundExpression receiver)
|
|
{
|
|
TypeSymbol type = receiver.Type;
|
|
if (type.IsReferenceType)
|
|
{
|
|
if (type.IsTypeParameter())
|
|
{
|
|
return ExprContext.Box;
|
|
}
|
|
return ExprContext.Value;
|
|
}
|
|
return ExprContext.Address;
|
|
}
|
|
|
|
private ImmutableArray<BoundExpression> VisitArguments(ImmutableArray<BoundExpression> arguments, ImmutableArray<ParameterSymbol> parameters, ImmutableArray<RefKind> argRefKindsOpt)
|
|
{
|
|
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
|
|
ArrayBuilder<BoundExpression> rewrittenArguments = null;
|
|
for (int i = 0; i < arguments.Length; i++)
|
|
{
|
|
RefKind argumentRefKind = CodeGenerator.GetArgumentRefKind(arguments, parameters, argRefKindsOpt, i);
|
|
VisitArgument(arguments, ref rewrittenArguments, i, argumentRefKind);
|
|
}
|
|
return rewrittenArguments?.ToImmutableAndFree() ?? arguments;
|
|
}
|
|
|
|
private void VisitArgument(ImmutableArray<BoundExpression> arguments, ref ArrayBuilder<BoundExpression> rewrittenArguments, int i, RefKind argRefKind)
|
|
{
|
|
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
|
|
ExprContext context = (((int)argRefKind == 0) ? ExprContext.Value : ExprContext.Address);
|
|
BoundExpression boundExpression = arguments[i];
|
|
BoundExpression boundExpression2 = VisitExpression(boundExpression, context);
|
|
if (rewrittenArguments == null && boundExpression != boundExpression2)
|
|
{
|
|
rewrittenArguments = ArrayBuilder<BoundExpression>.GetInstance();
|
|
rewrittenArguments.AddRange(arguments, i);
|
|
}
|
|
if (rewrittenArguments != null)
|
|
{
|
|
rewrittenArguments.Add(boundExpression2);
|
|
}
|
|
}
|
|
|
|
public override BoundNode VisitArgListOperator(BoundArgListOperator node)
|
|
{
|
|
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0028: 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)
|
|
ArrayBuilder<BoundExpression> rewrittenArguments = null;
|
|
ImmutableArray<BoundExpression> arguments = node.Arguments;
|
|
ImmutableArray<RefKind> argumentRefKindsOpt = node.ArgumentRefKindsOpt;
|
|
for (int i = 0; i < arguments.Length; i++)
|
|
{
|
|
RefKind argRefKind = (RefKind)((!argumentRefKindsOpt.IsDefaultOrEmpty) ? ((int)argumentRefKindsOpt[i]) : 0);
|
|
VisitArgument(arguments, ref rewrittenArguments, i, argRefKind);
|
|
}
|
|
return node.Update(rewrittenArguments?.ToImmutableAndFree() ?? arguments, argumentRefKindsOpt, node.Type);
|
|
}
|
|
|
|
public override BoundNode VisitMakeRefOperator(BoundMakeRefOperator node)
|
|
{
|
|
BoundExpression operand = VisitExpression(node.Operand, ExprContext.Address);
|
|
return node.Update(operand, node.Type);
|
|
}
|
|
|
|
public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpression node)
|
|
{
|
|
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
|
|
MethodSymbol constructor = node.Constructor;
|
|
ImmutableArray<BoundExpression> arguments = VisitArguments(node.Arguments, constructor.Parameters, node.ArgumentRefKindsOpt);
|
|
return node.Update(constructor, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.ConstantValueOpt, null, node.Type);
|
|
}
|
|
|
|
public override BoundNode VisitArrayAccess(BoundArrayAccess node)
|
|
{
|
|
ExprContext context = _context;
|
|
_context = ExprContext.Value;
|
|
BoundNode? result = base.VisitArrayAccess(node);
|
|
_context = context;
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitFieldAccess(BoundFieldAccess node)
|
|
{
|
|
FieldSymbol fieldSymbol = node.FieldSymbol;
|
|
BoundExpression receiverOpt = node.ReceiverOpt;
|
|
if (!fieldSymbol.IsStatic)
|
|
{
|
|
receiverOpt = (receiverOpt.Type.IsTypeParameter() ? VisitExpression(receiverOpt, ExprContext.Box) : ((!receiverOpt.Type.IsValueType || (_context != ExprContext.AssignmentTarget && _context != ExprContext.Address && !CodeGenerator.FieldLoadMustUseRef(receiverOpt))) ? VisitExpression(receiverOpt, ExprContext.Value) : VisitExpression(receiverOpt, ExprContext.Address)));
|
|
}
|
|
else
|
|
{
|
|
_counter++;
|
|
receiverOpt = null;
|
|
}
|
|
return node.Update(receiverOpt, fieldSymbol, node.ConstantValueOpt, node.ResultKind, node.Type);
|
|
}
|
|
|
|
public override BoundNode VisitLabelStatement(BoundLabelStatement node)
|
|
{
|
|
RecordLabel(node.Label);
|
|
return base.VisitLabelStatement(node);
|
|
}
|
|
|
|
public override BoundNode VisitLabel(BoundLabel node)
|
|
{
|
|
return node;
|
|
}
|
|
|
|
public override BoundNode VisitIsPatternExpression(BoundIsPatternExpression node)
|
|
{
|
|
return node;
|
|
}
|
|
|
|
public override BoundNode VisitGotoStatement(BoundGotoStatement node)
|
|
{
|
|
BoundNode? result = base.VisitGotoStatement(node);
|
|
RecordBranch(node.Label);
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitConditionalGoto(BoundConditionalGoto node)
|
|
{
|
|
BoundNode? result = base.VisitConditionalGoto(node);
|
|
PopEvalStack();
|
|
RecordBranch(node.Label);
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitSwitchDispatch(BoundSwitchDispatch node)
|
|
{
|
|
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
|
|
BoundExpression expression = node.Expression;
|
|
if (expression.Kind == BoundKind.Local)
|
|
{
|
|
LocalSymbol localSymbol = ((BoundLocal)expression).LocalSymbol;
|
|
if ((int)localSymbol.RefKind == 0)
|
|
{
|
|
ShouldNotSchedule(localSymbol);
|
|
}
|
|
}
|
|
expression = (BoundExpression)Visit(expression);
|
|
PopEvalStack();
|
|
EnsureOnlyEvalStack();
|
|
RecordBranch(node.DefaultLabel);
|
|
ImmutableArray<(ConstantValue, LabelSymbol)>.Enumerator enumerator = node.Cases.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LabelSymbol item = enumerator.Current.Item2;
|
|
RecordBranch(item);
|
|
}
|
|
return node.Update(expression, node.Cases, node.DefaultLabel, node.LengthBasedStringSwitchDataOpt);
|
|
}
|
|
|
|
public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
|
|
{
|
|
int stackDepth = StackDepth();
|
|
BoundExpression condition = VisitExpression(node.Condition, ExprContext.Value);
|
|
object stackStateCookie = GetStackStateCookie();
|
|
ExprContext context = (node.IsRef ? ExprContext.Address : ExprContext.Value);
|
|
SetStackDepth(stackDepth);
|
|
BoundExpression consequence = VisitExpression(node.Consequence, context);
|
|
EnsureStackState(stackStateCookie);
|
|
SetStackDepth(stackDepth);
|
|
BoundExpression alternative = VisitExpression(node.Alternative, context);
|
|
EnsureStackState(stackStateCookie);
|
|
return node.Update(node.IsRef, condition, consequence, alternative, node.ConstantValueOpt, node.NaturalTypeOpt, node.WasCompilerGenerated, node.Type);
|
|
}
|
|
|
|
public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
|
|
{
|
|
BoundExpression left = node.Left;
|
|
if (left.Kind != BoundKind.BinaryOperator || left.ConstantValueOpt != (ConstantValue)null)
|
|
{
|
|
return VisitBinaryOperatorSimple(node);
|
|
}
|
|
ArrayBuilder<BoundBinaryOperator> instance = ArrayBuilder<BoundBinaryOperator>.GetInstance();
|
|
ArrayBuilderExtensions.Push<BoundBinaryOperator>(instance, node);
|
|
BoundBinaryOperator boundBinaryOperator = (BoundBinaryOperator)left;
|
|
while (true)
|
|
{
|
|
ArrayBuilderExtensions.Push<BoundBinaryOperator>(instance, boundBinaryOperator);
|
|
left = boundBinaryOperator.Left;
|
|
if (left.Kind != BoundKind.BinaryOperator || left.ConstantValueOpt != (ConstantValue)null)
|
|
{
|
|
break;
|
|
}
|
|
boundBinaryOperator = (BoundBinaryOperator)left;
|
|
}
|
|
ExprContext context = _context;
|
|
int stackDepth = StackDepth();
|
|
BoundExpression boundExpression = (BoundExpression)Visit(left);
|
|
while (true)
|
|
{
|
|
boundBinaryOperator = ArrayBuilderExtensions.Pop<BoundBinaryOperator>(instance);
|
|
bool num = (boundBinaryOperator.OperatorKind & BinaryOperatorKind.Logical) != 0;
|
|
object cookie = null;
|
|
if (num)
|
|
{
|
|
cookie = GetStackStateCookie();
|
|
SetStackDepth(stackDepth);
|
|
}
|
|
BoundExpression right = (BoundExpression)Visit(boundBinaryOperator.Right);
|
|
if (num)
|
|
{
|
|
EnsureStackState(cookie);
|
|
}
|
|
TypeSymbol type = VisitType(boundBinaryOperator.Type);
|
|
boundExpression = boundBinaryOperator.Update(boundBinaryOperator.OperatorKind, boundBinaryOperator.ConstantValueOpt, boundBinaryOperator.Method, boundBinaryOperator.ConstrainedToType, boundBinaryOperator.ResultKind, boundExpression, right, type);
|
|
if (instance.Count == 0)
|
|
{
|
|
break;
|
|
}
|
|
_context = context;
|
|
_counter++;
|
|
SetStackDepth(stackDepth);
|
|
PushEvalStack(boundBinaryOperator, ExprContext.Value);
|
|
}
|
|
instance.Free();
|
|
return boundExpression;
|
|
}
|
|
|
|
private BoundNode VisitBinaryOperatorSimple(BoundBinaryOperator node)
|
|
{
|
|
if ((node.OperatorKind & BinaryOperatorKind.Logical) != BinaryOperatorKind.Error)
|
|
{
|
|
int stackDepth = StackDepth();
|
|
BoundExpression left = (BoundExpression)Visit(node.Left);
|
|
object stackStateCookie = GetStackStateCookie();
|
|
SetStackDepth(stackDepth);
|
|
BoundExpression right = (BoundExpression)Visit(node.Right);
|
|
EnsureStackState(stackStateCookie);
|
|
return node.Update(node.OperatorKind, node.ConstantValueOpt, node.Method, node.ConstrainedToType, node.ResultKind, left, right, node.Type);
|
|
}
|
|
return base.VisitBinaryOperator(node);
|
|
}
|
|
|
|
public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
|
|
{
|
|
int stackDepth = StackDepth();
|
|
BoundExpression leftOperand = (BoundExpression)Visit(node.LeftOperand);
|
|
object stackStateCookie = GetStackStateCookie();
|
|
SetStackDepth(stackDepth);
|
|
BoundExpression rightOperand = (BoundExpression)Visit(node.RightOperand);
|
|
EnsureStackState(stackStateCookie);
|
|
return node.Update(leftOperand, rightOperand, node.LeftPlaceholder, node.LeftConversion, node.OperatorResultKind, node.Checked, node.Type);
|
|
}
|
|
|
|
public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalAccess node)
|
|
{
|
|
int stackDepth = StackDepth();
|
|
BoundExpression receiver = VisitCallOrConditionalAccessReceiver(node.Receiver, null);
|
|
object stackStateCookie = GetStackStateCookie();
|
|
SetStackDepth(stackDepth);
|
|
BoundExpression whenNotNull = (BoundExpression)Visit(node.WhenNotNull);
|
|
EnsureStackState(stackStateCookie);
|
|
BoundExpression boundExpression = node.WhenNullOpt;
|
|
if (boundExpression != null)
|
|
{
|
|
SetStackDepth(stackDepth);
|
|
boundExpression = (BoundExpression)Visit(boundExpression);
|
|
EnsureStackState(stackStateCookie);
|
|
}
|
|
else
|
|
{
|
|
_counter++;
|
|
}
|
|
return node.Update(receiver, node.HasValueMethodOpt, whenNotNull, boundExpression, node.Id, node.ForceCopyOfNullableValueType, node.Type);
|
|
}
|
|
|
|
public override BoundNode VisitComplexConditionalReceiver(BoundComplexConditionalReceiver node)
|
|
{
|
|
EnsureOnlyEvalStack();
|
|
int stackDepth = StackDepth();
|
|
PushEvalStack(null, ExprContext.None);
|
|
object stackStateCookie = GetStackStateCookie();
|
|
SetStackDepth(stackDepth);
|
|
BoundExpression valueTypeReceiver = (BoundExpression)Visit(node.ValueTypeReceiver);
|
|
EnsureStackState(stackStateCookie);
|
|
SetStackDepth(stackDepth);
|
|
BoundExpression boundExpression;
|
|
for (boundExpression = node.ReferenceTypeReceiver; boundExpression is BoundSequence boundSequence; boundExpression = boundSequence.Value)
|
|
{
|
|
}
|
|
if (boundExpression is BoundLocal boundLocal)
|
|
{
|
|
LocalSymbol localSymbol = boundLocal.LocalSymbol;
|
|
if ((object)localSymbol != null)
|
|
{
|
|
ShouldNotSchedule(localSymbol);
|
|
}
|
|
}
|
|
BoundExpression referenceTypeReceiver = (BoundExpression)Visit(node.ReferenceTypeReceiver);
|
|
EnsureStackState(stackStateCookie);
|
|
return node.Update(valueTypeReceiver, referenceTypeReceiver, node.Type);
|
|
}
|
|
|
|
public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
|
|
{
|
|
if (node.OperatorKind.IsChecked() && node.OperatorKind.Operator() == UnaryOperatorKind.UnaryMinus)
|
|
{
|
|
StackDepth();
|
|
PushEvalStack(new BoundDefaultExpression(node.Syntax, node.Operand.Type), ExprContext.Value);
|
|
BoundExpression operand = (BoundExpression)Visit(node.Operand);
|
|
return node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ConstrainedToTypeOpt, node.ResultKind, node.Type);
|
|
}
|
|
return base.VisitUnaryOperator(node);
|
|
}
|
|
|
|
public override BoundNode VisitTryStatement(BoundTryStatement node)
|
|
{
|
|
EnsureOnlyEvalStack();
|
|
BoundBlock tryBlock = (BoundBlock)Visit(node.TryBlock);
|
|
ImmutableArray<BoundCatchBlock> catchBlocks = VisitList(node.CatchBlocks);
|
|
EnsureOnlyEvalStack();
|
|
BoundBlock finallyBlockOpt = (BoundBlock)Visit(node.FinallyBlockOpt);
|
|
EnsureOnlyEvalStack();
|
|
return node.Update(tryBlock, catchBlocks, finallyBlockOpt, node.FinallyLabelOpt, node.PreferFaultHandler);
|
|
}
|
|
|
|
public override BoundNode VisitCatchBlock(BoundCatchBlock node)
|
|
{
|
|
EnsureOnlyEvalStack();
|
|
BoundExpression boundExpression = node.ExceptionSourceOpt;
|
|
DeclareLocals(node.Locals, 0);
|
|
if (boundExpression != null)
|
|
{
|
|
PushEvalStack(null, ExprContext.None);
|
|
_counter++;
|
|
if (boundExpression.Kind == BoundKind.Local)
|
|
{
|
|
RecordVarWrite(((BoundLocal)boundExpression).LocalSymbol);
|
|
}
|
|
else
|
|
{
|
|
int stackDepth = StackDepth();
|
|
boundExpression = VisitExpression(boundExpression, ExprContext.AssignmentTarget);
|
|
_assignmentLocal = null;
|
|
SetStackDepth(stackDepth);
|
|
}
|
|
PopEvalStack();
|
|
_counter++;
|
|
}
|
|
BoundStatementList exceptionFilterPrologueOpt;
|
|
if (node.ExceptionFilterPrologueOpt != null)
|
|
{
|
|
EnsureOnlyEvalStack();
|
|
exceptionFilterPrologueOpt = (BoundStatementList)Visit(node.ExceptionFilterPrologueOpt);
|
|
}
|
|
else
|
|
{
|
|
exceptionFilterPrologueOpt = null;
|
|
}
|
|
BoundExpression exceptionFilterOpt;
|
|
if (node.ExceptionFilterOpt != null)
|
|
{
|
|
exceptionFilterOpt = (BoundExpression)Visit(node.ExceptionFilterOpt);
|
|
PopEvalStack();
|
|
_counter++;
|
|
EnsureOnlyEvalStack();
|
|
}
|
|
else
|
|
{
|
|
exceptionFilterOpt = null;
|
|
}
|
|
BoundBlock body = (BoundBlock)Visit(node.Body);
|
|
TypeSymbol exceptionTypeOpt = VisitType(node.ExceptionTypeOpt);
|
|
return node.Update(node.Locals, boundExpression, exceptionTypeOpt, exceptionFilterPrologueOpt, exceptionFilterOpt, body, node.IsSynthesizedAsyncCatchAll);
|
|
}
|
|
|
|
public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression node)
|
|
{
|
|
EnsureOnlyEvalStack();
|
|
return base.VisitConvertedStackAllocExpression(node);
|
|
}
|
|
|
|
public override BoundNode VisitArrayInitialization(BoundArrayInitialization node)
|
|
{
|
|
EnsureOnlyEvalStack();
|
|
ImmutableArray<BoundExpression> initializers = node.Initializers;
|
|
ArrayBuilder<BoundExpression> val = null;
|
|
if (!initializers.IsDefault)
|
|
{
|
|
for (int i = 0; i < initializers.Length; i++)
|
|
{
|
|
EnsureOnlyEvalStack();
|
|
BoundExpression boundExpression = initializers[i];
|
|
BoundExpression boundExpression2 = VisitExpression(boundExpression, ExprContext.Value);
|
|
if (val == null && boundExpression2 != boundExpression)
|
|
{
|
|
val = ArrayBuilder<BoundExpression>.GetInstance();
|
|
val.AddRange(initializers, i);
|
|
}
|
|
val?.Add(boundExpression2);
|
|
}
|
|
}
|
|
return node.Update(val?.ToImmutableAndFree() ?? initializers);
|
|
}
|
|
|
|
public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
|
|
{
|
|
BoundExpression operand = VisitExpression(node.Operand, ExprContext.Address);
|
|
return node.Update(operand, node.IsManaged, node.Type);
|
|
}
|
|
|
|
public override BoundNode VisitReturnStatement(BoundReturnStatement node)
|
|
{
|
|
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
|
|
BoundExpression expressionOpt = (BoundExpression)Visit(node.ExpressionOpt);
|
|
EnsureOnlyEvalStack();
|
|
return node.Update(node.RefKind, expressionOpt, node.Checked);
|
|
}
|
|
|
|
private void EnsureOnlyEvalStack()
|
|
{
|
|
RecordVarRead(empty);
|
|
}
|
|
|
|
private object GetStackStateCookie()
|
|
{
|
|
DummyLocal dummyLocal = new DummyLocal();
|
|
_dummyVariables.Add((object)dummyLocal, dummyLocal);
|
|
_locals.Add(dummyLocal, LocalDefUseInfo.GetInstance(StackDepth()));
|
|
RecordDummyWrite(dummyLocal);
|
|
return dummyLocal;
|
|
}
|
|
|
|
private void EnsureStackState(object cookie)
|
|
{
|
|
RecordVarRead(_dummyVariables[cookie]);
|
|
}
|
|
|
|
private void RecordBranch(LabelSymbol label)
|
|
{
|
|
DummyLocal local = default(DummyLocal);
|
|
if (_dummyVariables.TryGetValue((object)label, ref local))
|
|
{
|
|
RecordVarRead(local);
|
|
return;
|
|
}
|
|
local = new DummyLocal();
|
|
_dummyVariables.Add((object)label, local);
|
|
_locals.Add(local, LocalDefUseInfo.GetInstance(StackDepth()));
|
|
RecordDummyWrite(local);
|
|
}
|
|
|
|
private void RecordLabel(LabelSymbol label)
|
|
{
|
|
DummyLocal local = default(DummyLocal);
|
|
if (_dummyVariables.TryGetValue((object)label, ref local))
|
|
{
|
|
RecordVarRead(local);
|
|
return;
|
|
}
|
|
local = empty;
|
|
_dummyVariables.Add((object)label, local);
|
|
RecordVarRead(local);
|
|
}
|
|
|
|
private void ShouldNotSchedule(LocalSymbol localSymbol)
|
|
{
|
|
if (_locals.TryGetValue(localSymbol, out var value))
|
|
{
|
|
value.ShouldNotSchedule();
|
|
}
|
|
}
|
|
|
|
private void RecordVarRef(LocalSymbol local)
|
|
{
|
|
if (CanScheduleToStack(local))
|
|
{
|
|
ShouldNotSchedule(local);
|
|
}
|
|
}
|
|
|
|
private void RecordVarRead(LocalSymbol local)
|
|
{
|
|
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_003e: Invalid comparison between Unknown and I4
|
|
if (!CanScheduleToStack(local))
|
|
{
|
|
return;
|
|
}
|
|
LocalDefUseInfo localDefUseInfo = _locals[local];
|
|
if (!localDefUseInfo.CannotSchedule)
|
|
{
|
|
ArrayBuilder<LocalDefUseSpan> localDefs = localDefUseInfo.LocalDefs;
|
|
if (localDefs.Count == 0)
|
|
{
|
|
localDefUseInfo.ShouldNotSchedule();
|
|
return;
|
|
}
|
|
if ((int)local.SynthesizedKind != -3 && localDefUseInfo.StackAtDeclaration != StackDepth() && !EvalStackHasLocal(local))
|
|
{
|
|
localDefUseInfo.ShouldNotSchedule();
|
|
return;
|
|
}
|
|
int num = localDefs.Count - 1;
|
|
localDefs[num] = localDefs[num].WithEnd(_counter);
|
|
LocalDefUseSpan localDefUseSpan = new LocalDefUseSpan(_counter);
|
|
localDefs.Add(localDefUseSpan);
|
|
}
|
|
}
|
|
|
|
private bool EvalStackHasLocal(LocalSymbol local)
|
|
{
|
|
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
|
|
(BoundExpression, ExprContext) tuple = _evalStack.Last();
|
|
if (tuple.Item2 == (ExprContext)(((int)local.RefKind == 0) ? 2 : 3) && tuple.Item1.Kind == BoundKind.Local)
|
|
{
|
|
return ((BoundLocal)tuple.Item1).LocalSymbol == local;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void RecordDummyWrite(LocalSymbol local)
|
|
{
|
|
LocalDefUseInfo localDefUseInfo = _locals[local];
|
|
LocalDefUseSpan localDefUseSpan = new LocalDefUseSpan(_counter);
|
|
localDefUseInfo.LocalDefs.Add(localDefUseSpan);
|
|
}
|
|
|
|
private void RecordVarWrite(LocalSymbol local)
|
|
{
|
|
if (!CanScheduleToStack(local))
|
|
{
|
|
return;
|
|
}
|
|
LocalDefUseInfo localDefUseInfo = _locals[local];
|
|
if (!localDefUseInfo.CannotSchedule)
|
|
{
|
|
int num = StackDepth() - 1;
|
|
if (localDefUseInfo.StackAtDeclaration != num)
|
|
{
|
|
localDefUseInfo.ShouldNotSchedule();
|
|
return;
|
|
}
|
|
LocalDefUseSpan localDefUseSpan = new LocalDefUseSpan(_counter);
|
|
localDefUseInfo.LocalDefs.Add(localDefUseSpan);
|
|
}
|
|
}
|
|
|
|
private bool CanScheduleToStack(LocalSymbol local)
|
|
{
|
|
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
|
|
if (local.CanScheduleToStack)
|
|
{
|
|
if (_debugFriendly)
|
|
{
|
|
return !SynthesizedLocalKindExtensions.IsLongLived(local.SynthesizedKind);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void DeclareLocals(ImmutableArray<LocalSymbol> locals, int stack)
|
|
{
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
DeclareLocal(current, stack);
|
|
}
|
|
}
|
|
|
|
private void DeclareLocal(LocalSymbol local, int stack)
|
|
{
|
|
if ((object)local != null && CanScheduleToStack(local))
|
|
{
|
|
if (!_locals.TryGetValue(local, out var value))
|
|
{
|
|
_locals.Add(local, LocalDefUseInfo.GetInstance(stack));
|
|
}
|
|
else if (value.StackAtDeclaration != stack)
|
|
{
|
|
value.ShouldNotSchedule();
|
|
}
|
|
}
|
|
}
|
|
}
|