Browse Source

Initial version of IL pattern matching.

pull/728/merge
Daniel Grunwald 9 years ago
parent
commit
14815abd7c
  1. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  2. 300
      ICSharpCode.Decompiler/IL/Instructions.cs
  3. 50
      ICSharpCode.Decompiler/IL/Instructions.tt
  4. 8
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  5. 9
      ICSharpCode.Decompiler/IL/Instructions/Comp.cs
  6. 52
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  7. 2
      ICSharpCode.Decompiler/IL/Instructions/InstructionCollection.cs
  8. 175
      ICSharpCode.Decompiler/IL/Patterns/ListMatch.cs
  9. 100
      ICSharpCode.Decompiler/IL/Patterns/Match.cs
  10. 1
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -123,6 +123,8 @@ @@ -123,6 +123,8 @@
<Compile Include="IL\Instructions\UnaryInstruction.cs" />
<Compile Include="IL\IInlineContext.cs" />
<Compile Include="IL\Instructions\VariableScope.cs" />
<Compile Include="IL\Patterns\ListMatch.cs" />
<Compile Include="IL\Patterns\Match.cs" />
<Compile Include="IL\SlotInfo.cs" />
<Compile Include="IL\Transforms\CopyPropagation.cs" />
<Compile Include="IL\Transforms\IILTransform.cs" />
@ -204,6 +206,7 @@ @@ -204,6 +206,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="ILAst\" />
<Folder Include="IL\Patterns" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Target Name="BeforeBuild">

300
ICSharpCode.Decompiler/IL/Instructions.cs

