Browse Source

Worked on ILAst instruction representation

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
49ce1bcea3
  1. 23
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 44
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 31
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  4. 9
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  5. 35
      ICSharpCode.Decompiler/IL/BlockBuilder.cs
  6. 36
      ICSharpCode.Decompiler/IL/ILReader.cs
  7. 20
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  8. 37
      ICSharpCode.Decompiler/IL/ILVariable.cs
  9. 37
      ICSharpCode.Decompiler/IL/InstructionFlags.cs
  10. 20
      ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
  11. 646
      ICSharpCode.Decompiler/IL/Instructions.cs
  12. 230
      ICSharpCode.Decompiler/IL/Instructions.tt
  13. 56
      ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs
  14. 133
      ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs
  15. 84
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  16. 18
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  17. 143
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  18. 57
      ICSharpCode.Decompiler/IL/Instructions/Conv.cs
  19. 73
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  20. 58
      ICSharpCode.Decompiler/IL/Instructions/Return.cs
  21. 38
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  22. 60
      ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
  23. 22
      ICSharpCode.Decompiler/IL/PrimitiveType.cs
  24. 20
      ICSharpCode.Decompiler/IL/SemanticHelper.cs
  25. 20
      ICSharpCode.Decompiler/IL/StackType.cs
  26. 40
      ICSharpCode.Decompiler/IL/Visitors/CountPopInstructionsVisitor.cs
  27. 9
      ICSharpCode.Decompiler/Util/Interval.cs

23
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;
using ICSharpCode.NRefactory.CSharp.Refactoring; using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
@ -54,7 +72,8 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
var unresolved = member.UnresolvedMember; var unresolved = member.UnresolvedMember;
lock (entityDict) { lock (entityDict) {
if (unresolved != null && entityDict.TryGetValue(unresolved, out var mr)) MemberReference mr;
if (unresolved != null && entityDict.TryGetValue(unresolved, out mr))
return mr; return mr;
} }
return null; return null;

