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

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();
}
}
}
}