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

454 lines
20 KiB
C#

using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Collections;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp;
internal sealed class LocalStateTracingInstrumenter : CompoundInstrumenter
{
private sealed class Scope
{
public LocalSymbol ContextVariable;
private ArrayBuilder<LocalSymbol>? _lazyPreviousContextVariables;
public Scope(LocalSymbol contextVariable)
{
ContextVariable = contextVariable;
}
public void Open(LocalSymbol local)
{
if (_lazyPreviousContextVariables == null)
{
_lazyPreviousContextVariables = ArrayBuilder<LocalSymbol>.GetInstance();
}
ArrayBuilderExtensions.Push<LocalSymbol>(_lazyPreviousContextVariables, ContextVariable);
ContextVariable = local;
}
public void Close(bool isMethodBody)
{
ArrayBuilder<LocalSymbol> lazyPreviousContextVariables = _lazyPreviousContextVariables;
if (lazyPreviousContextVariables != null && lazyPreviousContextVariables.Count > 0)
{
ContextVariable = ArrayBuilderExtensions.Pop<LocalSymbol>(_lazyPreviousContextVariables);
}
if (isMethodBody)
{
_lazyPreviousContextVariables?.Free();
_lazyPreviousContextVariables = null;
}
}
}
private readonly Scope _scope;
private readonly SyntheticBoundNodeFactory _factory;
private readonly BindingDiagnosticBag _diagnostics;
private readonly TypeSymbol _contextType;
private LocalStateTracingInstrumenter(Scope scope, TypeSymbol contextType, SyntheticBoundNodeFactory factory, BindingDiagnosticBag diagnostics, Instrumenter previous)
: base(previous)
{
_scope = scope;
_contextType = contextType;
_factory = factory;
_diagnostics = diagnostics;
}
protected override CompoundInstrumenter WithPreviousImpl(Instrumenter previous)
{
return new LocalStateTracingInstrumenter(_scope, _contextType, _factory, _diagnostics, previous);
}
public static bool TryCreate(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory factory, BindingDiagnosticBag diagnostics, Instrumenter previous, [NotNullWhen(true)] out LocalStateTracingInstrumenter? instrumenter)
{
instrumenter = null;
if (method.IsImplicitlyDeclared && !method.IsImplicitConstructor)
{
return false;
}
if (method is SourceMemberMethodSymbol sourceMemberMethodSymbol)
{
(BlockSyntax, ArrowExpressionClauseSyntax) bodies = sourceMemberMethodSymbol.Bodies;
if (bodies.Item2 == null && bodies.Item1 == null && !(sourceMemberMethodSymbol is SynthesizedSimpleProgramEntryPointSymbol))
{
return false;
}
}
NamedTypeSymbol wellKnownType = factory.Compilation.GetWellKnownType((WellKnownType)265);
if (IsSameOrNestedType(method.ContainingType, wellKnownType))
{
return false;
}
Scope scope = new Scope(factory.SynthesizedLocal(wellKnownType, methodBody.Syntax, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)36));
instrumenter = new LocalStateTracingInstrumenter(scope, wellKnownType, factory, diagnostics, previous);
return true;
}
private static bool IsSameOrNestedType(NamedTypeSymbol type, NamedTypeSymbol otherType)
{
while (true)
{
if (type.Equals(otherType))
{
return true;
}
if ((object)type.ContainingType == null)
{
break;
}
type = type.ContainingType;
}
return false;
}
private MethodSymbol? GetLocalOrParameterStoreLogger(TypeSymbol variableType, Symbol targetSymbol, bool? refAssignmentSourceIsLocal, SyntaxNode syntax)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Invalid comparison between Unknown and I4
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Expected I4, but got Unknown
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
//IL_01af: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
//IL_0173: Unknown result type (might be due to invalid IL or missing references)
//IL_017a: Invalid comparison between Unknown and I4
int num = (((int)targetSymbol.Kind == 13) ? 13 : 0);
WellKnownMember? val;
if (refAssignmentSourceIsLocal.HasValue)
{
val = ((refAssignmentSourceIsLocal != true) ? new WellKnownMember?((WellKnownMember)374) : new WellKnownMember?((WellKnownMember)388));
}
else
{
SpecialType specialType = variableType.EnumUnderlyingTypeOrSelf().SpecialType;
WellKnownMember? val2;
switch (specialType - 7)
{
case 0:
val2 = (WellKnownMember)362;
break;
case 2:
case 3:
val2 = (WellKnownMember)363;
break;
case 1:
case 4:
case 5:
val2 = (WellKnownMember)364;
break;
case 6:
case 7:
val2 = (WellKnownMember)365;
break;
case 8:
case 9:
val2 = (WellKnownMember)366;
break;
case 11:
val2 = (WellKnownMember)367;
break;
case 12:
val2 = (WellKnownMember)368;
break;
case 10:
val2 = (WellKnownMember)369;
break;
case 13:
val2 = (WellKnownMember)370;
break;
default:
val2 = ((!variableType.IsPointerOrFunctionPointer()) ? (variableType.IsManagedTypeNoUseSiteDiagnostics ? ((variableType.IsRefLikeType && !hasOverriddenToString(variableType)) ? ((WellKnownMember?)null) : (((int)variableType.TypeKind != 10) ? new WellKnownMember?((WellKnownMember)371) : new WellKnownMember?((WellKnownMember)370))) : new WellKnownMember?((WellKnownMember)373)) : new WellKnownMember?((WellKnownMember)372));
break;
}
val = val2;
}
WellKnownMember? val3 = val;
if (!val3.HasValue)
{
return null;
}
WellKnownMember overload = (WellKnownMember)(val3.Value + num);
return GetWellKnownMethodSymbol(overload, syntax);
static bool hasOverriddenToString(TypeSymbol typeSymbol)
{
return typeSymbol.GetMembers("ToString").Any((Symbol m) => (object)m.GetOverriddenMember() != null);
}
}
private MethodSymbol? GetWellKnownMethodSymbol(WellKnownMember overload, SyntaxNode syntax)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (MethodSymbol)Binder.GetWellKnownTypeMember(_factory.Compilation, overload, _diagnostics, null, syntax);
}
public override void PreInstrumentBlock(BoundBlock original, LocalRewriter rewriter)
{
base.Previous.PreInstrumentBlock(original, rewriter);
if (rewriter.CurrentLambdaBody == original)
{
_scope.Open(_factory.SynthesizedLocal(_contextType, original.Syntax, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)36));
}
}
public override void InstrumentBlock(BoundBlock original, LocalRewriter rewriter, ref TemporaryArray<LocalSymbol> additionalLocals, out BoundStatement? prologue, out BoundStatement? epilogue, out BoundBlockInstrumentation? instrumentation)
{
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Invalid comparison between Unknown and I4
//IL_029c: Unknown result type (might be due to invalid IL or missing references)
//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
base.InstrumentBlock(original, rewriter, ref additionalLocals, out BoundStatement prologue2, out epilogue, out instrumentation);
bool flag = rewriter.CurrentMethodBody == original;
bool flag2 = rewriter.CurrentLambdaBody == original;
if (!flag && !flag2)
{
prologue = prologue2;
return;
}
bool flag3 = _factory.CurrentFunction.IsAsync || _factory.CurrentFunction.IsIterator;
ArrayBuilder<BoundStatement> instance = ArrayBuilder<BoundStatement>.GetInstance(_factory.CurrentFunction.ParameterCount);
ImmutableArray<ParameterSymbol>.Enumerator enumerator = _factory.CurrentFunction.Parameters.GetEnumerator();
while (enumerator.MoveNext())
{
ParameterSymbol current = enumerator.Current;
if ((int)current.RefKind != 2 && !current.IsDiscard)
{
MethodSymbol localOrParameterStoreLogger = GetLocalOrParameterStoreLogger(current.Type, current, null, _factory.Syntax);
if (localOrParameterStoreLogger != null)
{
instance.Add((BoundStatement)_factory.ExpressionStatement(_factory.Call(_factory.Local(_scope.ContextVariable), localOrParameterStoreLogger, MakeStoreLoggerArguments(localOrParameterStoreLogger.Parameters[0], current, current.Type, _factory.Parameter(current), null, _factory.Literal((int)(ushort)current.Ordinal)))));
}
}
}
if (prologue2 != null)
{
instance.Add(prologue2);
}
prologue = _factory.StatementList(instance.ToImmutableAndFree());
(WellKnownMember, BoundExpression[]) tuple = ((!flag2) ? (flag3 ? ((WellKnownMember)358, new BoundExpression[2]
{
_factory.MethodDefIndex(_factory.TopLevelMethod),
_factory.StateMachineInstanceId()
}) : ((WellKnownMember)356, new BoundExpression[1] { _factory.MethodDefIndex(_factory.TopLevelMethod) })) : (flag3 ? ((WellKnownMember)359, new BoundExpression[3]
{
_factory.MethodDefIndex(_factory.TopLevelMethod),
_factory.MethodDefIndex(_factory.CurrentFunction),
_factory.StateMachineInstanceId()
}) : ((WellKnownMember)357, new BoundExpression[2]
{
_factory.MethodDefIndex(_factory.TopLevelMethod),
_factory.MethodDefIndex(_factory.CurrentFunction)
})));
(WellKnownMember, BoundExpression[]) tuple2 = tuple;
WellKnownMember item = tuple2.Item1;
BoundExpression[] item2 = tuple2.Item2;
MethodSymbol wellKnownMethodSymbol = GetWellKnownMethodSymbol(item, _factory.Syntax);
BoundStatement prologue3 = ((wellKnownMethodSymbol != null) ? _factory.Assignment(_factory.Local(_scope.ContextVariable), _factory.Call(null, wellKnownMethodSymbol, item2)) : _factory.NoOp(NoOpStatementFlavor.Default));
MethodSymbol wellKnownMethodSymbol2 = GetWellKnownMethodSymbol((WellKnownMember)360, _factory.Syntax);
BoundStatement epilogue2 = ((wellKnownMethodSymbol2 != null) ? _factory.ExpressionStatement(_factory.Call(_factory.Local(_scope.ContextVariable), wellKnownMethodSymbol2)) : _factory.NoOp(NoOpStatementFlavor.Default));
instrumentation = new BoundBlockInstrumentation(_factory.Syntax, _scope.ContextVariable, prologue3, epilogue2);
_scope.Close(flag);
}
public override BoundExpression InstrumentUserDefinedLocalAssignment(BoundAssignmentOperator original)
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
BoundExpression boundExpression = base.InstrumentUserDefinedLocalAssignment(original);
bool? refAssignmentSourceIsLocal;
BoundExpression refAssignmentSourceIndex;
if (original.IsRef)
{
if (original.Right is BoundLocal boundLocal)
{
LocalSymbol localSymbol = boundLocal.LocalSymbol;
if ((object)localSymbol != null && (int)localSymbol.SynthesizedKind == 0)
{
refAssignmentSourceIsLocal = true;
refAssignmentSourceIndex = _factory.LocalId(boundLocal.LocalSymbol);
goto IL_008e;
}
}
if (!(original.Right is BoundParameter boundParameter))
{
return boundExpression;
}
refAssignmentSourceIsLocal = false;
refAssignmentSourceIndex = _factory.ParameterId(boundParameter.ParameterSymbol);
}
else
{
refAssignmentSourceIsLocal = null;
refAssignmentSourceIndex = null;
}
goto IL_008e;
IL_008e:
if (!TryGetLocalOrParameterInfo(original.Left, out Symbol symbol, out TypeSymbol type, out BoundExpression indexExpression))
{
throw ExceptionUtilities.UnexpectedValue((object)original.Left);
}
MethodSymbol localOrParameterStoreLogger = GetLocalOrParameterStoreLogger(type, symbol, refAssignmentSourceIsLocal, original.Syntax);
if ((object)localOrParameterStoreLogger == null)
{
return boundExpression;
}
SyntheticBoundNodeFactory factory = _factory;
BoundExpression[] sideEffects = new BoundCall[1] { _factory.Call(_factory.Local(_scope.ContextVariable), localOrParameterStoreLogger, MakeStoreLoggerArguments(localOrParameterStoreLogger.Parameters[0], symbol, type, boundExpression, refAssignmentSourceIndex, indexExpression)) };
return factory.Sequence(sideEffects, VariableRead(symbol));
}
private bool TryGetLocalOrParameterInfo(BoundNode node, [NotNullWhen(true)] out Symbol? symbol, [NotNullWhen(true)] out TypeSymbol? type, [NotNullWhen(true)] out BoundExpression? indexExpression)
{
if (node is BoundLocal boundLocal)
{
LocalSymbol localSymbol = (LocalSymbol)(symbol = boundLocal.LocalSymbol);
type = localSymbol.Type;
indexExpression = _factory.LocalId(localSymbol);
return true;
}
if (node is BoundParameter boundParameter)
{
ParameterSymbol parameterSymbol = (ParameterSymbol)(symbol = boundParameter.ParameterSymbol);
type = parameterSymbol.Type;
indexExpression = _factory.ParameterId(parameterSymbol);
return true;
}
symbol = null;
indexExpression = null;
type = null;
return false;
}
private ImmutableArray<BoundExpression> MakeStoreLoggerArguments(ParameterSymbol parameter, Symbol targetSymbol, TypeSymbol targetType, BoundExpression value, BoundExpression? refAssignmentSourceIndex, BoundExpression index)
{
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Invalid comparison between Unknown and I4
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Invalid comparison between Unknown and I4
if (refAssignmentSourceIndex != null)
{
return ImmutableArray.Create(_factory.Sequence(new BoundExpression[1] { value }, refAssignmentSourceIndex), index);
}
if (parameter.Type.IsVoidPointer() && !targetType.IsPointerOrFunctionPointer())
{
bool flag = ((value is BoundLocal || value is BoundParameter) ? true : false);
return ImmutableArray.Create(flag ? ((BoundExpression)new BoundAddressOfOperator(_factory.Syntax, value, isManaged: false, parameter.Type)) : ((BoundExpression)_factory.Sequence(new BoundExpression[1] { value }, new BoundAddressOfOperator(_factory.Syntax, VariableRead(targetSymbol), isManaged: false, parameter.Type))), _factory.Sizeof(targetType), index);
}
if ((int)parameter.Type.SpecialType == 20 && (int)targetType.SpecialType != 20)
{
MethodSymbol wellKnownMethodSymbol = GetWellKnownMethodSymbol((WellKnownMember)0, value.Syntax);
BoundExpression item = (((object)wellKnownMethodSymbol != null) ? ((BoundExpression)_factory.Call(value, wellKnownMethodSymbol)) : ((BoundExpression)_factory.Literal("")));
return ImmutableArray.Create(item, index);
}
return ImmutableArray.Create(_factory.Convert(parameter.Type, value), index);
}
private BoundExpression VariableRead(Symbol localOrParameterSymbol)
{
if (!(localOrParameterSymbol is LocalSymbol local))
{
if (localOrParameterSymbol is ParameterSymbol p)
{
return _factory.Parameter(p);
}
throw ExceptionUtilities.UnexpectedValue((object)localOrParameterSymbol);
}
return _factory.Local(local);
}
public override void InstrumentCatchBlock(BoundCatchBlock original, ref BoundExpression? rewrittenSource, ref BoundStatementList? rewrittenFilterPrologue, ref BoundExpression? rewrittenFilter, ref BoundBlock rewrittenBody, ref TypeSymbol? rewrittenType, SyntheticBoundNodeFactory factory)
{
base.InstrumentCatchBlock(original, ref rewrittenSource, ref rewrittenFilterPrologue, ref rewrittenFilter, ref rewrittenBody, ref rewrittenType, factory);
if (original.WasCompilerGenerated)
{
return;
}
LocalSymbol localSymbol = original.Locals.FirstOrDefault((LocalSymbol l) => (int)l.SynthesizedKind == 0);
if ((object)localSymbol != null)
{
TypeSymbol type = localSymbol.Type;
BoundExpression index = _factory.LocalId(localSymbol);
MethodSymbol localOrParameterStoreLogger = GetLocalOrParameterStoreLogger(type, localSymbol, null, original.Syntax);
if ((object)localOrParameterStoreLogger != null)
{
BoundExpressionStatement boundExpressionStatement = _factory.ExpressionStatement(_factory.Call(_factory.Local(_scope.ContextVariable), localOrParameterStoreLogger, MakeStoreLoggerArguments(localOrParameterStoreLogger.Parameters[0], localSymbol, type, VariableRead(localSymbol), null, index)));
rewrittenFilterPrologue = _factory.StatementList((rewrittenFilterPrologue != null) ? ImmutableArray.Create((BoundStatement)boundExpressionStatement, (BoundStatement)rewrittenFilterPrologue) : ImmutableArray.Create((BoundStatement)boundExpressionStatement));
}
}
}
public override BoundExpression InstrumentCall(BoundCall original, BoundExpression rewritten)
{
return InstrumentCall(base.InstrumentCall(original, rewritten), original.Arguments, original.ArgumentRefKindsOpt);
}
public override BoundExpression InstrumentObjectCreationExpression(BoundObjectCreationExpression original, BoundExpression rewritten)
{
return InstrumentCall(base.InstrumentObjectCreationExpression(original, rewritten), original.Arguments, original.ArgumentRefKindsOpt);
}
public override BoundExpression InstrumentFunctionPointerInvocation(BoundFunctionPointerInvocation original, BoundExpression rewritten)
{
return InstrumentCall(base.InstrumentFunctionPointerInvocation(original, rewritten), original.Arguments, original.ArgumentRefKindsOpt);
}
private BoundExpression InstrumentCall(BoundExpression invocation, ImmutableArray<BoundExpression> arguments, ImmutableArray<RefKind> refKinds)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Invalid comparison between Unknown and I4
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Invalid comparison between Unknown and I4
if (refKinds.IsDefaultOrEmpty)
{
return invocation;
}
ArrayBuilder<BoundExpression> instance = ArrayBuilder<BoundExpression>.GetInstance();
BoundLocal boundLocal = null;
if ((int)invocation.Type.SpecialType != 6)
{
boundLocal = _factory.StoreToTemp(invocation, out BoundAssignmentOperator store, (RefKind)0, (SynthesizedLocalKind)(-2));
instance.Add((BoundExpression)store);
}
else
{
instance.Add(invocation);
}
for (int i = 0; i < arguments.Length; i++)
{
RefKind val = refKinds[i];
bool flag = val - 1 <= 1;
if (flag && TryGetLocalOrParameterInfo(arguments[i], out Symbol symbol, out TypeSymbol type, out BoundExpression indexExpression))
{
MethodSymbol localOrParameterStoreLogger = GetLocalOrParameterStoreLogger(type, symbol, null, invocation.Syntax);
if ((object)localOrParameterStoreLogger != null)
{
instance.Add((BoundExpression)_factory.Call(_factory.Local(_scope.ContextVariable), localOrParameterStoreLogger, MakeStoreLoggerArguments(localOrParameterStoreLogger.Parameters[0], symbol, type, VariableRead(symbol), null, indexExpression)));
}
}
}
if (boundLocal != null)
{
return _factory.Sequence(ImmutableArray.Create(boundLocal.LocalSymbol), instance.ToImmutableAndFree(), boundLocal);
}
BoundExpression result = instance.Last();
instance.RemoveLast();
return _factory.Sequence(ImmutableArray<LocalSymbol>.Empty, instance.ToImmutableAndFree(), result);
}
}