Browse Source

Try to detect while conditions, do-while-loops and for-loops

pull/728/merge
Siegfried Pammer 9 years ago
parent
commit
fc8825d895
  1. 85
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  2. 16
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  3. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 329
      ICSharpCode.Decompiler/IL/Instructions.cs
  5. 26
      ICSharpCode.Decompiler/IL/Instructions.tt
  6. 57
      ICSharpCode.Decompiler/IL/Patterns/AnyNode.cs

85
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -24,6 +24,7 @@ using ICSharpCode.Decompiler.CSharp.Syntax; @@ -24,6 +24,7 @@ using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using ICSharpCode.Decompiler.IL.Patterns;
namespace ICSharpCode.Decompiler.CSharp
{
@ -267,25 +268,87 @@ namespace ICSharpCode.Decompiler.CSharp @@ -267,25 +268,87 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
WhileStatement ConvertLoop(BlockContainer container)
Statement ConvertLoop(BlockContainer container)
{
continueTarget = container.EntryPoint;
continueCount = 0;
breakTarget = container;
var blockStatement = ConvertBlockContainer(container, true);
Debug.Assert(continueCount < container.EntryPoint.IncomingEdgeCount);
Debug.Assert(blockStatement.Statements.First() is LabelStatement);
if (container.EntryPoint.IncomingEdgeCount == continueCount + 1) {
// Remove the entrypoint label if all jumps to the label were replaced with 'continue;' statements
blockStatement.Statements.First().Remove();
Expression conditionExpr = new PrimitiveExpression(true);
BlockStatement blockStatement;
if (container.EntryPoint.Instructions.Count == 2
&& container.EntryPoint.Instructions[0].MatchIfInstruction(out var conditionInst, out var trueInst)
&& container.EntryPoint.Instructions[1].MatchLeave(container)) {
// detected while(condition)-loop or for-loop
conditionExpr = exprBuilder.TranslateCondition(conditionInst);
if (container.EntryPoint.IncomingEdgeCount == 2) {
var incrementBlock = container.Blocks.SingleOrDefault(b => b.Instructions.Last().MatchBranch(container.EntryPoint));
if (incrementBlock != null) {
// for-loop
continueTarget = incrementBlock;
var forStmt = new ForStatement() {
Condition = conditionExpr,
EmbeddedStatement = ConvertBlockContainer(ConvertAsBlock(trueInst), container, container.Blocks.Skip(1).Where(b => b != incrementBlock), true)
};
for (int i = 0; i < incrementBlock.Instructions.Count - 1; i++) {
forStmt.Iterators.Add(Convert(incrementBlock.Instructions[i]));
}
return forStmt;
}
}
blockStatement = ConvertBlockContainer(ConvertAsBlock(trueInst), container, container.Blocks.Skip(1), true);
} else {
// do-while or while(true)-loop
if (container.EntryPoint.IncomingEdgeCount == 2) {
Block conditionBlock = FindDoWhileConditionBlock(container, out var condition);
if (conditionBlock != null) {
continueTarget = conditionBlock;
return new DoWhileStatement {
EmbeddedStatement = ConvertBlockContainer(new BlockStatement(), container, container.Blocks.Where(b => b != conditionBlock), true),
Condition = exprBuilder.TranslateCondition(condition)
};
}
}
blockStatement = ConvertBlockContainer(container, true);
Debug.Assert(continueCount < container.EntryPoint.IncomingEdgeCount);
Debug.Assert(blockStatement.Statements.First() is LabelStatement);
if (container.EntryPoint.IncomingEdgeCount == continueCount + 1) {
// Remove the entrypoint label if all jumps to the label were replaced with 'continue;' statements
blockStatement.Statements.First().Remove();
}
}
return new WhileStatement(new PrimitiveExpression(true), blockStatement);
if (blockStatement.LastOrDefault() is ContinueStatement stmt)
stmt.Remove();
return new WhileStatement(conditionExpr, blockStatement);
}
private static Block FindDoWhileConditionBlock(BlockContainer container, out ILInstruction condition)
{
var conditionGroup = new CaptureGroup();
var conditionBlockPattern = new Block {
Instructions = {
new IfInstruction(new AnyNode(conditionGroup), new Branch(container.EntryPoint)),
new Leave(container)
}
};
foreach (var b in container.Blocks) {
var match = conditionBlockPattern.Match(b);
if (match.Success) {
condition = match.Get(conditionGroup).Single();
return b;
}
}
condition = null;
return null;
}
BlockStatement ConvertBlockContainer(BlockContainer container, bool isLoop)
{
BlockStatement blockStatement = new BlockStatement();
foreach (var block in container.Blocks) {
return ConvertBlockContainer(new BlockStatement(), container, container.Blocks, isLoop);
}
BlockStatement ConvertBlockContainer(BlockStatement blockStatement, BlockContainer container, IEnumerable<Block> blocks, bool isLoop)
{
foreach (var block in blocks) {
if (block.IncomingEdgeCount > 1 || block != container.EntryPoint) {
// If there are any incoming branches to this block, add a label:
blockStatement.Add(new LabelStatement { Label = block.Label });

16
ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs

@ -33,6 +33,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -33,6 +33,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// </summary>
public class DeclareVariables : IAstTransform
{
/// <summary>
/// Represents a position immediately before nextNode.
/// nextNode is either an ExpressionStatement in a BlockStatement, or an initializer in a for-loop.
/// </summary>
struct InsertionPoint
{
internal int level;
@ -212,6 +216,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -212,6 +216,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
// guarantee that it finds only blocks.
// Fix that up now.
while (!(v.InsertionPoint.nextNode.Parent is BlockStatement)) {
if (v.InsertionPoint.nextNode.Parent is ForStatement f && v.InsertionPoint.nextNode == f.Initializers.FirstOrDefault())
break;
v.InsertionPoint = v.InsertionPoint.Up();
}
@ -254,22 +260,22 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -254,22 +260,22 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (v.RemovedDueToCollision)
continue;
var boe = (v.InsertionPoint.nextNode as ExpressionStatement)?.Expression as AssignmentExpression;
var assignment = (v.InsertionPoint.nextNode as ExpressionStatement)?.Expression as AssignmentExpression;
Expression expectedExpr = new IdentifierExpression(v.Name);
if (v.Type.Kind == TypeKind.ByReference) {
expectedExpr = new DirectionExpression(FieldDirection.Ref, expectedExpr);
}
if (boe != null && boe.Left.IsMatch(expectedExpr)) {
if (assignment != null && assignment.Left.IsMatch(expectedExpr)) {
AstType type;
if (v.Type.ContainsAnonymousType()) {
type = new SimpleType("var");
} else {
type = context.TypeSystemAstBuilder.ConvertType(v.Type);
}
var vds = new VariableDeclarationStatement(type, v.Name, boe.Right.Detach());
var vds = new VariableDeclarationStatement(type, v.Name, assignment.Right.Detach());
var init = vds.Variables.Single();
init.AddAnnotation(boe.Left.GetResolveResult());
foreach (object annotation in boe.Left.Annotations.Concat(boe.Annotations)) {
init.AddAnnotation(assignment.Left.GetResolveResult());
foreach (object annotation in assignment.Left.Annotations.Concat(assignment.Annotations)) {
if (!(annotation is ResolveResult)) {
init.AddAnnotation(annotation);
}

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -275,6 +275,7 @@ @@ -275,6 +275,7 @@
<Compile Include="Documentation\IdStringMemberReference.cs" />
<Compile Include="Documentation\IdStringProvider.cs" />
<Compile Include="Documentation\XmlDocumentationProvider.cs" />
<Compile Include="IL\Patterns\AnyNode.cs" />
<Compile Include="Util\UnicodeNewline.cs" />
<Compile Include="FlowAnalysis\ControlFlowNode.cs" />
<Compile Include="FlowAnalysis\DataFlowVisitor.cs" />

329
ICSharpCode.Decompiler/IL/Instructions.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
@ -155,8 +156,13 @@ namespace ICSharpCode.Decompiler.IL @@ -155,8 +156,13 @@ namespace ICSharpCode.Decompiler.IL
RefAnyType,
/// <summary>Push the address stored in a typed reference.</summary>
RefAnyValue,
/// <summary>Matches any node</summary>
AnyNode,
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Instruction without any arguments</summary>
public abstract partial class SimpleInstruction : ILInstruction
{
@ -203,7 +209,9 @@ namespace ICSharpCode.Decompiler.IL @@ -203,7 +209,9 @@ namespace ICSharpCode.Decompiler.IL
}
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Instruction with a single argument</summary>
public abstract partial class UnaryInstruction : ILInstruction
{
@ -275,7 +283,9 @@ namespace ICSharpCode.Decompiler.IL @@ -275,7 +283,9 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')');
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Instruction with two arguments: Left and Right</summary>
public abstract partial class BinaryInstruction : ILInstruction
{
@ -367,7 +377,9 @@ namespace ICSharpCode.Decompiler.IL @@ -367,7 +377,9 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')');
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Instruction with a list of arguments.</summary>
public abstract partial class CallInstruction : ILInstruction
{
@ -421,7 +433,20 @@ namespace ICSharpCode.Decompiler.IL @@ -421,7 +433,20 @@ namespace ICSharpCode.Decompiler.IL
}
}
}
}
namespace ICSharpCode.Decompiler.IL.Patterns
{
/// <summary>Base class for pattern matching in ILAst.</summary>
public abstract partial class PatternInstruction : ILInstruction
{
protected PatternInstruction(OpCode opCode) : base(opCode)
{
}
public override StackType ResultType { get { return StackType.Unknown; } }
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Represents invalid IL. Semantically, this instruction is considered to throw some kind of exception.</summary>
public sealed partial class InvalidInstruction : SimpleInstruction
{
@ -456,7 +481,9 @@ namespace ICSharpCode.Decompiler.IL @@ -456,7 +481,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>No operation. Takes 0 arguments and returns void.</summary>
public sealed partial class Nop : SimpleInstruction
{
@ -482,7 +509,9 @@ namespace ICSharpCode.Decompiler.IL @@ -482,7 +509,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>A container of IL blocks.</summary>
public sealed partial class ILFunction : ILVariableScope
{
@ -553,7 +582,9 @@ namespace ICSharpCode.Decompiler.IL @@ -553,7 +582,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.body.PerformMatch(o.body, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>A container of IL blocks.</summary>
public sealed partial class BlockContainer : ILInstruction
{
@ -576,7 +607,9 @@ namespace ICSharpCode.Decompiler.IL @@ -576,7 +607,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && Patterns.ListMatch.DoMatch(this.Blocks, o.Blocks, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>A block of IL instructions.</summary>
public sealed partial class Block : ILInstruction
{
@ -599,7 +632,9 @@ namespace ICSharpCode.Decompiler.IL @@ -599,7 +632,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Type == o.Type && Patterns.ListMatch.DoMatch(this.Instructions, o.Instructions, ref match) && this.FinalInstruction.PerformMatch(o.FinalInstruction, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>A region where a pinned variable is used (initial representation of future fixed statement).</summary>
public sealed partial class PinnedRegion : ILInstruction, IInstructionWithVariableOperand
{
@ -742,7 +777,9 @@ namespace ICSharpCode.Decompiler.IL @@ -742,7 +777,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && variable == o.variable && this.init.PerformMatch(o.init, ref match) && this.body.PerformMatch(o.body, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <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>
public sealed partial class LogicNot : UnaryInstruction
{
@ -768,7 +805,9 @@ namespace ICSharpCode.Decompiler.IL @@ -768,7 +805,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.</summary>
public sealed partial class BinaryNumericInstruction : BinaryInstruction
{
@ -791,7 +830,9 @@ namespace ICSharpCode.Decompiler.IL @@ -791,7 +830,9 @@ namespace ICSharpCode.Decompiler.IL
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;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Common instruction for compound assignments.</summary>
public sealed partial class CompoundAssignmentInstruction : ILInstruction
{
@ -881,7 +922,9 @@ namespace ICSharpCode.Decompiler.IL @@ -881,7 +922,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.target.PerformMatch(o.target, ref match) && this.value.PerformMatch(o.value, ref match) && type.Equals(o.type) && CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Bitwise NOT</summary>
public sealed partial class BitNot : UnaryInstruction
{
@ -907,7 +950,9 @@ namespace ICSharpCode.Decompiler.IL @@ -907,7 +950,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Retrieves the RuntimeArgumentHandle.</summary>
public sealed partial class Arglist : SimpleInstruction
{
@ -933,7 +978,9 @@ namespace ICSharpCode.Decompiler.IL @@ -933,7 +978,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Unconditional branch. <c>goto target;</c></summary>
public sealed partial class Branch : SimpleInstruction
{
@ -956,7 +1003,9 @@ namespace ICSharpCode.Decompiler.IL @@ -956,7 +1003,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.TargetBlock == o.TargetBlock;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Unconditional branch to end of block container. <c>goto container_end;</c>, often <c>break;</c></summary>
public sealed partial class Leave : SimpleInstruction
{
@ -979,7 +1028,9 @@ namespace ICSharpCode.Decompiler.IL @@ -979,7 +1028,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.TargetContainer == o.TargetContainer;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c></summary>
public sealed partial class IfInstruction : ILInstruction
{
@ -1082,7 +1133,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1082,7 +1133,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.condition.PerformMatch(o.condition, ref match) && this.trueInst.PerformMatch(o.trueInst, ref match) && this.falseInst.PerformMatch(o.falseInst, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Switch statement</summary>
public sealed partial class SwitchInstruction : ILInstruction
{
@ -1105,7 +1158,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1105,7 +1158,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && Value.PerformMatch(o.Value, ref match) && DefaultBody.PerformMatch(o.DefaultBody, ref match) && Patterns.ListMatch.DoMatch(this.Sections, o.Sections, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Switch section within a switch statement</summary>
public sealed partial class SwitchSection : ILInstruction
{
@ -1175,7 +1230,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1175,7 +1230,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.body.PerformMatch(o.body, ref match) && this.Labels.Intervals.SequenceEqual(o.Labels.Intervals);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Try-catch statement.</summary>
public sealed partial class TryCatch : TryInstruction
{
@ -1198,7 +1255,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1198,7 +1255,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && TryBlock.PerformMatch(o.TryBlock, ref match) && Patterns.ListMatch.DoMatch(Handlers, o.Handlers, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Catch handler within a try-catch statement.</summary>
public sealed partial class TryCatchHandler : ILInstruction, IInstructionWithVariableOperand
{
@ -1315,7 +1374,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1315,7 +1374,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.filter.PerformMatch(o.filter, ref match) && this.body.PerformMatch(o.body, ref match) && variable == o.variable;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Try-finally statement</summary>
public sealed partial class TryFinally : TryInstruction
{
@ -1338,7 +1399,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1338,7 +1399,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && TryBlock.PerformMatch(o.TryBlock, ref match) && finallyBlock.PerformMatch(o.finallyBlock, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Try-fault statement</summary>
public sealed partial class TryFault : TryInstruction
{
@ -1361,7 +1424,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1361,7 +1424,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && TryBlock.PerformMatch(o.TryBlock, ref match) && faultBlock.PerformMatch(o.faultBlock, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Breakpoint instruction</summary>
public sealed partial class DebugBreak : SimpleInstruction
{
@ -1396,7 +1461,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1396,7 +1461,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <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>
public sealed partial class Comp : BinaryInstruction
{
@ -1419,7 +1486,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1419,7 +1486,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Left.PerformMatch(o.Left, ref match) && this.Right.PerformMatch(o.Right, ref match) && this.Kind == o.Kind && this.Sign == o.Sign;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Non-virtual method call.</summary>
public sealed partial class Call : CallInstruction
{
@ -1440,7 +1509,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1440,7 +1509,9 @@ namespace ICSharpCode.Decompiler.IL
return visitor.VisitCall(this, context);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Virtual method call.</summary>
public sealed partial class CallVirt : CallInstruction
{
@ -1461,7 +1532,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1461,7 +1532,9 @@ namespace ICSharpCode.Decompiler.IL
return visitor.VisitCallVirt(this, context);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Checks that the input float is not NaN or infinite.</summary>
public sealed partial class Ckfinite : UnaryInstruction
{
@ -1496,7 +1569,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1496,7 +1569,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Numeric cast.</summary>
public sealed partial class Conv : UnaryInstruction
{
@ -1519,7 +1594,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1519,7 +1594,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && CheckForOverflow == o.CheckForOverflow && Kind == o.Kind && InputSign == o.InputSign && TargetType == o.TargetType;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Loads the value of a local variable. (ldarg/ldloc)</summary>
public sealed partial class LdLoc : SimpleInstruction, IInstructionWithVariableOperand
{
@ -1591,7 +1668,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1591,7 +1668,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && variable == o.variable;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Loads the address of a local variable. (ldarga/ldloca)</summary>
public sealed partial class LdLoca : SimpleInstruction, IInstructionWithVariableOperand
{
@ -1654,7 +1733,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1654,7 +1733,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && variable == o.variable;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Stores a value into a local variable. (starg/stloc)</summary>
public sealed partial class StLoc : ILInstruction, IInstructionWithVariableOperand
{
@ -1777,7 +1858,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1777,7 +1858,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && variable == o.variable && this.value.PerformMatch(o.value, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Stores the value into an anonymous temporary variable, and returns the address of that variable.</summary>
public sealed partial class AddressOf : ILInstruction
{
@ -1867,7 +1950,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1867,7 +1950,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.value.PerformMatch(o.value, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Loads a constant string.</summary>
public sealed partial class LdStr : SimpleInstruction
{
@ -1901,7 +1986,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1901,7 +1986,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Value == o.Value;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Loads a constant 32-bit integer.</summary>
public sealed partial class LdcI4 : SimpleInstruction
{
@ -1935,7 +2022,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1935,7 +2022,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Value == o.Value;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Loads a constant 64-bit integer.</summary>
public sealed partial class LdcI8 : SimpleInstruction
{
@ -1969,7 +2058,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1969,7 +2058,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Value == o.Value;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Loads a constant floating-point number.</summary>
public sealed partial class LdcF : SimpleInstruction
{
@ -2003,7 +2094,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2003,7 +2094,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Value == o.Value;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Loads a constant decimal.</summary>
public sealed partial class LdcDecimal : SimpleInstruction
{
@ -2037,7 +2130,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2037,7 +2130,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Value == o.Value;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Loads the null reference.</summary>
public sealed partial class LdNull : SimpleInstruction
{
@ -2063,7 +2158,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2063,7 +2158,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Load method pointer</summary>
public sealed partial class LdFtn : SimpleInstruction, IInstructionWithMethodOperand
{
@ -2099,7 +2196,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2099,7 +2196,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && method.Equals(o.method);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Load method pointer</summary>
public sealed partial class LdVirtFtn : UnaryInstruction, IInstructionWithMethodOperand
{
@ -2147,7 +2246,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2147,7 +2246,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && method.Equals(o.method);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Loads runtime representation of metadata token</summary>
public sealed partial class LdTypeToken : SimpleInstruction
{
@ -2183,7 +2284,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2183,7 +2284,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Loads runtime representation of metadata token</summary>
public sealed partial class LdMemberToken : SimpleInstruction
{
@ -2219,7 +2322,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2219,7 +2322,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && member.Equals(o.member);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Allocates space in the stack frame</summary>
public sealed partial class LocAlloc : UnaryInstruction
{
@ -2254,7 +2359,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2254,7 +2359,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Returns from the current method or lambda.</summary>
public sealed partial class Return : ILInstruction
{
@ -2277,7 +2384,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2277,7 +2384,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.hasArgument == o.hasArgument && (!hasArgument || this.ReturnValue.PerformMatch(o.ReturnValue, ref match));
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Load address of instance field</summary>
public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand
{
@ -2374,7 +2483,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2374,7 +2483,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.target.PerformMatch(o.target, ref match) && field.Equals(o.field);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Load static field address</summary>
public sealed partial class LdsFlda : SimpleInstruction, IInstructionWithFieldOperand
{
@ -2410,7 +2521,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2410,7 +2521,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && field.Equals(o.field);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Casts an object to a class.</summary>
public sealed partial class CastClass : UnaryInstruction
{
@ -2458,7 +2571,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2458,7 +2571,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Test if object is instance of class or interface.</summary>
public sealed partial class IsInst : UnaryInstruction
{
@ -2497,7 +2612,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2497,7 +2612,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Indirect load (ref/pointer dereference).</summary>
public sealed partial class LdObj : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
@ -2601,7 +2718,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2601,7 +2718,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.target.PerformMatch(o.target, ref match) && type.Equals(o.type) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Indirect store (store to ref/pointer).</summary>
public sealed partial class StObj : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
@ -2725,7 +2844,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2725,7 +2844,9 @@ namespace ICSharpCode.Decompiler.IL
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;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Boxes a value.</summary>
public sealed partial class Box : UnaryInstruction
{
@ -2773,7 +2894,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2773,7 +2894,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Compute address inside box.</summary>
public sealed partial class Unbox : UnaryInstruction
{
@ -2821,7 +2944,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2821,7 +2944,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Unbox a value.</summary>
public sealed partial class UnboxAny : UnaryInstruction
{
@ -2869,7 +2994,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2869,7 +2994,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Creates an object instance and calls the constructor.</summary>
public sealed partial class NewObj : CallInstruction
{
@ -2890,7 +3017,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2890,7 +3017,9 @@ namespace ICSharpCode.Decompiler.IL
return visitor.VisitNewObj(this, context);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Creates an array instance.</summary>
public sealed partial class NewArr : ILInstruction
{
@ -2979,7 +3108,9 @@ namespace ICSharpCode.Decompiler.IL @@ -2979,7 +3108,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && type.Equals(o.type) && Patterns.ListMatch.DoMatch(this.Indices, o.Indices, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Returns the default value for a type.</summary>
public sealed partial class DefaultValue : SimpleInstruction
{
@ -3015,7 +3146,9 @@ namespace ICSharpCode.Decompiler.IL @@ -3015,7 +3146,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Throws an exception.</summary>
public sealed partial class Throw : UnaryInstruction
{
@ -3050,7 +3183,9 @@ namespace ICSharpCode.Decompiler.IL @@ -3050,7 +3183,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Rethrows the current exception.</summary>
public sealed partial class Rethrow : SimpleInstruction
{
@ -3085,7 +3220,9 @@ namespace ICSharpCode.Decompiler.IL @@ -3085,7 +3220,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Gets the size of a type in bytes.</summary>
public sealed partial class SizeOf : SimpleInstruction
{
@ -3121,7 +3258,9 @@ namespace ICSharpCode.Decompiler.IL @@ -3121,7 +3258,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Returns the length of an array as 'native unsigned int'.</summary>
public sealed partial class LdLen : ILInstruction
{
@ -3199,7 +3338,9 @@ namespace ICSharpCode.Decompiler.IL @@ -3199,7 +3338,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.array.PerformMatch(o.array, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Load address of array element.</summary>
public sealed partial class LdElema : ILInstruction
{
@ -3311,7 +3452,9 @@ namespace ICSharpCode.Decompiler.IL @@ -3311,7 +3452,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && type.Equals(o.type) && this.array.PerformMatch(o.array, ref match) && Patterns.ListMatch.DoMatch(this.Indices, o.Indices, ref match) && IsReadOnly == o.IsReadOnly;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <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.
/// Also used to convert a string to a reference to the first character.</summary>
public sealed partial class ArrayToPointer : ILInstruction
@ -3402,7 +3545,9 @@ namespace ICSharpCode.Decompiler.IL @@ -3402,7 +3545,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.array.PerformMatch(o.array, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Push a typed reference of type class onto the stack.</summary>
public sealed partial class MakeRefAny : UnaryInstruction
{
@ -3441,7 +3586,9 @@ namespace ICSharpCode.Decompiler.IL @@ -3441,7 +3586,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Push the type token stored in a typed reference.</summary>
public sealed partial class RefAnyType : UnaryInstruction
{
@ -3467,7 +3614,9 @@ namespace ICSharpCode.Decompiler.IL @@ -3467,7 +3614,9 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Push the address stored in a typed reference.</summary>
public sealed partial class RefAnyValue : UnaryInstruction
{
@ -3515,8 +3664,53 @@ namespace ICSharpCode.Decompiler.IL @@ -3515,8 +3664,53 @@ namespace ICSharpCode.Decompiler.IL
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL.Patterns
{
/// <summary>Matches any node</summary>
public sealed partial class AnyNode : PatternInstruction
{
protected sealed override int GetChildCount()
{
return 0;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (AnyNode)ShallowClone();
return clone;
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
output.Write(')');
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>
/// Base class for visitor pattern.
/// </summary>
@ -4369,6 +4563,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4369,6 +4563,7 @@ namespace ICSharpCode.Decompiler.IL
"mkrefany",
"refanytype",
"refanyval",
"AnyNode",
};
}

26
ICSharpCode.Decompiler/IL/Instructions.tt

@ -33,6 +33,7 @@ @@ -33,6 +33,7 @@
new OpCode("CallInstruction", "Instruction with a list of arguments.",
AbstractBaseClass, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}),
CustomWriteTo, MayThrow, SideEffect),
new OpCode("PatternInstruction", "Base class for pattern matching in ILAst.", AbstractBaseClass, ResultType("Unknown")) { Namespace = "ICSharpCode.Decompiler.IL.Patterns" }
};
OpCode[] opCodes = {
@ -209,6 +210,9 @@ @@ -209,6 +210,9 @@
CustomClassName("RefAnyType"), Unary, ResultType("O")),
new OpCode("refanyval", "Push the address stored in a typed reference.",
CustomClassName("RefAnyValue"), Unary, HasTypeOperand, MayThrow, ResultType("Ref")),
// patterns
new OpCode("AnyNode", "Matches any node", Pattern, CustomArguments(), CustomConstructor),
};
#>
using System;
@ -229,8 +233,11 @@ namespace ICSharpCode.Decompiler.IL @@ -229,8 +233,11 @@ namespace ICSharpCode.Decompiler.IL
<#=opCode.Name#>,
<# } #>
}
}
<# foreach (OpCode opCode in baseClasses.Concat(opCodes)) { #>
namespace <#=opCode.Namespace#>
{
/// <summary><#=opCode.Description.Replace("\n", "\n\t/// ")#></summary>
<#=opCode.ClassModifiers#> partial class <#=opCode.Name#> : <#=string.Join(", ", new[]{opCode.BaseClass}.Concat(opCode.Interfaces))#>
{
@ -278,9 +285,11 @@ namespace ICSharpCode.Decompiler.IL @@ -278,9 +285,11 @@ namespace ICSharpCode.Decompiler.IL
}
<# } #>
}
}
<# } #>
namespace ICSharpCode.Decompiler.IL
{
/// <summary>
/// Base class for visitor pattern.
/// </summary>
@ -289,7 +298,7 @@ namespace ICSharpCode.Decompiler.IL @@ -289,7 +298,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Called by Visit*() methods that were not overridden</summary>
protected abstract void Default(ILInstruction inst);
<# foreach (OpCode opCode in opCodes) { #>
<# foreach (OpCode opCode in opCodes.Where(o => o.GenerateAcceptVisitor)) { #>
protected internal virtual void Visit<#=opCode.Name#>(<#=opCode.Name#> <#=opCode.VariableName#>)
{
Default(<#=opCode.VariableName#>);
@ -305,7 +314,7 @@ namespace ICSharpCode.Decompiler.IL @@ -305,7 +314,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Called by Visit*() methods that were not overridden</summary>
protected abstract T Default(ILInstruction inst);
<# foreach (OpCode opCode in opCodes) { #>
<# foreach (OpCode opCode in opCodes.Where(o => o.GenerateAcceptVisitor)) { #>
protected internal virtual T Visit<#=opCode.Name#>(<#=opCode.Name#> <#=opCode.VariableName#>)
{
return Default(<#=opCode.VariableName#>);
@ -321,7 +330,7 @@ namespace ICSharpCode.Decompiler.IL @@ -321,7 +330,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Called by Visit*() methods that were not overridden</summary>
protected abstract T Default(ILInstruction inst, C context);
<# foreach (OpCode opCode in opCodes) { #>
<# foreach (OpCode opCode in opCodes.Where(o => o.GenerateAcceptVisitor)) { #>
protected internal virtual T Visit<#=opCode.Name#>(<#=opCode.Name#> <#=opCode.VariableName#>, C context)
{
return Default(<#=opCode.VariableName#>, context);
@ -395,6 +404,7 @@ namespace ICSharpCode.Decompiler.IL @@ -395,6 +404,7 @@ namespace ICSharpCode.Decompiler.IL
{
public readonly string OriginalName;
public string Name;
public string Namespace = "ICSharpCode.Decompiler.IL";
public readonly string Description;
public string VariableName = "inst";
@ -944,4 +954,12 @@ protected override void Disconnected() @@ -944,4 +954,12 @@ protected override void Disconnected()
opCode.WriteOpCodePrefix.Add("if (IsReadOnly)" + Environment.NewLine + "\toutput.Write(\"readonly.\");");
opCode.PerformMatchConditions.Add("IsReadOnly == o.IsReadOnly");
};
static Action<OpCode> Pattern = opCode => {
BaseClass("PatternInstruction")(opCode);
opCode.Namespace = "ICSharpCode.Decompiler.IL.Patterns";
opCode.GenerateAcceptVisitor = false;
opCode.GenerateMatch = false;
opCode.GeneratePerformMatch = false;
};
#>

57
ICSharpCode.Decompiler/IL/Patterns/AnyNode.cs

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL.Patterns
{
partial class PatternInstruction : ILInstruction
{
public override void AcceptVisitor(ILVisitor visitor)
{
throw new NotSupportedException();
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
throw new NotSupportedException();
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
throw new NotSupportedException();
}
protected override InstructionFlags ComputeFlags()
{
throw new NotSupportedException();
}
public override InstructionFlags DirectFlags
{
get {
throw new NotSupportedException();
}
}
}
partial class AnyNode : PatternInstruction
{
CaptureGroup group;
public AnyNode(CaptureGroup group = null)
: base(OpCode.AnyNode)
{
this.group = group;
}
protected internal override bool PerformMatch(ILInstruction other, ref Match match)
{
if (other == null)
return false;
match.Add(group, other);
return true;
}
}
}
Loading…
Cancel
Save