Browse Source

Pass the compilation to ILInstruction.CheckInvariant

Invariants that involve types (stack type of a variable against its IType,
the element type of an array access, the operand types of a comparison)
need a type system to resolve them against, and the only correct one is the
type system the instruction tree was decoded with. Until now CheckInvariant
took only the phase, so such a check had no compilation to use:
DeconstructInstruction.CheckInvariant called IsAssignment with a null type
system, which only held up because the targets it sees are ldloc, whose
InferType never touches the compilation; a ldflda-wrapped or pointer target
would have failed inside the invariant instead of reporting a violation.

Every call site already has that type system in scope: the ILReader's
compilation, the ILTransformContext of the running transform, or the
decompiler's own IDecompilerTypeSystem. It is now passed explicitly and the
base implementation asserts it is present, so a future invariant can rely
on it without re-plumbing the callers.

Assisted-by: Claude:claude-fable-5:Claude Code
pull/4085/head
Siegfried Pammer 2 weeks ago
parent
commit
cd212ea05f
  1. 2
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 4
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  3. 2
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  4. 2
      ICSharpCode.Decompiler/IL/ILReader.cs
  5. 76
      ICSharpCode.Decompiler/IL/Instructions.cs
  6. 4
      ICSharpCode.Decompiler/IL/Instructions.tt
  7. 4
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  8. 8
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  9. 5
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  10. 6
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  11. 4
      ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs
  12. 4
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  13. 4
      ICSharpCode.Decompiler/IL/Instructions/Comp.cs
  14. 4
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  15. 4
      ICSharpCode.Decompiler/IL/Instructions/Conv.cs
  16. 6
      ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs
  17. 8
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  18. 11
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  19. 6
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  20. 6
      ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs
  21. 6
      ICSharpCode.Decompiler/IL/Instructions/Leave.cs
  22. 10
      ICSharpCode.Decompiler/IL/Instructions/LogicInstructions.cs
  23. 6
      ICSharpCode.Decompiler/IL/Instructions/NullCoalescingInstruction.cs
  24. 9
      ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs
  25. 6
      ICSharpCode.Decompiler/IL/Instructions/StLoc.cs
  26. 4
      ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs
  27. 5
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  28. 6
      ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
  29. 2
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  30. 2
      ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs
  31. 2
      ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs
  32. 2
      ICSharpCode.Decompiler/IL/Transforms/StatementTransform.cs
  33. 2
      doc/DecompilerArchitecture.html

2
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -2389,7 +2389,7 @@ namespace ICSharpCode.Decompiler.CSharp
return; return;
} }
function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, methodBody, cancellationToken: CancellationToken); function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, methodBody, cancellationToken: CancellationToken);
function.CheckInvariant(ILPhase.Normal); function.CheckInvariant(ILPhase.Normal, typeSystem);
AddAnnotationsToDeclaration(method, entityDecl, function, parameterOffset); AddAnnotationsToDeclaration(method, entityDecl, function, parameterOffset);

4
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -143,9 +143,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
InlineBodyOfMoveNext(function); InlineBodyOfMoveNext(function);
function.CheckInvariant(ILPhase.InAsyncAwait); function.CheckInvariant(ILPhase.InAsyncAwait, context.TypeSystem);
CleanUpBodyOfMoveNext(function); CleanUpBodyOfMoveNext(function);
function.CheckInvariant(ILPhase.InAsyncAwait); function.CheckInvariant(ILPhase.InAsyncAwait, context.TypeSystem);
AnalyzeStateMachine(function); AnalyzeStateMachine(function);
DetectAwaitPattern(function); DetectAwaitPattern(function);

2
ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