@ -447,6 +447,11 @@ namespace ICSharpCode.Decompiler.IL @@ -447,6 +447,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitInvalidInstruction(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as InvalidInstruction;
return o != null;
}
}
/// <summary>No operation. Takes 0 arguments and returns void.</summary>
@ -464,6 +469,11 @@ namespace ICSharpCode.Decompiler.IL @@ -464,6 +469,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitNop(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Nop;
return o != null;
}
}
/// <summary>A container of IL blocks.</summary>
@ -526,6 +536,11 @@ namespace ICSharpCode.Decompiler.IL @@ -526,6 +536,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitILFunction(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as ILFunction;
return o != null && this.body.PerformMatch(o.body, ref match);
}
}
/// <summary>A container of IL blocks.</summary>
@ -540,6 +555,11 @@ namespace ICSharpCode.Decompiler.IL @@ -540,6 +555,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitBlockContainer(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as BlockContainer;
return o != null && Patterns.ListMatch.DoMatch(this.Blocks, o.Blocks, ref match);
}
}
/// <summary>A block of IL instructions.</summary>
@ -554,6 +574,11 @@ namespace ICSharpCode.Decompiler.IL @@ -554,6 +574,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitBlock(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Block;
return o != null && this.Type == o.Type && Patterns.ListMatch.DoMatch(this.Instructions, o.Instructions, ref match) && this.FinalInstruction.PerformMatch(o.FinalInstruction, ref match);
}
}
/// <summary>A region where a pinned variable is used (initial representation of future fixed statement).</summary>
@ -688,6 +713,11 @@ namespace ICSharpCode.Decompiler.IL @@ -688,6 +713,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitPinnedRegion(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
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);
}
}
/// <summary>Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).</summary>
@ -705,6 +735,11 @@ namespace ICSharpCode.Decompiler.IL @@ -705,6 +735,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLogicNot(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LogicNot;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
/// <summary>Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.</summary>
@ -719,6 +754,11 @@ namespace ICSharpCode.Decompiler.IL @@ -719,6 +754,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitBinaryNumericInstruction(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as BinaryNumericInstruction;
return o != null && this.Left.PerformMatch(o.Left, ref match) && this.Right.PerformMatch(o.Right, ref match) && CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator;
}
}
/// <summary>Common instruction for compound assignments.</summary>
@ -800,6 +840,11 @@ namespace ICSharpCode.Decompiler.IL @@ -800,6 +840,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitCompoundAssignmentInstruction(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as CompoundAssignmentInstruction;
return o != null && this.target.PerformMatch(o.target, ref match) && this.value.PerformMatch(o.value, ref match);
}
}
/// <summary>Bitwise NOT</summary>
@ -817,6 +862,11 @@ namespace ICSharpCode.Decompiler.IL @@ -817,6 +862,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitBitNot(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as BitNot;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
/// <summary>Retrieves the RuntimeArgumentHandle.</summary>
@ -834,6 +884,11 @@ namespace ICSharpCode.Decompiler.IL @@ -834,6 +884,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitArglist(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Arglist;
return o != null;
}
}
/// <summary>Unconditional branch. <c>goto target;</c></summary>
@ -848,6 +903,11 @@ namespace ICSharpCode.Decompiler.IL @@ -848,6 +903,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitBranch(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Branch;
return o != null && this.TargetBlock == o.TargetBlock;
}
}
/// <summary>Unconditional branch to end of block container. <c>goto container_end;</c>, often <c>break;</c></summary>
@ -862,6 +922,11 @@ namespace ICSharpCode.Decompiler.IL @@ -862,6 +922,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLeave(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Leave;
return o != null;
}
}
/// <summary>If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c></summary>
@ -956,6 +1021,11 @@ namespace ICSharpCode.Decompiler.IL @@ -956,6 +1021,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitIfInstruction(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as IfInstruction;
return o != null && this.condition.PerformMatch(o.condition, ref match) && this.trueInst.PerformMatch(o.trueInst, ref match) && this.falseInst.PerformMatch(o.falseInst, ref match);
}
}
/// <summary>Switch statement</summary>
@ -970,6 +1040,11 @@ namespace ICSharpCode.Decompiler.IL @@ -970,6 +1040,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitSwitchInstruction(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as SwitchInstruction;
return o != null;
}
}
/// <summary>Switch section within a switch statement</summary>
@ -1031,6 +1106,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1031,6 +1106,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitSwitchSection(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as SwitchSection;
return o != null && this.body.PerformMatch(o.body, ref match);
}
}
/// <summary>Try-catch statement.</summary>
@ -1045,6 +1125,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1045,6 +1125,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitTryCatch(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as TryCatch;
return o != null;
}
}
/// <summary>Catch handler within a try-catch statement.</summary>
@ -1153,6 +1238,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1153,6 +1238,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitTryCatchHandler(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as TryCatchHandler;
return o != null && this.filter.PerformMatch(o.filter, ref match) && this.body.PerformMatch(o.body, ref match) && variable == o.variable;
}
}
/// <summary>Try-finally statement</summary>
@ -1167,6 +1257,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1167,6 +1257,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitTryFinally(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as TryFinally;
return o != null;
}
}
/// <summary>Try-fault statement</summary>
@ -1181,6 +1276,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1181,6 +1276,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitTryFault(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as TryFault;
return o != null;
}
}
/// <summary>Breakpoint instruction</summary>
@ -1207,6 +1307,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1207,6 +1307,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitDebugBreak(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as DebugBreak;
return o != null;
}
}
/// <summary>Comparison. The inputs must be both integers; or both floats; or both object references. Object references can only be compared for equality or inequality. Floating-point comparisons evaluate to 0 (false) when an input is NaN, except for 'NaN != NaN' which evaluates to 1 (true).</summary>
@ -1221,6 +1326,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1221,6 +1326,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitComp(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Comp;
return o != null && this.Left.PerformMatch(o.Left, ref match) && this.Right.PerformMatch(o.Right, ref match) && this.Kind == o.Kind;
}
}
/// <summary>Non-virtual method call.</summary>
@ -1281,6 +1391,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1281,6 +1391,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitCkfinite(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Ckfinite;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
/// <summary>Numeric cast.</summary>
@ -1295,6 +1410,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1295,6 +1410,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitConv(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Conv;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
/// <summary>Loads the value of a local variable. (ldarg/ldloc)</summary>
@ -1358,6 +1478,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1358,6 +1478,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdLoc(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdLoc;
return o != null && variable == o.variable;
}
}
/// <summary>Loads the address of a local variable. (ldarga/ldloca)</summary>
@ -1412,6 +1537,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1412,6 +1537,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdLoca(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdLoca;
return o != null && variable == o.variable;
}
}
/// <summary>Stores a value into a local variable. (starg/stloc)</summary>
@ -1526,6 +1656,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1526,6 +1656,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitStLoc(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as StLoc;
return o != null && variable == o.variable && this.value.PerformMatch(o.value, ref match);
}
}
/// <summary>Stores the value into an anonymous temporary variable, and returns the address of that variable.</summary>
@ -1607,6 +1742,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1607,6 +1742,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitAddressOf(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as AddressOf;
return o != null && this.value.PerformMatch(o.value, ref match);
}
}
/// <summary>Loads a constant string.</summary>
@ -1632,6 +1772,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1632,6 +1772,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdStr(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdStr;
return o != null && this.Value == o.Value;
}
}
/// <summary>Loads a constant 32-bit integer.</summary>
@ -1657,6 +1802,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1657,6 +1802,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdcI4(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdcI4;
return o != null && this.Value == o.Value;
}
}
/// <summary>Loads a constant 64-bit integer.</summary>
@ -1682,6 +1832,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1682,6 +1832,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdcI8(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdcI8;
return o != null && this.Value == o.Value;
}
}
/// <summary>Loads a constant floating-point number.</summary>
@ -1707,6 +1862,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1707,6 +1862,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdcF(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdcF;
return o != null && this.Value == o.Value;
}
}
/// <summary>Loads a constant decimal.</summary>
@ -1732,6 +1892,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1732,6 +1892,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdcDecimal(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdcDecimal;
return o != null && this.Value == o.Value;
}
}
/// <summary>Loads the null reference.</summary>
@ -1749,6 +1914,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1749,6 +1914,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdNull(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdNull;
return o != null;
}
}
/// <summary>Load method pointer</summary>
@ -1776,6 +1946,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1776,6 +1946,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdFtn(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdFtn;
return o != null && method.Equals(o.method);
}
}
/// <summary>Load method pointer</summary>
@ -1815,6 +1990,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1815,6 +1990,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdVirtFtn(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdVirtFtn;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && method.Equals(o.method);
}
}
/// <summary>Loads runtime representation of metadata token</summary>
@ -1842,6 +2022,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1842,6 +2022,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdTypeToken(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdTypeToken;
return o != null && type.Equals(o.type);
}
}
/// <summary>Loads runtime representation of metadata token</summary>
@ -1869,6 +2054,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1869,6 +2054,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdMemberToken(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdMemberToken;
return o != null && member.Equals(o.member);
}
}
/// <summary>Allocates space in the stack frame</summary>
@ -1895,6 +2085,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1895,6 +2085,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLocAlloc(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LocAlloc;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
/// <summary>Returns from the current method or lambda.</summary>
@ -1909,6 +2104,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1909,6 +2104,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitReturn(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Return;
return o != null;
}
}
/// <summary>Load address of instance field</summary>
@ -1997,6 +2197,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1997,6 +2197,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdFlda(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdFlda;
return o != null && this.target.PerformMatch(o.target, ref match) && field.Equals(o.field);
}
}
/// <summary>Load static field address</summary>
@ -2024,6 +2229,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2024,6 +2229,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdsFlda(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdsFlda;
return o != null && field.Equals(o.field);
}
}
/// <summary>Casts an object to a class.</summary>
@ -2063,6 +2273,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2063,6 +2273,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitCastClass(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as CastClass;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
/// <summary>Test if object is instance of class or interface.</summary>
@ -2093,6 +2308,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2093,6 +2308,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitIsInst(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as IsInst;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
/// <summary>Indirect load (ref/pointer dereference).</summary>
@ -2188,6 +2408,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2188,6 +2408,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdObj(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
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;
}
}
/// <summary>Indirect store (store to ref/pointer).</summary>
@ -2303,6 +2528,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2303,6 +2528,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitStObj(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
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;
}
}
/// <summary>Boxes a value.</summary>
@ -2342,6 +2572,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2342,6 +2572,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitBox(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Box;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
/// <summary>Compute address inside box.</summary>
@ -2381,6 +2616,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2381,6 +2616,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitUnbox(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Unbox;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
/// <summary>Unbox a value.</summary>
@ -2420,6 +2660,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2420,6 +2660,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitUnboxAny(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as UnboxAny;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
/// <summary>Creates an object instance and calls the constructor.</summary>
@ -2517,6 +2762,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2517,6 +2762,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitNewArr(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as NewArr;
return o != null && type.Equals(o.type);
}
}
/// <summary>Returns the default value for a type.</summary>
@ -2544,6 +2794,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2544,6 +2794,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitDefaultValue(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as DefaultValue;
return o != null && type.Equals(o.type);
}
}
/// <summary>Throws an exception.</summary>
@ -2570,6 +2825,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2570,6 +2825,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitThrow(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Throw;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
/// <summary>Rethrows the current exception.</summary>
@ -2596,6 +2856,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2596,6 +2856,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitRethrow(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Rethrow;
return o != null;
}
}
/// <summary>Gets the size of a type in bytes.</summary>
@ -2623,6 +2888,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2623,6 +2888,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitSizeOf(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as SizeOf;
return o != null && type.Equals(o.type);
}
}
/// <summary>Returns the length of an array as 'native unsigned int'.</summary>
@ -2692,6 +2962,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2692,6 +2962,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdLen(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdLen;
return o != null && this.array.PerformMatch(o.array, ref match);
}
}
/// <summary>Load address of array element.</summary>
@ -2795,6 +3070,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2795,6 +3070,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitLdElema(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdElema;
return o != null && type.Equals(o.type) && this.array.PerformMatch(o.array, ref match) && IsReadOnly == o.IsReadOnly;
}
}
/// <summary>Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty.
@ -2877,6 +3157,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2877,6 +3157,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitArrayToPointer(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as ArrayToPointer;
return o != null && this.array.PerformMatch(o.array, ref match);
}
}
/// <summary>Push a typed reference of type class onto the stack.</summary>
@ -2907,6 +3192,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2907,6 +3192,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitMakeRefAny(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as MakeRefAny;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
/// <summary>Push the type token stored in a typed reference.</summary>
@ -2924,6 +3214,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2924,6 +3214,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitRefAnyType(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as RefAnyType;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
/// <summary>Push the address stored in a typed reference.</summary>
@ -2963,6 +3258,11 @@ namespace ICSharpCode.Decompiler.IL @@ -2963,6 +3258,11 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.VisitRefAnyValue(this);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as RefAnyValue;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}

50
ICSharpCode.Decompiler/IL/Instructions.tt

@ -46,9 +46,13 @@ @@ -46,9 +46,13 @@
}), CustomConstructor, CustomWriteTo, CustomComputeFlags, CustomVariableName("function"), ResultType("O")
) { BaseClass = "ILVariableScope" },
new OpCode("BlockContainer", "A container of IL blocks.",
VoidResult, CustomConstructor, CustomVariableName("container")),
VoidResult, CustomConstructor, CustomVariableName("container"),
MatchCondition("Patterns.ListMatch.DoMatch(this.Blocks, o.Blocks, ref match)")),
new OpCode("Block", "A block of IL instructions.",
CustomConstructor, CustomVariableName("block")),
CustomConstructor, CustomVariableName("block"),
MatchCondition("this.Type == o.Type"),
MatchCondition("Patterns.ListMatch.DoMatch(this.Instructions, o.Instructions, ref match)"),
MatchCondition("this.FinalInstruction.PerformMatch(o.FinalInstruction, ref match)")),
new OpCode("PinnedRegion", "A region where a pinned variable is used (initial representation of future fixed statement).",
ResultType("Void"),
HasVariableOperand("Store"),
@ -59,14 +63,16 @@ @@ -59,14 +63,16 @@
new OpCode("logic.not", "Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).",
ResultType("I4"), Unary),
new OpCode("binary", "Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.",
CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags),
CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags,
MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator")),
new OpCode("compound", "Common instruction for compound assignments.",
CustomClassName("CompoundAssignmentInstruction"), CustomConstructor, CustomComputeFlags,
MayThrow, CustomArguments("target", "value"), HasTypeOperand, ResultType("type.GetStackType()"), CustomWriteTo),
new OpCode("bit.not", "Bitwise NOT", Unary),
new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
new OpCode("br", "Unconditional branch. <c>goto target;</c>",
CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags),
CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags,
MatchCondition("this.TargetBlock == o.TargetBlock")),
new OpCode("leave", "Unconditional branch to end of block container. <c>goto container_end;</c>, often <c>break;</c>",
NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags),
new OpCode("if", "If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c>",
@ -98,7 +104,8 @@ @@ -98,7 +104,8 @@
+ "Object references can only be compared for equality or inequality. "
+ "Floating-point comparisons evaluate to 0 (false) when an input is NaN, except for 'NaN != NaN' which "
+ "evaluates to 1 (true).",
Binary, CustomConstructor, CustomWriteTo, ResultType("I4")),
Binary, CustomConstructor, CustomWriteTo, ResultType("I4"),
MatchCondition("this.Kind == o.Kind")),
new OpCode("call", "Non-virtual method call.", Call),
new OpCode("callvirt", "Virtual method call.",
CustomClassName("CallVirt"), Call),
@ -247,6 +254,13 @@ namespace ICSharpCode.Decompiler.IL @@ -247,6 +254,13 @@ namespace ICSharpCode.Decompiler.IL
{
return visitor.Visit<#=opCode.Name#>(this);
}
<# } #>
<# if (opCode.GeneratePerformMatch) { #>
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as <#=opCode.Name#>;
return <#=string.Join(" && ", opCode.PerformMatchConditions)#>;
}
<# } #>
}
@ -387,7 +401,9 @@ namespace ICSharpCode.Decompiler.IL @@ -387,7 +401,9 @@ namespace ICSharpCode.Decompiler.IL
public List<string> ConstructorBody = new List<string>();
public bool GenerateMatch = true;
public bool GeneratePerformMatch = true;
public List<MatchParamInfo> MatchParameters = new List<MatchParamInfo>();
public List<string> PerformMatchConditions = new List<string>() { "o != null" };
public string BaseClass = "ILInstruction";
public List<string> Interfaces = new List<string>();
@ -401,6 +417,7 @@ namespace ICSharpCode.Decompiler.IL @@ -401,6 +417,7 @@ namespace ICSharpCode.Decompiler.IL
public bool GenerateAcceptVisitor = true;
public bool GenerateWriteTo = false;
public List<string> WriteOpCodePrefix = new List<string>();
public List<string> WriteOpCodeSuffix = new List<string>();
@ -457,6 +474,14 @@ namespace ICSharpCode.Decompiler.IL @@ -457,6 +474,14 @@ namespace ICSharpCode.Decompiler.IL
opCode.GenerateComputeFlags = false;
};
// Call trait: the instruction performs a method call
static Action<OpCode> MatchCondition(string name)
{
return opCode => {
opCode.PerformMatchConditions.Add(name);
};
}
static Action<OpCode> HasFlag(string name)
{
return opCode => {
@ -523,6 +548,7 @@ namespace ICSharpCode.Decompiler.IL @@ -523,6 +548,7 @@ namespace ICSharpCode.Decompiler.IL
BaseClass("UnaryInstruction")(opCode);
opCode.ConstructorParameters.Add("ILInstruction argument");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILInstruction", Name = "argument", FieldName = "Argument" });
opCode.PerformMatchConditions.Add("this.Argument.PerformMatch(o.Argument, ref match)");
opCode.BaseConstructorArguments.Add("argument");
opCode.WriteArguments.Add("output.Write('(');");
opCode.WriteArguments.Add("Argument.WriteTo(output);");
@ -538,6 +564,8 @@ namespace ICSharpCode.Decompiler.IL @@ -538,6 +564,8 @@ namespace ICSharpCode.Decompiler.IL
opCode.BaseConstructorArguments.Add("right");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILInstruction", Name = "left", FieldName = "Left" });
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILInstruction", Name = "right", FieldName = "Right" });
opCode.PerformMatchConditions.Add("this.Left.PerformMatch(o.Left, ref match)");
opCode.PerformMatchConditions.Add("this.Right.PerformMatch(o.Right, ref match)");
opCode.WriteArguments.Add("output.Write('(');");
opCode.WriteArguments.Add("Left.WriteTo(output);");
opCode.WriteArguments.Add("output.Write(\", \");");
@ -619,6 +647,7 @@ namespace ICSharpCode.Decompiler.IL @@ -619,6 +647,7 @@ namespace ICSharpCode.Decompiler.IL
opCode.ConstructorParameters.Add("ILInstruction " + arg);
opCode.ConstructorBody.Add("this." + argProp + " = " + arg + ";");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILInstruction", Name = arg, FieldName = argProp });
opCode.PerformMatchConditions.Add("this." + arg + ".PerformMatch(o." + arg + ", ref match)");
if (i > 0)
opCode.WriteArguments.Add("output.Write(\", \");");
opCode.WriteArguments.Add("this." + arg + ".WriteTo(output);");
@ -731,6 +760,7 @@ namespace ICSharpCode.Decompiler.IL @@ -731,6 +760,7 @@ namespace ICSharpCode.Decompiler.IL
opCode.ConstructorParameters.Add("OpCode opCode");
opCode.BaseConstructorArguments.Add("opCode");
opCode.GenerateMatch = false;
opCode.GeneratePerformMatch = false;
};
// SideEffect trait: the instruction has a non-local side effect
@ -743,6 +773,7 @@ namespace ICSharpCode.Decompiler.IL @@ -743,6 +773,7 @@ namespace ICSharpCode.Decompiler.IL
opCode.ConstructorParameters.Add("IMethod method");
opCode.BaseConstructorArguments.Add("method");
opCode.GenerateMatch = false;
opCode.GeneratePerformMatch = false;
};
// HasVariableOperand trait: the instruction refers to a local variable
@ -754,6 +785,7 @@ namespace ICSharpCode.Decompiler.IL @@ -754,6 +785,7 @@ namespace ICSharpCode.Decompiler.IL
opCode.ConstructorBody.Add("Debug.Assert(variable != null);");
opCode.ConstructorBody.Add("this.variable = variable;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILVariable", Name = "variable", FieldName = "Variable" });
opCode.PerformMatchConditions.Add("variable == o.variable");
opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("output.Write(' ');");
opCode.WriteOperand.Add("variable.WriteTo(output);");
@ -805,6 +837,7 @@ protected override void Disconnected() @@ -805,6 +837,7 @@ protected override void Disconnected()
opCode.Members.Add("readonly IField field;");
opCode.ConstructorBody.Add("this.field = field;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "IField", Name = "field", FieldName = "Field" });
opCode.PerformMatchConditions.Add("field.Equals(o.field)");
opCode.Members.Add("/// <summary>Returns the field operand.</summary>" + Environment.NewLine
+ "public IField Field { get { return field; } }");
opCode.GenerateWriteTo = true;
@ -818,6 +851,7 @@ protected override void Disconnected() @@ -818,6 +851,7 @@ protected override void Disconnected()
opCode.Members.Add("readonly IType type;");
opCode.ConstructorBody.Add("this.type = type;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "IType", Name = "type", FieldName = "Type" });
opCode.PerformMatchConditions.Add("type.Equals(o.type)");
opCode.Members.Add("/// <summary>Returns the type operand.</summary>" + Environment.NewLine
+ "public IType Type { get { return type; } }");
opCode.GenerateWriteTo = true;
@ -830,6 +864,7 @@ protected override void Disconnected() @@ -830,6 +864,7 @@ protected override void Disconnected()
opCode.Members.Add("readonly IMethod method;");
opCode.ConstructorBody.Add("this.method = method;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "IMethod", Name = "method", FieldName = "Method" });
opCode.PerformMatchConditions.Add("method.Equals(o.method)");
opCode.Members.Add("/// <summary>Returns the method operand.</summary>" + Environment.NewLine
+ "public IMethod Method { get { return method; } }");
opCode.GenerateWriteTo = true;
@ -843,6 +878,7 @@ protected override void Disconnected() @@ -843,6 +878,7 @@ protected override void Disconnected()
opCode.Members.Add("readonly IMember member;");
opCode.ConstructorBody.Add("this.member = member;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "IMember", Name = "member", FieldName = "Member" });
opCode.PerformMatchConditions.Add("member.Equals(o.member)");
opCode.Members.Add("/// <summary>Returns the token operand.</summary>" + Environment.NewLine
+ "public IMember Member { get { return member; } }");
opCode.GenerateWriteTo = true;
@ -857,6 +893,7 @@ protected override void Disconnected() @@ -857,6 +893,7 @@ protected override void Disconnected()
NoArguments(opCode);
opCode.ConstructorParameters.Add(operandType + " value");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = operandType, Name = "value", FieldName = "Value" });
opCode.PerformMatchConditions.Add("this.Value == o.Value");
opCode.Members.Add("public readonly " + operandType + " Value;");
opCode.ConstructorBody.Add("this.Value = value;");
opCode.GenerateWriteTo = true;
@ -871,6 +908,7 @@ protected override void Disconnected() @@ -871,6 +908,7 @@ protected override void Disconnected()
+ "public bool IsVolatile { get; set; }");
opCode.GenerateWriteTo = true;
opCode.WriteOpCodePrefix.Add("if (IsVolatile)" + Environment.NewLine + "\toutput.Write(\"volatile.\");");
opCode.PerformMatchConditions.Add("IsVolatile == o.IsVolatile");
};
static Action<OpCode> SupportsUnalignedPrefix = opCode => {
@ -879,6 +917,7 @@ protected override void Disconnected() @@ -879,6 +917,7 @@ protected override void Disconnected()
+ "public byte UnalignedPrefix { get; set; }");
opCode.GenerateWriteTo = true;
opCode.WriteOpCodePrefix.Add("if (UnalignedPrefix > 0)" + Environment.NewLine + "\toutput.Write(\"unaligned(\" + UnalignedPrefix + \").\");");
opCode.PerformMatchConditions.Add("UnalignedPrefix == o.UnalignedPrefix");
};
static Action<OpCode> SupportsReadonlyPrefix = opCode => {
@ -886,5 +925,6 @@ protected override void Disconnected() @@ -886,5 +925,6 @@ protected override void Disconnected()
+ "public bool IsReadOnly { get; set; }");
opCode.GenerateWriteTo = true;
opCode.WriteOpCodePrefix.Add("if (IsReadOnly)" + Environment.NewLine + "\toutput.Write(\"readonly.\");");
opCode.PerformMatchConditions.Add("IsReadOnly == o.IsReadOnly");
};
#>

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

