219 lines
8.1 KiB
C#
219 lines
8.1 KiB
C#
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<LocalSymbol, LocalDefUseInfo> _info;
|
||
|
|
|
||
|
|
private StackOptimizerPass2(Dictionary<LocalSymbol, LocalDefUseInfo> info)
|
||
|
|
{
|
||
|
|
_info = info;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static BoundStatement Rewrite(BoundStatement src, Dictionary<LocalSymbol, LocalDefUseInfo> 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<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;
|
||
|
|
}
|
||
|
|
BoundExpression boundExpression = (BoundExpression)Visit(left);
|
||
|
|
while (true)
|
||
|
|
{
|
||
|
|
boundBinaryOperator = ArrayBuilderExtensions.Pop<BoundBinaryOperator>(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<LocalDefUseSpan>(locInfo.LocalDefs, (Func<LocalDefUseSpan, bool>)((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<BoundExpression> 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<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);
|
||
|
|
if (!ArrayBuilderExtensions.TryPop<BoundCall>(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<BoundExpression> 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<BoundExpression>.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);
|
||
|
|
}
|
||
|
|
}
|