@ -189,7 +189,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// Note: because this only deletes blocks outright, the 'stateChanges' entries remain valid // Note: because this only deletes blocks outright, the 'stateChanges' entries remain valid
// (though some may point to now-deleted blocks) // (though some may point to now-deleted blocks)
newBody.SortBlocks(deleteUnreachableBlocks: true); newBody.SortBlocks(deleteUnreachableBlocks: true);
function.CheckInvariant(ILPhase.Normal); function.CheckInvariant(ILPhase.Normal, context.TypeSystem);
try try
{ {

2
ICSharpCode.Decompiler/IL/ILReader.cs

@ -543,7 +543,7 @@ namespace ICSharpCode.Decompiler.IL
var inst = decodedInstruction.Instruction; var inst = decodedInstruction.Instruction;
if (inst.ResultType == StackType.Unknown && inst.OpCode != OpCode.InvalidBranch && inst.OpCode != OpCode.InvalidExpression) if (inst.ResultType == StackType.Unknown && inst.OpCode != OpCode.InvalidBranch && inst.OpCode != OpCode.InvalidExpression)
Warn("Unknown result type (might be due to invalid IL or missing references)"); Warn("Unknown result type (might be due to invalid IL or missing references)");
inst.CheckInvariant(ILPhase.InILReader); inst.CheckInvariant(ILPhase.InILReader, compilation);
int end = reader.Offset; int end = reader.Offset;
inst.AddILRange(new Interval(start, end)); inst.AddILRange(new Interval(start, end));
if (!decodedInstruction.PushedOnExpressionStack) if (!decodedInstruction.PushedOnExpressionStack)

76
ICSharpCode.Decompiler/IL/Instructions.cs

@ -1038,9 +1038,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as PinnedRegion; var o = other as PinnedRegion;
return o != null && variable == o.variable && this.init.PerformMatch(o.init, ref match) && this.body.PerformMatch(o.body, ref match); return o != null && variable == o.variable && this.init.PerformMatch(o.init, ref match) && this.body.PerformMatch(o.body, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!)); DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!));
DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable); DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable);
DebugAssert(Variable.Kind == VariableKind.PinnedRegionLocal); DebugAssert(Variable.Kind == VariableKind.PinnedRegionLocal);
@ -1940,9 +1940,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as LockInstruction; var o = other as LockInstruction;
return o != null && this.onExpression.PerformMatch(o.onExpression, ref match) && this.body.PerformMatch(o.body, ref match); return o != null && this.onExpression.PerformMatch(o.onExpression, ref match) && this.body.PerformMatch(o.body, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(onExpression.ResultType == StackType.O); DebugAssert(onExpression.ResultType == StackType.O);
} }
} }
@ -2084,9 +2084,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as UsingInstruction; var o = other as UsingInstruction;
return o != null && variable == o.variable && this.resourceExpression.PerformMatch(o.resourceExpression, ref match) && this.body.PerformMatch(o.body, ref match); return o != null && variable == o.variable && this.resourceExpression.PerformMatch(o.resourceExpression, ref match) && this.body.PerformMatch(o.body, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!)); DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!));
DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable); DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable);
DebugAssert(resourceExpression.ResultType == StackType.O); DebugAssert(resourceExpression.ResultType == StackType.O);
@ -2363,9 +2363,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as LdLoc; var o = other as LdLoc;
return o != null && variable == o.variable; return o != null && variable == o.variable;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!)); DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!));
DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable); DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable);
} }
@ -2437,9 +2437,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as LdLoca; var o = other as LdLoca;
return o != null && variable == o.variable; return o != null && variable == o.variable;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!)); DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!));
DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable); DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable);
} }
@ -3567,9 +3567,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as Cpblk; var o = other as Cpblk;
return o != null && this.destAddress.PerformMatch(o.destAddress, ref match) && this.sourceAddress.PerformMatch(o.sourceAddress, ref match) && this.size.PerformMatch(o.size, ref match) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix; return o != null && this.destAddress.PerformMatch(o.destAddress, ref match) && this.sourceAddress.PerformMatch(o.sourceAddress, ref match) && this.size.PerformMatch(o.size, ref match) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(destAddress.ResultType == StackType.I || destAddress.ResultType == StackType.Ref); DebugAssert(destAddress.ResultType == StackType.I || destAddress.ResultType == StackType.Ref);
DebugAssert(sourceAddress.ResultType == StackType.I || sourceAddress.ResultType == StackType.Ref); DebugAssert(sourceAddress.ResultType == StackType.I || sourceAddress.ResultType == StackType.Ref);
DebugAssert(size.ResultType == StackType.I4); DebugAssert(size.ResultType == StackType.I4);
@ -3718,9 +3718,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as Initblk; var o = other as Initblk;
return o != null && this.address.PerformMatch(o.address, ref match) && this.value.PerformMatch(o.value, ref match) && this.size.PerformMatch(o.size, ref match) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix; return o != null && this.address.PerformMatch(o.address, ref match) && this.value.PerformMatch(o.value, ref match) && this.size.PerformMatch(o.size, ref match) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(address.ResultType == StackType.I || address.ResultType == StackType.Ref); DebugAssert(address.ResultType == StackType.I || address.ResultType == StackType.Ref);
DebugAssert(value.ResultType == StackType.I4); DebugAssert(value.ResultType == StackType.I4);
DebugAssert(size.ResultType == StackType.I4); DebugAssert(size.ResultType == StackType.I4);
@ -4081,9 +4081,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as LdObj; var o = other as LdObj;
return o != null && this.target.PerformMatch(o.target, ref match) && type.Equals(o.type) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix; return o != null && this.target.PerformMatch(o.target, ref match) && type.Equals(o.type) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(target.ResultType == StackType.Ref || target.ResultType == StackType.I); DebugAssert(target.ResultType == StackType.Ref || target.ResultType == StackType.I);
} }
} }
@ -4191,9 +4191,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as LdObjIfRef; var o = other as LdObjIfRef;
return o != null && this.target.PerformMatch(o.target, ref match) && type.Equals(o.type); return o != null && this.target.PerformMatch(o.target, ref match) && type.Equals(o.type);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(target.ResultType == StackType.Ref || target.ResultType == StackType.I); DebugAssert(target.ResultType == StackType.Ref || target.ResultType == StackType.I);
} }
} }
@ -4330,9 +4330,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as StObj; var o = other as StObj;
return o != null && this.target.PerformMatch(o.target, ref match) && this.value.PerformMatch(o.value, ref match) && type.Equals(o.type) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix; return o != null && this.target.PerformMatch(o.target, ref match) && this.value.PerformMatch(o.value, ref match) && type.Equals(o.type) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(target.ResultType == StackType.Ref || target.ResultType == StackType.I); DebugAssert(target.ResultType == StackType.Ref || target.ResultType == StackType.I);
DebugAssert(value.ResultType == type.GetStackType()); DebugAssert(value.ResultType == type.GetStackType());
CheckTargetSlot(); CheckTargetSlot();
@ -4856,9 +4856,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as LdLen; var o = other as LdLen;
return o != null && this.array.PerformMatch(o.array, ref match); return o != null && this.array.PerformMatch(o.array, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(array.ResultType == StackType.O); DebugAssert(array.ResultType == StackType.O);
} }
} }
@ -5218,9 +5218,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as GetPinnableReference; var o = other as GetPinnableReference;
return o != null && this.argument.PerformMatch(o.argument, ref match) && object.Equals(method, o.method); return o != null && this.argument.PerformMatch(o.argument, ref match) && object.Equals(method, o.method);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(argument.ResultType == StackType.O); DebugAssert(argument.ResultType == StackType.O);
} }
} }
@ -5307,9 +5307,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as StringToInt; var o = other as StringToInt;
return o != null && this.argument.PerformMatch(o.argument, ref match); return o != null && this.argument.PerformMatch(o.argument, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(argument.ResultType == StackType.O); DebugAssert(argument.ResultType == StackType.O);
} }
} }
@ -5831,9 +5831,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as DynamicConvertInstruction; var o = other as DynamicConvertInstruction;
return o != null && type.Equals(o.type) && this.argument.PerformMatch(o.argument, ref match); return o != null && type.Equals(o.type) && this.argument.PerformMatch(o.argument, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(argument.ResultType == StackType.O); DebugAssert(argument.ResultType == StackType.O);
} }
} }
@ -5919,9 +5919,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as DynamicGetMemberInstruction; var o = other as DynamicGetMemberInstruction;
return o != null && this.target.PerformMatch(o.target, ref match); return o != null && this.target.PerformMatch(o.target, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(target.ResultType == StackType.O); DebugAssert(target.ResultType == StackType.O);
} }
} }
@ -6024,9 +6024,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as DynamicSetMemberInstruction; var o = other as DynamicSetMemberInstruction;
return o != null && this.target.PerformMatch(o.target, ref match) && this.value.PerformMatch(o.value, ref match); return o != null && this.target.PerformMatch(o.target, ref match) && this.value.PerformMatch(o.value, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(target.ResultType == StackType.O); DebugAssert(target.ResultType == StackType.O);
} }
} }
@ -6467,9 +6467,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as DynamicIsEventInstruction; var o = other as DynamicIsEventInstruction;
return o != null && this.argument.PerformMatch(o.argument, ref match); return o != null && this.argument.PerformMatch(o.argument, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(argument.ResultType == StackType.O); DebugAssert(argument.ResultType == StackType.O);
} }
} }
@ -6608,9 +6608,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as MatchInstruction; var o = other as MatchInstruction;
return o != null && variable == o.variable && object.Equals(method, o.method) && this.IsDeconstructCall == o.IsDeconstructCall && this.IsDeconstructTuple == o.IsDeconstructTuple && this.CheckType == o.CheckType && this.CheckNotNull == o.CheckNotNull && this.testedOperand.PerformMatch(o.testedOperand, ref match) && Patterns.ListMatch.DoMatch(this.SubPatterns, o.SubPatterns, ref match); return o != null && variable == o.variable && object.Equals(method, o.method) && this.IsDeconstructCall == o.IsDeconstructCall && this.IsDeconstructTuple == o.IsDeconstructTuple && this.CheckType == o.CheckType && this.CheckNotNull == o.CheckNotNull && this.testedOperand.PerformMatch(o.testedOperand, ref match) && Patterns.ListMatch.DoMatch(this.SubPatterns, o.SubPatterns, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!)); DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!));
DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable); DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable);
AdditionalInvariants(); AdditionalInvariants();
@ -6984,9 +6984,9 @@ namespace ICSharpCode.Decompiler.IL
var o = other as DeconstructResultInstruction; var o = other as DeconstructResultInstruction;
return o != null && this.Argument.PerformMatch(o.Argument, ref match); return o != null && this.Argument.PerformMatch(o.Argument, ref match);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
AdditionalInvariants(); AdditionalInvariants();
} }
} }