@ -91,5 +91,13 @@ namespace ICSharpCode.Decompiler.IL @@ -91,5 +91,13 @@ namespace ICSharpCode.Decompiler.IL
}
output.Write(')');
}
protected internal sealed override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
CallInstruction o = other as CallInstruction;
return o != null && this.OpCode == o.OpCode && this.Method.Equals(o.Method) && this.IsTail == o.IsTail
&& object.Equals(this.ConstrainedTo, o.ConstrainedTo)
&& Patterns.ListMatch.DoMatch(this.Arguments, o.Arguments, ref match);
}
}
}

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

@ -97,17 +97,11 @@ namespace ICSharpCode.Decompiler.IL @@ -97,17 +97,11 @@ namespace ICSharpCode.Decompiler.IL
}
}
StackType inputType;
/// <summary>
/// Gets the stack type of the comparison inputs.
/// </summary>
public StackType InputType {
get { return inputType; }
set {
inputType = value;
MakeDirty();
}
get { return Left.ResultType; }
}
/// <summary>
@ -119,7 +113,6 @@ namespace ICSharpCode.Decompiler.IL @@ -119,7 +113,6 @@ namespace ICSharpCode.Decompiler.IL
{
this.kind = kind;
this.Sign = sign;
this.inputType = left.ResultType;
Debug.Assert(left.ResultType == right.ResultType);
}

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