44
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.CSharp;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using System; using System;
@ -12,13 +30,25 @@ namespace ICSharpCode.Decompiler.CSharp
/// <summary> /// <summary>
/// Translates from ILAst to C# expressions. /// Translates from ILAst to C# expressions.
/// </summary> /// </summary>
class ExpressionBuilder(ICompilation compilation) : ILVisitor<ExpressionBuilder.ConvertedExpression> class ExpressionBuilder : ILVisitor<ExpressionBuilder.ConvertedExpression>
{ {
private readonly ICompilation compilation = compilation; private readonly ICompilation compilation;
internal struct ConvertedExpression(Expression expression, IType type) { public ExpressionBuilder(ICompilation compilation)
public readonly Expression Expression = expression; {
public readonly IType Type = type; 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) public Expression Convert(ILInstruction inst)

31
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.CSharp;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using System; using System;
@ -9,10 +27,15 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.CSharp namespace ICSharpCode.Decompiler.CSharp
{ {
class StatementBuilder(ICompilation compilation) : ILVisitor<Statement> class StatementBuilder : ILVisitor<Statement>
{ {
readonly ExpressionBuilder exprBuilder = new ExpressionBuilder(compilation); readonly ExpressionBuilder exprBuilder;
public StatementBuilder(ICompilation compilation)
{
this.exprBuilder = new ExpressionBuilder(compilation);
}
public Statement Convert(ILInstruction inst) public Statement Convert(ILInstruction inst)
{ {
return inst.AcceptVisitor(this); return inst.AcceptVisitor(this);

9
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -19,7 +19,6 @@
<AssemblyOriginatorKeyFile>..\NRefactory\ICSharpCode.NRefactory.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\NRefactory\ICSharpCode.NRefactory.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign> <DelaySign>False</DelaySign>
<AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode> <AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode>
<LangVersion>experimental</LangVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' "> <PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@ -72,12 +71,17 @@
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<DependentUpon>Instructions.tt</DependentUpon> <DependentUpon>Instructions.tt</DependentUpon>
</Compile> </Compile>
<Compile Include="IL\Instructions\BinaryComparisonInstruction.cs" />
<Compile Include="IL\Instructions\BinaryInstruction.cs" /> <Compile Include="IL\Instructions\BinaryInstruction.cs" />
<Compile Include="IL\Instructions\BinaryNumericInstruction.cs" />
<Compile Include="IL\Instructions\Block.cs" /> <Compile Include="IL\Instructions\Block.cs" />
<Compile Include="IL\Instructions\CallInstruction.cs" /> <Compile Include="IL\Instructions\CallInstruction.cs" />
<Compile Include="IL\Instructions\Conv.cs" />
<Compile Include="IL\Instructions\ILInstruction.cs" /> <Compile Include="IL\Instructions\ILInstruction.cs" />
<Compile Include="IL\Instructions\Return.cs" />
<Compile Include="IL\Instructions\SimpleInstruction.cs" /> <Compile Include="IL\Instructions\SimpleInstruction.cs" />
<Compile Include="IL\Instructions\UnaryInstruction.cs" /> <Compile Include="IL\Instructions\UnaryInstruction.cs" />
<Compile Include="IL\Visitors\CountPopInstructionsVisitor.cs" />
<Compile Include="TypesHierarchyHelpers.cs" /> <Compile Include="TypesHierarchyHelpers.cs" />
<Compile Include="CecilExtensions.cs" /> <Compile Include="CecilExtensions.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" /> <Compile Include="Disassembler\DisassemblerHelpers.cs" />
@ -138,6 +142,9 @@
<ItemGroup> <ItemGroup>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" /> <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="IL\Visitors" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">
<MSBuild Projects="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\UpdateAssemblyInfo.csproj" Targets="Build" Properties="Configuration=Debug" /> <MSBuild Projects="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\UpdateAssemblyInfo.csproj" Targets="Build" Properties="Configuration=Debug" />

35
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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -8,12 +26,18 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
class BlockBuilder(Mono.Cecil.Cil.MethodBody body, bool instructionInlining) class BlockBuilder
{ {
readonly Stack<ILInstruction> instructionStack;
public BlockBuilder(Mono.Cecil.Cil.MethodBody body, bool instructionInlining)
{
this.instructionStack = (instructionInlining ? new Stack<ILInstruction>() : null);
}
BlockContainer currentContainer; BlockContainer currentContainer;
Block currentBlock; Block currentBlock;
Stack<ILInstruction> instructionStack = (instructionInlining ? new Stack<ILInstruction>() : null);
public BlockContainer CreateBlocks(List<ILInstruction> instructions, BitArray incomingBranches) public BlockContainer CreateBlocks(List<ILInstruction> instructions, BitArray incomingBranches)
{ {
currentContainer = new BlockContainer(); currentContainer = new BlockContainer();
@ -35,7 +59,8 @@ namespace ICSharpCode.Decompiler.IL
// inlining disabled // inlining disabled
currentBlock.Instructions.Add(inst); currentBlock.Instructions.Add(inst);
} else { } 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) { if (inlinedInst is Branch) {
// Values currently on the stack might be used on both sides of the branch, // Values currently on the stack might be used on both sides of the branch,
// so we can't inline them. // so we can't inline them.

36
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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -11,11 +29,19 @@ using System.Threading;
namespace ICSharpCode.Decompiler.IL 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 Mono.Cecil.Cil.MethodBody body;
private readonly CancellationToken cancellationToken = cancellationToken; 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) internal static ILOpCode ReadOpCode(ref BlobReader reader)
{ {
byte b = reader.ReadByte(); byte b = reader.ReadByte();
@ -699,7 +725,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
var method = (MethodReference)ReadAndDecodeMetadataToken(); var method = (MethodReference)ReadAndDecodeMetadataToken();
var inst = new CallInstruction(opCode, method); 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(); stack.Pop();
} }
var returnType = (opCode == OpCode.NewObj ? method.DeclaringType : method.ReturnType).GetStackType(); var returnType = (opCode == OpCode.NewObj ? method.DeclaringType : method.ReturnType).GetStackType();

20
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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;

37
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 Mono.Cecil.Cil;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -14,14 +32,23 @@ namespace ICSharpCode.Decompiler.IL
Parameter, Parameter,
} }
class ILVariable(VariableKind kind, TypeReference type, int index) class ILVariable
{ {
public readonly VariableKind Kind = kind; public readonly VariableKind Kind;
public readonly TypeReference Type = type; public readonly TypeReference Type;
public readonly int Index = index; public readonly int Index;
readonly object CecilObject; 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) public ILVariable(VariableDefinition v)
: this(VariableKind.Local, v.VariableType, v.Index) : this(VariableKind.Local, v.VariableType, v.Index)
{ {

37
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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -10,6 +28,9 @@ namespace ICSharpCode.Decompiler.IL
public enum InstructionFlags public enum InstructionFlags
{ {
None = 0, None = 0,
/// <summary>
/// The instruction may pop from the evaluation stack.
/// </summary>
MayPop = 0x01, MayPop = 0x01,
MayPeek = 0x02, MayPeek = 0x02,
/// <summary> /// <summary>
@ -17,19 +38,19 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
MayThrow = 0x04, MayThrow = 0x04,
/// <summary> /// <summary>
/// The instruction may read from local variables. /// The instruction may exit with a branch or return.
/// </summary> /// </summary>
MayReadLocals = 0x08, MayBranch = 0x08,
/// <summary> /// <summary>
/// The instruction may write to local variables. /// The instruction may read from local variables.
/// </summary> /// </summary>
MayWriteLocals = 0x10, MayReadLocals = 0x10,
/// <summary> /// <summary>
/// The instruction may exit with a jump or return. /// The instruction may write to local variables.
/// </summary> /// </summary>
MayJump = 0x20, MayWriteLocals = 0x20,
/// <summary> /// <summary>
/// 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. /// performing system calls, writing to local variables through pointers, etc.
/// </summary> /// </summary>
SideEffects = 0x40, SideEffects = 0x40,

20
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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;

646
ICSharpCode.Decompiler/IL/Instructions.cs

File diff suppressed because it is too large Load Diff

230
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" #> <#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #> <#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #> <#@ import namespace="System.Text" #>
@ -6,61 +24,97 @@
<#@ output extension=".cs" #> <#@ output extension=".cs" #>
<# <#
OpCode[] opCodes = { OpCode[] opCodes = {
new OpCode("Nop", "No operation. Takes 0 arguments and returns void.", VoidResult, NoArguments), new OpCode("Nop", "No operation. Takes 0 arguments and returns void.",
new OpCode("Pop", "Pops the top of the evaluation stack and returns the value.", NoArguments, NonVoidResult), VoidResult, NoArguments),
new OpCode("Peek", "Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.", Peeking, NoArguments, NonVoidResult), new OpCode("Pop", "Pops the top of the evaluation stack and returns the value.",
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), 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("BlockContainer", "A container of IL blocks.", VoidResult),
new OpCode("Block", "A block of IL instructions."), 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("Add", "Adds two numbers.", BinaryNumeric),
new OpCode("Sub", "Subtracts two numbers", BinaryNumeric), new OpCode("Sub", "Subtracts two numbers", BinaryNumeric),
new OpCode("Mul", "Multiplies two numbers", BinaryNumeric), new OpCode("Mul", "Multiplies two numbers", BinaryNumeric),
new OpCode("Div", "Divides two numbers", BinaryNumeric, MayThrow), new OpCode("Div", "Divides two numbers", BinaryNumeric, MayThrow),
new OpCode("Rem", "Division remainder", 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("BitAnd", "Bitwise AND", BinaryNumeric),
new OpCode("BitOr", "Bitwise OR", BinaryNumeric), new OpCode("BitOr", "Bitwise OR", BinaryNumeric),
new OpCode("BitXor", "Bitwise XOR", BinaryNumeric), new OpCode("BitXor", "Bitwise XOR", BinaryNumeric),
new OpCode("BitNot", "Bitwise NOT", Unary, NonVoidResult), new OpCode("BitNot", "Bitwise NOT", Unary, ResultTypeParam),
new OpCode("Arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, NonVoidResult), new OpCode("Arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
new OpCode("ConditionalBranch", "<c>if (condition) goto target;</c>.", Unary, MayBranch, HasBranchTarget, VoidResult), new OpCode("ConditionalBranch", "<c>if (condition) goto target;</c>.",
new OpCode("Branch", "<c>goto target;</c>.", NoArguments, UnconditionalBranch, MayBranch, HasBranchTarget), Unary, MayBranch, HasBranchTarget, VoidResult),
new OpCode("DebugBreak", "Breakpoint instruction", NoArguments, VoidResult, SideEffect), new OpCode("Branch", "<c>goto target;</c>.",
new OpCode("Ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.", BinaryComparison), NoArguments, UnconditionalBranch, MayBranch, HasBranchTarget),
new OpCode("Cgt", "Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.", BinaryComparison), new OpCode("DebugBreak", "Breakpoint instruction",
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), NoArguments, VoidResult, SideEffect),
new OpCode("Clt", "Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.", BinaryComparison), new OpCode("Ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.",
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), 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("Call", "Non-virtual method call.", Call),
new OpCode("CallVirt", "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("CkFinite", "Checks that the float on top of the stack is not NaN or infinite.",
new OpCode("Conv", "Numeric cast.", Unary, NonVoidResult), Peeking, NoArguments, MayThrow, VoidResult),
new OpCode("Ldloc", "Loads the value of a local variable. (ldarg/ldloc)", NoArguments, NonVoidResult, HasVariableOperand), new OpCode("Conv", "Numeric cast.",
new OpCode("Ldloca", "Loads the address of a local variable. (ldarga/ldloca)", NoArguments, RefResult, HasVariableOperand), Unary, CustomConstructor),
new OpCode("Stloc", "Stores a value into a local variable. (starg/stloc)", Unary, VoidResult, HasVariableOperand), new OpCode("LdLoc", "Loads the value of a local variable. (ldarg/ldloc)",
new OpCode("LdStr", "Loads a constant string.", LoadConstant), NoArguments, HasVariableOperand, ResultType("Variable.Type.ToStackType()")),
new OpCode("LdcI4", "Loads a constant 32-bit integer.", LoadConstant, I4Result), new OpCode("LdLoca", "Loads the address of a local variable. (ldarga/ldloca)",
new OpCode("LdcI8", "Loads a constant 64-bit integer.", LoadConstant, NonVoidResult), NoArguments, ResultType("Ref"), HasVariableOperand),
new OpCode("LdcF", "Loads a constant floating-point number.", LoadConstant), new OpCode("StLoc", "Stores a value into a local variable. (starg/stloc)",
new OpCode("LdNull", "Loads the null reference.", LoadConstant), Unary, VoidResult, HasVariableOperand),
new OpCode("Return", "Returns from the current method or lambda.", MayBranch, UnconditionalBranch), 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("Shl", "Shift left", BinaryNumeric),
new OpCode("Shr", "Shift right", BinaryNumeric), new OpCode("Shr", "Shift right", BinaryNumeric),
new OpCode("Ldfld", "Load instance field", Unary, MayThrow, SideEffect, NonVoidResult, HasFieldOperand), new OpCode("Ldfld", "Load instance field",
new OpCode("Ldflda", "Load address of instance field", Unary, MayThrow, RefResult, HasFieldOperand), Unary, MayThrow, SideEffect, HasFieldOperand),
new OpCode("Stfld", "Store value to instance field", Binary, SideEffect, MayThrow, VoidResult, HasFieldOperand), new OpCode("Ldflda", "Load address of instance field",
new OpCode("Ldsfld", "Load static field", NoArguments, SideEffect, NonVoidResult, HasFieldOperand), Unary, MayThrow, HasFieldOperand, ResultType("Ref")),
new OpCode("Ldsflda", "Load static field address", NoArguments, RefResult, HasFieldOperand), new OpCode("Stfld", "Store value to instance field",
new OpCode("Stsfld", "Store value to static field", Unary, SideEffect, VoidResult, HasFieldOperand), Binary, SideEffect, MayThrow, VoidResult, HasFieldOperand),
new OpCode("Ldsfld", "Load static field",
new OpCode("IsInst", "Test if object is instance of class or interface.", Unary, NonVoidResult, HasTypeOperand), NoArguments, SideEffect, HasFieldOperand),
new OpCode("LdInd", "Indirect load (ref/pointer dereference).", Unary, NonVoidResult, HasTypeOperand, SideEffect, MayThrow), new OpCode("Ldsflda", "Load static field address",
new OpCode("UnboxAny", "Unbox a value.", Unary, NonVoidResult, HasTypeOperand, SideEffect, MayThrow), NoArguments, ResultType("Ref"), HasFieldOperand),
new OpCode("NewObj", "Creates an object instance and calls the constructor.", Call), new OpCode("Stsfld", "Store value to static field",
new OpCode("Throw", "Throws an exception.", Unary, MayThrow, UnconditionalBranch), Unary, SideEffect, VoidResult, HasFieldOperand),
new OpCode("LdLen", "Returns the length of an array as 'native unsigned int'.", Unary, MayThrow, NonVoidResult),
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) { #> <# foreach (OpCode opCode in opCodes) { #>
/// <summary><#=opCode.Description#></summary> /// <summary><#=opCode.Description#></summary>
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)#> <# if (opCode.GenerateConstructor) { #>
public override TReturn AcceptVisitor<TReturn>(ILVisitor<TReturn> visitor) 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<T>(ILVisitor<T> visitor)
{ {
return visitor.Visit<#=opCode.Name#>(this); return visitor.Visit<#=opCode.Name#>(this);
} }
@ -95,12 +159,12 @@ namespace ICSharpCode.Decompiler.IL
<# } #> <# } #>
public abstract class ILVisitor<TReturn> public abstract class ILVisitor<T>
{ {
protected abstract TReturn Default(ILInstruction inst); protected abstract T Default(ILInstruction inst);
<# foreach (OpCode opCode in opCodes) { #> <# 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); return Default(inst);
} }
@ -109,6 +173,19 @@ namespace ICSharpCode.Decompiler.IL
} }
<#+ <#+
static string Body(List<string> 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 { class OpCode {
public readonly string Name; public readonly string Name;
public readonly string Description; public readonly string Description;
@ -122,39 +199,65 @@ namespace ICSharpCode.Decompiler.IL
trait(this); trait(this);
} }
public bool GenerateConstructor = true;
public List<string> ConstructorParameters = new List<string>(); public List<string> ConstructorParameters = new List<string>();
public List<string> ConstructorBody = new List<string>();
public string BaseClass = "ILInstruction"; public string BaseClass = "ILInstruction";
public List<string> BaseConstructorArguments = new List<string>(); public List<string> BaseConstructorArguments = new List<string>();
public List<string> Members = new List<string>(); public List<string> Members = new List<string>();
public List<string> Flags = new List<string>() { "base.ComputeFlags()" };
}
static Action<OpCode> CustomConstructor = opCode => {
opCode.GenerateConstructor = false;
};
static Action<OpCode> HasFlag(string name)
{
return opCode => {
opCode.Flags.Add(name);
};
} }
// Peeking trait: the instruction looks at the top-of-stack without popping // Peeking trait: the instruction looks at the top-of-stack without popping
static Action<OpCode> Peeking = opCode => { }; static Action<OpCode> Peeking = HasFlag("InstructionFlags.MayPeek");
// ResultType trait: the instruction has the specified result type.
static Action<OpCode> 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 // VoidResult trait: the instruction has no result and is not usable as an argument
static Action<OpCode> VoidResult = opCode => { }; static Action<OpCode> VoidResult = ResultType("Void");
// NonVoidResult trait: the instruction has a result and is usable as an argument
static Action<OpCode> NonVoidResult = opCode => { };
// I4Result trait: the instruction results in StackType.I4. Implies NonVoidResult. // ResultTypeParam trait: the instruction takes its result type as ctor parameter
static Action<OpCode> I4Result = NonVoidResult; static Action<OpCode> ResultTypeParam = opCode => {
opCode.ConstructorParameters.Add("StackType resultType");
// RefResult trait: the instruction results in StackType.Ref. Implies NonVoidResult. opCode.ConstructorBody.Add("this.resultType = resultType;");
static Action<OpCode> RefResult = NonVoidResult; opCode.Members.Add("StackType resultType;");
opCode.Members.Add("public override StackType ResultType { get { return resultType; } }");
};
// MayThrow trait: the instruction may throw exceptions // MayThrow trait: the instruction may throw exceptions
static Action<OpCode> MayThrow = opCode => {}; static Action<OpCode> MayThrow = HasFlag("InstructionFlags.MayThrow");
// MayBranch trait: the instruction may cause control flow to branch (e.g. branch, conditionalbranch, return) // MayBranch trait: the instruction may cause control flow to branch (e.g. branch, conditionalbranch, return)
static Action<OpCode> MayBranch = opCode => {}; static Action<OpCode> MayBranch = HasFlag("InstructionFlags.MayBranch");
// HasBranchTarget trait: the instruction has an explicit branch target offset // HasBranchTarget trait: the instruction has an explicit branch target offset
static Action<OpCode> HasBranchTarget = opCode => {}; static Action<OpCode> HasBranchTarget = opCode => {};
// UnconditionalBranch trait: the instruction does not produce a result normally; it always branches or throws an exception. Implies VoidResult. // UnconditionalBranch trait: the instruction does not produce a result normally; it always branches or throws an exception. Implies VoidResult.
static Action<OpCode> UnconditionalBranch = opCode => {}; static Action<OpCode> UnconditionalBranch = opCode => {
VoidResult(opCode);
};
// NoArguments trait: the instruction no arguments // NoArguments trait: the instruction no arguments
static Action<OpCode> NoArguments = opCode => { static Action<OpCode> NoArguments = opCode => {
@ -175,8 +278,10 @@ namespace ICSharpCode.Decompiler.IL
static Action<OpCode> BinaryNumeric = opCode => { static Action<OpCode> BinaryNumeric = opCode => {
opCode.BaseClass = "BinaryNumericInstruction"; opCode.BaseClass = "BinaryNumericInstruction";
opCode.ConstructorParameters.Add("StackType opType"); opCode.ConstructorParameters.Add("StackType opType");
opCode.ConstructorParameters.Add("StackType resultType");
opCode.ConstructorParameters.Add("OverflowMode overflowMode"); opCode.ConstructorParameters.Add("OverflowMode overflowMode");
opCode.BaseConstructorArguments.Add("opType"); opCode.BaseConstructorArguments.Add("opType");
opCode.BaseConstructorArguments.Add("resultType");
opCode.BaseConstructorArguments.Add("overflowMode"); opCode.BaseConstructorArguments.Add("overflowMode");
}; };
@ -188,7 +293,7 @@ namespace ICSharpCode.Decompiler.IL
}; };
// SideEffect trait: the instruction has a non-local side effect // SideEffect trait: the instruction has a non-local side effect
static Action<OpCode> SideEffect = opCode => {}; static Action<OpCode> SideEffect = HasFlag("InstructionFlags.SideEffect");
// Call trait: the instruction performs a method call // Call trait: the instruction performs a method call
static Action<OpCode> Call = opCode => { static Action<OpCode> Call = opCode => {
@ -204,9 +309,8 @@ namespace ICSharpCode.Decompiler.IL
static Action<OpCode> HasTypeOperand = opCode => {}; static Action<OpCode> 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<OpCode> LoadConstant = opCode => { static Action<OpCode> LoadConstant = opCode => {
NoArguments(opCode); NoArguments(opCode);
NonVoidResult(opCode);
}; };
#> #>

56
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(')');
}
}
}

133
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.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
public abstract class BinaryInstruction(OpCode opCode) : ILInstruction(opCode) public abstract class BinaryInstruction : ILInstruction
{ {
public ILInstruction Left = Pop; ILInstruction left = Pop;
public ILInstruction Right = 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<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> 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; } } public override bool IsPeeking { get { return Left.IsPeeking; } }
@ -29,54 +102,4 @@ namespace ICSharpCode.Decompiler.IL
return this; 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
{
/// <summary>Don't check for overflow, treat integers as signed.</summary>
None = 0,
/// <summary>Check for overflow, treat integers as signed.</summary>
Ovf = 1,
/// <summary>Don't check for overflow, treat integers as unsigned.</summary>
Un = 2,
/// <summary>Check for overflow, treat integers as unsigned.</summary>
Ovf_Un = 3
}
} }

84
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
{
/// <summary>Don't check for overflow, treat integers as signed.</summary>
None = 0,
/// <summary>Check for overflow, treat integers as signed.</summary>
Ovf = 1,
/// <summary>Don't check for overflow, treat integers as unsigned.</summary>
Un = 2,
/// <summary>Check for overflow, treat integers as unsigned.</summary>
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(')');
}
}
}

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

@ -47,6 +47,15 @@ namespace ICSharpCode.Decompiler.IL
output.WriteLine("}"); output.WriteLine("}");
} }
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate value = initial;
foreach (var inst in Instructions) {
value = func(value, inst.AcceptVisitor(visitor));
}
return value;
}
/* /*
public override InstructionFlags Flags public override InstructionFlags Flags
{ {
@ -107,6 +116,15 @@ namespace ICSharpCode.Decompiler.IL
output.WriteLine("}"); output.WriteLine("}");
} }
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate value = initial;
foreach (var block in Blocks) {
value = func(value, block.AcceptVisitor(visitor));
}
return value;
}
/* /*
public override InstructionFlags Flags public override InstructionFlags Flags
{ {

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

@ -1,30 +1,143 @@
using ICSharpCode.Decompiler.Disassembler; // Copyright (c) 2014 Daniel Grunwald
using Mono.Cecil; //
// 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Mono.Cecil;
using ICSharpCode.Decompiler.Disassembler;
namespace ICSharpCode.Decompiler.IL 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 struct ArgumentCollection : IReadOnlyList<ILInstruction>
public readonly ILInstruction[] Operands = InitOperands(opCode, methodReference); {
readonly CallInstruction inst;
static ILInstruction[] InitOperands(OpCode opCode, MethodReference mr)
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<ILInstruction> IEnumerable<ILInstruction>.GetEnumerator()
{
IEnumerable<ILInstruction> 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; readonly ILInstruction[] arguments;
if (opCode != OpCode.NewObj && mr.HasThis) 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++; popCount++;
ILInstruction[] operands = new ILInstruction[popCount]; this.arguments = new ILInstruction[popCount];
for (int i = 0; i < operands.Length; i++) { for (int i = 0; i < arguments.Length; i++) {
operands[i] = Pop; 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<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> 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; } } public override bool IsPeeking { get { return Operands.Length > 0 && Operands[0].IsPeeking; } }
@ -66,10 +179,10 @@ namespace ICSharpCode.Decompiler.IL
output.Write(' '); output.Write(' ');
Method.WriteTo(output); Method.WriteTo(output);
output.Write('('); output.Write('(');
for (int i = 0; i < Operands.Length; i++) { for (int i = 0; i < Arguments.Length; i++) {
if (i > 0) if (i > 0)
output.Write(", "); output.Write(", ");
Operands[i].WriteTo(output); Arguments[i].WriteTo(output);
} }
output.Write(')'); output.Write(')');
} }

57
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;
}
}
}

73
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.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -10,12 +29,45 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Represents a decoded IL instruction /// Represents a decoded IL instruction
/// </summary> /// </summary>
public abstract class ILInstruction(OpCode opCode) public abstract class ILInstruction
{ {
public static readonly ILInstruction Pop = new Pop(); 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()
{
}
/// <summary>
/// Gets the stack type of the value produced by this instruction.
/// </summary>
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();
/// <summary> /// <summary>
/// Gets the ILRange for this instruction alone, ignoring the operands. /// Gets the ILRange for this instruction alone, ignoring the operands.
/// </summary> /// </summary>
@ -32,8 +84,17 @@ namespace ICSharpCode.Decompiler.IL
get { return true; } get { return true; }
} }
public abstract TReturn AcceptVisitor<TReturn>(ILVisitor<TReturn> visitor); public abstract T AcceptVisitor<T>(ILVisitor<T> visitor);
/// <summary>
/// Computes an aggregate value over the direct children of this instruction.
/// </summary>
/// <param name="initial">The initial value used to initialize the accumulator.</param>
/// <param name="visitor">The visitor used to compute the value for the child instructions.</param>
/// <param name="func">The function that combines the accumulator with the computed child value.</param>
/// <returns>The final value in the accumulator.</returns>
public abstract TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func);
/* /*
/// <summary> /// <summary>
/// Gets whether this instruction peeks at the top value of the stack. /// Gets whether this instruction peeks at the top value of the stack.

58
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
{
/// <summary>
/// The value to return. Null if this return statement is within a void method.
/// </summary>
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<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate value = initial;
if (Argument != null)
value = func(value, Argument.AcceptVisitor(visitor));
return value;
}
}
}

38
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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -9,13 +27,27 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// A simple instruction that does not have any arguments. /// A simple instruction that does not have any arguments.
/// </summary> /// </summary>
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) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); output.Write(OpCode);
} }
public sealed override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
return initial;
}
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.None;
}
/*public override bool IsPeeking { get { return false; } } /*public override bool IsPeeking { get { return false; } }
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc) public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc)

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

@ -1,17 +1,51 @@
using ICSharpCode.Decompiler.Disassembler; // Copyright (c) 2014 Daniel Grunwald
using Mono.Cecil; //
// 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;
using System.Collections.Generic; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL 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 sealed override bool IsPeeking { get { return Operand.IsPeeking; } }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
@ -21,7 +55,17 @@ namespace ICSharpCode.Decompiler.IL
Argument.WriteTo(output); Argument.WriteTo(output);
output.Write(')'); output.Write(')');
} }
public sealed override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
return func(initial, Argument.AcceptVisitor(visitor));
}
protected override InstructionFlags ComputeFlags()
{
return Argument.Flags;
}
/* /*
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc) public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc)
{ {

22
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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -7,7 +25,7 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
enum PrimitiveType : byte public enum PrimitiveType : byte
{ {
None = 0, None = 0,
I1 = MetadataType.SByte, I1 = MetadataType.SByte,

20
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; using System;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
internal class SemanticHelper static class SemanticHelper
{ {
/// <summary> /// <summary>
/// Gets whether the instruction sequence 'inst1; inst2;' may be ordered to 'inst2; inst1;' /// Gets whether the instruction sequence 'inst1; inst2;' may be ordered to 'inst2; inst1;'

20
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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;

40
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<int>
{
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();
}
}
}

9
ICSharpCode.Decompiler/Util/Interval.cs

@ -48,10 +48,15 @@ namespace ICSharpCode.Decompiler
/// <summary> /// <summary>
/// An immutable set of integers, that is implemented as a list of intervals. /// An immutable set of integers, that is implemented as a list of intervals.
/// </summary> /// </summary>
struct IntegerSet(ImmutableArray<Interval> intervals) struct IntegerSet
{ {
public readonly ImmutableArray<Interval> Intervals = intervals; public readonly ImmutableArray<Interval> Intervals;
public IntegerSet(ImmutableArray<Interval> intervals)
{
this.Intervals = intervals;
}
public bool IsEmpty public bool IsEmpty
{ {
get { return Intervals.IsDefaultOrEmpty; } get { return Intervals.IsDefaultOrEmpty; }

Loading…
Cancel
Save