4
ICSharpCode.Decompiler/IL/Instructions.tt

@ -455,9 +455,9 @@ namespace <#=opCode.Namespace#>
} }
<# } #> <# } #>
<# if (opCode.Invariants.Count > 0) { #> <# if (opCode.Invariants.Count > 0) { #>
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
<# foreach (var invariant in opCode.Invariants) {#> <# foreach (var invariant in opCode.Invariants) {#>
<#=invariant#> <#=invariant#>
<# } #> <# } #>

4
ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs

@ -129,9 +129,9 @@ namespace ICSharpCode.Decompiler.IL
get => IsLifted ? StackType.O : resultType; get => IsLifted ? StackType.O : resultType;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
if (!IsLifted) if (!IsLifted)
{ {
Debug.Assert(LeftInputType == Left.ResultType); Debug.Assert(LeftInputType == Left.ResultType);

8
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -103,9 +103,9 @@ namespace ICSharpCode.Decompiler.IL
return clone; return clone;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
for (int i = 0; i < Instructions.Count - 1; i++) for (int i = 0; i < Instructions.Count - 1; i++)
{ {
// only the last instruction may have an unreachable endpoint // only the last instruction may have an unreachable endpoint
@ -358,14 +358,14 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
public void RunTransforms(IEnumerable<IBlockTransform> transforms, BlockTransformContext context) public void RunTransforms(IEnumerable<IBlockTransform> transforms, BlockTransformContext context)
{ {
this.CheckInvariant(ILPhase.Normal); this.CheckInvariant(ILPhase.Normal, context.TypeSystem);
foreach (var transform in transforms) foreach (var transform in transforms)
{ {
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
Debug.Assert(context.IndexOfFirstAlreadyTransformedInstruction <= this.Instructions.Count); Debug.Assert(context.IndexOfFirstAlreadyTransformedInstruction <= this.Instructions.Count);
context.StepStartGroup(transform.GetType().Name); context.StepStartGroup(transform.GetType().Name);
transform.Run(this, context); transform.Run(this, context);
this.CheckInvariant(ILPhase.Normal); this.CheckInvariant(ILPhase.Normal, context.TypeSystem);
context.StepEndGroup(); context.StepEndGroup();
} }
} }

5
ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs

@ -24,6 +24,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
@ -191,9 +192,9 @@ namespace ICSharpCode.Decompiler.IL
return BlockSlot; return BlockSlot;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(Blocks.Count > 0 && EntryPoint == Blocks[0]); Debug.Assert(Blocks.Count > 0 && EntryPoint == Blocks[0]);
Debug.Assert(!IsConnected || EntryPoint.IncomingEdgeCount >= 1); Debug.Assert(!IsConnected || EntryPoint.IncomingEdgeCount >= 1);
Debug.Assert(Parent is ILFunction || !ILRangeIsEmpty); Debug.Assert(Parent is ILFunction || !ILRangeIsEmpty);

6
ICSharpCode.Decompiler/IL/Instructions/Branch.cs

@ -20,6 +20,8 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary> /// <summary>
@ -108,9 +110,9 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
if (phase > ILPhase.InILReader) if (phase > ILPhase.InILReader)
{ {
Debug.Assert(targetBlock?.Parent is BlockContainer); Debug.Assert(targetBlock?.Parent is BlockContainer);

4
ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs

@ -68,9 +68,9 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType => FunctionPointerType.ReturnType.GetStackType(); public override StackType ResultType => FunctionPointerType.ReturnType.GetStackType();
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(Arguments.Count == FunctionPointerType.ParameterTypes.Length + (IsInstance ? 1 : 0)); Debug.Assert(Arguments.Count == FunctionPointerType.ParameterTypes.Length + (IsInstance ? 1 : 0));
} }

4
ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs

@ -121,9 +121,9 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
int firstArgument = (OpCode != OpCode.NewObj && !Method.IsStatic) ? 1 : 0; int firstArgument = (OpCode != OpCode.NewObj && !Method.IsStatic) ? 1 : 0;
Debug.Assert(Method.Parameters.Count + firstArgument == Arguments.Count); Debug.Assert(Method.Parameters.Count + firstArgument == Arguments.Count);
if (firstArgument == 1) if (firstArgument == 1)

4
ICSharpCode.Decompiler/IL/Instructions/Comp.cs

@ -164,9 +164,9 @@ namespace ICSharpCode.Decompiler.IL
public bool IsLifted => LiftingKind != ComparisonLiftingKind.None; public bool IsLifted => LiftingKind != ComparisonLiftingKind.None;
public StackType UnderlyingResultType => StackType.I4; public StackType UnderlyingResultType => StackType.I4;
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
if (LiftingKind == ComparisonLiftingKind.None) if (LiftingKind == ComparisonLiftingKind.None)
{ {
Debug.Assert(Left.ResultType == InputType); Debug.Assert(Left.ResultType == InputType);

4
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -79,9 +79,9 @@ namespace ICSharpCode.Decompiler.IL
CheckValidTarget(); CheckValidTarget();
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
CheckValidTarget(); CheckValidTarget();
} }

4
ICSharpCode.Decompiler/IL/Instructions/Conv.cs

@ -169,9 +169,9 @@ namespace ICSharpCode.Decompiler.IL
this.IsLifted = isLifted; this.IsLifted = isLifted;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
// Debug.Assert(Kind != ConversionKind.Invalid); // invalid conversion can happen with invalid IL/missing references // Debug.Assert(Kind != ConversionKind.Invalid); // invalid conversion can happen with invalid IL/missing references
Debug.Assert(Argument.ResultType == (IsLifted ? StackType.O : InputType)); Debug.Assert(Argument.ResultType == (IsLifted ? StackType.O : InputType));
Debug.Assert(!(IsLifted && Kind == ConversionKind.StopGCTracking)); Debug.Assert(!(IsLifted && Kind == ConversionKind.StopGCTracking));

6
ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs

@ -296,9 +296,9 @@ namespace ICSharpCode.Decompiler.IL
return null; return null;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
var patternVariables = new HashSet<ILVariable>(); var patternVariables = new HashSet<ILVariable>();
var conversionVariables = new HashSet<ILVariable>(); var conversionVariables = new HashSet<ILVariable>();
@ -323,7 +323,7 @@ namespace ICSharpCode.Decompiler.IL
foreach (var inst in assignments.Instructions) foreach (var inst in assignments.Instructions)
{ {
if (!(IsAssignment(inst, typeSystem: null, out _, out var value) && value.MatchLdLoc(out var inputVariable))) if (!(IsAssignment(inst, compilation, out _, out var value) && value.MatchLdLoc(out var inputVariable)))
throw new InvalidOperationException("inst is not an assignment!"); throw new InvalidOperationException("inst is not an assignment!");
Debug.Assert(patternVariables.Contains(inputVariable) || conversionVariables.Contains(inputVariable)); Debug.Assert(patternVariables.Contains(inputVariable) || conversionVariables.Contains(inputVariable));
} }

8
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -230,7 +230,7 @@ namespace ICSharpCode.Decompiler.IL
this.kind = kind; this.kind = kind;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
switch (kind) switch (kind)
{ {
@ -263,7 +263,7 @@ namespace ICSharpCode.Decompiler.IL
Debug.Assert(Variables[i].IndexInFunction == i); Debug.Assert(Variables[i].IndexInFunction == i);
Variables[i].CheckInvariant(); Variables[i].CheckInvariant();
} }
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
} }
void CloneVariables() void CloneVariables()
@ -401,7 +401,7 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
public void RunTransforms(IEnumerable<IILTransform> transforms, ILTransformContext context) public void RunTransforms(IEnumerable<IILTransform> transforms, ILTransformContext context)
{ {
this.CheckInvariant(ILPhase.Normal); this.CheckInvariant(ILPhase.Normal, context.TypeSystem);
bool traceTransforms = DecompilerEventSource.Log.IsTransformTracingEnabled(); bool traceTransforms = DecompilerEventSource.Log.IsTransformTracingEnabled();
foreach (var transform in transforms) foreach (var transform in transforms)
{ {
@ -421,7 +421,7 @@ namespace ICSharpCode.Decompiler.IL
transform.Run(this, context); transform.Run(this, context);
if (traceTransforms) if (traceTransforms)
DecompilerEventSource.Log.ILTransformExecuted(transform, this, traceStart); DecompilerEventSource.Log.ILTransformExecuted(transform, this, traceStart);
this.CheckInvariant(ILPhase.Normal); this.CheckInvariant(ILPhase.Normal, context.TypeSystem);
context.StepEndGroup(keepIfEmpty: true); context.StepEndGroup(keepIfEmpty: true);
} }
} }

11
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -81,9 +81,16 @@ namespace ICSharpCode.Decompiler.IL
Debug.Assert(b, msg); Debug.Assert(b, msg);
} }
/// <summary>
/// Verifies the invariants of this instruction and its descendants. Only active in debug builds.
/// </summary>
/// <param name="phase">Which set of invariants applies; they tighten as the pipeline progresses.</param>
/// <param name="compilation">The compilation the instruction tree was decoded against, so that
/// invariants involving types can be resolved against the same type system the decompiler uses.</param>
[Conditional("DEBUG")] [Conditional("DEBUG")]
internal virtual void CheckInvariant(ILPhase phase) internal virtual void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
Debug.Assert(compilation != null);
foreach (var child in Children) foreach (var child in Children)
{ {
Debug.Assert(child.Parent == this); Debug.Assert(child.Parent == this);
@ -92,7 +99,7 @@ namespace ICSharpCode.Decompiler.IL
// exception: nested ILFunctions (lambdas) // exception: nested ILFunctions (lambdas)
Debug.Assert(this is ILFunction || child.flags != invalidFlags || this.flags == invalidFlags); Debug.Assert(this is ILFunction || child.flags != invalidFlags || this.flags == invalidFlags);
Debug.Assert(child.IsConnected == this.IsConnected); Debug.Assert(child.IsConnected == this.IsConnected);
child.CheckInvariant(phase); child.CheckInvariant(phase, compilation);
} }
Debug.Assert((this.DirectFlags & ~this.Flags) == 0, "All DirectFlags must also appear in this.Flags"); Debug.Assert((this.DirectFlags & ~this.Flags) == 0, "All DirectFlags must also appear in this.Flags");
} }

