From 49ce1bcea3f48ebcf7dd763b45178b05c98c82c0 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 12 Jul 2014 00:41:46 +0200 Subject: [PATCH] Worked on ILAst instruction representation --- .../CSharp/CSharpDecompiler.cs | 23 +- .../CSharp/ExpressionBuilder.cs | 44 +- .../CSharp/StatementBuilder.cs | 31 +- .../ICSharpCode.Decompiler.csproj | 9 +- ICSharpCode.Decompiler/IL/BlockBuilder.cs | 35 +- ICSharpCode.Decompiler/IL/ILReader.cs | 36 +- ICSharpCode.Decompiler/IL/ILTypeExtensions.cs | 20 +- ICSharpCode.Decompiler/IL/ILVariable.cs | 37 +- ICSharpCode.Decompiler/IL/InstructionFlags.cs | 37 +- .../IL/InstructionOutputExtensions.cs | 20 +- ICSharpCode.Decompiler/IL/Instructions.cs | 646 ++++++++++++------ ICSharpCode.Decompiler/IL/Instructions.tt | 230 +++++-- .../BinaryComparisonInstruction.cs | 56 ++ .../IL/Instructions/BinaryInstruction.cs | 133 ++-- .../Instructions/BinaryNumericInstruction.cs | 84 +++ .../IL/Instructions/Block.cs | 18 + .../IL/Instructions/CallInstruction.cs | 143 +++- .../IL/Instructions/Conv.cs | 57 ++ .../IL/Instructions/ILInstruction.cs | 73 +- .../IL/Instructions/Return.cs | 58 ++ .../IL/Instructions/SimpleInstruction.cs | 38 +- .../IL/Instructions/UnaryInstruction.cs | 60 +- ICSharpCode.Decompiler/IL/PrimitiveType.cs | 22 +- ICSharpCode.Decompiler/IL/SemanticHelper.cs | 20 +- ICSharpCode.Decompiler/IL/StackType.cs | 20 +- .../Visitors/CountPopInstructionsVisitor.cs | 40 ++ ICSharpCode.Decompiler/Util/Interval.cs | 9 +- 27 files changed, 1606 insertions(+), 393 deletions(-) create mode 100644 ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs create mode 100644 ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs create mode 100644 ICSharpCode.Decompiler/IL/Instructions/Conv.cs create mode 100644 ICSharpCode.Decompiler/IL/Instructions/Return.cs create mode 100644 ICSharpCode.Decompiler/IL/Visitors/CountPopInstructionsVisitor.cs diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 96feea144..3e0db9753 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -1,4 +1,22 @@ -using ICSharpCode.Decompiler.IL; +// Copyright (c) 2014 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 ICSharpCode.Decompiler.IL; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp.Refactoring; using ICSharpCode.NRefactory.TypeSystem; @@ -54,7 +72,8 @@ namespace ICSharpCode.Decompiler.CSharp { var unresolved = member.UnresolvedMember; lock (entityDict) { - if (unresolved != null && entityDict.TryGetValue(unresolved, out var mr)) + MemberReference mr; + if (unresolved != null && entityDict.TryGetValue(unresolved, out mr)) return mr; } return null; diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 7ca69ac4c..985ff8f55 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1,4 +1,22 @@ -using ICSharpCode.Decompiler.IL; +// Copyright (c) 2014 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 ICSharpCode.Decompiler.IL; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.TypeSystem; using System; @@ -12,13 +30,25 @@ namespace ICSharpCode.Decompiler.CSharp /// /// Translates from ILAst to C# expressions. /// - class ExpressionBuilder(ICompilation compilation) : ILVisitor + class ExpressionBuilder : ILVisitor { - private readonly ICompilation compilation = compilation; - - internal struct ConvertedExpression(Expression expression, IType type) { - public readonly Expression Expression = expression; - public readonly IType Type = type; + private readonly ICompilation compilation; + + public ExpressionBuilder(ICompilation compilation) + { + this.compilation = compilation; + } + + internal struct ConvertedExpression + { + public readonly Expression Expression; + public readonly IType Type; + + public ConvertedExpression(Expression expression, IType type) + { + this.Expression = expression; + this.Type = type; + } } public Expression Convert(ILInstruction inst) diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index a48e3ac7a..6b16bf194 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -1,4 +1,22 @@ -using ICSharpCode.Decompiler.IL; +// Copyright (c) 2014 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 ICSharpCode.Decompiler.IL; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.TypeSystem; using System; @@ -9,10 +27,15 @@ using System.Threading.Tasks; namespace ICSharpCode.Decompiler.CSharp { - class StatementBuilder(ICompilation compilation) : ILVisitor + class StatementBuilder : ILVisitor { - readonly ExpressionBuilder exprBuilder = new ExpressionBuilder(compilation); - + readonly ExpressionBuilder exprBuilder; + + public StatementBuilder(ICompilation compilation) + { + this.exprBuilder = new ExpressionBuilder(compilation); + } + public Statement Convert(ILInstruction inst) { return inst.AcceptVisitor(this); diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index c1c3b717d..4b4a5ca92 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -19,7 +19,6 @@ ..\NRefactory\ICSharpCode.NRefactory.snk False File - experimental AnyCPU @@ -72,12 +71,17 @@ True Instructions.tt + + + + + @@ -138,6 +142,9 @@ + + + diff --git a/ICSharpCode.Decompiler/IL/BlockBuilder.cs b/ICSharpCode.Decompiler/IL/BlockBuilder.cs index 1f4d28944..ae4f43a7a 100644 --- a/ICSharpCode.Decompiler/IL/BlockBuilder.cs +++ b/ICSharpCode.Decompiler/IL/BlockBuilder.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2014 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; using System.Collections.Generic; using System.Diagnostics; @@ -8,12 +26,18 @@ using System.Threading.Tasks; namespace ICSharpCode.Decompiler.IL { - class BlockBuilder(Mono.Cecil.Cil.MethodBody body, bool instructionInlining) + class BlockBuilder { + readonly Stack instructionStack; + + public BlockBuilder(Mono.Cecil.Cil.MethodBody body, bool instructionInlining) + { + this.instructionStack = (instructionInlining ? new Stack() : null); + } + BlockContainer currentContainer; Block currentBlock; - Stack instructionStack = (instructionInlining ? new Stack() : null); - + public BlockContainer CreateBlocks(List instructions, BitArray incomingBranches) { currentContainer = new BlockContainer(); @@ -35,7 +59,8 @@ namespace ICSharpCode.Decompiler.IL // inlining disabled currentBlock.Instructions.Add(inst); } else { - var inlinedInst = inst.Inline(InstructionFlags.None, instructionStack, out bool finished); + bool finished; + var inlinedInst = inst.Inline(InstructionFlags.None, instructionStack, out finished); if (inlinedInst is Branch) { // Values currently on the stack might be used on both sides of the branch, // so we can't inline them. diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 36de0fc3f..871dbb267 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2014 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; using System.Linq; using System.Text; @@ -11,11 +29,19 @@ using System.Threading; namespace ICSharpCode.Decompiler.IL { - public class ILReader(Mono.Cecil.Cil.MethodBody body, CancellationToken cancellationToken) + public class ILReader { - private readonly Mono.Cecil.Cil.MethodBody body = body; - private readonly CancellationToken cancellationToken = cancellationToken; + private readonly Mono.Cecil.Cil.MethodBody body; + private readonly CancellationToken cancellationToken; + public ILReader(Mono.Cecil.Cil.MethodBody body, CancellationToken cancellationToken) + { + if (body == null) + throw new ArgumentNullException("body"); + this.body = body; + this.cancellationToken = cancellationToken; + } + internal static ILOpCode ReadOpCode(ref BlobReader reader) { byte b = reader.ReadByte(); @@ -699,7 +725,7 @@ namespace ICSharpCode.Decompiler.IL { var method = (MethodReference)ReadAndDecodeMetadataToken(); var inst = new CallInstruction(opCode, method); - for (int i = 0; i < inst.Operands.Length; i++) { + for (int i = 0; i < inst.Arguments.Length; i++) { stack.Pop(); } var returnType = (opCode == OpCode.NewObj ? method.DeclaringType : method.ReturnType).GetStackType(); diff --git a/ICSharpCode.Decompiler/IL/ILTypeExtensions.cs b/ICSharpCode.Decompiler/IL/ILTypeExtensions.cs index 2d4339a16..dd9f78386 100644 --- a/ICSharpCode.Decompiler/IL/ILTypeExtensions.cs +++ b/ICSharpCode.Decompiler/IL/ILTypeExtensions.cs @@ -1,4 +1,22 @@ -using Mono.Cecil; +// Copyright (c) 2014 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 Mono.Cecil; using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/ICSharpCode.Decompiler/IL/ILVariable.cs b/ICSharpCode.Decompiler/IL/ILVariable.cs index b91b9011b..f58a14c0f 100644 --- a/ICSharpCode.Decompiler/IL/ILVariable.cs +++ b/ICSharpCode.Decompiler/IL/ILVariable.cs @@ -1,4 +1,22 @@ -using Mono.Cecil; +// Copyright (c) 2014 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 Mono.Cecil; using Mono.Cecil.Cil; using System; using System.Collections.Generic; @@ -14,14 +32,23 @@ namespace ICSharpCode.Decompiler.IL Parameter, } - class ILVariable(VariableKind kind, TypeReference type, int index) + class ILVariable { - public readonly VariableKind Kind = kind; - public readonly TypeReference Type = type; - public readonly int Index = index; + public readonly VariableKind Kind; + public readonly TypeReference Type; + public readonly int Index; readonly object CecilObject; + public ILVariable(VariableKind kind, TypeReference type, int index) + { + if (type == null) + throw new ArgumentNullException("type"); + this.Kind = kind; + this.Type = type; + this.Index = index; + } + public ILVariable(VariableDefinition v) : this(VariableKind.Local, v.VariableType, v.Index) { diff --git a/ICSharpCode.Decompiler/IL/InstructionFlags.cs b/ICSharpCode.Decompiler/IL/InstructionFlags.cs index 24fc9ca6b..091a5ca14 100644 --- a/ICSharpCode.Decompiler/IL/InstructionFlags.cs +++ b/ICSharpCode.Decompiler/IL/InstructionFlags.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2014 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; using System.Linq; using System.Text; @@ -10,6 +28,9 @@ namespace ICSharpCode.Decompiler.IL public enum InstructionFlags { None = 0, + /// + /// The instruction may pop from the evaluation stack. + /// MayPop = 0x01, MayPeek = 0x02, /// @@ -17,19 +38,19 @@ namespace ICSharpCode.Decompiler.IL /// MayThrow = 0x04, /// - /// The instruction may read from local variables. + /// The instruction may exit with a branch or return. /// - MayReadLocals = 0x08, + MayBranch = 0x08, /// - /// The instruction may write to local variables. + /// The instruction may read from local variables. /// - MayWriteLocals = 0x10, + MayReadLocals = 0x10, /// - /// The instruction may exit with a jump or return. + /// The instruction may write to local variables. /// - MayJump = 0x20, + MayWriteLocals = 0x20, /// - /// The instruction may have side effects, such as writing to heap memory, + /// The instruction may have side effects, such as accessing heap memory, /// performing system calls, writing to local variables through pointers, etc. /// SideEffects = 0x40, diff --git a/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs b/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs index 351767a47..4e2521237 100644 --- a/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs +++ b/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2014 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; using System.Linq; using System.Text; diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index d4d4cc7c1..c0fb91e6a 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2014 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 Mono.Cecil; namespace ICSharpCode.Decompiler.IL @@ -69,11 +87,11 @@ namespace ICSharpCode.Decompiler.IL /// Numeric cast. Conv, /// Loads the value of a local variable. (ldarg/ldloc) - Ldloc, + LdLoc, /// Loads the address of a local variable. (ldarga/ldloca) - Ldloca, + LdLoca, /// Stores a value into a local variable. (starg/stloc) - Stloc, + StLoc, /// Loads a constant string. LdStr, /// Loads a constant 32-bit integer. @@ -117,530 +135,762 @@ namespace ICSharpCode.Decompiler.IL } /// No operation. Takes 0 arguments and returns void. - public sealed partial class Nop() : SimpleInstruction(OpCode.Nop) + public sealed partial class Nop : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Nop() : base(OpCode.Nop) + { + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitNop(this); } } /// Pops the top of the evaluation stack and returns the value. - public sealed partial class Pop() : SimpleInstruction(OpCode.Pop) + public sealed partial class Pop : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Pop(StackType resultType) : base(OpCode.Pop) + { + this.resultType = resultType; + } + StackType resultType; + public override StackType ResultType { get { return resultType; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitPop(this); } } /// Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'. - public sealed partial class Peek() : SimpleInstruction(OpCode.Peek) + public sealed partial class Peek : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Peek(StackType resultType) : base(OpCode.Peek) + { + this.resultType = resultType; + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayPeek; + } + StackType resultType; + public override StackType ResultType { get { return resultType; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitPeek(this); } } /// Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack. - public sealed partial class Void() : UnaryInstruction(OpCode.Void) + public sealed partial class Void : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Void() : base(OpCode.Void) + { + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitVoid(this); } } /// A container of IL blocks. - public sealed partial class BlockContainer() : ILInstruction(OpCode.BlockContainer) + public sealed partial class BlockContainer : ILInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public BlockContainer() : base(OpCode.BlockContainer) + { + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitBlockContainer(this); } } /// A block of IL instructions. - public sealed partial class Block() : ILInstruction(OpCode.Block) + public sealed partial class Block : ILInstruction { + public Block() : base(OpCode.Block) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitBlock(this); } } /// 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). - public sealed partial class LogicNot() : UnaryInstruction(OpCode.LogicNot) + public sealed partial class LogicNot : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public LogicNot() : base(OpCode.LogicNot) + { + } + public override StackType ResultType { get { return StackType.I4; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLogicNot(this); } } /// Adds two numbers. - public sealed partial class Add(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Add, opType, overflowMode) + public sealed partial class Add : BinaryNumericInstruction { + public Add(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Add, opType, resultType, overflowMode) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitAdd(this); } } /// Subtracts two numbers - public sealed partial class Sub(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Sub, opType, overflowMode) + public sealed partial class Sub : BinaryNumericInstruction { + public Sub(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Sub, opType, resultType, overflowMode) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitSub(this); } } /// Multiplies two numbers - public sealed partial class Mul(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Mul, opType, overflowMode) + public sealed partial class Mul : BinaryNumericInstruction { + public Mul(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Mul, opType, resultType, overflowMode) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitMul(this); } } /// Divides two numbers - public sealed partial class Div(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Div, opType, overflowMode) + public sealed partial class Div : BinaryNumericInstruction { + public Div(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Div, opType, resultType, overflowMode) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow; + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitDiv(this); } } /// Division remainder - public sealed partial class Rem(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Rem, opType, overflowMode) + public sealed partial class Rem : BinaryNumericInstruction { + public Rem(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Rem, opType, resultType, overflowMode) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow; + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitRem(this); } } /// Unary negation - public sealed partial class Neg() : UnaryInstruction(OpCode.Neg) + public sealed partial class Neg : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Neg(StackType resultType) : base(OpCode.Neg) + { + this.resultType = resultType; + } + StackType resultType; + public override StackType ResultType { get { return resultType; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitNeg(this); } } /// Bitwise AND - public sealed partial class BitAnd(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.BitAnd, opType, overflowMode) + public sealed partial class BitAnd : BinaryNumericInstruction { + public BitAnd(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.BitAnd, opType, resultType, overflowMode) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitBitAnd(this); } } /// Bitwise OR - public sealed partial class BitOr(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.BitOr, opType, overflowMode) + public sealed partial class BitOr : BinaryNumericInstruction { + public BitOr(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.BitOr, opType, resultType, overflowMode) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitBitOr(this); } } /// Bitwise XOR - public sealed partial class BitXor(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.BitXor, opType, overflowMode) + public sealed partial class BitXor : BinaryNumericInstruction { + public BitXor(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.BitXor, opType, resultType, overflowMode) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitBitXor(this); } } /// Bitwise NOT - public sealed partial class BitNot() : UnaryInstruction(OpCode.BitNot) + public sealed partial class BitNot : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public BitNot(StackType resultType) : base(OpCode.BitNot) + { + this.resultType = resultType; + } + StackType resultType; + public override StackType ResultType { get { return resultType; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitBitNot(this); } } /// Retrieves the RuntimeArgumentHandle. - public sealed partial class Arglist() : SimpleInstruction(OpCode.Arglist) + public sealed partial class Arglist : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Arglist() : base(OpCode.Arglist) + { + } + public override StackType ResultType { get { return StackType.O; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitArglist(this); } } /// if (condition) goto target;. - public sealed partial class ConditionalBranch() : UnaryInstruction(OpCode.ConditionalBranch) + public sealed partial class ConditionalBranch : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public ConditionalBranch() : base(OpCode.ConditionalBranch) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayBranch; + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitConditionalBranch(this); } } /// goto target;. - public sealed partial class Branch() : SimpleInstruction(OpCode.Branch) + public sealed partial class Branch : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Branch() : base(OpCode.Branch) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayBranch; + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitBranch(this); } } /// Breakpoint instruction - public sealed partial class DebugBreak() : SimpleInstruction(OpCode.DebugBreak) + public sealed partial class DebugBreak : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public DebugBreak() : base(OpCode.DebugBreak) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.SideEffect; + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitDebugBreak(this); } } /// Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise. - public sealed partial class Ceq(StackType opType) : BinaryComparisonInstruction(OpCode.Ceq, opType) + public sealed partial class Ceq : BinaryComparisonInstruction { + public Ceq(StackType opType) : base(OpCode.Ceq, opType) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitCeq(this); } } /// Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers. - public sealed partial class Cgt(StackType opType) : BinaryComparisonInstruction(OpCode.Cgt, opType) + public sealed partial class Cgt : BinaryComparisonInstruction { + public Cgt(StackType opType) : base(OpCode.Cgt, opType) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitCgt(this); } } /// Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers. - public sealed partial class Cgt_Un(StackType opType) : BinaryComparisonInstruction(OpCode.Cgt_Un, opType) + public sealed partial class Cgt_Un : BinaryComparisonInstruction { + public Cgt_Un(StackType opType) : base(OpCode.Cgt_Un, opType) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitCgt_Un(this); } } /// Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers. - public sealed partial class Clt(StackType opType) : BinaryComparisonInstruction(OpCode.Clt, opType) + public sealed partial class Clt : BinaryComparisonInstruction { + public Clt(StackType opType) : base(OpCode.Clt, opType) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitClt(this); } } /// Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers. - public sealed partial class Clt_Un(StackType opType) : BinaryComparisonInstruction(OpCode.Clt_Un, opType) + public sealed partial class Clt_Un : BinaryComparisonInstruction { + public Clt_Un(StackType opType) : base(OpCode.Clt_Un, opType) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitClt_Un(this); } } /// Non-virtual method call. - public sealed partial class Call(MethodReference method) : CallInstruction(OpCode.Call, method) + public sealed partial class Call : CallInstruction { + public Call(MethodReference method) : base(OpCode.Call, method) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitCall(this); } } /// Virtual method call. - public sealed partial class CallVirt(MethodReference method) : CallInstruction(OpCode.CallVirt, method) + public sealed partial class CallVirt : CallInstruction { + public CallVirt(MethodReference method) : base(OpCode.CallVirt, method) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitCallVirt(this); } } /// Checks that the float on top of the stack is not NaN or infinite. - public sealed partial class CkFinite() : SimpleInstruction(OpCode.CkFinite) + public sealed partial class CkFinite : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public CkFinite() : base(OpCode.CkFinite) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayPeek | InstructionFlags.MayThrow; + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitCkFinite(this); } } /// Numeric cast. - public sealed partial class Conv() : UnaryInstruction(OpCode.Conv) + public sealed partial class Conv : UnaryInstruction { - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitConv(this); } } /// Loads the value of a local variable. (ldarg/ldloc) - public sealed partial class Ldloc() : SimpleInstruction(OpCode.Ldloc) + public sealed partial class LdLoc : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public LdLoc() : base(OpCode.LdLoc) + { + } + public override StackType ResultType { get { return Variable.Type.ToStackType(); } } + public sealed override T AcceptVisitor(ILVisitor visitor) { - return visitor.VisitLdloc(this); + return visitor.VisitLdLoc(this); } } /// Loads the address of a local variable. (ldarga/ldloca) - public sealed partial class Ldloca() : SimpleInstruction(OpCode.Ldloca) + public sealed partial class LdLoca : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public LdLoca() : base(OpCode.LdLoca) { - return visitor.VisitLdloca(this); + } + public override StackType ResultType { get { return StackType.Ref; } } + public sealed override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdLoca(this); } } /// Stores a value into a local variable. (starg/stloc) - public sealed partial class Stloc() : UnaryInstruction(OpCode.Stloc) + public sealed partial class StLoc : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public StLoc() : base(OpCode.StLoc) { - return visitor.VisitStloc(this); + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitStLoc(this); } } /// Loads a constant string. - public sealed partial class LdStr() : SimpleInstruction(OpCode.LdStr) + public sealed partial class LdStr : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public LdStr() : base(OpCode.LdStr) + { + } + public override StackType ResultType { get { return StackType.O; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdStr(this); } } /// Loads a constant 32-bit integer. - public sealed partial class LdcI4() : SimpleInstruction(OpCode.LdcI4) + public sealed partial class LdcI4 : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public LdcI4() : base(OpCode.LdcI4) + { + } + public override StackType ResultType { get { return StackType.I4; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdcI4(this); } } /// Loads a constant 64-bit integer. - public sealed partial class LdcI8() : SimpleInstruction(OpCode.LdcI8) + public sealed partial class LdcI8 : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public LdcI8() : base(OpCode.LdcI8) + { + } + public override StackType ResultType { get { return StackType.I8; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdcI8(this); } } /// Loads a constant floating-point number. - public sealed partial class LdcF() : SimpleInstruction(OpCode.LdcF) + public sealed partial class LdcF : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public LdcF() : base(OpCode.LdcF) + { + } + public override StackType ResultType { get { return StackType.F; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdcF(this); } } /// Loads the null reference. - public sealed partial class LdNull() : SimpleInstruction(OpCode.LdNull) + public sealed partial class LdNull : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public LdNull() : base(OpCode.LdNull) + { + } + public override StackType ResultType { get { return StackType.O; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdNull(this); } } /// Returns from the current method or lambda. - public sealed partial class Return() : ILInstruction(OpCode.Return) + public sealed partial class Return : ILInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Return() : base(OpCode.Return) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayBranch; + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitReturn(this); } } /// Shift left - public sealed partial class Shl(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Shl, opType, overflowMode) + public sealed partial class Shl : BinaryNumericInstruction { + public Shl(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Shl, opType, resultType, overflowMode) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitShl(this); } } /// Shift right - public sealed partial class Shr(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Shr, opType, overflowMode) + public sealed partial class Shr : BinaryNumericInstruction { + public Shr(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Shr, opType, resultType, overflowMode) + { + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitShr(this); } } /// Load instance field - public sealed partial class Ldfld() : UnaryInstruction(OpCode.Ldfld) + public sealed partial class Ldfld : UnaryInstruction { + public Ldfld() : base(OpCode.Ldfld) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.SideEffect; + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdfld(this); } } /// Load address of instance field - public sealed partial class Ldflda() : UnaryInstruction(OpCode.Ldflda) + public sealed partial class Ldflda : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Ldflda() : base(OpCode.Ldflda) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow; + } + public override StackType ResultType { get { return StackType.Ref; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdflda(this); } } /// Store value to instance field - public sealed partial class Stfld() : BinaryInstruction(OpCode.Stfld) + public sealed partial class Stfld : BinaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Stfld() : base(OpCode.Stfld) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow; + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitStfld(this); } } /// Load static field - public sealed partial class Ldsfld() : SimpleInstruction(OpCode.Ldsfld) + public sealed partial class Ldsfld : SimpleInstruction { + public Ldsfld() : base(OpCode.Ldsfld) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.SideEffect; + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdsfld(this); } } /// Load static field address - public sealed partial class Ldsflda() : SimpleInstruction(OpCode.Ldsflda) + public sealed partial class Ldsflda : SimpleInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Ldsflda() : base(OpCode.Ldsflda) + { + } + public override StackType ResultType { get { return StackType.Ref; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdsflda(this); } } /// Store value to static field - public sealed partial class Stsfld() : UnaryInstruction(OpCode.Stsfld) + public sealed partial class Stsfld : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Stsfld() : base(OpCode.Stsfld) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.SideEffect; + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitStsfld(this); } } /// Test if object is instance of class or interface. - public sealed partial class IsInst() : UnaryInstruction(OpCode.IsInst) + public sealed partial class IsInst : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public IsInst() : base(OpCode.IsInst) + { + } + public override StackType ResultType { get { return StackType.O; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitIsInst(this); } } /// Indirect load (ref/pointer dereference). - public sealed partial class LdInd() : UnaryInstruction(OpCode.LdInd) + public sealed partial class LdInd : UnaryInstruction { + public LdInd() : base(OpCode.LdInd) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow; + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdInd(this); } } /// Unbox a value. - public sealed partial class UnboxAny() : UnaryInstruction(OpCode.UnboxAny) + public sealed partial class UnboxAny : UnaryInstruction { + public UnboxAny() : base(OpCode.UnboxAny) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow; + } - public override TReturn AcceptVisitor(ILVisitor visitor) + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitUnboxAny(this); } } /// Creates an object instance and calls the constructor. - public sealed partial class NewObj(MethodReference method) : CallInstruction(OpCode.NewObj, method) + public sealed partial class NewObj : CallInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public NewObj(MethodReference method) : base(OpCode.NewObj, method) + { + } + public override StackType ResultType { get { return StackType.O; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitNewObj(this); } } /// Throws an exception. - public sealed partial class Throw() : UnaryInstruction(OpCode.Throw) + public sealed partial class Throw : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public Throw() : base(OpCode.Throw) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow; + } + public override StackType ResultType { get { return StackType.Void; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitThrow(this); } } /// Returns the length of an array as 'native unsigned int'. - public sealed partial class LdLen() : UnaryInstruction(OpCode.LdLen) + public sealed partial class LdLen : UnaryInstruction { - - public override TReturn AcceptVisitor(ILVisitor visitor) + public LdLen() : base(OpCode.LdLen) + { + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow; + } + public override StackType ResultType { get { return StackType.I; } } + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdLen(this); } @@ -648,219 +898,219 @@ namespace ICSharpCode.Decompiler.IL - public abstract class ILVisitor + public abstract class ILVisitor { - protected abstract TReturn Default(ILInstruction inst); + protected abstract T Default(ILInstruction inst); - protected internal virtual TReturn VisitNop(Nop inst) + protected internal virtual T VisitNop(Nop inst) { return Default(inst); } - protected internal virtual TReturn VisitPop(Pop inst) + protected internal virtual T VisitPop(Pop inst) { return Default(inst); } - protected internal virtual TReturn VisitPeek(Peek inst) + protected internal virtual T VisitPeek(Peek inst) { return Default(inst); } - protected internal virtual TReturn VisitVoid(Void inst) + protected internal virtual T VisitVoid(Void inst) { return Default(inst); } - protected internal virtual TReturn VisitBlockContainer(BlockContainer inst) + protected internal virtual T VisitBlockContainer(BlockContainer inst) { return Default(inst); } - protected internal virtual TReturn VisitBlock(Block inst) + protected internal virtual T VisitBlock(Block inst) { return Default(inst); } - protected internal virtual TReturn VisitLogicNot(LogicNot inst) + protected internal virtual T VisitLogicNot(LogicNot inst) { return Default(inst); } - protected internal virtual TReturn VisitAdd(Add inst) + protected internal virtual T VisitAdd(Add inst) { return Default(inst); } - protected internal virtual TReturn VisitSub(Sub inst) + protected internal virtual T VisitSub(Sub inst) { return Default(inst); } - protected internal virtual TReturn VisitMul(Mul inst) + protected internal virtual T VisitMul(Mul inst) { return Default(inst); } - protected internal virtual TReturn VisitDiv(Div inst) + protected internal virtual T VisitDiv(Div inst) { return Default(inst); } - protected internal virtual TReturn VisitRem(Rem inst) + protected internal virtual T VisitRem(Rem inst) { return Default(inst); } - protected internal virtual TReturn VisitNeg(Neg inst) + protected internal virtual T VisitNeg(Neg inst) { return Default(inst); } - protected internal virtual TReturn VisitBitAnd(BitAnd inst) + protected internal virtual T VisitBitAnd(BitAnd inst) { return Default(inst); } - protected internal virtual TReturn VisitBitOr(BitOr inst) + protected internal virtual T VisitBitOr(BitOr inst) { return Default(inst); } - protected internal virtual TReturn VisitBitXor(BitXor inst) + protected internal virtual T VisitBitXor(BitXor inst) { return Default(inst); } - protected internal virtual TReturn VisitBitNot(BitNot inst) + protected internal virtual T VisitBitNot(BitNot inst) { return Default(inst); } - protected internal virtual TReturn VisitArglist(Arglist inst) + protected internal virtual T VisitArglist(Arglist inst) { return Default(inst); } - protected internal virtual TReturn VisitConditionalBranch(ConditionalBranch inst) + protected internal virtual T VisitConditionalBranch(ConditionalBranch inst) { return Default(inst); } - protected internal virtual TReturn VisitBranch(Branch inst) + protected internal virtual T VisitBranch(Branch inst) { return Default(inst); } - protected internal virtual TReturn VisitDebugBreak(DebugBreak inst) + protected internal virtual T VisitDebugBreak(DebugBreak inst) { return Default(inst); } - protected internal virtual TReturn VisitCeq(Ceq inst) + protected internal virtual T VisitCeq(Ceq inst) { return Default(inst); } - protected internal virtual TReturn VisitCgt(Cgt inst) + protected internal virtual T VisitCgt(Cgt inst) { return Default(inst); } - protected internal virtual TReturn VisitCgt_Un(Cgt_Un inst) + protected internal virtual T VisitCgt_Un(Cgt_Un inst) { return Default(inst); } - protected internal virtual TReturn VisitClt(Clt inst) + protected internal virtual T VisitClt(Clt inst) { return Default(inst); } - protected internal virtual TReturn VisitClt_Un(Clt_Un inst) + protected internal virtual T VisitClt_Un(Clt_Un inst) { return Default(inst); } - protected internal virtual TReturn VisitCall(Call inst) + protected internal virtual T VisitCall(Call inst) { return Default(inst); } - protected internal virtual TReturn VisitCallVirt(CallVirt inst) + protected internal virtual T VisitCallVirt(CallVirt inst) { return Default(inst); } - protected internal virtual TReturn VisitCkFinite(CkFinite inst) + protected internal virtual T VisitCkFinite(CkFinite inst) { return Default(inst); } - protected internal virtual TReturn VisitConv(Conv inst) + protected internal virtual T VisitConv(Conv inst) { return Default(inst); } - protected internal virtual TReturn VisitLdloc(Ldloc inst) + protected internal virtual T VisitLdLoc(LdLoc inst) { return Default(inst); } - protected internal virtual TReturn VisitLdloca(Ldloca inst) + protected internal virtual T VisitLdLoca(LdLoca inst) { return Default(inst); } - protected internal virtual TReturn VisitStloc(Stloc inst) + protected internal virtual T VisitStLoc(StLoc inst) { return Default(inst); } - protected internal virtual TReturn VisitLdStr(LdStr inst) + protected internal virtual T VisitLdStr(LdStr inst) { return Default(inst); } - protected internal virtual TReturn VisitLdcI4(LdcI4 inst) + protected internal virtual T VisitLdcI4(LdcI4 inst) { return Default(inst); } - protected internal virtual TReturn VisitLdcI8(LdcI8 inst) + protected internal virtual T VisitLdcI8(LdcI8 inst) { return Default(inst); } - protected internal virtual TReturn VisitLdcF(LdcF inst) + protected internal virtual T VisitLdcF(LdcF inst) { return Default(inst); } - protected internal virtual TReturn VisitLdNull(LdNull inst) + protected internal virtual T VisitLdNull(LdNull inst) { return Default(inst); } - protected internal virtual TReturn VisitReturn(Return inst) + protected internal virtual T VisitReturn(Return inst) { return Default(inst); } - protected internal virtual TReturn VisitShl(Shl inst) + protected internal virtual T VisitShl(Shl inst) { return Default(inst); } - protected internal virtual TReturn VisitShr(Shr inst) + protected internal virtual T VisitShr(Shr inst) { return Default(inst); } - protected internal virtual TReturn VisitLdfld(Ldfld inst) + protected internal virtual T VisitLdfld(Ldfld inst) { return Default(inst); } - protected internal virtual TReturn VisitLdflda(Ldflda inst) + protected internal virtual T VisitLdflda(Ldflda inst) { return Default(inst); } - protected internal virtual TReturn VisitStfld(Stfld inst) + protected internal virtual T VisitStfld(Stfld inst) { return Default(inst); } - protected internal virtual TReturn VisitLdsfld(Ldsfld inst) + protected internal virtual T VisitLdsfld(Ldsfld inst) { return Default(inst); } - protected internal virtual TReturn VisitLdsflda(Ldsflda inst) + protected internal virtual T VisitLdsflda(Ldsflda inst) { return Default(inst); } - protected internal virtual TReturn VisitStsfld(Stsfld inst) + protected internal virtual T VisitStsfld(Stsfld inst) { return Default(inst); } - protected internal virtual TReturn VisitIsInst(IsInst inst) + protected internal virtual T VisitIsInst(IsInst inst) { return Default(inst); } - protected internal virtual TReturn VisitLdInd(LdInd inst) + protected internal virtual T VisitLdInd(LdInd inst) { return Default(inst); } - protected internal virtual TReturn VisitUnboxAny(UnboxAny inst) + protected internal virtual T VisitUnboxAny(UnboxAny inst) { return Default(inst); } - protected internal virtual TReturn VisitNewObj(NewObj inst) + protected internal virtual T VisitNewObj(NewObj inst) { return Default(inst); } - protected internal virtual TReturn VisitThrow(Throw inst) + protected internal virtual T VisitThrow(Throw inst) { return Default(inst); } - protected internal virtual TReturn VisitLdLen(LdLen inst) + protected internal virtual T VisitLdLen(LdLen inst) { return Default(inst); } diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index e8554e9dd..a3bee27d9 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -1,4 +1,22 @@ -<#@ template debug="false" hostspecific="false" language="C#" #> +// Copyright (c) 2014 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. + +<#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> @@ -6,61 +24,97 @@ <#@ output extension=".cs" #> <# OpCode[] opCodes = { - new OpCode("Nop", "No operation. Takes 0 arguments and returns void.", VoidResult, NoArguments), - new OpCode("Pop", "Pops the top of the evaluation stack and returns the value.", NoArguments, NonVoidResult), - new OpCode("Peek", "Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.", Peeking, NoArguments, NonVoidResult), - new OpCode("Void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.", VoidResult, Unary), + new OpCode("Nop", "No operation. Takes 0 arguments and returns void.", + VoidResult, NoArguments), + new OpCode("Pop", "Pops the top of the evaluation stack and returns the value.", + NoArguments, ResultTypeParam), + new OpCode("Peek", "Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.", + Peeking, NoArguments, ResultTypeParam), + new OpCode("Void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.", + VoidResult, Unary), new OpCode("BlockContainer", "A container of IL blocks.", VoidResult), new OpCode("Block", "A block of IL instructions."), - new OpCode("LogicNot", "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).", I4Result, Unary), + new OpCode("LogicNot", "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("Add", "Adds two numbers.", BinaryNumeric), new OpCode("Sub", "Subtracts two numbers", BinaryNumeric), new OpCode("Mul", "Multiplies two numbers", BinaryNumeric), new OpCode("Div", "Divides two numbers", BinaryNumeric, MayThrow), new OpCode("Rem", "Division remainder", BinaryNumeric, MayThrow), - new OpCode("Neg", "Unary negation", Unary, NonVoidResult), + new OpCode("Neg", "Unary negation", Unary, ResultTypeParam), new OpCode("BitAnd", "Bitwise AND", BinaryNumeric), new OpCode("BitOr", "Bitwise OR", BinaryNumeric), new OpCode("BitXor", "Bitwise XOR", BinaryNumeric), - new OpCode("BitNot", "Bitwise NOT", Unary, NonVoidResult), - new OpCode("Arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, NonVoidResult), - new OpCode("ConditionalBranch", "if (condition) goto target;.", Unary, MayBranch, HasBranchTarget, VoidResult), - new OpCode("Branch", "goto target;.", NoArguments, UnconditionalBranch, MayBranch, HasBranchTarget), - new OpCode("DebugBreak", "Breakpoint instruction", NoArguments, VoidResult, SideEffect), - new OpCode("Ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.", BinaryComparison), - new OpCode("Cgt", "Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.", BinaryComparison), - new OpCode("Cgt_Un", "Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.", BinaryComparison), - new OpCode("Clt", "Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.", BinaryComparison), - new OpCode("Clt_Un", "Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.", BinaryComparison), + new OpCode("BitNot", "Bitwise NOT", Unary, ResultTypeParam), + new OpCode("Arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")), + new OpCode("ConditionalBranch", "if (condition) goto target;.", + Unary, MayBranch, HasBranchTarget, VoidResult), + new OpCode("Branch", "goto target;.", + NoArguments, UnconditionalBranch, MayBranch, HasBranchTarget), + new OpCode("DebugBreak", "Breakpoint instruction", + NoArguments, VoidResult, SideEffect), + new OpCode("Ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.", + BinaryComparison), + new OpCode("Cgt", "Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.", + BinaryComparison), + new OpCode("Cgt_Un", "Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.", + BinaryComparison), + new OpCode("Clt", "Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.", + BinaryComparison), + new OpCode("Clt_Un", "Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.", + BinaryComparison), new OpCode("Call", "Non-virtual method call.", Call), new OpCode("CallVirt", "Virtual method call.", Call), - new OpCode("CkFinite", "Checks that the float on top of the stack is not NaN or infinite.", Peeking, NoArguments, MayThrow, VoidResult), - new OpCode("Conv", "Numeric cast.", Unary, NonVoidResult), - new OpCode("Ldloc", "Loads the value of a local variable. (ldarg/ldloc)", NoArguments, NonVoidResult, HasVariableOperand), - new OpCode("Ldloca", "Loads the address of a local variable. (ldarga/ldloca)", NoArguments, RefResult, HasVariableOperand), - new OpCode("Stloc", "Stores a value into a local variable. (starg/stloc)", Unary, VoidResult, HasVariableOperand), - new OpCode("LdStr", "Loads a constant string.", LoadConstant), - new OpCode("LdcI4", "Loads a constant 32-bit integer.", LoadConstant, I4Result), - new OpCode("LdcI8", "Loads a constant 64-bit integer.", LoadConstant, NonVoidResult), - new OpCode("LdcF", "Loads a constant floating-point number.", LoadConstant), - new OpCode("LdNull", "Loads the null reference.", LoadConstant), - new OpCode("Return", "Returns from the current method or lambda.", MayBranch, UnconditionalBranch), + new OpCode("CkFinite", "Checks that the float on top of the stack is not NaN or infinite.", + Peeking, NoArguments, MayThrow, VoidResult), + new OpCode("Conv", "Numeric cast.", + Unary, CustomConstructor), + new OpCode("LdLoc", "Loads the value of a local variable. (ldarg/ldloc)", + NoArguments, HasVariableOperand, ResultType("Variable.Type.ToStackType()")), + new OpCode("LdLoca", "Loads the address of a local variable. (ldarga/ldloca)", + NoArguments, ResultType("Ref"), HasVariableOperand), + new OpCode("StLoc", "Stores a value into a local variable. (starg/stloc)", + Unary, VoidResult, HasVariableOperand), + new OpCode("LdStr", "Loads a constant string.", + LoadConstant, ResultType("O")), + new OpCode("LdcI4", "Loads a constant 32-bit integer.", + LoadConstant, ResultType("I4")), + new OpCode("LdcI8", "Loads a constant 64-bit integer.", + LoadConstant, ResultType("I8")), + new OpCode("LdcF", "Loads a constant floating-point number.", + LoadConstant, ResultType("F")), + new OpCode("LdNull", "Loads the null reference.", + LoadConstant, ResultType("O")), + new OpCode("Return", "Returns from the current method or lambda.", + MayBranch, UnconditionalBranch), new OpCode("Shl", "Shift left", BinaryNumeric), new OpCode("Shr", "Shift right", BinaryNumeric), - new OpCode("Ldfld", "Load instance field", Unary, MayThrow, SideEffect, NonVoidResult, HasFieldOperand), - new OpCode("Ldflda", "Load address of instance field", Unary, MayThrow, RefResult, HasFieldOperand), - new OpCode("Stfld", "Store value to instance field", Binary, SideEffect, MayThrow, VoidResult, HasFieldOperand), - new OpCode("Ldsfld", "Load static field", NoArguments, SideEffect, NonVoidResult, HasFieldOperand), - new OpCode("Ldsflda", "Load static field address", NoArguments, RefResult, HasFieldOperand), - new OpCode("Stsfld", "Store value to static field", Unary, SideEffect, VoidResult, HasFieldOperand), - - new OpCode("IsInst", "Test if object is instance of class or interface.", Unary, NonVoidResult, HasTypeOperand), - new OpCode("LdInd", "Indirect load (ref/pointer dereference).", Unary, NonVoidResult, HasTypeOperand, SideEffect, MayThrow), - new OpCode("UnboxAny", "Unbox a value.", Unary, NonVoidResult, HasTypeOperand, SideEffect, MayThrow), - new OpCode("NewObj", "Creates an object instance and calls the constructor.", Call), - new OpCode("Throw", "Throws an exception.", Unary, MayThrow, UnconditionalBranch), - new OpCode("LdLen", "Returns the length of an array as 'native unsigned int'.", Unary, MayThrow, NonVoidResult), + new OpCode("Ldfld", "Load instance field", + Unary, MayThrow, SideEffect, HasFieldOperand), + new OpCode("Ldflda", "Load address of instance field", + Unary, MayThrow, HasFieldOperand, ResultType("Ref")), + new OpCode("Stfld", "Store value to instance field", + Binary, SideEffect, MayThrow, VoidResult, HasFieldOperand), + new OpCode("Ldsfld", "Load static field", + NoArguments, SideEffect, HasFieldOperand), + new OpCode("Ldsflda", "Load static field address", + NoArguments, ResultType("Ref"), HasFieldOperand), + new OpCode("Stsfld", "Store value to static field", + Unary, SideEffect, VoidResult, HasFieldOperand), + + new OpCode("IsInst", "Test if object is instance of class or interface.", + Unary, HasTypeOperand, ResultType("O")), + new OpCode("LdInd", "Indirect load (ref/pointer dereference).", + Unary, HasTypeOperand, SideEffect, MayThrow), + new OpCode("UnboxAny", "Unbox a value.", + Unary, HasTypeOperand, SideEffect, MayThrow), + new OpCode("NewObj", "Creates an object instance and calls the constructor.", + Call, ResultType("O")), + new OpCode("Throw", "Throws an exception.", + Unary, MayThrow, UnconditionalBranch), + new OpCode("LdLen", "Returns the length of an array as 'native unsigned int'.", + Unary, MayThrow, ResultType("I")), }; @@ -83,10 +137,20 @@ namespace ICSharpCode.Decompiler.IL <# foreach (OpCode opCode in opCodes) { #> /// <#=opCode.Description#> - public sealed partial class <#=opCode.Name#>(<#=string.Join(", ", opCode.ConstructorParameters)#>) : <#=opCode.BaseClass#>(<#=string.Join(", ", opCode.BaseConstructorArguments)#>) + public sealed partial class <#=opCode.Name#> : <#=opCode.BaseClass#> { -<#=string.Join(Environment.NewLine, opCode.Members)#> - public override TReturn AcceptVisitor(ILVisitor visitor) +<# if (opCode.GenerateConstructor) { #> + public <#=opCode.Name#>(<#=string.Join(", ", opCode.ConstructorParameters)#>) : base(<#=string.Join(", ", opCode.BaseConstructorArguments)#>) + {<#=Body(opCode.ConstructorBody)#>} +<# } #> +<# if (opCode.Flags.Count > 1) { #> + protected override InstructionFlags ComputeFlags() + { + return <#=string.Join(" | ", opCode.Flags)#>; + } +<# } #> +<#=string.Join(Environment.NewLine, opCode.Members.Select(m => "\t\t" + m))#> + public sealed override T AcceptVisitor(ILVisitor visitor) { return visitor.Visit<#=opCode.Name#>(this); } @@ -95,12 +159,12 @@ namespace ICSharpCode.Decompiler.IL <# } #> - public abstract class ILVisitor + public abstract class ILVisitor { - protected abstract TReturn Default(ILInstruction inst); + protected abstract T Default(ILInstruction inst); <# foreach (OpCode opCode in opCodes) { #> - protected internal virtual TReturn Visit<#=opCode.Name#>(<#=opCode.Name#> inst) + protected internal virtual T Visit<#=opCode.Name#>(<#=opCode.Name#> inst) { return Default(inst); } @@ -109,6 +173,19 @@ namespace ICSharpCode.Decompiler.IL } <#+ + static string Body(List statements) + { + StringBuilder b = new StringBuilder(); + foreach (var st in statements) { + b.AppendLine(); + b.Append("\t\t\t"); + b.Append(st); + } + b.AppendLine(); + b.Append("\t\t"); + return b.ToString(); + } + class OpCode { public readonly string Name; public readonly string Description; @@ -122,39 +199,65 @@ namespace ICSharpCode.Decompiler.IL trait(this); } + public bool GenerateConstructor = true; public List ConstructorParameters = new List(); + public List ConstructorBody = new List(); public string BaseClass = "ILInstruction"; public List BaseConstructorArguments = new List(); public List Members = new List(); + + public List Flags = new List() { "base.ComputeFlags()" }; + } + + static Action CustomConstructor = opCode => { + opCode.GenerateConstructor = false; + }; + + static Action HasFlag(string name) + { + return opCode => { + opCode.Flags.Add(name); + }; } // Peeking trait: the instruction looks at the top-of-stack without popping - static Action Peeking = opCode => { }; + static Action Peeking = HasFlag("InstructionFlags.MayPeek"); + + // ResultType trait: the instruction has the specified result type. + static Action ResultType(string type) + { + if (!type.Contains(".")) + type = "StackType." + type; + return opCode => { + opCode.Members.Add("public override StackType ResultType { get { return " + type + "; } }"); + }; + } // VoidResult trait: the instruction has no result and is not usable as an argument - static Action VoidResult = opCode => { }; - - // NonVoidResult trait: the instruction has a result and is usable as an argument - static Action NonVoidResult = opCode => { }; + static Action VoidResult = ResultType("Void"); - // I4Result trait: the instruction results in StackType.I4. Implies NonVoidResult. - static Action I4Result = NonVoidResult; - - // RefResult trait: the instruction results in StackType.Ref. Implies NonVoidResult. - static Action RefResult = NonVoidResult; + // ResultTypeParam trait: the instruction takes its result type as ctor parameter + static Action ResultTypeParam = opCode => { + opCode.ConstructorParameters.Add("StackType resultType"); + opCode.ConstructorBody.Add("this.resultType = resultType;"); + opCode.Members.Add("StackType resultType;"); + opCode.Members.Add("public override StackType ResultType { get { return resultType; } }"); + }; // MayThrow trait: the instruction may throw exceptions - static Action MayThrow = opCode => {}; + static Action MayThrow = HasFlag("InstructionFlags.MayThrow"); // MayBranch trait: the instruction may cause control flow to branch (e.g. branch, conditionalbranch, return) - static Action MayBranch = opCode => {}; + static Action MayBranch = HasFlag("InstructionFlags.MayBranch"); // HasBranchTarget trait: the instruction has an explicit branch target offset static Action HasBranchTarget = opCode => {}; // UnconditionalBranch trait: the instruction does not produce a result normally; it always branches or throws an exception. Implies VoidResult. - static Action UnconditionalBranch = opCode => {}; + static Action UnconditionalBranch = opCode => { + VoidResult(opCode); + }; // NoArguments trait: the instruction no arguments static Action NoArguments = opCode => { @@ -175,8 +278,10 @@ namespace ICSharpCode.Decompiler.IL static Action BinaryNumeric = opCode => { opCode.BaseClass = "BinaryNumericInstruction"; opCode.ConstructorParameters.Add("StackType opType"); + opCode.ConstructorParameters.Add("StackType resultType"); opCode.ConstructorParameters.Add("OverflowMode overflowMode"); opCode.BaseConstructorArguments.Add("opType"); + opCode.BaseConstructorArguments.Add("resultType"); opCode.BaseConstructorArguments.Add("overflowMode"); }; @@ -188,7 +293,7 @@ namespace ICSharpCode.Decompiler.IL }; // SideEffect trait: the instruction has a non-local side effect - static Action SideEffect = opCode => {}; + static Action SideEffect = HasFlag("InstructionFlags.SideEffect"); // Call trait: the instruction performs a method call static Action Call = opCode => { @@ -204,9 +309,8 @@ namespace ICSharpCode.Decompiler.IL static Action HasTypeOperand = opCode => {}; - // LoadConstant trait: the instruction loads a compile-time constant. Implies NoArguments and NonVoidResult + // LoadConstant trait: the instruction loads a compile-time constant. Implies NoArguments. static Action LoadConstant = opCode => { NoArguments(opCode); - NonVoidResult(opCode); }; #> \ No newline at end of file diff --git a/ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs new file mode 100644 index 000000000..0a957514a --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2014 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; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +namespace ICSharpCode.Decompiler.IL +{ + public abstract class BinaryComparisonInstruction : BinaryInstruction + { + public readonly StackType OpType; + + protected BinaryComparisonInstruction(OpCode opCode, StackType opType) : base(opCode) + { + this.OpType = opType; + } + + public sealed override StackType ResultType { + get { + return StackType.I4; + } + } + + public override void WriteTo(ITextOutput output) + { + output.Write(OpCode); + output.Write('.'); + output.Write(OpType); + output.Write('('); + Left.WriteTo(output); + output.Write(", "); + Right.WriteTo(output); + output.Write(')'); + } + } +} + + diff --git a/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs index 4c95801ee..69a3dbfa2 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs @@ -1,16 +1,89 @@ -using System; +// Copyright (c) 2014 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; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ICSharpCode.Decompiler.IL { - public abstract class BinaryInstruction(OpCode opCode) : ILInstruction(opCode) + public abstract class BinaryInstruction : ILInstruction { - public ILInstruction Left = Pop; - public ILInstruction Right = Pop; - + ILInstruction left = Pop; + ILInstruction right = Pop; + + protected BinaryInstruction(OpCode opCode) : base(opCode) + { + } + + public ILInstruction Left { + get { return left; } + set { + Debug.Assert(value.ResultType != StackType.Void); + left = value; + InvalidateFlags(); + } + } + + public ILInstruction Right { + get { return right; } + set { + Debug.Assert(value.ResultType != StackType.Void); + right = value; + InvalidateFlags(); + } + } + + internal override void CheckInvariant() + { + base.CheckInvariant(); + Left.CheckInvariant(); + Right.CheckInvariant(); + Debug.Assert(Left.ResultType != StackType.Void); + Debug.Assert(Right.ResultType != StackType.Void); + } + + public override void WriteTo(ITextOutput output) + { + output.Write(OpCode); + output.Write('('); + Left.WriteTo(output); + output.Write(", "); + Right.WriteTo(output); + output.Write(')'); + } + + protected override InstructionFlags ComputeFlags() + { + return Left.Flags | Right.Flags; + } + + public sealed override TAccumulate AggregateChildren(TAccumulate initial, ILVisitor visitor, Func func) + { + TAccumulate value = initial; + value = func(value, Left.AcceptVisitor(visitor)); + value = func(value, Right.AcceptVisitor(visitor)); + return value; + } + /* public override bool IsPeeking { get { return Left.IsPeeking; } } @@ -29,54 +102,4 @@ namespace ICSharpCode.Decompiler.IL return this; }*/ } - - public abstract class BinaryNumericInstruction(OpCode opCode, StackType opType, OverflowMode overflowMode) - : BinaryInstruction(opCode) - { - public readonly StackType OpType = opType; - public readonly OverflowMode OverflowMode = overflowMode; - - public override void WriteTo(ITextOutput output) - { - output.Write(OpCode); - output.WriteSuffix(OverflowMode); - output.Write(' '); - output.Write(OpType); - output.Write('('); - Left.WriteTo(output); - output.Write(", "); - Right.WriteTo(output); - output.Write(')'); - } - } - - public abstract class BinaryComparisonInstruction(OpCode opCode, StackType opType) - : BinaryInstruction(opCode) - { - public readonly StackType OpType = opType; - - public override void WriteTo(ITextOutput output) - { - output.Write(OpCode); - output.Write('.'); - output.Write(OpType); - output.Write('('); - Left.WriteTo(output); - output.Write(", "); - Right.WriteTo(output); - output.Write(')'); - } - } - - public enum OverflowMode : byte - { - /// Don't check for overflow, treat integers as signed. - None = 0, - /// Check for overflow, treat integers as signed. - Ovf = 1, - /// Don't check for overflow, treat integers as unsigned. - Un = 2, - /// Check for overflow, treat integers as unsigned. - Ovf_Un = 3 - } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs new file mode 100644 index 000000000..7a722f979 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs @@ -0,0 +1,84 @@ +// Copyright (c) 2014 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; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +namespace ICSharpCode.Decompiler.IL +{ + [Flags] + public enum OverflowMode : byte + { + /// Don't check for overflow, treat integers as signed. + None = 0, + /// Check for overflow, treat integers as signed. + Ovf = 1, + /// Don't check for overflow, treat integers as unsigned. + Un = 2, + /// Check for overflow, treat integers as unsigned. + Ovf_Un = 3 + } + + public abstract class BinaryNumericInstruction : BinaryInstruction + { + public readonly StackType OpType; + + public readonly OverflowMode OverflowMode; + + readonly StackType resultType; + + protected BinaryNumericInstruction(OpCode opCode, StackType opType, StackType resultType, OverflowMode overflowMode) : base(opCode) + { + this.OpType = opType; + this.resultType = resultType; + this.OverflowMode = overflowMode; + } + + public sealed override StackType ResultType { + get { + return resultType; + } + } + + protected override InstructionFlags ComputeFlags() + { + var flags = base.ComputeFlags(); + if ((OverflowMode & OverflowMode.Ovf) != 0) + flags |= InstructionFlags.MayThrow; + return flags; + } + + public override void WriteTo(ITextOutput output) + { + output.Write(OpCode); + output.WriteSuffix(OverflowMode); + output.Write(' '); + output.Write(OpType); + output.Write('('); + Left.WriteTo(output); + output.Write(", "); + Right.WriteTo(output); + output.Write(')'); + } + } +} + + diff --git a/ICSharpCode.Decompiler/IL/Instructions/Block.cs b/ICSharpCode.Decompiler/IL/Instructions/Block.cs index 206b3e6a8..5fc2d3cbe 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Block.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Block.cs @@ -47,6 +47,15 @@ namespace ICSharpCode.Decompiler.IL output.WriteLine("}"); } + public override TAccumulate AggregateChildren(TAccumulate initial, ILVisitor visitor, Func func) + { + TAccumulate value = initial; + foreach (var inst in Instructions) { + value = func(value, inst.AcceptVisitor(visitor)); + } + return value; + } + /* public override InstructionFlags Flags { @@ -107,6 +116,15 @@ namespace ICSharpCode.Decompiler.IL output.WriteLine("}"); } + public override TAccumulate AggregateChildren(TAccumulate initial, ILVisitor visitor, Func func) + { + TAccumulate value = initial; + foreach (var block in Blocks) { + value = func(value, block.AcceptVisitor(visitor)); + } + return value; + } + /* public override InstructionFlags Flags { diff --git a/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs index a2c1930a4..d7c446724 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs @@ -1,30 +1,143 @@ -using ICSharpCode.Decompiler.Disassembler; -using Mono.Cecil; +// Copyright (c) 2014 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; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; +using Mono.Cecil; +using ICSharpCode.Decompiler.Disassembler; namespace ICSharpCode.Decompiler.IL { - public abstract class CallInstruction(OpCode opCode, MethodReference methodReference) : ILInstruction(opCode) + public abstract class CallInstruction : ILInstruction { - public readonly MethodReference Method = methodReference; - public readonly ILInstruction[] Operands = InitOperands(opCode, methodReference); - - static ILInstruction[] InitOperands(OpCode opCode, MethodReference mr) + public struct ArgumentCollection : IReadOnlyList + { + readonly CallInstruction inst; + + public ArgumentCollection(CallInstruction inst) + { + this.inst = inst; + } + + public int Count { + get { return inst.arguments.Length; } + } + + public ILInstruction this[int index] { + get { return inst.arguments[index]; } + set { + Debug.Assert(value.ResultType != StackType.Void); + inst.arguments[index] = value; + inst.InvalidateFlags(); + } + } + + public ArgumentEnumerator GetEnumerator() + { + return new ArgumentEnumerator(inst.arguments); + } + + IEnumerator IEnumerable.GetEnumerator() + { + IEnumerable arguments = inst.arguments; + return arguments.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return inst.arguments.GetEnumerator(); + } + } + + public struct ArgumentEnumerator { - int popCount = mr.Parameters.Count; - if (opCode != OpCode.NewObj && mr.HasThis) + readonly ILInstruction[] arguments; + int index; + + public ArgumentEnumerator(ILInstruction[] arguments) + { + this.arguments = arguments; + } + + public bool MoveNext() + { + return ++index < arguments.Length; + } + + public ILInstruction Current { + get { return arguments[index]; } + } + } + + readonly ILInstruction[] arguments; + public readonly MethodReference Method; + + public ArgumentCollection Arguments { + get { return new ArgumentCollection(this); } + } + + protected CallInstruction(OpCode opCode, MethodReference methodReference) : base(opCode) + { + this.Method = methodReference; + int popCount = methodReference.Parameters.Count; + if (opCode != OpCode.NewObj && methodReference.HasThis) popCount++; - ILInstruction[] operands = new ILInstruction[popCount]; - for (int i = 0; i < operands.Length; i++) { - operands[i] = Pop; + this.arguments = new ILInstruction[popCount]; + for (int i = 0; i < arguments.Length; i++) { + arguments[i] = Pop; + } + } + + public override StackType ResultType { + get { + throw new NotImplementedException(); + } + } + + internal override void CheckInvariant() + { + base.CheckInvariant(); + foreach (var op in arguments) { + op.CheckInvariant(); + Debug.Assert(op.ResultType != StackType.Void); } - return operands; } + public override TAccumulate AggregateChildren(TAccumulate initial, ILVisitor visitor, Func func) + { + TAccumulate value = initial; + foreach (var op in arguments) + value = func(value, op.AcceptVisitor(visitor)); + return value; + } + + protected override InstructionFlags ComputeFlags() + { + var flags = InstructionFlags.MayThrow | InstructionFlags.SideEffects; + foreach (var op in arguments) + flags |= op.Flags; + return flags; + } + /* public override bool IsPeeking { get { return Operands.Length > 0 && Operands[0].IsPeeking; } } @@ -66,10 +179,10 @@ namespace ICSharpCode.Decompiler.IL output.Write(' '); Method.WriteTo(output); output.Write('('); - for (int i = 0; i < Operands.Length; i++) { + for (int i = 0; i < Arguments.Length; i++) { if (i > 0) output.Write(", "); - Operands[i].WriteTo(output); + Arguments[i].WriteTo(output); } output.Write(')'); } diff --git a/ICSharpCode.Decompiler/IL/Instructions/Conv.cs b/ICSharpCode.Decompiler/IL/Instructions/Conv.cs new file mode 100644 index 000000000..c0a480c45 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Instructions/Conv.cs @@ -0,0 +1,57 @@ +// Copyright (c) 2014 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; + +namespace ICSharpCode.Decompiler.IL +{ + partial class Conv : UnaryInstruction + { + public readonly StackType FromType; + public readonly PrimitiveType ToType; + public readonly OverflowMode ConvMode; + + public Conv(StackType fromType, PrimitiveType toType, OverflowMode convMode) : base(OpCode.Conv) + { + this.FromType = fromType; + this.ToType = toType; + this.ConvMode = convMode; + } + + public override void WriteTo(ITextOutput output) + { + output.Write(OpCode); + output.WriteSuffix(ConvMode); + output.Write(' '); + output.Write(FromType); + output.Write("->"); + output.Write(ToType); + output.Write('('); + Argument.WriteTo(output); + output.Write(')'); + } + + protected override InstructionFlags ComputeFlags() + { + var flags = base.ComputeFlags(); + if ((ConvMode & OverflowMode.Ovf) != 0) + flags |= InstructionFlags.MayThrow; + return flags; + } + } +} diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs index 8b4d74900..dbd6baefb 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs @@ -1,5 +1,24 @@ -using System; +// Copyright (c) 2014 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; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -10,12 +29,45 @@ namespace ICSharpCode.Decompiler.IL /// /// Represents a decoded IL instruction /// - public abstract class ILInstruction(OpCode opCode) + public abstract class ILInstruction { public static readonly ILInstruction Pop = new Pop(); + + public readonly OpCode OpCode; + + protected ILInstruction(OpCode opCode) + { + this.OpCode = opCode; + } - public readonly OpCode OpCode = opCode; - + [Conditional("DEBUG")] + internal virtual void CheckInvariant() + { + } + + /// + /// Gets the stack type of the value produced by this instruction. + /// + public abstract StackType ResultType { get; } + + InstructionFlags flags = (InstructionFlags)-1; + + public InstructionFlags Flags { + get { + if (flags == (InstructionFlags)-1) { + flags = ComputeFlags(); + } + return flags; + } + } + + protected void InvalidateFlags() + { + flags = (InstructionFlags)-1; + } + + protected abstract InstructionFlags ComputeFlags(); + /// /// Gets the ILRange for this instruction alone, ignoring the operands. /// @@ -32,8 +84,17 @@ namespace ICSharpCode.Decompiler.IL get { return true; } } - public abstract TReturn AcceptVisitor(ILVisitor visitor); - + public abstract T AcceptVisitor(ILVisitor visitor); + + /// + /// Computes an aggregate value over the direct children of this instruction. + /// + /// The initial value used to initialize the accumulator. + /// The visitor used to compute the value for the child instructions. + /// The function that combines the accumulator with the computed child value. + /// The final value in the accumulator. + public abstract TAccumulate AggregateChildren(TAccumulate initial, ILVisitor visitor, Func func); + /* /// /// Gets whether this instruction peeks at the top value of the stack. diff --git a/ICSharpCode.Decompiler/IL/Instructions/Return.cs b/ICSharpCode.Decompiler/IL/Instructions/Return.cs new file mode 100644 index 000000000..b0ab607a3 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Instructions/Return.cs @@ -0,0 +1,58 @@ +// Copyright (c) 2014 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.Diagnostics; + +namespace ICSharpCode.Decompiler.IL +{ + partial class Return + { + /// + /// The value to return. Null if this return statement is within a void method. + /// + public ILInstruction Argument = null; + + internal override void CheckInvariant() + { + base.CheckInvariant(); + if (Argument != null) { + Argument.CheckInvariant(); + Debug.Assert(Argument.ResultType != StackType.Void); + } + } + + public override void WriteTo(ITextOutput output) + { + output.Write(OpCode); + if (Argument != null) { + output.Write('('); + Argument.WriteTo(output); + output.Write(')'); + } + } + + public override TAccumulate AggregateChildren(TAccumulate initial, ILVisitor visitor, Func func) + { + TAccumulate value = initial; + if (Argument != null) + value = func(value, Argument.AcceptVisitor(visitor)); + return value; + } + } +} diff --git a/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs index 03968cbdc..000e2843c 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2014 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; using System.Linq; using System.Text; @@ -9,13 +27,27 @@ namespace ICSharpCode.Decompiler.IL /// /// A simple instruction that does not have any arguments. /// - public abstract class SimpleInstruction(OpCode opCode) : ILInstruction(opCode) + public abstract class SimpleInstruction : ILInstruction { + protected SimpleInstruction(OpCode opCode) : base(opCode) + { + } + public override void WriteTo(ITextOutput output) { output.Write(OpCode); } - + + public sealed override TAccumulate AggregateChildren(TAccumulate initial, ILVisitor visitor, Func func) + { + return initial; + } + + protected override InstructionFlags ComputeFlags() + { + return InstructionFlags.None; + } + /*public override bool IsPeeking { get { return false; } } public override void TransformChildren(Func transformFunc) diff --git a/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs index 32792f604..56f5dfd83 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs @@ -1,17 +1,51 @@ -using ICSharpCode.Decompiler.Disassembler; -using Mono.Cecil; +// Copyright (c) 2014 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; +using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace ICSharpCode.Decompiler.IL { - public abstract class UnaryInstruction(OpCode opCode) : ILInstruction(opCode) + public abstract class UnaryInstruction : ILInstruction { - public ILInstruction Argument = Pop; + ILInstruction argument = Pop; + + public ILInstruction Argument { + get { return argument; } + set { + Debug.Assert(value.ResultType != StackType.Void); + argument = value; + InvalidateFlags(); + } + } + + protected UnaryInstruction(OpCode opCode) : base(opCode) + { + } + internal override void CheckInvariant() + { + base.CheckInvariant(); + Argument.CheckInvariant(); + Debug.Assert(Argument.ResultType != StackType.Void); + } + //public sealed override bool IsPeeking { get { return Operand.IsPeeking; } } public override void WriteTo(ITextOutput output) @@ -21,7 +55,17 @@ namespace ICSharpCode.Decompiler.IL Argument.WriteTo(output); output.Write(')'); } - + + public sealed override TAccumulate AggregateChildren(TAccumulate initial, ILVisitor visitor, Func func) + { + return func(initial, Argument.AcceptVisitor(visitor)); + } + + protected override InstructionFlags ComputeFlags() + { + return Argument.Flags; + } + /* public override void TransformChildren(Func transformFunc) { diff --git a/ICSharpCode.Decompiler/IL/PrimitiveType.cs b/ICSharpCode.Decompiler/IL/PrimitiveType.cs index e4cdf57da..092b7e169 100644 --- a/ICSharpCode.Decompiler/IL/PrimitiveType.cs +++ b/ICSharpCode.Decompiler/IL/PrimitiveType.cs @@ -1,4 +1,22 @@ -using Mono.Cecil; +// Copyright (c) 2014 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 Mono.Cecil; using System; using System.Collections.Generic; using System.Linq; @@ -7,7 +25,7 @@ using System.Threading.Tasks; namespace ICSharpCode.Decompiler.IL { - enum PrimitiveType : byte + public enum PrimitiveType : byte { None = 0, I1 = MetadataType.SByte, diff --git a/ICSharpCode.Decompiler/IL/SemanticHelper.cs b/ICSharpCode.Decompiler/IL/SemanticHelper.cs index e17d8a40c..9f60dad08 100644 --- a/ICSharpCode.Decompiler/IL/SemanticHelper.cs +++ b/ICSharpCode.Decompiler/IL/SemanticHelper.cs @@ -1,8 +1,26 @@ +// Copyright (c) 2014 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; namespace ICSharpCode.Decompiler.IL { - internal class SemanticHelper + static class SemanticHelper { /// /// Gets whether the instruction sequence 'inst1; inst2;' may be ordered to 'inst2; inst1;' diff --git a/ICSharpCode.Decompiler/IL/StackType.cs b/ICSharpCode.Decompiler/IL/StackType.cs index 0198aff36..89c353365 100644 --- a/ICSharpCode.Decompiler/IL/StackType.cs +++ b/ICSharpCode.Decompiler/IL/StackType.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2014 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; using System.Linq; using System.Text; diff --git a/ICSharpCode.Decompiler/IL/Visitors/CountPopInstructionsVisitor.cs b/ICSharpCode.Decompiler/IL/Visitors/CountPopInstructionsVisitor.cs new file mode 100644 index 000000000..be27c6ed6 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Visitors/CountPopInstructionsVisitor.cs @@ -0,0 +1,40 @@ +// Copyright (c) 2014 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; + +namespace ICSharpCode.Decompiler.IL.Visitors +{ + sealed class CountPopInstructionsVisitor : ILVisitor + { + protected override int Default(ILInstruction inst) + { + return inst.AggregateChildren(0, this, (a, b) => a + b); + } + + protected internal override int VisitPop(Pop inst) + { + return 1; + } + + protected internal override int VisitBlock(Block inst) + { + throw new NotImplementedException(); + } + } +} diff --git a/ICSharpCode.Decompiler/Util/Interval.cs b/ICSharpCode.Decompiler/Util/Interval.cs index 7b76659c6..2b479ded0 100644 --- a/ICSharpCode.Decompiler/Util/Interval.cs +++ b/ICSharpCode.Decompiler/Util/Interval.cs @@ -48,10 +48,15 @@ namespace ICSharpCode.Decompiler /// /// An immutable set of integers, that is implemented as a list of intervals. /// - struct IntegerSet(ImmutableArray intervals) + struct IntegerSet { - public readonly ImmutableArray Intervals = intervals; + public readonly ImmutableArray Intervals; + public IntegerSet(ImmutableArray intervals) + { + this.Intervals = intervals; + } + public bool IsEmpty { get { return Intervals.IsDefaultOrEmpty; }