using System; using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.CodeGen; internal sealed class StackOptimizerPass2 : BoundTreeRewriterWithStackGuard { private int _nodeCounter; private readonly Dictionary _info; private StackOptimizerPass2(Dictionary info) { _info = info; } public static BoundStatement Rewrite(BoundStatement src, Dictionary info) { return (BoundStatement)new StackOptimizerPass2(info).Visit(src); } public override BoundNode Visit(BoundNode node) { BoundNode result = ((!(node is BoundExpression boundExpression) || !(boundExpression.ConstantValueOpt != (ConstantValue)null)) ? base.Visit(node) : node); _nodeCounter++; return result; } public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) { BoundExpression left = node.Left; if (left.Kind != BoundKind.BinaryOperator || left.ConstantValueOpt != (ConstantValue)null) { return base.VisitBinaryOperator(node); } ArrayBuilder instance = ArrayBuilder.GetInstance(); ArrayBuilderExtensions.Push(instance, node); BoundBinaryOperator boundBinaryOperator = (BoundBinaryOperator)left; while (true) { ArrayBuilderExtensions.Push(instance, boundBinaryOperator); left = boundBinaryOperator.Left; if (left.Kind != BoundKind.BinaryOperator || left.ConstantValueOpt != (ConstantValue)null) { break; } boundBinaryOperator = (BoundBinaryOperator)left; } BoundExpression boundExpression = (BoundExpression)Visit(left); while (true) { boundBinaryOperator = ArrayBuilderExtensions.Pop(instance); BoundExpression right = (BoundExpression)Visit(boundBinaryOperator.Right); 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; } _nodeCounter++; } instance.Free(); return boundExpression; } private static bool IsLastAccess(LocalDefUseInfo locInfo, int counter) { return ArrayBuilderExtensions.Any(locInfo.LocalDefs, (Func)((LocalDefUseSpan d) => counter == d.Start && counter == d.End)); } public override BoundNode VisitLocal(BoundLocal node) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (!_info.TryGetValue(node.LocalSymbol, out var value)) { return base.VisitLocal(node); } if (!IsLastAccess(value, _nodeCounter)) { return new BoundDup(node.Syntax, node.LocalSymbol.RefKind, node.Type); } return base.VisitLocal(node); } public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpression node) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) ImmutableArray arguments = VisitList(node.Arguments); TypeSymbol type = VisitType(node.Type); return node.Update(node.Constructor, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.DefaultArguments, node.ConstantValueOpt, null, type); } public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (!(node.Left is BoundLocal boundLocal) || !_info.TryGetValue(boundLocal.LocalSymbol, out var value)) { return base.VisitAssignmentOperator(node); } if ((int)boundLocal.LocalSymbol.RefKind != 0 && !node.IsRef) { return base.VisitAssignmentOperator(node); } _nodeCounter++; BoundExpression boundExpression = (BoundExpression)Visit(node.Right); if (IsLastAccess(value, _nodeCounter)) { return boundExpression; } return node.Update(boundLocal, boundExpression, node.IsRef, node.Type); } public override BoundNode VisitCall(BoundCall node) { if (node.ReceiverOpt is BoundCall boundCall) { ArrayBuilder instance = ArrayBuilder.GetInstance(); ArrayBuilderExtensions.Push(instance, node); node = boundCall; while (node.ReceiverOpt is BoundCall boundCall2) { ArrayBuilderExtensions.Push(instance, node); node = boundCall2; } BoundExpression boundExpression = visitReceiver(node); while (true) { boundExpression = visitArgumentsAndUpdateCall(node, boundExpression); if (!ArrayBuilderExtensions.TryPop(instance, ref node)) { break; } _nodeCounter++; } instance.Free(); return boundExpression; } BoundExpression receiverOpt = visitReceiver(node); return visitArgumentsAndUpdateCall(node, receiverOpt); BoundExpression visitArgumentsAndUpdateCall(BoundCall boundCall3, BoundExpression? receiverOpt2) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) ImmutableArray arguments = VisitList(boundCall3.Arguments); TypeSymbol type = VisitType(boundCall3.Type); return boundCall3.Update(receiverOpt2, boundCall3.InitialBindingReceiverIsSubjectToCloning, boundCall3.Method, arguments, boundCall3.ArgumentNamesOpt, boundCall3.ArgumentRefKindsOpt, boundCall3.IsDelegateCall, boundCall3.Expanded, boundCall3.InvokedAsExtensionMethod, boundCall3.ArgsToParamsOpt, boundCall3.DefaultArguments, boundCall3.ResultKind, boundCall3.OriginalMethodsOpt, type); } BoundExpression? visitReceiver(BoundCall boundCall3) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 BoundExpression boundExpression2 = boundCall3.ReceiverOpt; if (boundCall3.Method.RequiresInstanceReceiver) { boundExpression2 = (BoundExpression)Visit(boundExpression2); } else { _nodeCounter++; if (boundExpression2 is BoundTypeExpression { AliasOpt: null, BoundContainingTypeOpt: null } boundTypeExpression && boundTypeExpression.BoundDimensionsOpt.IsEmpty) { TypeSymbol type = boundTypeExpression.Type; if ((object)type != null && (int)type.TypeKind == 11) { boundExpression2 = boundTypeExpression.Update(null, null, ImmutableArray.Empty, boundTypeExpression.TypeWithAnnotations, VisitType(boundTypeExpression.Type)); goto IL_00a7; } } if (boundExpression2 != null) { throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs", 2259); } } goto IL_00a7; IL_00a7: return boundExpression2; } } public override BoundNode VisitCatchBlock(BoundCatchBlock node) { BoundExpression boundExpression = node.ExceptionSourceOpt; TypeSymbol exceptionTypeOpt = node.ExceptionTypeOpt; BoundStatementList exceptionFilterPrologueOpt = node.ExceptionFilterPrologueOpt; BoundExpression boundExpression2 = node.ExceptionFilterOpt; BoundBlock body = node.Body; if (boundExpression != null) { _nodeCounter++; if (boundExpression.Kind == BoundKind.Local) { LocalSymbol localSymbol = ((BoundLocal)boundExpression).LocalSymbol; if (_info.TryGetValue(localSymbol, out var value) && IsLastAccess(value, _nodeCounter)) { boundExpression = null; } } else { boundExpression = (BoundExpression)Visit(boundExpression); } _nodeCounter++; } exceptionFilterPrologueOpt = ((exceptionFilterPrologueOpt != null) ? ((BoundStatementList)Visit(exceptionFilterPrologueOpt)) : null); if (boundExpression2 != null) { boundExpression2 = (BoundExpression)Visit(boundExpression2); _nodeCounter++; } body = (BoundBlock)Visit(body); exceptionTypeOpt = VisitType(exceptionTypeOpt); return node.Update(node.Locals, boundExpression, exceptionTypeOpt, exceptionFilterPrologueOpt, boundExpression2, body, node.IsSynthesizedAsyncCatchAll); } }