6
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -19,6 +19,8 @@
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary>If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c></summary> /// <summary>If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c></summary>
@ -53,9 +55,9 @@ namespace ICSharpCode.Decompiler.IL
return new IfInstruction(lhs, new LdcI4(1), rhs); return new IfInstruction(lhs, new LdcI4(1), rhs);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(condition.ResultType == StackType.I4); Debug.Assert(condition.ResultType == StackType.I4);
Debug.Assert(trueInst.ResultType == falseInst.ResultType Debug.Assert(trueInst.ResultType == falseInst.ResultType
|| trueInst.HasDirectFlag(InstructionFlags.EndPointUnreachable) || trueInst.HasDirectFlag(InstructionFlags.EndPointUnreachable)

6
ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs

@ -19,13 +19,15 @@
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
public sealed partial class LdFlda public sealed partial class LdFlda
{ {
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
switch (field.DeclaringType.IsReferenceType) switch (field.DeclaringType.IsReferenceType)
{ {
case true: case true:

6
ICSharpCode.Decompiler/IL/Instructions/Leave.cs

@ -19,6 +19,8 @@
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary> /// <summary>
@ -106,9 +108,9 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(targetContainer!)); Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(targetContainer!));
Debug.Assert(phase <= ILPhase.InILReader || phase == ILPhase.InAsyncAwait || value.ResultType == targetContainer!.ResultType); Debug.Assert(phase <= ILPhase.InILReader || phase == ILPhase.InAsyncAwait || value.ResultType == targetContainer!.ResultType);
} }

10
ICSharpCode.Decompiler/IL/Instructions/LogicInstructions.cs

@ -19,6 +19,8 @@
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
// Note: The comp instruction also supports three-valued logic via ComparisonLiftingKind.ThreeValuedLogic. // Note: The comp instruction also supports three-valued logic via ComparisonLiftingKind.ThreeValuedLogic.
@ -29,9 +31,9 @@ namespace ICSharpCode.Decompiler.IL
bool ILiftableInstruction.IsLifted => true; bool ILiftableInstruction.IsLifted => true;
StackType ILiftableInstruction.UnderlyingResultType => StackType.I4; StackType ILiftableInstruction.UnderlyingResultType => StackType.I4;
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(Left.ResultType == StackType.I4 || Left.ResultType == StackType.O); Debug.Assert(Left.ResultType == StackType.I4 || Left.ResultType == StackType.O);
} }
} }
@ -41,9 +43,9 @@ namespace ICSharpCode.Decompiler.IL
bool ILiftableInstruction.IsLifted => true; bool ILiftableInstruction.IsLifted => true;
StackType ILiftableInstruction.UnderlyingResultType => StackType.I4; StackType ILiftableInstruction.UnderlyingResultType => StackType.I4;
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(Left.ResultType == StackType.I4 || Left.ResultType == StackType.O); Debug.Assert(Left.ResultType == StackType.I4 || Left.ResultType == StackType.O);
} }
} }