@ -22,6 +22,7 @@ using System.Diagnostics; @@ -22,6 +22,7 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.IL.Patterns;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.Decompiler.CSharp;
@ -607,6 +608,57 @@ namespace ICSharpCode.Decompiler.IL @@ -607,6 +608,57 @@ namespace ICSharpCode.Decompiler.IL
#endif
return inst;
}
/// <summary>
/// Attempts to match the specified node against the pattern.
/// </summary>
/// <c>this</c>: The syntactic pattern.
/// <param name="node">The syntax node to test against the pattern.</param>
/// <returns>
/// Returns a match object describing the result of the matching operation.
/// Check the <see cref="Match.Success"/> property to see whether the match was successful.
/// For successful matches, the match object allows retrieving the nodes that were matched with the captured groups.
/// </returns>
public Match Match(ILInstruction node)
{
Match match = new Match();
match.Success = PerformMatch(node, ref match);
return match;
}
/// <summary>
/// Attempts matching this instruction against the other instruction.
/// </summary>
/// <param name="other">The instruction to compare with.</param>
/// <param name="match">The match object, used to store global state during the match (such as the results of capture groups).</param>
/// <returns>Returns whether the (partial) match was successful.
/// If the method returns true, it adds the capture groups (if any) to the match.
/// If the method returns false, the match object may remain in a partially-updated state and
/// needs to be restored before it can be reused.</returns>
protected internal abstract bool PerformMatch(ILInstruction other, ref Match match);
/// <summary>
/// Attempts matching this instruction against a list of other instructions (or a part of said list).
/// </summary>
/// <param name="listMatch">Stores state about the current list match.</param>
/// <param name="match">The match object, used to store global state during the match (such as the results of capture groups).</param>
/// <returns>Returns whether the (partial) match was successful.
/// If the method returns true, it updates listMatch.SyntaxIndex to point to the next node that was not part of the match,
/// and adds the capture groups (if any) to the match.
/// If the method returns false, the listMatch and match objects remain in a partially-updated state and need to be restored
/// before they can be reused.</returns>
protected internal virtual bool PerformMatch(ref ListMatch listMatch, ref Match match)
{
// Base implementation expects the node to match a single element.
// Any patterns matching 0 or more than 1 element must override this method.
if (listMatch.SyntaxIndex < listMatch.SyntaxList.Count) {
if (PerformMatch(listMatch.SyntaxList[listMatch.SyntaxIndex], ref match)) {
listMatch.SyntaxIndex++;
return true;
}
}
return false;
}
}
public interface IInstructionWithTypeOperand