6
ICSharpCode.Decompiler/IL/Instructions/NullCoalescingInstruction.cs

@ -19,6 +19,8 @@
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary> /// <summary>
@ -63,9 +65,9 @@ namespace ICSharpCode.Decompiler.IL
this.FallbackInst = fallbackInst; this.FallbackInst = fallbackInst;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(valueInst.ResultType == StackType.O); // lhs is reference type or nullable type Debug.Assert(valueInst.ResultType == StackType.O); // lhs is reference type or nullable type
Debug.Assert(fallbackInst.ResultType == StackType.O || Kind == NullCoalescingKind.NullableWithValueFallback); Debug.Assert(fallbackInst.ResultType == StackType.O || Kind == NullCoalescingKind.NullableWithValueFallback);
Debug.Assert(ResultType == UnderlyingResultType || Kind == NullCoalescingKind.Nullable); Debug.Assert(ResultType == UnderlyingResultType || Kind == NullCoalescingKind.Nullable);

9
ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs

@ -21,6 +21,7 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
@ -76,9 +77,9 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
if (this.RefInput) if (this.RefInput)
{ {
Debug.Assert(Argument.ResultType == StackType.Ref, "nullable.unwrap expects reference to nullable type as input"); Debug.Assert(Argument.ResultType == StackType.Ref, "nullable.unwrap expects reference to nullable type as input");
@ -108,9 +109,9 @@ namespace ICSharpCode.Decompiler.IL
partial class NullableRewrap partial class NullableRewrap
{ {
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(Argument.HasFlag(InstructionFlags.MayUnwrapNull)); Debug.Assert(Argument.HasFlag(InstructionFlags.MayUnwrapNull));
} }

6
ICSharpCode.Decompiler/IL/Instructions/StLoc.cs

@ -19,6 +19,8 @@
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
partial class StLoc partial class StLoc
@ -36,9 +38,9 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
internal bool ILStackWasEmpty; internal bool ILStackWasEmpty;
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!)); Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!));
Debug.Assert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable); Debug.Assert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable);
Debug.Assert(value.ResultType == variable.StackType); Debug.Assert(value.ResultType == variable.StackType);

4
ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs

@ -152,9 +152,9 @@ namespace ICSharpCode.Decompiler.IL
this.resultType = resultType; this.resultType = resultType;
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
bool expectNullSection = this.IsLifted; bool expectNullSection = this.IsLifted;
LongSet sets = LongSet.Empty; LongSet sets = LongSet.Empty;
foreach (var section in Sections) foreach (var section in Sections)

5
ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs

@ -21,6 +21,7 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
@ -140,9 +141,9 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
partial class TryCatchHandler partial class TryCatchHandler
{ {
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(Parent is TryCatch); Debug.Assert(Parent is TryCatch);
Debug.Assert(filter.ResultType == StackType.I4); Debug.Assert(filter.ResultType == StackType.I4);
Debug.Assert(this.IsDescendantOf(variable.Function!)); Debug.Assert(this.IsDescendantOf(variable.Function!));

6
ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs

@ -19,6 +19,8 @@
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
partial class BitNot : ILiftableInstruction partial class BitNot : ILiftableInstruction
@ -43,9 +45,9 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase, ICompilation compilation)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase, compilation);
Debug.Assert(IsLifted == (ResultType == StackType.O)); Debug.Assert(IsLifted == (ResultType == StackType.O));
Debug.Assert(IsLifted || ResultType == UnderlyingResultType); Debug.Assert(IsLifted || ResultType == UnderlyingResultType);
} }