2
ICSharpCode.Decompiler/IL/Instructions/InstructionCollection.cs

@ -24,7 +24,7 @@ using System.Linq; @@ -24,7 +24,7 @@ using System.Linq;
namespace ICSharpCode.Decompiler.IL
{
public sealed class InstructionCollection<T> : IList<T> where T : ILInstruction
public sealed class InstructionCollection<T> : IList<T>, IReadOnlyList<T> where T : ILInstruction
{
readonly ILInstruction parentInstruction;
readonly int firstChildIndex;

175
ICSharpCode.Decompiler/IL/Patterns/ListMatch.cs

@ -0,0 +1,175 @@ @@ -0,0 +1,175 @@
// Copyright (c) 2016 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.IL.Patterns
{
/// <summary>
/// Data holder for a single list matching operation.
/// </summary>
/// <remarks>
/// Notes on backtracking:
/// PerformMatch() may save backtracking-savepoints to the ListMatch instance.
/// Each backtracking-savepoints is a Stack{int} with instructions of how to restore the saved state.
/// When a savepoint is created by a PerformMatch() call, that call may be nested in several other PerformMatch() calls that operate on
/// the same list.
/// When leaving those calls (whether with a successful match or not), the outer PerformMatch() calls may push additional state onto
/// all of the added backtracking-savepoints.
/// When the overall list match fails but savepoints exists, the most recently added savepoint is restored by calling PerformMatch()
/// with listMatch.restoreFrom set to that savepoint. Each PerformMatch() call must pop its state from the savepoint
/// This state is popped again when resuming from the checkpoint.
/// </remarks>
public struct ListMatch
{
/// <summary>
/// The main list matching logic.
/// </summary>
/// <returns>Returns whether the list match was successful.
/// If the method returns true, it adds the capture groups (if any) to the match.
/// If the method returns false, the match object remains in a partially-updated state and needs to be restored
/// before it can be reused.</returns>
internal static bool DoMatch(IReadOnlyList<ILInstruction> patterns, IReadOnlyList<ILInstruction> syntaxList, ref Match match)
{
ListMatch listMatch = new ListMatch(syntaxList);
do {
if (PerformMatchSequence(patterns, ref listMatch, ref match)) {
// If we have a successful match and it matches the whole list,
// we are done.
if (listMatch.SyntaxIndex == syntaxList.Count)
return true;
}
// Otherwise, restore a savepoint created by PerformMatch() and resume the matching logic at that savepoint.
} while (listMatch.RestoreSavePoint(ref match));
return false;
}
/// <summary>
/// PerformMatch() for a sequence of patterns.
/// </summary>
/// <param name="patterns">List of patterns to match.</param>
/// <param name="listMatch">Stores state about the current list match.</param>
/// <param name="match">The match object, used to store global state during the match (such as the results of capture groups).</param>
/// <returns>Returns whether all patterns were matched successfully against a part of the list.
/// If the method returns true, it updates listMatch.SyntaxIndex to point to the next node that was not part of the match,
/// and adds the capture groups (if any) to the match.
/// If the method returns false, the listMatch and match objects remain in a partially-updated state and need to be restored
/// before they can be reused.</returns>
internal static bool PerformMatchSequence(IReadOnlyList<ILInstruction> patterns, ref ListMatch listMatch, ref Match match)
{
// The patterns may create savepoints, so we need to save the 'i' variable
// as part of those checkpoints.
for (int i = listMatch.PopFromSavePoint() ?? 0; i < patterns.Count; i++) {
int startMarker = listMatch.GetSavePointStartMarker();
bool success = patterns[i].PerformMatch(ref listMatch, ref match);
listMatch.PushToSavePoints(startMarker, i);
if (!success)
return false;
}
return true;
}
/// <summary>
/// A savepoint that the list matching operation can be restored from.
/// </summary>
struct SavePoint
{
internal readonly int CheckPoint;
internal readonly int SyntaxIndex;
internal readonly Stack<int> stack;
public SavePoint(int checkpoint, int syntaxIndex)
{
this.CheckPoint = checkpoint;
this.SyntaxIndex = syntaxIndex;
this.stack = new Stack<int>();
}
}
/// <summary>
/// The syntax list we are matching against.
/// </summary>
internal readonly IReadOnlyList<ILInstruction> SyntaxList;
/// <summary>
/// The current index in the syntax list.
/// </summary>
internal int SyntaxIndex;
ListMatch(IReadOnlyList<ILInstruction> syntaxList)
{
this.SyntaxList = syntaxList;
this.SyntaxIndex = 0;
this.backtrackingStack = null;
this.restoreStack = null;
}
List<SavePoint> backtrackingStack;
Stack<int> restoreStack;
void AddSavePoint(SavePoint savepoint)
{
if (backtrackingStack == null)
backtrackingStack = new List<SavePoint>();
backtrackingStack.Add(savepoint);
}
internal void AddSavePoint(ref Match match, int data)
{
var savepoint = new SavePoint(match.CheckPoint(), this.SyntaxIndex);
savepoint.stack.Push(data);
AddSavePoint(savepoint);
}
internal int GetSavePointStartMarker()
{
return backtrackingStack != null ? backtrackingStack.Count : 0;
}
internal void PushToSavePoints(int startMarker, int data)
{
for (int i = startMarker; i < backtrackingStack.Count; i++) {
backtrackingStack[i].stack.Push(data);
}
}
internal int? PopFromSavePoint()
{
if (restoreStack == null || restoreStack.Count == 0)
return null;
return restoreStack.Pop();
}
/// <summary>
/// Restores the listmatch state from a savepoint.
/// </summary>
/// <returns>Returns whether a savepoint exists</returns>
internal bool RestoreSavePoint(ref Match match)
{
if (backtrackingStack == null || backtrackingStack.Count == 0)
return false;
var savepoint = backtrackingStack[backtrackingStack.Count - 1];
backtrackingStack.RemoveAt(backtrackingStack.Count - 1);
match.RestoreCheckPoint(savepoint.CheckPoint);
this.SyntaxIndex = savepoint.SyntaxIndex;
restoreStack = savepoint.stack;
return true;
}
}
}

100
ICSharpCode.Decompiler/IL/Patterns/Match.cs

@ -0,0 +1,100 @@ @@ -0,0 +1,100 @@
// Copyright (c) 2016 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.IL.Patterns
{
public class CaptureGroup {}
/// <summary>
/// Data holder for the overall pattern matching operation.
/// </summary>
/// <remarks>
/// This type is a struct in order to prevent unnecessary memory allocations during pattern matching.
/// The default value <c>default(Match)</c> represents an unsuccessful match.
/// </remarks>
public struct Match
{
static readonly List<KeyValuePair<CaptureGroup, ILInstruction>> emptyResults = new List<KeyValuePair<CaptureGroup, ILInstruction>>();
List<KeyValuePair<CaptureGroup, ILInstruction>> results;
/// <summary>
/// Gets whether the match was successful.
/// </summary>
public bool Success {
get {
return results != null;
}
internal set {
if (value) {
if (results == null)
results = emptyResults;
} else {
results = null;
}
}
}
/// <summary>
/// Gets whether the match was successful.
/// </summary>
public static bool operator true(Match m)
{
return m.Success;
}
/// <summary>
/// Gets whether the match failed.
/// </summary>
public static bool operator false(Match m)
{
return !m.Success;
}
internal void Add(CaptureGroup g, ILInstruction n)
{
if (results == null)
results = new List<KeyValuePair<CaptureGroup, ILInstruction>>();
results.Add(new KeyValuePair<CaptureGroup, ILInstruction>(g, n));
}
internal int CheckPoint()
{
return results != null ? results.Count : 0;
}
internal void RestoreCheckPoint(int checkPoint)
{
if (results != null)
results.RemoveRange(checkPoint, results.Count - checkPoint);
}
public IEnumerable<ILInstruction> Get(CaptureGroup captureGroup)
{
if (results != null) {
foreach (var pair in results) {
if (pair.Key == captureGroup)
yield return pair.Value;
}
}
}
}
}

1
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -74,7 +74,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -74,7 +74,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// => comp(ldlen.i4 array > ldc.i4 0)
// This is a special case where the C# compiler doesn't generate conv.i4 after ldlen.
inst.Left.ReplaceWith(new LdLen(StackType.I4, array) { ILRange = inst.Left.ILRange });
inst.InputType = StackType.I4;
inst.Right = rightWithoutConv;
}
// comp.unsigned(left > ldc.i4 0) => comp(left != ldc.i4 0)

Loading…
Cancel
Save