2
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -199,7 +199,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// Embed the lambda into the parent function's ILAst, so that "Show steps" can show // Embed the lambda into the parent function's ILAst, so that "Show steps" can show
// how the lambda body is being transformed. // how the lambda body is being transformed.
value.ReplaceWith(function); value.ReplaceWith(function);
function.CheckInvariant(ILPhase.Normal); function.CheckInvariant(ILPhase.Normal, context.TypeSystem);
var contextPrefix = targetMethod.Name; var contextPrefix = targetMethod.Name;
foreach (ILVariable v in function.Variables.Where(v => v.Kind != VariableKind.Parameter)) foreach (ILVariable v in function.Variables.Where(v => v.Kind != VariableKind.Parameter))

2
ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
/// <summary> /// <summary>
/// If possible, transforms plain ILAst loops into while (condition), do-while and for-loops. /// If possible, transforms plain ILAst loops into while (condition), do-while and for-loops.
/// For the invariants of the transforms <see cref="BlockContainer.CheckInvariant(ILPhase)"/>. /// For the invariants of the transforms <see cref="BlockContainer.CheckInvariant(ILPhase, TypeSystem.ICompilation)"/>.
/// </summary> /// </summary>
public class HighLevelLoopTransform : IILTransform public class HighLevelLoopTransform : IILTransform
{ {

2
ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs

@ -487,7 +487,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (hasBody) if (hasBody)
{ {
function.DeclarationScope = (BlockContainer)rootFunction.Body; function.DeclarationScope = (BlockContainer)rootFunction.Body;
function.CheckInvariant(ILPhase.Normal); function.CheckInvariant(ILPhase.Normal, context.TypeSystem);
var nestedContext = new ILTransformContext(context, function); var nestedContext = new ILTransformContext(context, function);
function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is LocalFunctionDecompiler)), nestedContext); function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is LocalFunctionDecompiler)), nestedContext);
function.DeclarationScope = null; function.DeclarationScope = null;

2
ICSharpCode.Decompiler/IL/Transforms/StatementTransform.cs

@ -139,7 +139,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
transform.Run(block, pos, ctx); transform.Run(block, pos, ctx);
#if DEBUG #if DEBUG
block.Instructions[pos].CheckInvariant(ILPhase.Normal); block.Instructions[pos].CheckInvariant(ILPhase.Normal, context.TypeSystem);
for (int i = Math.Max(0, pos - 100); i < pos; ++i) for (int i = Math.Max(0, pos - 100); i < pos; ++i)
{ {
if (block.Instructions[i].IsDirty) if (block.Instructions[i].IsDirty)

2
doc/DecompilerArchitecture.html

@ -751,7 +751,7 @@ matching is cheap. (See also <span class="filecite">doc/ILAst Pattern Matching.m
<h3>5.6 Invariants</h3> <h3>5.6 Invariants</h3>
<p><code>CheckInvariant(ILPhase)</code> verifies parent/child consistency, flag correctness, and <p><code>CheckInvariant(ILPhase, ICompilation)</code> verifies parent/child consistency, flag correctness, and
connectedness. The phase parameter exists because invariants tighten over time: in connectedness. The phase parameter exists because invariants tighten over time: in
<code>ILPhase.InILReader</code>, branches may still point at offsets; from <code>ILPhase.InILReader</code>, branches may still point at offsets; from
<code>ILPhase.Normal</code> on, the full rules apply. <code>ILFunction.RunTransforms</code> checks the <code>ILPhase.Normal</code> on, the full rules apply. <code>ILFunction.RunTransforms</code> checks the

Loading…
Cancel
Save