Browse Source

Finish the move to the new generated ILAst classes

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
42bfff077d
  1. 4
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  2. 8
      ICSharpCode.Decompiler/IL/BlockBuilder.cs
  3. 388
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 4
      ICSharpCode.Decompiler/IL/ILVariable.cs
  5. 6
      ICSharpCode.Decompiler/IL/InstructionFlags.cs
  6. 394
      ICSharpCode.Decompiler/IL/Instructions.cs
  7. 177
      ICSharpCode.Decompiler/IL/Instructions.tt
  8. 6
      ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs
  9. 41
      ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs
  10. 36
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  11. 104
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  12. 91
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  13. 68
      ICSharpCode.Decompiler/IL/Instructions/BranchInstruction.cs
  14. 148
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  15. 16
      ICSharpCode.Decompiler/IL/Instructions/Conv.cs
  16. 71
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  17. 65
      ICSharpCode.Decompiler/IL/Instructions/InstructionCollection.cs
  18. 51
      ICSharpCode.Decompiler/IL/Instructions/MemoryInstruction.cs
  19. 26
      ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs
  20. 43
      ICSharpCode.Decompiler/IL/Instructions/Return.cs
  21. 10
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  22. 114
      ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
  23. 13
      ICSharpCode.Decompiler/Util/CollectionExtensions.cs
  24. 3
      ILSpy.sln
  25. 1
      ILSpy/ILSpy.csproj
  26. 24
      ILSpy/Languages/ILAstLanguage.cs

4
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -75,9 +75,13 @@
<Compile Include="IL\Instructions\BinaryInstruction.cs" /> <Compile Include="IL\Instructions\BinaryInstruction.cs" />
<Compile Include="IL\Instructions\BinaryNumericInstruction.cs" /> <Compile Include="IL\Instructions\BinaryNumericInstruction.cs" />
<Compile Include="IL\Instructions\Block.cs" /> <Compile Include="IL\Instructions\Block.cs" />
<Compile Include="IL\Instructions\BlockContainer.cs" />
<Compile Include="IL\Instructions\BranchInstruction.cs" />
<Compile Include="IL\Instructions\CallInstruction.cs" /> <Compile Include="IL\Instructions\CallInstruction.cs" />
<Compile Include="IL\Instructions\Conv.cs" /> <Compile Include="IL\Instructions\Conv.cs" />
<Compile Include="IL\Instructions\ILInstruction.cs" /> <Compile Include="IL\Instructions\ILInstruction.cs" />
<Compile Include="IL\Instructions\InstructionCollection.cs" />
<Compile Include="IL\Instructions\MemoryInstructions.cs" />
<Compile Include="IL\Instructions\Return.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" />

8
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -28,10 +28,12 @@ namespace ICSharpCode.Decompiler.IL
{ {
class BlockBuilder class BlockBuilder
{ {
readonly Mono.Cecil.Cil.MethodBody body;
readonly Stack<ILInstruction> instructionStack; readonly Stack<ILInstruction> instructionStack;
public BlockBuilder(Mono.Cecil.Cil.MethodBody body, bool instructionInlining) public BlockBuilder(Mono.Cecil.Cil.MethodBody body, bool instructionInlining)
{ {
this.body = body;
this.instructionStack = (instructionInlining ? new Stack<ILInstruction>() : null); this.instructionStack = (instructionInlining ? new Stack<ILInstruction>() : null);
} }
@ -66,7 +68,7 @@ namespace ICSharpCode.Decompiler.IL
// so we can't inline them. // so we can't inline them.
FlushInstructionStack(); FlushInstructionStack();
} }
if (inlinedInst.NoResult) { if (inlinedInst.ResultType == StackType.Void) {
// We cannot directly push instructions onto the stack if they don't produce // We cannot directly push instructions onto the stack if they don't produce
// a result. // a result.
if (finished && instructionStack.Count > 0) { if (finished && instructionStack.Count > 0) {
@ -87,7 +89,7 @@ namespace ICSharpCode.Decompiler.IL
instructionStack.Push(inlinedInst); instructionStack.Push(inlinedInst);
} }
} }
if (!inst.IsEndReachable) if (inst.HasFlag(InstructionFlags.EndPointUnreachable))
FinalizeCurrentBlock(inst.ILRange.End, fallthrough: false); FinalizeCurrentBlock(inst.ILRange.End, fallthrough: false);
} }
} }
@ -102,7 +104,7 @@ namespace ICSharpCode.Decompiler.IL
FlushInstructionStack(); FlushInstructionStack();
currentBlock.ILRange = new Interval(currentBlock.ILRange.Start, currentILOffset); currentBlock.ILRange = new Interval(currentBlock.ILRange.Start, currentILOffset);
if (fallthrough) if (fallthrough)
currentBlock.Instructions.Add(new Branch(OpCode.Branch, currentILOffset)); currentBlock.Instructions.Add(new Branch(currentILOffset));
currentBlock = null; currentBlock = null;
} }

388
ICSharpCode.Decompiler/IL/ILReader.cs

@ -31,17 +31,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
public class ILReader public class ILReader
{ {
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) internal static ILOpCode ReadOpCode(ref BlobReader reader)
{ {
byte b = reader.ReadByte(); byte b = reader.ReadByte();
@ -56,14 +45,30 @@ namespace ICSharpCode.Decompiler.IL
return new MetadataToken(reader.ReadUInt32()); return new MetadataToken(reader.ReadUInt32());
} }
readonly TypeSystem typeSystem = body.Method.Module.TypeSystem; readonly Mono.Cecil.Cil.MethodBody body;
BlobReader reader = body.GetILReader(); readonly CancellationToken cancellationToken;
Stack<StackType> stack = new Stack<StackType>(body.MaxStackSize); readonly TypeSystem typeSystem;
ILVariable[] parameterVariables = InitParameterVariables(body);
ILVariable[] localVariables = body.Variables.Select(v => new ILVariable(v)).ToArray(); BlobReader reader;
readonly Stack<StackType> stack;
ILVariable[] parameterVariables;
ILVariable[] localVariables;
BitArray isBranchTarget; BitArray isBranchTarget;
List<ILInstruction> instructionBuilder; List<ILInstruction> instructionBuilder;
public ILReader(Mono.Cecil.Cil.MethodBody body, CancellationToken cancellationToken)
{
if (body == null)
throw new ArgumentNullException("body");
this.body = body;
this.cancellationToken = cancellationToken;
this.typeSystem = body.Method.Module.TypeSystem;
this.reader = body.GetILReader();
this.stack = new Stack<StackType>(body.MaxStackSize);
this.parameterVariables = InitParameterVariables(body);
this.localVariables = body.Variables.Select(v => new ILVariable(v)).ToArray();
}
IMetadataTokenProvider ReadAndDecodeMetadataToken() IMetadataTokenProvider ReadAndDecodeMetadataToken()
{ {
var token = ReadMetadataToken(ref reader); var token = ReadMetadataToken(ref reader);
@ -82,6 +87,11 @@ namespace ICSharpCode.Decompiler.IL
return parameterVariables; return parameterVariables;
} }
void Warn(string message)
{
}
void ReadInstructions(Dictionary<int, ImmutableArray<StackType>> outputStacks) void ReadInstructions(Dictionary<int, ImmutableArray<StackType>> outputStacks)
{ {
instructionBuilder = new List<ILInstruction>(); instructionBuilder = new List<ILInstruction>();
@ -98,15 +108,17 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction decodedInstruction = DecodeInstruction(); ILInstruction decodedInstruction = DecodeInstruction();
decodedInstruction.ILRange = new Interval(start, reader.Position); decodedInstruction.ILRange = new Interval(start, reader.Position);
instructionBuilder.Add(decodedInstruction); instructionBuilder.Add(decodedInstruction);
if ((var branch = decodedInstruction as Branch) != null) { Branch branch = decodedInstruction as Branch;
if (branch != null) {
isBranchTarget[branch.TargetILOffset] = true; isBranchTarget[branch.TargetILOffset] = true;
if (branch.TargetILOffset >= reader.Position) { if (branch.TargetILOffset >= reader.Position) {
branchStackDict[branch.TargetILOffset] = stack.ToImmutableArray(); branchStackDict[branch.TargetILOffset] = stack.ToImmutableArray();
} }
} }
if (!decodedInstruction.IsEndReachable) { if (decodedInstruction.HasFlag(InstructionFlags.EndPointUnreachable)) {
stack.Clear(); stack.Clear();
if (branchStackDict.TryGetValue(reader.Position, out var stackFromBranch)) { ImmutableArray<StackType> stackFromBranch;
if (branchStackDict.TryGetValue(reader.Position, out stackFromBranch)) {
for (int i = stackFromBranch.Length - 1; i >= 0; i--) { for (int i = stackFromBranch.Length - 1; i >= 0; i--) {
stack.Push(stackFromBranch[i]); stack.Push(stackFromBranch[i]);
} }
@ -146,14 +158,30 @@ namespace ICSharpCode.Decompiler.IL
public void WriteBlocks(ITextOutput output, bool instructionInlining) public void WriteBlocks(ITextOutput output, bool instructionInlining)
{ {
CreateBlocks(instructionInlining).WriteTo(output); CreateBlocks(instructionInlining).WriteTo(output);
} }
internal BlockContainer CreateBlocks(bool instructionInlining) internal BlockContainer CreateBlocks(bool instructionInlining)
{ {
if (instructionBuilder == null) if (instructionBuilder == null)
ReadInstructions(null); ReadInstructions(null);
return new BlockBuilder(body, instructionInlining).CreateBlocks(instructionBuilder, isBranchTarget); return new BlockBuilder(body, instructionInlining).CreateBlocks(instructionBuilder, isBranchTarget);
} }
ILInstruction Neg()
{
switch (stack.PeekOrDefault()) {
case StackType.I4:
case StackType.I:
return new Sub(new LdcI4(0), Pop(), OverflowMode.None);
case StackType.I8:
return new Sub(new LdcI8(0), Pop(), OverflowMode.None);
case StackType.F:
return new Sub(new LdcF(0), Pop(), OverflowMode.None);
default:
Warn("Unsupported input type for neg: ");
goto case StackType.I4;
}
}
ILInstruction DecodeInstruction() ILInstruction DecodeInstruction()
{ {
@ -178,7 +206,6 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.And: case ILOpCode.And:
return BinaryNumeric(OpCode.BitAnd); return BinaryNumeric(OpCode.BitAnd);
case ILOpCode.Arglist: case ILOpCode.Arglist:
stack.Push(StackType.O);
return new Arglist(); return new Arglist();
case ILOpCode.Beq: case ILOpCode.Beq:
return DecodeComparisonBranch(false, OpCode.Ceq, OpCode.Ceq, false); return DecodeComparisonBranch(false, OpCode.Ceq, OpCode.Ceq, false);
@ -253,71 +280,71 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ckfinite: case ILOpCode.Ckfinite:
return new CkFinite(); return new CkFinite();
case ILOpCode.Conv_I1: case ILOpCode.Conv_I1:
return Conv(PrimitiveType.I1, OverflowMode.None); return new Conv(Pop(), PrimitiveType.I1, OverflowMode.None);
case ILOpCode.Conv_I2: case ILOpCode.Conv_I2:
return Conv(PrimitiveType.I2, OverflowMode.None); return new Conv(Pop(), PrimitiveType.I2, OverflowMode.None);
case ILOpCode.Conv_I4: case ILOpCode.Conv_I4:
return Conv(PrimitiveType.I4, OverflowMode.None); return new Conv(Pop(), PrimitiveType.I4, OverflowMode.None);
case ILOpCode.Conv_I8: case ILOpCode.Conv_I8:
return Conv(PrimitiveType.I8, OverflowMode.None); return new Conv(Pop(), PrimitiveType.I8, OverflowMode.None);
case ILOpCode.Conv_R4: case ILOpCode.Conv_R4:
return Conv(PrimitiveType.R4, OverflowMode.None); return new Conv(Pop(), PrimitiveType.R4, OverflowMode.None);
case ILOpCode.Conv_R8: case ILOpCode.Conv_R8:
return Conv(PrimitiveType.R8, OverflowMode.None); return new Conv(Pop(), PrimitiveType.R8, OverflowMode.None);
case ILOpCode.Conv_U1: case ILOpCode.Conv_U1:
return Conv(PrimitiveType.U1, OverflowMode.None); return new Conv(Pop(), PrimitiveType.U1, OverflowMode.None);
case ILOpCode.Conv_U2: case ILOpCode.Conv_U2:
return Conv(PrimitiveType.U2, OverflowMode.None); return new Conv(Pop(), PrimitiveType.U2, OverflowMode.None);
case ILOpCode.Conv_U4: case ILOpCode.Conv_U4:
return Conv(PrimitiveType.U4, OverflowMode.None); return new Conv(Pop(), PrimitiveType.U4, OverflowMode.None);
case ILOpCode.Conv_U8: case ILOpCode.Conv_U8:
return Conv(PrimitiveType.U8, OverflowMode.None); return new Conv(Pop(), PrimitiveType.U8, OverflowMode.None);
case ILOpCode.Conv_I: case ILOpCode.Conv_I:
return Conv(PrimitiveType.I, OverflowMode.None); return new Conv(Pop(), PrimitiveType.I, OverflowMode.None);
case ILOpCode.Conv_U: case ILOpCode.Conv_U:
return Conv(PrimitiveType.U, OverflowMode.None); return new Conv(Pop(), PrimitiveType.U, OverflowMode.None);
case ILOpCode.Conv_R_Un: case ILOpCode.Conv_R_Un:
return Conv(PrimitiveType.R8, OverflowMode.Un); return new Conv(Pop(), PrimitiveType.R8, OverflowMode.Un);
case ILOpCode.Conv_Ovf_I1: case ILOpCode.Conv_Ovf_I1:
return Conv(PrimitiveType.I1, OverflowMode.Ovf); return new Conv(Pop(), PrimitiveType.I1, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_I2: case ILOpCode.Conv_Ovf_I2:
return Conv(PrimitiveType.I2, OverflowMode.Ovf); return new Conv(Pop(), PrimitiveType.I2, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_I4: case ILOpCode.Conv_Ovf_I4:
return Conv(PrimitiveType.I4, OverflowMode.Ovf); return new Conv(Pop(), PrimitiveType.I4, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_I8: case ILOpCode.Conv_Ovf_I8:
return Conv(PrimitiveType.I8, OverflowMode.Ovf); return new Conv(Pop(), PrimitiveType.I8, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_U1: case ILOpCode.Conv_Ovf_U1:
return Conv(PrimitiveType.U1, OverflowMode.Ovf); return new Conv(Pop(), PrimitiveType.U1, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_U2: case ILOpCode.Conv_Ovf_U2:
return Conv(PrimitiveType.U2, OverflowMode.Ovf); return new Conv(Pop(), PrimitiveType.U2, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_U4: case ILOpCode.Conv_Ovf_U4:
return Conv(PrimitiveType.U4, OverflowMode.Ovf); return new Conv(Pop(), PrimitiveType.U4, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_U8: case ILOpCode.Conv_Ovf_U8:
return Conv(PrimitiveType.U8, OverflowMode.Ovf); return new Conv(Pop(), PrimitiveType.U8, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_I: case ILOpCode.Conv_Ovf_I:
return Conv(PrimitiveType.I, OverflowMode.Ovf); return new Conv(Pop(), PrimitiveType.I, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_U: case ILOpCode.Conv_Ovf_U:
return Conv(PrimitiveType.U, OverflowMode.Ovf); return new Conv(Pop(), PrimitiveType.U, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_I1_Un: case ILOpCode.Conv_Ovf_I1_Un:
return Conv(PrimitiveType.I1, OverflowMode.Ovf_Un); return new Conv(Pop(), PrimitiveType.I1, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_I2_Un: case ILOpCode.Conv_Ovf_I2_Un:
return Conv(PrimitiveType.I2, OverflowMode.Ovf_Un); return new Conv(Pop(), PrimitiveType.I2, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_I4_Un: case ILOpCode.Conv_Ovf_I4_Un:
return Conv(PrimitiveType.I4, OverflowMode.Ovf_Un); return new Conv(Pop(), PrimitiveType.I4, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_I8_Un: case ILOpCode.Conv_Ovf_I8_Un:
return Conv(PrimitiveType.I8, OverflowMode.Ovf_Un); return new Conv(Pop(), PrimitiveType.I8, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_U1_Un: case ILOpCode.Conv_Ovf_U1_Un:
return Conv(PrimitiveType.U1, OverflowMode.Ovf_Un); return new Conv(Pop(), PrimitiveType.U1, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_U2_Un: case ILOpCode.Conv_Ovf_U2_Un:
return Conv(PrimitiveType.U2, OverflowMode.Ovf_Un); return new Conv(Pop(), PrimitiveType.U2, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_U4_Un: case ILOpCode.Conv_Ovf_U4_Un:
return Conv(PrimitiveType.U4, OverflowMode.Ovf_Un); return new Conv(Pop(), PrimitiveType.U4, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_U8_Un: case ILOpCode.Conv_Ovf_U8_Un:
return Conv(PrimitiveType.U8, OverflowMode.Ovf_Un); return new Conv(Pop(), PrimitiveType.U8, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_I_Un: case ILOpCode.Conv_Ovf_I_Un:
return Conv(PrimitiveType.I, OverflowMode.Ovf_Un); return new Conv(Pop(), PrimitiveType.I, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_U_Un: case ILOpCode.Conv_Ovf_U_Un:
return Conv(PrimitiveType.U, OverflowMode.Ovf_Un); return new Conv(Pop(), PrimitiveType.U, OverflowMode.Ovf_Un);
case ILOpCode.Cpblk: case ILOpCode.Cpblk:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Div: case ILOpCode.Div:
@ -325,7 +352,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Div_Un: case ILOpCode.Div_Un:
return BinaryNumeric(OpCode.Div, OverflowMode.Un); return BinaryNumeric(OpCode.Div, OverflowMode.Un);
case ILOpCode.Dup: case ILOpCode.Dup:
return new Peek(); return new Peek(stack.Count > 0 ? stack.Peek() : StackType.Unknown);
case ILOpCode.Endfilter: case ILOpCode.Endfilter:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Endfinally: case ILOpCode.Endfinally:
@ -348,13 +375,13 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldarga_S: case ILOpCode.Ldarga_S:
return Ldarga(reader.ReadByte()); return Ldarga(reader.ReadByte());
case ILOpCode.Ldc_I4: case ILOpCode.Ldc_I4:
return LdcI4(reader.ReadInt32()); return new LdcI4(reader.ReadInt32());
case ILOpCode.Ldc_I8: case ILOpCode.Ldc_I8:
return LdcI8(reader.ReadInt64()); return new LdcI8(reader.ReadInt64());
case ILOpCode.Ldc_R4: case ILOpCode.Ldc_R4:
return LdcF(reader.ReadSingle()); return new LdcF(reader.ReadSingle());
case ILOpCode.Ldc_R8: case ILOpCode.Ldc_R8:
return LdcF(reader.ReadDouble()); return new LdcF(reader.ReadDouble());
case ILOpCode.Ldc_I4_M1: case ILOpCode.Ldc_I4_M1:
case ILOpCode.Ldc_I4_0: case ILOpCode.Ldc_I4_0:
case ILOpCode.Ldc_I4_1: case ILOpCode.Ldc_I4_1:
@ -365,9 +392,9 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldc_I4_6: case ILOpCode.Ldc_I4_6:
case ILOpCode.Ldc_I4_7: case ILOpCode.Ldc_I4_7:
case ILOpCode.Ldc_I4_8: case ILOpCode.Ldc_I4_8:
return LdcI4((int)ilOpCode - (int)ILOpCode.Ldc_I4_0); return new LdcI4((int)ilOpCode - (int)ILOpCode.Ldc_I4_0);
case ILOpCode.Ldc_I4_S: case ILOpCode.Ldc_I4_S:
return LdcI4(reader.ReadSByte()); return new LdcI4(reader.ReadSByte());
case ILOpCode.Ldnull: case ILOpCode.Ldnull:
stack.Push(StackType.O); stack.Push(StackType.O);
return new LdNull(); return new LdNull();
@ -376,27 +403,27 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldftn: case ILOpCode.Ldftn:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Ldind_I1: case ILOpCode.Ldind_I1:
return LdInd(typeSystem.SByte); return new LdInd(Pop(), typeSystem.SByte);
case ILOpCode.Ldind_I2: case ILOpCode.Ldind_I2:
return LdInd(typeSystem.Int16); return new LdInd(Pop(), typeSystem.Int16);
case ILOpCode.Ldind_I4: case ILOpCode.Ldind_I4:
return LdInd(typeSystem.Int32); return new LdInd(Pop(), typeSystem.Int32);
case ILOpCode.Ldind_I8: case ILOpCode.Ldind_I8:
return LdInd(typeSystem.Int64); return new LdInd(Pop(), typeSystem.Int64);
case ILOpCode.Ldind_U1: case ILOpCode.Ldind_U1:
return LdInd(typeSystem.Byte); return new LdInd(Pop(), typeSystem.Byte);
case ILOpCode.Ldind_U2: case ILOpCode.Ldind_U2:
return LdInd(typeSystem.UInt16); return new LdInd(Pop(), typeSystem.UInt16);
case ILOpCode.Ldind_U4: case ILOpCode.Ldind_U4:
return LdInd(typeSystem.UInt32); return new LdInd(Pop(), typeSystem.UInt32);
case ILOpCode.Ldind_R4: case ILOpCode.Ldind_R4:
return LdInd(typeSystem.Single); return new LdInd(Pop(), typeSystem.Single);
case ILOpCode.Ldind_R8: case ILOpCode.Ldind_R8:
return LdInd(typeSystem.Double); return new LdInd(Pop(), typeSystem.Double);
case ILOpCode.Ldind_I: case ILOpCode.Ldind_I:
return LdInd(typeSystem.IntPtr); return new LdInd(Pop(), typeSystem.IntPtr);
case ILOpCode.Ldind_Ref: case ILOpCode.Ldind_Ref:
return LdInd(typeSystem.Object); return new LdInd(Pop(), typeSystem.Object);
case ILOpCode.Ldloc: case ILOpCode.Ldloc:
return Ldloc(reader.ReadUInt16()); return Ldloc(reader.ReadUInt16());
case ILOpCode.Ldloc_S: case ILOpCode.Ldloc_S:
@ -425,18 +452,17 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Mul_Ovf_Un: case ILOpCode.Mul_Ovf_Un:
return BinaryNumeric(OpCode.Mul, OverflowMode.Ovf_Un); return BinaryNumeric(OpCode.Mul, OverflowMode.Ovf_Un);
case ILOpCode.Neg: case ILOpCode.Neg:
return UnaryNumeric(OpCode.Neg); return Neg();
case ILOpCode.Newobj: case ILOpCode.Newobj:
return DecodeCall(OpCode.NewObj); return DecodeCall(OpCode.NewObj);
case ILOpCode.Nop: case ILOpCode.Nop:
return new Nop(); return new Nop();
case ILOpCode.Not: case ILOpCode.Not:
return UnaryNumeric(OpCode.BitNot); return new BitNot(Pop());
case ILOpCode.Or: case ILOpCode.Or:
return BinaryNumeric(OpCode.BitOr); return BinaryNumeric(OpCode.BitOr);
case ILOpCode.Pop: case ILOpCode.Pop:
stack.PopOrDefault(); return new Void(Pop());
return new Void();
case ILOpCode.Rem: case ILOpCode.Rem:
return BinaryNumeric(OpCode.Rem, OverflowMode.None); return BinaryNumeric(OpCode.Rem, OverflowMode.None);
case ILOpCode.Rem_Un: case ILOpCode.Rem_Un:
@ -444,11 +470,11 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ret: case ILOpCode.Ret:
return Return(); return Return();
case ILOpCode.Shl: case ILOpCode.Shl:
return Shift(OpCode.Shl); return BinaryNumeric(OpCode.Shl, OverflowMode.None);
case ILOpCode.Shr: case ILOpCode.Shr:
return Shift(OpCode.Shr); return BinaryNumeric(OpCode.Shr, OverflowMode.None);
case ILOpCode.Shr_Un: case ILOpCode.Shr_Un:
return Shift(OpCode.Shl, OverflowMode.Un); return BinaryNumeric(OpCode.Shr, OverflowMode.Un);
case ILOpCode.Starg: case ILOpCode.Starg:
return Starg(reader.ReadUInt16()); return Starg(reader.ReadUInt16());
case ILOpCode.Starg_S: case ILOpCode.Starg_S:
@ -490,9 +516,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Initobj: case ILOpCode.Initobj:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Isinst: case ILOpCode.Isinst:
stack.PopOrDefault(); return new IsInst(Pop(), (TypeReference)ReadAndDecodeMetadataToken());
stack.Push(StackType.O);
return new IsInst((TypeReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldelem: case ILOpCode.Ldelem:
case ILOpCode.Ldelem_I1: case ILOpCode.Ldelem_I1:
case ILOpCode.Ldelem_I2: case ILOpCode.Ldelem_I2:
@ -509,38 +533,22 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldelema: case ILOpCode.Ldelema:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Ldfld: case ILOpCode.Ldfld:
{ return new Ldfld(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
stack.PopOrDefault();
FieldReference field = (FieldReference)ReadAndDecodeMetadataToken();
stack.Push(field.FieldType.GetStackType());
return new LoadInstanceField(field);
}
case ILOpCode.Ldflda: case ILOpCode.Ldflda:
stack.PopOrDefault(); return new Ldflda(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
stack.Push(StackType.Ref);
return new LoadInstanceField((FieldReference)ReadAndDecodeMetadataToken(), OpCode.Ldflda);
case ILOpCode.Stfld: case ILOpCode.Stfld:
stack.PopOrDefault(); throw new NotImplementedException();
stack.PopOrDefault(); //\return new Stfld(Pop(), Pop(), (FieldReference)ReadAndDecodeMetadataToken());
return new StoreInstanceField((FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldlen: case ILOpCode.Ldlen:
stack.PopOrDefault(); return new LdLen(Pop());
stack.Push(StackType.I);
return new LdLen();
case ILOpCode.Ldobj: case ILOpCode.Ldobj:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Ldsfld: case ILOpCode.Ldsfld:
{ return new Ldsfld((FieldReference)ReadAndDecodeMetadataToken());
FieldReference field = (FieldReference)ReadAndDecodeMetadataToken();
stack.Push(field.FieldType.GetStackType());
return new LoadStaticField(field);
}
case ILOpCode.Ldsflda: case ILOpCode.Ldsflda:
stack.Push(StackType.Ref); return new Ldsflda((FieldReference)ReadAndDecodeMetadataToken());
return new LoadStaticField((FieldReference)ReadAndDecodeMetadataToken(), OpCode.Ldsflda);
case ILOpCode.Stsfld: case ILOpCode.Stsfld:
stack.PopOrDefault(); return new Stsfld(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
return new StoreStaticField((FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldtoken: case ILOpCode.Ldtoken:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Ldvirtftn: case ILOpCode.Ldvirtftn:
@ -570,121 +578,77 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Stobj: case ILOpCode.Stobj:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Throw: case ILOpCode.Throw:
stack.PopOrDefault(); return new Throw(Pop());
return new ThrowInstruction();
case ILOpCode.Unbox: case ILOpCode.Unbox:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Unbox_Any: case ILOpCode.Unbox_Any:
return DecodeUnboxAny(); return new UnboxAny(Pop(), (TypeReference)ReadAndDecodeMetadataToken());
default: default:
throw new NotImplementedException(ilOpCode.ToString()); throw new NotImplementedException(ilOpCode.ToString());
} }
} }
private ILInstruction DecodeUnboxAny() private IL.Pop Pop()
{
TypeReference typeRef = (TypeReference)ReadAndDecodeMetadataToken();
stack.PopOrDefault();
stack.Push(typeRef.GetStackType());
return new UnboxAny(typeRef);
}
private ILInstruction LdInd(TypeReference typeRef)
{ {
stack.PopOrDefault(); // pointer if (stack.Count > 0) {
stack.Push(typeRef.GetStackType()); return new IL.Pop(stack.Pop());
return new LoadIndirect(typeRef); } else {
Warn("Stack underflow");
return new IL.Pop(StackType.Unknown);
}
} }
private ILInstruction Shift(OpCode opCode, OverflowMode overflowMode = OverflowMode.None)
{
var shiftAmountType = stack.PopOrDefault();
var valueType = stack.PopOrDefault();
stack.Push(valueType);
return new BinaryNumericInstruction(opCode, valueType, overflowMode);
}
private ILInstruction Return() private ILInstruction Return()
{ {
if (body.Method.ReturnType.GetStackType() == StackType.Void) if (body.Method.ReturnType.GetStackType() == StackType.Void)
return new ReturnVoidInstruction(); return new ICSharpCode.Decompiler.IL.Return();
else else
return new ReturnInstruction(); return new ICSharpCode.Decompiler.IL.Return(Pop());
}
private ILInstruction UnaryNumeric(OpCode opCode)
{
var opType = stack.PopOrDefault();
stack.Push(opType);
return new UnaryNumericInstruction(opCode, opType);
} }
private ILInstruction DecodeLdstr() private ILInstruction DecodeLdstr()
{ {
stack.Push(StackType.O);
var metadataToken = ReadMetadataToken(ref reader); var metadataToken = ReadMetadataToken(ref reader);
return new ConstantString(body.LookupStringToken(metadataToken)); return new LdStr(body.LookupStringToken(metadataToken));
}
private ILInstruction LdcI4(int val)
{
stack.Push(StackType.I4);
return new ConstantI4(val);
}
private ILInstruction LdcI8(long val)
{
stack.Push(StackType.I8);
return new ConstantI8(val);
}
private ILInstruction LdcF(double val)
{
stack.Push(StackType.F);
return new ConstantFloat(val);
} }
private ILInstruction Ldarg(ushort v) private ILInstruction Ldarg(ushort v)
{ {
stack.Push(parameterVariables[v].Type.GetStackType());
return new LdLoc(parameterVariables[v]); return new LdLoc(parameterVariables[v]);
} }
private ILInstruction Ldarga(ushort v) private ILInstruction Ldarga(ushort v)
{ {
stack.Push(StackType.Ref);
return new LdLoca(parameterVariables[v]); return new LdLoca(parameterVariables[v]);
} }
private ILInstruction Starg(ushort v) private ILInstruction Starg(ushort v)
{ {
stack.PopOrDefault(); return new StLoc(Pop(), parameterVariables[v]);
return new StLoc(parameterVariables[v]);
} }
private ILInstruction Ldloc(ushort v) private ILInstruction Ldloc(ushort v)
{ {
stack.Push(localVariables[v].Type.GetStackType());
return new LdLoc(localVariables[v]); return new LdLoc(localVariables[v]);
} }
private ILInstruction Ldloca(ushort v) private ILInstruction Ldloca(ushort v)
{ {
stack.Push(StackType.Ref);
return new LdLoca(localVariables[v]); return new LdLoca(localVariables[v]);
} }
private ILInstruction Stloc(ushort v) private ILInstruction Stloc(ushort v)
{ {
stack.PopOrDefault(); return new StLoc(Pop(), localVariables[v]);
return new StLoc(localVariables[v]);
} }
private ILInstruction DecodeConstrainedCall() private ILInstruction DecodeConstrainedCall()
{ {
var typeRef = ReadAndDecodeMetadataToken() as TypeReference; var typeRef = ReadAndDecodeMetadataToken() as TypeReference;
var inst = DecodeInstruction(); var inst = DecodeInstruction();
if ((var call = inst as CallInstruction) != null) var call = inst as CallInstruction;
if (call != null)
call.ConstrainedTo = typeRef; call.ConstrainedTo = typeRef;
return inst; return inst;
} }
@ -692,7 +656,8 @@ namespace ICSharpCode.Decompiler.IL
private ILInstruction DecodeTailCall() private ILInstruction DecodeTailCall()
{ {
var inst = DecodeInstruction(); var inst = DecodeInstruction();
if ((var call = inst as CallInstruction) != null) var call = inst as CallInstruction;
if (call != null)
call.IsTail = true; call.IsTail = true;
return inst; return inst;
} }
@ -701,51 +666,46 @@ namespace ICSharpCode.Decompiler.IL
{ {
byte alignment = reader.ReadByte(); byte alignment = reader.ReadByte();
var inst = DecodeInstruction(); var inst = DecodeInstruction();
if ((var smp = inst as ISupportsMemoryPrefix) != null) var sup = inst as ISupportsUnalignedPrefix;
smp.UnalignedPrefix = alignment; if (sup != null)
sup.UnalignedPrefix = alignment;
else
Warn("Ignored invalid 'unaligned' prefix");
return inst; return inst;
} }
private ILInstruction DecodeVolatile() private ILInstruction DecodeVolatile()
{ {
var inst = DecodeInstruction(); var inst = DecodeInstruction();
if ((var smp = inst as ISupportsMemoryPrefix) != null) var svp = inst as ISupportsVolatilePrefix;
smp.IsVolatile = true; if (svp != null)
svp.IsVolatile = true;
else
Warn("Ignored invalid 'volatile' prefix");
return inst; return inst;
} }
private ILInstruction Conv(PrimitiveType targetType, OverflowMode mode)
{
StackType from = stack.PopOrDefault();
stack.Push(targetType.GetStackType());
return new ConvInstruction(from, targetType, mode);
}
ILInstruction DecodeCall(OpCode opCode) ILInstruction DecodeCall(OpCode opCode)
{ {
var method = (MethodReference)ReadAndDecodeMetadataToken(); var method = (MethodReference)ReadAndDecodeMetadataToken();
var inst = new CallInstruction(opCode, method); var arguments = new ILInstruction[CallInstruction.GetPopCount(opCode, method)];
for (int i = 0; i < inst.Arguments.Length; i++) { for (int i = arguments.Length - 1; i >= 0; i--) {
stack.Pop(); arguments[i] = Pop();
} }
var returnType = (opCode == OpCode.NewObj ? method.DeclaringType : method.ReturnType).GetStackType(); var call = CallInstruction.Create(opCode, method);
if (returnType != StackType.Void) call.Arguments.AddRange(arguments);
stack.Push(returnType); return call;
return new CallInstruction(opCode, method);
} }
ILInstruction Comparison(OpCode opCode_I, OpCode opCode_F) ILInstruction Comparison(OpCode opCode_I, OpCode opCode_F)
{ {
StackType right = stack.PopOrDefault(); var right = Pop();
StackType left = stack.PopOrDefault(); var left = Pop();
stack.Push(StackType.I4);
// Based on Table 4: Binary Comparison or Branch Operation // Based on Table 4: Binary Comparison or Branch Operation
if (left == StackType.F && right == StackType.F) if (left.ResultType == StackType.F && right.ResultType == StackType.F)
return new BinaryNumericInstruction(opCode_F, StackType.F, OverflowMode.None); return BinaryComparisonInstruction.Create(opCode_F, left, right);
if (left == StackType.I || right == StackType.I) else
return new BinaryNumericInstruction(opCode_I, StackType.I, OverflowMode.None); return BinaryComparisonInstruction.Create(opCode_I, left, right);
Debug.Assert(left == right); // this should hold in all valid IL
return new BinaryNumericInstruction(opCode_I, left, OverflowMode.None);
} }
ILInstruction DecodeComparisonBranch(bool shortForm, OpCode comparisonOpCodeForInts, OpCode comparisonOpCodeForFloats, bool negate) ILInstruction DecodeComparisonBranch(bool shortForm, OpCode comparisonOpCodeForInts, OpCode comparisonOpCodeForFloats, bool negate)
@ -756,9 +716,8 @@ namespace ICSharpCode.Decompiler.IL
target += reader.Position; target += reader.Position;
condition.ILRange = new Interval(start, reader.Position); condition.ILRange = new Interval(start, reader.Position);
if (negate) { if (negate) {
condition = new LogicNotInstruction { Operand = condition }; condition = new LogicNot(condition);
} }
stack.PopOrDefault();
return new ConditionalBranch(condition, target); return new ConditionalBranch(condition, target);
} }
@ -766,11 +725,10 @@ namespace ICSharpCode.Decompiler.IL
{ {
int target = shortForm ? reader.ReadSByte() : reader.ReadInt32(); int target = shortForm ? reader.ReadSByte() : reader.ReadInt32();
target += reader.Position; target += reader.Position;
ILInstruction condition = ILInstruction.Pop; ILInstruction condition = Pop();
if (negate) { if (negate) {
condition = new LogicNotInstruction { Operand = condition }; condition = new LogicNot(condition);
} }
stack.PopOrDefault();
return new ConditionalBranch(condition, target); return new ConditionalBranch(condition, target);
} }
@ -778,36 +736,14 @@ namespace ICSharpCode.Decompiler.IL
{ {
int target = shortForm ? reader.ReadSByte() : reader.ReadInt32(); int target = shortForm ? reader.ReadSByte() : reader.ReadInt32();
target += reader.Position; target += reader.Position;
return new Branch(opCode, target); return new Branch(target);
} }
ILInstruction BinaryNumeric(OpCode opCode, OverflowMode overflowMode = OverflowMode.None) ILInstruction BinaryNumeric(OpCode opCode, OverflowMode overflowMode = OverflowMode.None)
{ {
StackType right = stack.PopOrDefault(); var right = Pop();
StackType left = stack.PopOrDefault(); var left = Pop();
// Based on Table 2: Binary Numeric Operations return BinaryNumericInstruction.Create(opCode, left, right, overflowMode);
// also works for Table 5: Integer Operations
// and for Table 7: Overflow Arithmetic Operations
if (left == right) {
stack.Push(left);
return new BinaryNumericInstruction(opCode, left, overflowMode);
}
if (left == StackType.Ref || right == StackType.Ref) {
if (left == StackType.Ref && right == StackType.Ref) {
// sub(&, &) = I
stack.Push(StackType.I);
} else {
// add/sub with I or I4 and &
stack.Push(StackType.Ref);
}
return new BinaryNumericInstruction(opCode, StackType.Ref, overflowMode);
}
if (left == StackType.I || right == StackType.I) {
stack.Push(left);
return new BinaryNumericInstruction(opCode, StackType.I, overflowMode);
}
stack.Push(StackType.Unknown);
return new BinaryNumericInstruction(opCode, StackType.Unknown, overflowMode);
} }
} }
} }

4
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -26,13 +26,13 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
enum VariableKind public enum VariableKind
{ {
Local, Local,
Parameter, Parameter,
} }
class ILVariable public class ILVariable
{ {
public readonly VariableKind Kind; public readonly VariableKind Kind;
public readonly TypeReference Type; public readonly TypeReference Type;

6
ICSharpCode.Decompiler/IL/InstructionFlags.cs

@ -53,6 +53,10 @@ namespace ICSharpCode.Decompiler.IL
/// The instruction may have side effects, such as accessing 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, SideEffect = 0x40,
/// <summary>
/// The instruction performs unconditional control flow, so that its endpoint is unreachable.
/// </summary>
EndPointUnreachable = 0x80,
} }
} }

394
ICSharpCode.Decompiler/IL/Instructions.cs

@ -50,8 +50,6 @@ namespace ICSharpCode.Decompiler.IL
Div, Div,
/// <summary>Division remainder</summary> /// <summary>Division remainder</summary>
Rem, Rem,
/// <summary>Unary negation</summary>
Neg,
/// <summary>Bitwise AND</summary> /// <summary>Bitwise AND</summary>
BitAnd, BitAnd,
/// <summary>Bitwise OR</summary> /// <summary>Bitwise OR</summary>
@ -141,7 +139,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
} }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitNop(this); return visitor.VisitNop(this);
} }
@ -156,7 +154,7 @@ namespace ICSharpCode.Decompiler.IL
} }
StackType resultType; StackType resultType;
public override StackType ResultType { get { return resultType; } } public override StackType ResultType { get { return resultType; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitPop(this); return visitor.VisitPop(this);
} }
@ -171,11 +169,11 @@ namespace ICSharpCode.Decompiler.IL
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayPeek; return InstructionFlags.MayPeek;
} }
StackType resultType; StackType resultType;
public override StackType ResultType { get { return resultType; } } public override StackType ResultType { get { return resultType; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitPeek(this); return visitor.VisitPeek(this);
} }
@ -184,11 +182,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.</summary> /// <summary>Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.</summary>
public sealed partial class Void : UnaryInstruction public sealed partial class Void : UnaryInstruction
{ {
public Void() : base(OpCode.Void) public Void(ILInstruction argument) : base(OpCode.Void, argument)
{ {
} }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitVoid(this); return visitor.VisitVoid(this);
} }
@ -197,11 +195,8 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>A container of IL blocks.</summary> /// <summary>A container of IL blocks.</summary>
public sealed partial class BlockContainer : ILInstruction public sealed partial class BlockContainer : ILInstruction
{ {
public BlockContainer() : base(OpCode.BlockContainer)
{
}
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitBlockContainer(this); return visitor.VisitBlockContainer(this);
} }
@ -210,11 +205,8 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>A block of IL instructions.</summary> /// <summary>A block of IL instructions.</summary>
public sealed partial class Block : ILInstruction public sealed partial class Block : ILInstruction
{ {
public Block() : base(OpCode.Block)
{
}
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitBlock(this); return visitor.VisitBlock(this);
} }
@ -223,11 +215,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).</summary> /// <summary>Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).</summary>
public sealed partial class LogicNot : UnaryInstruction public sealed partial class LogicNot : UnaryInstruction
{ {
public LogicNot() : base(OpCode.LogicNot) public LogicNot(ILInstruction argument) : base(OpCode.LogicNot, argument)
{ {
} }
public override StackType ResultType { get { return StackType.I4; } } public override StackType ResultType { get { return StackType.I4; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLogicNot(this); return visitor.VisitLogicNot(this);
} }
@ -236,11 +228,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Adds two numbers.</summary> /// <summary>Adds two numbers.</summary>
public sealed partial class Add : BinaryNumericInstruction public sealed partial class Add : BinaryNumericInstruction
{ {
public Add(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Add, opType, resultType, overflowMode) public Add(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Add, left, right, overflowMode)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitAdd(this); return visitor.VisitAdd(this);
} }
@ -249,11 +241,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Subtracts two numbers</summary> /// <summary>Subtracts two numbers</summary>
public sealed partial class Sub : BinaryNumericInstruction public sealed partial class Sub : BinaryNumericInstruction
{ {
public Sub(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Sub, opType, resultType, overflowMode) public Sub(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Sub, left, right, overflowMode)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitSub(this); return visitor.VisitSub(this);
} }
@ -262,11 +254,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Multiplies two numbers</summary> /// <summary>Multiplies two numbers</summary>
public sealed partial class Mul : BinaryNumericInstruction public sealed partial class Mul : BinaryNumericInstruction
{ {
public Mul(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Mul, opType, resultType, overflowMode) public Mul(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Mul, left, right, overflowMode)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitMul(this); return visitor.VisitMul(this);
} }
@ -275,7 +267,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Divides two numbers</summary> /// <summary>Divides two numbers</summary>
public sealed partial class Div : BinaryNumericInstruction public sealed partial class Div : BinaryNumericInstruction
{ {
public Div(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Div, opType, resultType, overflowMode) public Div(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Div, left, right, overflowMode)
{ {
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
@ -283,7 +275,7 @@ namespace ICSharpCode.Decompiler.IL
return base.ComputeFlags() | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.MayThrow;
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitDiv(this); return visitor.VisitDiv(this);
} }
@ -292,7 +284,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Division remainder</summary> /// <summary>Division remainder</summary>
public sealed partial class Rem : BinaryNumericInstruction public sealed partial class Rem : BinaryNumericInstruction
{ {
public Rem(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Rem, opType, resultType, overflowMode) public Rem(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Rem, left, right, overflowMode)
{ {
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
@ -300,35 +292,20 @@ namespace ICSharpCode.Decompiler.IL
return base.ComputeFlags() | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.MayThrow;
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitRem(this); return visitor.VisitRem(this);
} }
} }
/// <summary>Unary negation</summary>
public sealed partial class Neg : UnaryInstruction
{
public Neg(StackType resultType) : base(OpCode.Neg)
{
this.resultType = resultType;
}
StackType resultType;
public override StackType ResultType { get { return resultType; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitNeg(this);
}
}
/// <summary>Bitwise AND</summary> /// <summary>Bitwise AND</summary>
public sealed partial class BitAnd : BinaryNumericInstruction public sealed partial class BitAnd : BinaryNumericInstruction
{ {
public BitAnd(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.BitAnd, opType, resultType, overflowMode) public BitAnd(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.BitAnd, left, right, overflowMode)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitBitAnd(this); return visitor.VisitBitAnd(this);
} }
@ -337,11 +314,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise OR</summary> /// <summary>Bitwise OR</summary>
public sealed partial class BitOr : BinaryNumericInstruction public sealed partial class BitOr : BinaryNumericInstruction
{ {
public BitOr(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.BitOr, opType, resultType, overflowMode) public BitOr(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.BitOr, left, right, overflowMode)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitBitOr(this); return visitor.VisitBitOr(this);
} }
@ -350,11 +327,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise XOR</summary> /// <summary>Bitwise XOR</summary>
public sealed partial class BitXor : BinaryNumericInstruction public sealed partial class BitXor : BinaryNumericInstruction
{ {
public BitXor(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.BitXor, opType, resultType, overflowMode) public BitXor(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.BitXor, left, right, overflowMode)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitBitXor(this); return visitor.VisitBitXor(this);
} }
@ -363,13 +340,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise NOT</summary> /// <summary>Bitwise NOT</summary>
public sealed partial class BitNot : UnaryInstruction public sealed partial class BitNot : UnaryInstruction
{ {
public BitNot(StackType resultType) : base(OpCode.BitNot) public BitNot(ILInstruction argument) : base(OpCode.BitNot, argument)
{ {
this.resultType = resultType;
} }
StackType resultType;
public override StackType ResultType { get { return resultType; } } public override T AcceptVisitor<T>(ILVisitor<T> visitor)
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitBitNot(this); return visitor.VisitBitNot(this);
} }
@ -382,41 +357,34 @@ namespace ICSharpCode.Decompiler.IL
{ {
} }
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitArglist(this); return visitor.VisitArglist(this);
} }
} }
/// <summary><c>if (condition) goto target;</c>.</summary> /// <summary><c>if (condition) goto target;</c>.</summary>
public sealed partial class ConditionalBranch : UnaryInstruction public sealed partial class ConditionalBranch : BranchInstruction
{ {
public ConditionalBranch() : base(OpCode.ConditionalBranch)
{
}
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayBranch;
}
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitConditionalBranch(this); return visitor.VisitConditionalBranch(this);
} }
} }
/// <summary><c>goto target;</c>.</summary> /// <summary><c>goto target;</c>.</summary>
public sealed partial class Branch : SimpleInstruction public sealed partial class Branch : BranchInstruction
{ {
public Branch() : base(OpCode.Branch) public Branch(int targetILOffset) : base(OpCode.Branch, targetILOffset)
{ {
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayBranch; return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch;
} }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitBranch(this); return visitor.VisitBranch(this);
} }
@ -430,10 +398,10 @@ namespace ICSharpCode.Decompiler.IL
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.SideEffect; return InstructionFlags.SideEffect;
} }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitDebugBreak(this); return visitor.VisitDebugBreak(this);
} }
@ -442,11 +410,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.</summary> /// <summary>Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.</summary>
public sealed partial class Ceq : BinaryComparisonInstruction public sealed partial class Ceq : BinaryComparisonInstruction
{ {
public Ceq(StackType opType) : base(OpCode.Ceq, opType) public Ceq(ILInstruction left, ILInstruction right) : base(OpCode.Ceq, left, right)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitCeq(this); return visitor.VisitCeq(this);
} }
@ -455,11 +423,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.</summary> /// <summary>Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.</summary>
public sealed partial class Cgt : BinaryComparisonInstruction public sealed partial class Cgt : BinaryComparisonInstruction
{ {
public Cgt(StackType opType) : base(OpCode.Cgt, opType) public Cgt(ILInstruction left, ILInstruction right) : base(OpCode.Cgt, left, right)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitCgt(this); return visitor.VisitCgt(this);
} }
@ -468,11 +436,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.</summary> /// <summary>Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.</summary>
public sealed partial class Cgt_Un : BinaryComparisonInstruction public sealed partial class Cgt_Un : BinaryComparisonInstruction
{ {
public Cgt_Un(StackType opType) : base(OpCode.Cgt_Un, opType) public Cgt_Un(ILInstruction left, ILInstruction right) : base(OpCode.Cgt_Un, left, right)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitCgt_Un(this); return visitor.VisitCgt_Un(this);
} }
@ -481,11 +449,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.</summary> /// <summary>Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.</summary>
public sealed partial class Clt : BinaryComparisonInstruction public sealed partial class Clt : BinaryComparisonInstruction
{ {
public Clt(StackType opType) : base(OpCode.Clt, opType) public Clt(ILInstruction left, ILInstruction right) : base(OpCode.Clt, left, right)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitClt(this); return visitor.VisitClt(this);
} }
@ -494,11 +462,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.</summary> /// <summary>Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.</summary>
public sealed partial class Clt_Un : BinaryComparisonInstruction public sealed partial class Clt_Un : BinaryComparisonInstruction
{ {
public Clt_Un(StackType opType) : base(OpCode.Clt_Un, opType) public Clt_Un(ILInstruction left, ILInstruction right) : base(OpCode.Clt_Un, left, right)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitClt_Un(this); return visitor.VisitClt_Un(this);
} }
@ -511,7 +479,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitCall(this); return visitor.VisitCall(this);
} }
@ -524,7 +492,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitCallVirt(this); return visitor.VisitCallVirt(this);
} }
@ -538,10 +506,10 @@ namespace ICSharpCode.Decompiler.IL
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayPeek | InstructionFlags.MayThrow; return InstructionFlags.MayPeek | InstructionFlags.MayThrow;
} }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitCkFinite(this); return visitor.VisitCkFinite(this);
} }
@ -551,7 +519,7 @@ namespace ICSharpCode.Decompiler.IL
public sealed partial class Conv : UnaryInstruction public sealed partial class Conv : UnaryInstruction
{ {
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitConv(this); return visitor.VisitConv(this);
} }
@ -560,11 +528,15 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads the value of a local variable. (ldarg/ldloc)</summary> /// <summary>Loads the value of a local variable. (ldarg/ldloc)</summary>
public sealed partial class LdLoc : SimpleInstruction public sealed partial class LdLoc : SimpleInstruction
{ {
public LdLoc() : base(OpCode.LdLoc) public LdLoc(ILVariable variable) : base(OpCode.LdLoc)
{ {
this.variable = variable;
} }
public override StackType ResultType { get { return Variable.Type.ToStackType(); } } readonly ILVariable variable;
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) /// <summary>Returns the variable operand.</summary>
public ILVariable Variable { get { return variable; } }
public override StackType ResultType { get { return variable.Type.GetStackType(); } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdLoc(this); return visitor.VisitLdLoc(this);
} }
@ -573,11 +545,15 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads the address of a local variable. (ldarga/ldloca)</summary> /// <summary>Loads the address of a local variable. (ldarga/ldloca)</summary>
public sealed partial class LdLoca : SimpleInstruction public sealed partial class LdLoca : SimpleInstruction
{ {
public LdLoca() : base(OpCode.LdLoca) public LdLoca(ILVariable variable) : base(OpCode.LdLoca)
{ {
this.variable = variable;
} }
public override StackType ResultType { get { return StackType.Ref; } } public override StackType ResultType { get { return StackType.Ref; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) readonly ILVariable variable;
/// <summary>Returns the variable operand.</summary>
public ILVariable Variable { get { return variable; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdLoca(this); return visitor.VisitLdLoca(this);
} }
@ -586,11 +562,15 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Stores a value into a local variable. (starg/stloc)</summary> /// <summary>Stores a value into a local variable. (starg/stloc)</summary>
public sealed partial class StLoc : UnaryInstruction public sealed partial class StLoc : UnaryInstruction
{ {
public StLoc() : base(OpCode.StLoc) public StLoc(ILInstruction argument, ILVariable variable) : base(OpCode.StLoc, argument)
{ {
this.variable = variable;
} }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) readonly ILVariable variable;
/// <summary>Returns the variable operand.</summary>
public ILVariable Variable { get { return variable; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitStLoc(this); return visitor.VisitStLoc(this);
} }
@ -599,11 +579,13 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads a constant string.</summary> /// <summary>Loads a constant string.</summary>
public sealed partial class LdStr : SimpleInstruction public sealed partial class LdStr : SimpleInstruction
{ {
public LdStr() : base(OpCode.LdStr) public LdStr(string value) : base(OpCode.LdStr)
{ {
this.Value = value;
} }
public readonly string Value;
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdStr(this); return visitor.VisitLdStr(this);
} }
@ -612,11 +594,13 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads a constant 32-bit integer.</summary> /// <summary>Loads a constant 32-bit integer.</summary>
public sealed partial class LdcI4 : SimpleInstruction public sealed partial class LdcI4 : SimpleInstruction
{ {
public LdcI4() : base(OpCode.LdcI4) public LdcI4(int value) : base(OpCode.LdcI4)
{ {
this.Value = value;
} }
public readonly int Value;
public override StackType ResultType { get { return StackType.I4; } } public override StackType ResultType { get { return StackType.I4; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdcI4(this); return visitor.VisitLdcI4(this);
} }
@ -625,11 +609,13 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads a constant 64-bit integer.</summary> /// <summary>Loads a constant 64-bit integer.</summary>
public sealed partial class LdcI8 : SimpleInstruction public sealed partial class LdcI8 : SimpleInstruction
{ {
public LdcI8() : base(OpCode.LdcI8) public LdcI8(long value) : base(OpCode.LdcI8)
{ {
this.Value = value;
} }
public readonly long Value;
public override StackType ResultType { get { return StackType.I8; } } public override StackType ResultType { get { return StackType.I8; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdcI8(this); return visitor.VisitLdcI8(this);
} }
@ -638,11 +624,13 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads a constant floating-point number.</summary> /// <summary>Loads a constant floating-point number.</summary>
public sealed partial class LdcF : SimpleInstruction public sealed partial class LdcF : SimpleInstruction
{ {
public LdcF() : base(OpCode.LdcF) public LdcF(double value) : base(OpCode.LdcF)
{ {
this.Value = value;
} }
public readonly double Value;
public override StackType ResultType { get { return StackType.F; } } public override StackType ResultType { get { return StackType.F; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdcF(this); return visitor.VisitLdcF(this);
} }
@ -655,7 +643,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
} }
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdNull(this); return visitor.VisitLdNull(this);
} }
@ -664,15 +652,12 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns from the current method or lambda.</summary> /// <summary>Returns from the current method or lambda.</summary>
public sealed partial class Return : ILInstruction public sealed partial class Return : ILInstruction
{ {
public Return() : base(OpCode.Return)
{
}
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayBranch; return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
} }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitReturn(this); return visitor.VisitReturn(this);
} }
@ -681,11 +666,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Shift left</summary> /// <summary>Shift left</summary>
public sealed partial class Shl : BinaryNumericInstruction public sealed partial class Shl : BinaryNumericInstruction
{ {
public Shl(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Shl, opType, resultType, overflowMode) public Shl(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Shl, left, right, overflowMode)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitShl(this); return visitor.VisitShl(this);
} }
@ -694,28 +679,36 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Shift right</summary> /// <summary>Shift right</summary>
public sealed partial class Shr : BinaryNumericInstruction public sealed partial class Shr : BinaryNumericInstruction
{ {
public Shr(StackType opType, StackType resultType, OverflowMode overflowMode) : base(OpCode.Shr, opType, resultType, overflowMode) public Shr(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Shr, left, right, overflowMode)
{ {
} }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitShr(this); return visitor.VisitShr(this);
} }
} }
/// <summary>Load instance field</summary> /// <summary>Load instance field</summary>
public sealed partial class Ldfld : UnaryInstruction public sealed partial class Ldfld : UnaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{ {
public Ldfld() : base(OpCode.Ldfld) public Ldfld(ILInstruction argument, FieldReference field) : base(OpCode.Ldfld, argument)
{ {
this.field = field;
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.SideEffect; return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
} }
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
readonly FieldReference field;
/// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } }
public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdfld(this); return visitor.VisitLdfld(this);
} }
@ -724,49 +717,69 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Load address of instance field</summary> /// <summary>Load address of instance field</summary>
public sealed partial class Ldflda : UnaryInstruction public sealed partial class Ldflda : UnaryInstruction
{ {
public Ldflda() : base(OpCode.Ldflda) public Ldflda(ILInstruction argument, FieldReference field) : base(OpCode.Ldflda, argument)
{ {
this.field = field;
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.MayThrow;
} }
readonly FieldReference field;
/// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } }
public override StackType ResultType { get { return StackType.Ref; } } public override StackType ResultType { get { return StackType.Ref; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdflda(this); return visitor.VisitLdflda(this);
} }
} }
/// <summary>Store value to instance field</summary> /// <summary>Store value to instance field</summary>
public sealed partial class Stfld : BinaryInstruction public sealed partial class Stfld : BinaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{ {
public Stfld() : base(OpCode.Stfld) public Stfld(ILInstruction left, ILInstruction right, FieldReference field) : base(OpCode.Stfld, left, right)
{ {
this.field = field;
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
} }
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) readonly FieldReference field;
/// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitStfld(this); return visitor.VisitStfld(this);
} }
} }
/// <summary>Load static field</summary> /// <summary>Load static field</summary>
public sealed partial class Ldsfld : SimpleInstruction public sealed partial class Ldsfld : SimpleInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{ {
public Ldsfld() : base(OpCode.Ldsfld) public Ldsfld(FieldReference field) : base(OpCode.Ldsfld)
{ {
this.field = field;
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.SideEffect; return InstructionFlags.SideEffect;
} }
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
readonly FieldReference field;
/// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } }
public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdsfld(this); return visitor.VisitLdsfld(this);
} }
@ -775,28 +788,40 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Load static field address</summary> /// <summary>Load static field address</summary>
public sealed partial class Ldsflda : SimpleInstruction public sealed partial class Ldsflda : SimpleInstruction
{ {
public Ldsflda() : base(OpCode.Ldsflda) public Ldsflda(FieldReference field) : base(OpCode.Ldsflda)
{ {
this.field = field;
} }
public override StackType ResultType { get { return StackType.Ref; } } public override StackType ResultType { get { return StackType.Ref; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) readonly FieldReference field;
/// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdsflda(this); return visitor.VisitLdsflda(this);
} }
} }
/// <summary>Store value to static field</summary> /// <summary>Store value to static field</summary>
public sealed partial class Stsfld : UnaryInstruction public sealed partial class Stsfld : UnaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{ {
public Stsfld() : base(OpCode.Stsfld) public Stsfld(ILInstruction argument, FieldReference field) : base(OpCode.Stsfld, argument)
{ {
this.field = field;
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.SideEffect; return base.ComputeFlags() | InstructionFlags.SideEffect;
} }
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) readonly FieldReference field;
/// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitStsfld(this); return visitor.VisitStsfld(this);
} }
@ -805,28 +830,40 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Test if object is instance of class or interface.</summary> /// <summary>Test if object is instance of class or interface.</summary>
public sealed partial class IsInst : UnaryInstruction public sealed partial class IsInst : UnaryInstruction
{ {
public IsInst() : base(OpCode.IsInst) public IsInst(ILInstruction argument, TypeReference type) : base(OpCode.IsInst, argument)
{ {
this.type = type;
} }
public override StackType ResultType { get { return StackType.O; } } readonly TypeReference type;
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) /// <summary>Returns the type operand.</summary>
public TypeReference Type { get { return type; } }
public override StackType ResultType { get { return type.GetStackType(); } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitIsInst(this); return visitor.VisitIsInst(this);
} }
} }
/// <summary>Indirect load (ref/pointer dereference).</summary> /// <summary>Indirect load (ref/pointer dereference).</summary>
public sealed partial class LdInd : UnaryInstruction public sealed partial class LdInd : UnaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{ {
public LdInd() : base(OpCode.LdInd) public LdInd(ILInstruction argument, TypeReference type) : base(OpCode.LdInd, argument)
{ {
this.type = type;
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
} }
readonly TypeReference type;
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) /// <summary>Returns the type operand.</summary>
public TypeReference Type { get { return type; } }
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
public override StackType ResultType { get { return type.GetStackType(); } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdInd(this); return visitor.VisitLdInd(this);
} }
@ -835,15 +872,19 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Unbox a value.</summary> /// <summary>Unbox a value.</summary>
public sealed partial class UnboxAny : UnaryInstruction public sealed partial class UnboxAny : UnaryInstruction
{ {
public UnboxAny() : base(OpCode.UnboxAny) public UnboxAny(ILInstruction argument, TypeReference type) : base(OpCode.UnboxAny, argument)
{ {
this.type = type;
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
} }
readonly TypeReference type;
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) /// <summary>Returns the type operand.</summary>
public TypeReference Type { get { return type; } }
public override StackType ResultType { get { return type.GetStackType(); } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitUnboxAny(this); return visitor.VisitUnboxAny(this);
} }
@ -856,7 +897,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
} }
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitNewObj(this); return visitor.VisitNewObj(this);
} }
@ -865,15 +906,15 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Throws an exception.</summary> /// <summary>Throws an exception.</summary>
public sealed partial class Throw : UnaryInstruction public sealed partial class Throw : UnaryInstruction
{ {
public Throw() : base(OpCode.Throw) public Throw(ILInstruction argument) : base(OpCode.Throw, argument)
{ {
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;
} }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitThrow(this); return visitor.VisitThrow(this);
} }
@ -882,7 +923,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns the length of an array as 'native unsigned int'.</summary> /// <summary>Returns the length of an array as 'native unsigned int'.</summary>
public sealed partial class LdLen : UnaryInstruction public sealed partial class LdLen : UnaryInstruction
{ {
public LdLen() : base(OpCode.LdLen) public LdLen(ILInstruction argument) : base(OpCode.LdLen, argument)
{ {
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
@ -890,16 +931,19 @@ namespace ICSharpCode.Decompiler.IL
return base.ComputeFlags() | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.MayThrow;
} }
public override StackType ResultType { get { return StackType.I; } } public override StackType ResultType { get { return StackType.I; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdLen(this); return visitor.VisitLdLen(this);
} }
} }
/// <summary>
/// Base class for visitor pattern.
/// </summary>
public abstract class ILVisitor<T> public abstract class ILVisitor<T>
{ {
/// <summary>Called by Visit*() methods that were not overridden</summary>
protected abstract T Default(ILInstruction inst); protected abstract T Default(ILInstruction inst);
protected internal virtual T VisitNop(Nop inst) protected internal virtual T VisitNop(Nop inst)
@ -950,10 +994,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
return Default(inst); return Default(inst);
} }
protected internal virtual T VisitNeg(Neg inst)
{
return Default(inst);
}
protected internal virtual T VisitBitAnd(BitAnd inst) protected internal virtual T VisitBitAnd(BitAnd inst)
{ {
return Default(inst); return Default(inst);
@ -1115,5 +1155,57 @@ namespace ICSharpCode.Decompiler.IL
return Default(inst); return Default(inst);
} }
} }
partial class BinaryNumericInstruction
{
public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, OverflowMode overflowMode)
{
switch (opCode) {
case OpCode.Add:
return new Add(left, right, overflowMode);
case OpCode.Sub:
return new Sub(left, right, overflowMode);
case OpCode.Mul:
return new Mul(left, right, overflowMode);
case OpCode.Div:
return new Div(left, right, overflowMode);
case OpCode.Rem:
return new Rem(left, right, overflowMode);
case OpCode.BitAnd:
return new BitAnd(left, right, overflowMode);
case OpCode.BitOr:
return new BitOr(left, right, overflowMode);
case OpCode.BitXor:
return new BitXor(left, right, overflowMode);
case OpCode.Shl:
return new Shl(left, right, overflowMode);
case OpCode.Shr:
return new Shr(left, right, overflowMode);
default:
throw new ArgumentException("opCode is not a binary numeric instruction");
}
}
}
partial class BinaryComparisonInstruction
{
public static BinaryComparisonInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right)
{
switch (opCode) {
case OpCode.Ceq:
return new Ceq(left, right);
case OpCode.Cgt:
return new Cgt(left, right);
case OpCode.Cgt_Un:
return new Cgt_Un(left, right);
case OpCode.Clt:
return new Clt(left, right);
case OpCode.Clt_Un:
return new Clt_Un(left, right);
default:
throw new ArgumentException("opCode is not a binary comparison instruction");
}
}
}
} }

177
ICSharpCode.Decompiler/IL/Instructions.tt

@ -32,8 +32,8 @@
Peeking, NoArguments, ResultTypeParam), 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.", 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), VoidResult, Unary),
new OpCode("BlockContainer", "A container of IL blocks.", VoidResult), new OpCode("BlockContainer", "A container of IL blocks.", VoidResult, CustomConstructor),
new OpCode("Block", "A block of IL instructions."), new OpCode("Block", "A block of IL instructions.", CustomConstructor),
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).", 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), ResultType("I4"), Unary),
new OpCode("Add", "Adds two numbers.", BinaryNumeric), new OpCode("Add", "Adds two numbers.", BinaryNumeric),
@ -41,16 +41,15 @@
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, 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, ResultTypeParam), new OpCode("BitNot", "Bitwise NOT", Unary),
new OpCode("Arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")), new OpCode("Arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
new OpCode("ConditionalBranch", "<c>if (condition) goto target;</c>.", new OpCode("ConditionalBranch", "<c>if (condition) goto target;</c>.",
Unary, MayBranch, HasBranchTarget, VoidResult), BranchInstruction, CustomConstructor, CustomComputeFlags, MayBranch, VoidResult),
new OpCode("Branch", "<c>goto target;</c>.", new OpCode("Branch", "<c>goto target;</c>.",
NoArguments, UnconditionalBranch, MayBranch, HasBranchTarget), BranchInstruction, UnconditionalBranch, MayBranch),
new OpCode("DebugBreak", "Breakpoint instruction", new OpCode("DebugBreak", "Breakpoint instruction",
NoArguments, VoidResult, SideEffect), NoArguments, VoidResult, SideEffect),
new OpCode("Ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.", new OpCode("Ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.",
@ -70,45 +69,47 @@
new OpCode("Conv", "Numeric cast.", new OpCode("Conv", "Numeric cast.",
Unary, CustomConstructor), Unary, CustomConstructor),
new OpCode("LdLoc", "Loads the value of a local variable. (ldarg/ldloc)", new OpCode("LdLoc", "Loads the value of a local variable. (ldarg/ldloc)",
NoArguments, HasVariableOperand, ResultType("Variable.Type.ToStackType()")), NoArguments, HasVariableOperand, ResultType("variable.Type.GetStackType()")),
new OpCode("LdLoca", "Loads the address of a local variable. (ldarga/ldloca)", new OpCode("LdLoca", "Loads the address of a local variable. (ldarga/ldloca)",
NoArguments, ResultType("Ref"), HasVariableOperand), NoArguments, ResultType("Ref"), HasVariableOperand),
new OpCode("StLoc", "Stores a value into a local variable. (starg/stloc)", new OpCode("StLoc", "Stores a value into a local variable. (starg/stloc)",
Unary, VoidResult, HasVariableOperand), Unary, VoidResult, HasVariableOperand),
new OpCode("LdStr", "Loads a constant string.", new OpCode("LdStr", "Loads a constant string.",
LoadConstant, ResultType("O")), LoadConstant("string"), ResultType("O")),
new OpCode("LdcI4", "Loads a constant 32-bit integer.", new OpCode("LdcI4", "Loads a constant 32-bit integer.",
LoadConstant, ResultType("I4")), LoadConstant("int"), ResultType("I4")),
new OpCode("LdcI8", "Loads a constant 64-bit integer.", new OpCode("LdcI8", "Loads a constant 64-bit integer.",
LoadConstant, ResultType("I8")), LoadConstant("long"), ResultType("I8")),
new OpCode("LdcF", "Loads a constant floating-point number.", new OpCode("LdcF", "Loads a constant floating-point number.",
LoadConstant, ResultType("F")), LoadConstant("double"), ResultType("F")),
new OpCode("LdNull", "Loads the null reference.", new OpCode("LdNull", "Loads the null reference.",
LoadConstant, ResultType("O")), NoArguments, ResultType("O")),
new OpCode("Return", "Returns from the current method or lambda.", new OpCode("Return", "Returns from the current method or lambda.",
MayBranch, UnconditionalBranch), CustomConstructor, 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", new OpCode("Ldfld", "Load instance field",
Unary, MayThrow, SideEffect, HasFieldOperand), Unary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow,
HasFieldOperand, ResultType("field.FieldType.GetStackType()")),
new OpCode("Ldflda", "Load address of instance field", new OpCode("Ldflda", "Load address of instance field",
Unary, MayThrow, HasFieldOperand, ResultType("Ref")), Unary, MayThrow, HasFieldOperand, ResultType("Ref")),
new OpCode("Stfld", "Store value to instance field", new OpCode("Stfld", "Store value to instance field",
Binary, SideEffect, MayThrow, VoidResult, HasFieldOperand), Binary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, VoidResult, HasFieldOperand),
new OpCode("Ldsfld", "Load static field", new OpCode("Ldsfld", "Load static field",
NoArguments, SideEffect, HasFieldOperand), NoArguments, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix,
HasFieldOperand, ResultType("field.FieldType.GetStackType()")),
new OpCode("Ldsflda", "Load static field address", new OpCode("Ldsflda", "Load static field address",
NoArguments, ResultType("Ref"), HasFieldOperand), NoArguments, ResultType("Ref"), HasFieldOperand),
new OpCode("Stsfld", "Store value to static field", new OpCode("Stsfld", "Store value to static field",
Unary, SideEffect, VoidResult, HasFieldOperand), Unary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, VoidResult, HasFieldOperand),
new OpCode("IsInst", "Test if object is instance of class or interface.", new OpCode("IsInst", "Test if object is instance of class or interface.",
Unary, HasTypeOperand, ResultType("O")), Unary, HasTypeOperand, ResultType("type.GetStackType()")),
new OpCode("LdInd", "Indirect load (ref/pointer dereference).", new OpCode("LdInd", "Indirect load (ref/pointer dereference).",
Unary, HasTypeOperand, SideEffect, MayThrow), Unary, HasTypeOperand, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("type.GetStackType()")),
new OpCode("UnboxAny", "Unbox a value.", new OpCode("UnboxAny", "Unbox a value.",
Unary, HasTypeOperand, SideEffect, MayThrow), Unary, HasTypeOperand, MemoryAccess, MayThrow, ResultType("type.GetStackType()")),
new OpCode("NewObj", "Creates an object instance and calls the constructor.", new OpCode("NewObj", "Creates an object instance and calls the constructor.",
Call, ResultType("O")), Call, ResultType("O")),
new OpCode("Throw", "Throws an exception.", new OpCode("Throw", "Throws an exception.",
@ -137,20 +138,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#> : <#=opCode.BaseClass#> public sealed partial class <#=opCode.Name#> : <#=string.Join(", ", new[]{opCode.BaseClass}.Concat(opCode.Interfaces))#>
{ {
<# if (opCode.GenerateConstructor) { #> <# if (opCode.GenerateConstructor) { #>
public <#=opCode.Name#>(<#=string.Join(", ", opCode.ConstructorParameters)#>) : base(<#=string.Join(", ", opCode.BaseConstructorArguments)#>) public <#=opCode.Name#>(<#=string.Join(", ", opCode.ConstructorParameters)#>) : base(<#=string.Join(", ", opCode.BaseConstructorArguments)#>)
{<#=Body(opCode.ConstructorBody)#>} {<#=Body(opCode.ConstructorBody)#>}
<# } #> <# } #>
<# if (opCode.Flags.Count > 1) { #> <# if (opCode.GenerateComputeFlags && opCode.Flags.Any(f => f != "base.ComputeFlags()")) { #>
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return <#=string.Join(" | ", opCode.Flags)#>; return <#=string.Join(" | ", opCode.Flags)#>;
} }
<# } #> <# } #>
<#=string.Join(Environment.NewLine, opCode.Members.Select(m => "\t\t" + m))#> <#=string.Join(Environment.NewLine, opCode.Members.Select(m => "\t\t" + m.Replace("\n", "\n\t\t")))#>
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.Visit<#=opCode.Name#>(this); return visitor.Visit<#=opCode.Name#>(this);
} }
@ -158,9 +159,12 @@ namespace ICSharpCode.Decompiler.IL
<# } #> <# } #>
/// <summary>
/// Base class for visitor pattern.
/// </summary>
public abstract class ILVisitor<T> public abstract class ILVisitor<T>
{ {
/// <summary>Called by Visit*() methods that were not overridden</summary>
protected abstract T Default(ILInstruction inst); protected abstract T Default(ILInstruction inst);
<# foreach (OpCode opCode in opCodes) { #> <# foreach (OpCode opCode in opCodes) { #>
@ -170,6 +174,36 @@ namespace ICSharpCode.Decompiler.IL
} }
<# } #> <# } #>
} }
partial class BinaryNumericInstruction
{
public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, OverflowMode overflowMode)
{
switch (opCode) {
<# foreach (OpCode opCode in opCodes.Where(c => c.BaseClass == "BinaryNumericInstruction")) { #>
case OpCode.<#=opCode.Name#>:
return new <#=opCode.Name#>(left, right, overflowMode);
<# } #>
default:
throw new ArgumentException("opCode is not a binary numeric instruction");
}
}
}
partial class BinaryComparisonInstruction
{
public static BinaryComparisonInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right)
{
switch (opCode) {
<# foreach (OpCode opCode in opCodes.Where(c => c.BaseClass == "BinaryComparisonInstruction")) { #>
case OpCode.<#=opCode.Name#>:
return new <#=opCode.Name#>(left, right);
<# } #>
default:
throw new ArgumentException("opCode is not a binary comparison instruction");
}
}
}
} }
<#+ <#+
@ -179,7 +213,7 @@ namespace ICSharpCode.Decompiler.IL
foreach (var st in statements) { foreach (var st in statements) {
b.AppendLine(); b.AppendLine();
b.Append("\t\t\t"); b.Append("\t\t\t");
b.Append(st); b.Append(st.Replace("\n", "\n\t\t\t"));
} }
b.AppendLine(); b.AppendLine();
b.Append("\t\t"); b.Append("\t\t");
@ -204,16 +238,22 @@ namespace ICSharpCode.Decompiler.IL
public List<string> ConstructorBody = new List<string>(); public List<string> ConstructorBody = new List<string>();
public string BaseClass = "ILInstruction"; public string BaseClass = "ILInstruction";
public List<string> Interfaces = new List<string>();
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()" }; public List<string> Flags = new List<string>();
public bool GenerateComputeFlags = true;
} }
static Action<OpCode> CustomConstructor = opCode => { static Action<OpCode> CustomConstructor = opCode => {
opCode.GenerateConstructor = false; opCode.GenerateConstructor = false;
}; };
static Action<OpCode> CustomComputeFlags = opCode => {
opCode.GenerateComputeFlags = false;
};
static Action<OpCode> HasFlag(string name) static Action<OpCode> HasFlag(string name)
{ {
return opCode => { return opCode => {
@ -255,9 +295,15 @@ namespace ICSharpCode.Decompiler.IL
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 = VoidResult + HasFlag("InstructionFlags.EndPointUnreachable");
VoidResult(opCode);
}; static Action<OpCode> BaseClass(string name)
{
return opCode => {
opCode.BaseClass = name;
opCode.Flags.Add("base.ComputeFlags()");
};
}
// NoArguments trait: the instruction no arguments // NoArguments trait: the instruction no arguments
static Action<OpCode> NoArguments = opCode => { static Action<OpCode> NoArguments = opCode => {
@ -267,33 +313,44 @@ namespace ICSharpCode.Decompiler.IL
// Unary trait: the instruction has a single argument // Unary trait: the instruction has a single argument
static Action<OpCode> Unary = opCode => { static Action<OpCode> Unary = opCode => {
opCode.BaseClass = "UnaryInstruction"; opCode.BaseClass = "UnaryInstruction";
opCode.Flags.Add("base.ComputeFlags()");
opCode.ConstructorParameters.Add("ILInstruction argument");
opCode.BaseConstructorArguments.Add("argument");
}; };
// Binary trait: the instruction has two arguments named 'Left' and 'Right' // Binary trait: the instruction has two arguments named 'Left' and 'Right'
static Action<OpCode> Binary = opCode => { static Action<OpCode> Binary = opCode => {
opCode.BaseClass = "BinaryInstruction"; opCode.BaseClass = "BinaryInstruction";
opCode.Flags.Add("base.ComputeFlags()");
opCode.ConstructorParameters.Add("ILInstruction left");
opCode.ConstructorParameters.Add("ILInstruction right");
opCode.BaseConstructorArguments.Add("left");
opCode.BaseConstructorArguments.Add("right");
}; };
// BinaryNumeric trait: the instruction is derived from BinaryNumericInstruction. Implies Binary and NonVoidResult; and implies MayThrow if the overflow mode is checked. // BinaryNumeric trait: the instruction is derived from BinaryNumericInstruction. Implies Binary; and implies MayThrow if the overflow mode is checked.
static Action<OpCode> BinaryNumeric = opCode => { static Action<OpCode> BinaryNumeric = opCode => {
Binary(opCode);
opCode.BaseClass = "BinaryNumericInstruction"; opCode.BaseClass = "BinaryNumericInstruction";
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("resultType");
opCode.BaseConstructorArguments.Add("overflowMode"); opCode.BaseConstructorArguments.Add("overflowMode");
}; };
// BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result. // BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result.
static Action<OpCode> BinaryComparison = opCode => { static Action<OpCode> BinaryComparison = opCode => {
Binary(opCode);
opCode.BaseClass = "BinaryComparisonInstruction"; opCode.BaseClass = "BinaryComparisonInstruction";
opCode.ConstructorParameters.Add("StackType opType"); };
opCode.BaseConstructorArguments.Add("opType");
static Action<OpCode> BranchInstruction = opCode => {
opCode.BaseClass = "BranchInstruction";
opCode.ConstructorParameters.Add("int targetILOffset");
opCode.BaseConstructorArguments.Add("targetILOffset");
}; };
// SideEffect trait: the instruction has a non-local side effect // SideEffect trait: the instruction has a non-local side effect
static Action<OpCode> SideEffect = HasFlag("InstructionFlags.SideEffect"); static Action<OpCode> SideEffect = HasFlag("InstructionFlags.SideEffect");
static Action<OpCode> MemoryAccess = 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 => {
@ -303,14 +360,50 @@ namespace ICSharpCode.Decompiler.IL
}; };
// HasVariableOperand trait: the instruction refers to a local variable // HasVariableOperand trait: the instruction refers to a local variable
static Action<OpCode> HasVariableOperand = opCode => {}; static Action<OpCode> HasVariableOperand = opCode => {
opCode.ConstructorParameters.Add("ILVariable variable");
opCode.Members.Add("readonly ILVariable variable;");
opCode.ConstructorBody.Add("this.variable = variable;");
opCode.Members.Add("/// <summary>Returns the variable operand.</summary>" + Environment.NewLine
+ "public ILVariable Variable { get { return variable; } }");
};
static Action<OpCode> HasFieldOperand = opCode => {}; static Action<OpCode> HasFieldOperand = opCode => {
opCode.ConstructorParameters.Add("FieldReference field");
opCode.Members.Add("readonly FieldReference field;");
opCode.ConstructorBody.Add("this.field = field;");
opCode.Members.Add("/// <summary>Returns the field operand.</summary>" + Environment.NewLine
+ "public FieldReference Field { get { return field; } }");
};
static Action<OpCode> HasTypeOperand = opCode => {}; static Action<OpCode> HasTypeOperand = opCode => {
opCode.ConstructorParameters.Add("TypeReference type");
opCode.Members.Add("readonly TypeReference type;");
opCode.ConstructorBody.Add("this.type = type;");
opCode.Members.Add("/// <summary>Returns the type operand.</summary>" + Environment.NewLine
+ "public TypeReference Type { get { return type; } }");
};
// LoadConstant trait: the instruction loads a compile-time constant. Implies NoArguments. // LoadConstant trait: the instruction loads a compile-time constant. Implies NoArguments.
static Action<OpCode> LoadConstant = opCode => { static Action<OpCode> LoadConstant(string operandType)
NoArguments(opCode); {
return opCode => {
NoArguments(opCode);
opCode.ConstructorParameters.Add(operandType + " value");
opCode.Members.Add("public readonly " + operandType + " Value;");
opCode.ConstructorBody.Add("this.Value = value;");
};
}
static Action<OpCode> SupportsVolatilePrefix = opCode => {
opCode.Interfaces.Add("ISupportsVolatilePrefix");
opCode.Members.Add("/// <summary>Gets/Sets whether the memory access is volatile.</summary>" + Environment.NewLine
+ "public bool IsVolatile { get; set; }");
};
static Action<OpCode> SupportsUnalignedPrefix = opCode => {
opCode.Interfaces.Add("ISupportsUnalignedPrefix");
opCode.Members.Add("/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>" + Environment.NewLine
+ "public byte UnalignedPrefix { get; set; }");
}; };
#> #>

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

@ -24,13 +24,13 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
public abstract class BinaryComparisonInstruction : BinaryInstruction public abstract partial class BinaryComparisonInstruction : BinaryInstruction
{ {
public readonly StackType OpType; public readonly StackType OpType;
protected BinaryComparisonInstruction(OpCode opCode, StackType opType) : base(opCode) protected BinaryComparisonInstruction(OpCode opCode, ILInstruction left, ILInstruction right) : base(opCode, left, right)
{ {
this.OpType = opType; // TODO this.OpType = opType;
} }
public sealed override StackType ResultType { public sealed override StackType ResultType {

41
ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs

@ -27,40 +27,32 @@ namespace ICSharpCode.Decompiler.IL
{ {
public abstract class BinaryInstruction : ILInstruction public abstract class BinaryInstruction : ILInstruction
{ {
ILInstruction left = Pop; ILInstruction left;
ILInstruction right = Pop; ILInstruction right;
protected BinaryInstruction(OpCode opCode) : base(opCode) protected BinaryInstruction(OpCode opCode, ILInstruction left, ILInstruction right)
: base(opCode)
{ {
this.Left = left;
this.Right = right;
} }
public ILInstruction Left { public ILInstruction Left {
get { return left; } get { return left; }
set { set {
Debug.Assert(value.ResultType != StackType.Void); ValidateArgument(value);
left = value; SetChildInstruction(ref left, value);
InvalidateFlags();
} }
} }
public ILInstruction Right { public ILInstruction Right {
get { return right; } get { return right; }
set { set {
Debug.Assert(value.ResultType != StackType.Void); ValidateArgument(value);
right = value; SetChildInstruction(ref 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) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); output.Write(OpCode);
@ -84,22 +76,19 @@ namespace ICSharpCode.Decompiler.IL
return value; return value;
} }
/* public sealed override void TransformChildren(ILVisitor<ILInstruction> visitor)
public override bool IsPeeking { get { return Left.IsPeeking; } }
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc)
{ {
Left = transformFunc(Left); this.Left = left.AcceptVisitor(visitor);
Right = transformFunc(Right); this.Right = right.AcceptVisitor(visitor);
} }
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished) internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{ {
InstructionFlags flagsBeforeRight = flagsBefore | (Left.Flags & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)); InstructionFlags flagsBeforeRight = flagsBefore | (Left.Flags & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop));
Right = Right.Inline(flagsBeforeRight, instructionStack, out finished); Right = Right.Inline(flagsBeforeRight, instructionStack, out finished);
if (finished) if (finished)
Left = Left.Inline(flagsBefore, instructionStack, out finished); Left = Left.Inline(flagsBefore, instructionStack, out finished);
return this; return this;
}*/ }
} }
} }

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

@ -37,19 +37,41 @@ namespace ICSharpCode.Decompiler.IL
Ovf_Un = 3 Ovf_Un = 3
} }
public abstract class BinaryNumericInstruction : BinaryInstruction public abstract partial class BinaryNumericInstruction : BinaryInstruction
{ {
public readonly StackType OpType;
public readonly OverflowMode OverflowMode; public readonly OverflowMode OverflowMode;
readonly StackType resultType; readonly StackType resultType;
protected BinaryNumericInstruction(OpCode opCode, StackType opType, StackType resultType, OverflowMode overflowMode) : base(opCode) protected BinaryNumericInstruction(OpCode opCode, ILInstruction left, ILInstruction right, OverflowMode overflowMode)
: base(opCode, left, right)
{ {
this.OpType = opType;
this.resultType = resultType;
this.OverflowMode = overflowMode; this.OverflowMode = overflowMode;
this.resultType = ComputeResultType(opCode, left.ResultType, right.ResultType);
}
internal static StackType ComputeResultType(OpCode opCode, StackType left, StackType right)
{
// Based on Table 2: Binary Numeric Operations
// also works for Table 5: Integer Operations
// and for Table 7: Overflow Arithmetic Operations
if (left == right) {
return left;
}
if (left == StackType.Ref || right == StackType.Ref) {
if (left == StackType.Ref && right == StackType.Ref) {
// sub(&, &) = I
Debug.Assert(opCode == OpCode.Sub);
return StackType.I;
} else {
// add/sub with I or I4 and &
Debug.Assert(opCode == OpCode.Add || opCode == OpCode.Sub);
return StackType.Ref;
}
}
if (left == StackType.I || right == StackType.I)
return StackType.I;
return StackType.Unknown;
} }
public sealed override StackType ResultType { public sealed override StackType ResultType {
@ -70,8 +92,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
output.Write(OpCode); output.Write(OpCode);
output.WriteSuffix(OverflowMode); output.WriteSuffix(OverflowMode);
output.Write(' ');
output.Write(OpType);
output.Write('('); output.Write('(');
Left.WriteTo(output); Left.WriteTo(output);
output.Write(", "); output.Write(", ");

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

@ -1,17 +1,20 @@
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;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary>
/// A block of IL instructions.
/// </summary>
partial class Block : ILInstruction partial class Block : ILInstruction
{ {
public readonly List<ILInstruction> Instructions = new List<ILInstruction>(); public readonly InstructionCollection<ILInstruction> Instructions;
public Block() : base(OpCode.Block)
{
this.Instructions = new InstructionCollection<ILInstruction>(this);
}
/* /*
public override bool IsPeeking { get { return Instructions.Count > 0 && Instructions[0].IsPeeking; } } public override bool IsPeeking { get { return Instructions.Count > 0 && Instructions[0].IsPeeking; } }
@ -26,6 +29,12 @@ namespace ICSharpCode.Decompiler.IL
} }
*/ */
public override StackType ResultType {
get {
return StackType.Void;
}
}
/// <summary> /// <summary>
/// Gets the name of this block. /// Gets the name of this block.
/// </summary> /// </summary>
@ -56,18 +65,22 @@ namespace ICSharpCode.Decompiler.IL
return value; return value;
} }
/* public override void TransformChildren(ILVisitor<ILInstruction> visitor)
public override InstructionFlags Flags
{ {
get { for (int i = 0; i < Instructions.Count; i++) {
InstructionFlags flags = InstructionFlags.None; Instructions[i] = Instructions[i].AcceptVisitor(visitor);
for (int i = 0; i < Instructions.Count; i++) {
flags |= Instructions[i].Flags;
}
return flags;
} }
} }
protected override InstructionFlags ComputeFlags()
{
var flags = InstructionFlags.None;
foreach (var inst in Instructions)
flags |= inst.Flags;
return flags;
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished) internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{ {
if (Instructions.Count > 0) if (Instructions.Count > 0)
@ -75,73 +88,6 @@ namespace ICSharpCode.Decompiler.IL
else else
finished = true; finished = true;
return this; return this;
}*/
}
/// <summary>
/// A container of IL blocks.
/// Each block is an extended basic block (branches may only jump to the beginning of blocks, not into the middle),
/// and only branches within this container may reference the blocks in this container.
/// That means that viewed from the outside, the block container has a single entry point (but possibly multiple exit points),
/// and the same holds for every block within the container.
/// </summary>
partial class BlockContainer : ILInstruction
{
public List<Block> Blocks = new List<Block>();
public Block EntryPoint { get { return Blocks[0]; } }
/*
public override bool IsPeeking { get { return EntryPoint.IsPeeking; } }
public override bool NoResult { get { return true; } }
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc)
{
for (int i = 0; i < Blocks.Count; i++) {
if (transformFunc(Blocks[i]) != Blocks[i])
throw new InvalidOperationException("Cannot replace blocks");
}
} }
*/
public override void WriteTo(ITextOutput output)
{
output.WriteLine("BlockContainer {");
output.Indent();
foreach (var inst in Blocks) {
inst.WriteTo(output);
output.WriteLine();
}
output.Unindent();
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
{
get
{
InstructionFlags flags = InstructionFlags.None;
for (int i = 0; i < Blocks.Count; i++) {
flags |= Blocks[i].Flags;
}
return flags;
}
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
finished = false;
return this;
}*/
} }
} }

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

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
/// <summary>
/// A container of IL blocks.
/// Each block is an extended basic block (branches may only jump to the beginning of blocks, not into the middle),
/// and only branches within this container may reference the blocks in this container.
/// That means that viewed from the outside, the block container has a single entry point (but possibly multiple exit points),
/// and the same holds for every block within the container.
/// </summary>
partial class BlockContainer : ILInstruction
{
public readonly IList<Block> Blocks;
public Block EntryPoint {
get {
return Blocks[0];
}
}
public BlockContainer() : base(OpCode.BlockContainer)
{
this.Blocks = new InstructionCollection<Block>(this);
}
/*
public override bool IsPeeking { get { return EntryPoint.IsPeeking; } }
public override bool NoResult { get { return true; } }
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc)
{
for (int i = 0; i < Blocks.Count; i++) {
if (transformFunc(Blocks[i]) != Blocks[i])
throw new InvalidOperationException("Cannot replace blocks");
}
}
*/public override void WriteTo(ITextOutput output)
{
output.WriteLine("BlockContainer {");
output.Indent();
foreach (var inst in Blocks) {
inst.WriteTo(output);
output.WriteLine();
}
output.Unindent();
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 void TransformChildren(ILVisitor<ILInstruction> visitor)
{
foreach (var block in Blocks) {
// Recurse into the blocks, but don't allow replacing the block
if (block.AcceptVisitor(visitor) != block)
throw new InvalidOperationException("Cannot replace blocks in BlockContainer");
}
}
protected override InstructionFlags ComputeFlags()
{
var flags = InstructionFlags.None;
foreach (var block in Blocks) {
flags |= block.Flags;
}
return flags;
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
finished = false;
return this;
}
}
}

68
ICSharpCode.Decompiler/IL/Instructions/BranchInstruction.cs

@ -1,5 +1,6 @@
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;
@ -9,46 +10,87 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Base class for unconditional and conditional branches. /// Base class for unconditional and conditional branches.
/// </summary> /// </summary>
class Branch(OpCode opCode, public int TargetILOffset) : ILInstruction(opCode) public abstract class BranchInstruction : ILInstruction
{ {
public readonly int TargetILOffset;
protected BranchInstruction(OpCode opCode, int targetILOffset) : base(opCode)
{
this.TargetILOffset = targetILOffset;
}
public string TargetLabel { public string TargetLabel {
get { return CecilExtensions.OffsetToString(TargetILOffset); } get { return CecilExtensions.OffsetToString(TargetILOffset); }
} }
public override bool IsPeeking { get { return false; } }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode.ToString()); output.Write(OpCode.ToString());
output.Write(' '); output.Write(' ');
output.WriteReference(TargetLabel, TargetILOffset, isLocal: true); output.WriteReference(TargetLabel, TargetILOffset, isLocal: true);
} }
}
public override bool IsEndReachable partial class Branch
{
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{ {
get return initial;
{ }
// end is reachable for conditional branches, but not unconditional ones
return OpCode == OpCode.ConditionalBranch; public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
finished = true;
return this;
}
}
partial class ConditionalBranch
{
ILInstruction condition;
public ConditionalBranch(ILInstruction condition, int targetILOffset) : base(OpCode.ConditionalBranch, targetILOffset)
{
this.Condition = condition;
}
public ILInstruction Condition {
get {
return condition;
}
set {
ValidateArgument(condition);
SetChildInstruction(ref condition, value);
} }
} }
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc) public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{ {
return func(initial, condition.AcceptVisitor(visitor));
} }
public override InstructionFlags Flags public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{ {
get { return InstructionFlags.MayJump; } this.Condition = condition.AcceptVisitor(visitor);
} }
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished) internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{ {
finished = true; this.Condition = condition.Inline(flagsBefore, instructionStack, out finished);
return this; return this;
} }
protected override InstructionFlags ComputeFlags()
{
return condition.Flags | InstructionFlags.MayBranch;
}
} }
/*
/// <summary> /// <summary>
/// Special instruction for unresolved branches. /// Special instruction for unresolved branches.
/// Created by ILReader phase, replaced with TODO when building basic blocks. /// Created by ILReader phase, replaced with TODO when building basic blocks.
@ -110,5 +152,5 @@ namespace ICSharpCode.Decompiler.IL
{ {
get { return InstructionFlags.MayJump | Operand.Flags; } get { return InstructionFlags.MayJump | Operand.Flags; }
} }
} }*/
} }

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

@ -29,82 +29,35 @@ namespace ICSharpCode.Decompiler.IL
{ {
public abstract class CallInstruction : ILInstruction public abstract class CallInstruction : ILInstruction
{ {
public struct ArgumentCollection : IReadOnlyList<ILInstruction> public static CallInstruction Create(OpCode opCode, MethodReference method)
{ {
readonly CallInstruction inst; switch (opCode) {
case OpCode.Call:
public ArgumentCollection(CallInstruction inst) return new Call(method);
{ case OpCode.CallVirt:
this.inst = inst; return new CallVirt(method);
} case OpCode.NewObj:
return new NewObj(method);
public int Count { default:
get { return inst.arguments.Length; } throw new ArgumentException("Not a valid call opcode");
}
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
{
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 InstructionCollection<ILInstruction> Arguments;
public readonly MethodReference Method; public readonly MethodReference Method;
public ArgumentCollection Arguments {
get { return new ArgumentCollection(this); }
}
protected CallInstruction(OpCode opCode, MethodReference methodReference) : base(opCode) protected CallInstruction(OpCode opCode, MethodReference methodReference) : base(opCode)
{ {
this.Method = methodReference; this.Method = methodReference;
this.Arguments = new InstructionCollection<ILInstruction>(this);
}
public static int GetPopCount(OpCode callCode, MethodReference methodReference)
{
int popCount = methodReference.Parameters.Count; int popCount = methodReference.Parameters.Count;
if (opCode != OpCode.NewObj && methodReference.HasThis) if (callCode != OpCode.NewObj && methodReference.HasThis)
popCount++; popCount++;
this.arguments = new ILInstruction[popCount]; return popCount;
for (int i = 0; i < arguments.Length; i++) {
arguments[i] = Pop;
}
} }
public override StackType ResultType { public override StackType ResultType {
@ -113,48 +66,28 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal override void CheckInvariant()
{
base.CheckInvariant();
foreach (var op in arguments) {
op.CheckInvariant();
Debug.Assert(op.ResultType != StackType.Void);
}
}
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func) public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{ {
TAccumulate value = initial; TAccumulate value = initial;
foreach (var op in arguments) foreach (var op in Arguments)
value = func(value, op.AcceptVisitor(visitor)); value = func(value, op.AcceptVisitor(visitor));
return value; return value;
} }
protected override InstructionFlags ComputeFlags() public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{ {
var flags = InstructionFlags.MayThrow | InstructionFlags.SideEffects; for (int i = 0; i < Arguments.Count; i++) {
foreach (var op in arguments) Arguments[i] = Arguments[i].AcceptVisitor(visitor);
flags |= op.Flags;
return flags;
}
/*
public override bool IsPeeking { get { return Operands.Length > 0 && Operands[0].IsPeeking; } }
public override bool NoResult
{
get
{
return OpCode != OpCode.NewObj && Method.ReturnType.GetStackType() == StackType.Void;
} }
} }
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc) protected override InstructionFlags ComputeFlags()
{ {
for (int i = 0; i < Operands.Length; i++) { var flags = InstructionFlags.MayThrow | InstructionFlags.SideEffect;
Operands[i] = transformFunc(Operands[i]); foreach (var op in Arguments)
} flags |= op.Flags;
}*/ return flags;
}
/// <summary> /// <summary>
/// Gets/Sets whether the call has the 'tail.' prefix. /// Gets/Sets whether the call has the 'tail.' prefix.
@ -179,7 +112,7 @@ namespace ICSharpCode.Decompiler.IL
output.Write(' '); output.Write(' ');
Method.WriteTo(output); Method.WriteTo(output);
output.Write('('); output.Write('(');
for (int i = 0; i < Arguments.Length; i++) { for (int i = 0; i < Arguments.Count; i++) {
if (i > 0) if (i > 0)
output.Write(", "); output.Write(", ");
Arguments[i].WriteTo(output); Arguments[i].WriteTo(output);
@ -187,33 +120,20 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')'); output.Write(')');
} }
/*
public override InstructionFlags Flags
{
get
{
InstructionFlags flags = InstructionFlags.SideEffects | InstructionFlags.MayThrow;
for (int i = 0; i < Operands.Length; i++) {
flags |= Operands[i].Flags;
}
return flags;
}
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished) internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{ {
InstructionFlags operandFlags = InstructionFlags.None; InstructionFlags operandFlags = InstructionFlags.None;
for (int i = 0; i < Operands.Length - 1; i++) { for (int i = 0; i < Arguments.Count - 1; i++) {
operandFlags |= Operands[i].Flags; operandFlags |= Arguments[i].Flags;
} }
flagsBefore |= operandFlags & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop); flagsBefore |= operandFlags & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop);
finished = true; finished = true;
for (int i = Operands.Length - 1; i >= 0; i--) { for (int i = Arguments.Count - 1; i >= 0; i--) {
Operands[i] = Operands[i].Inline(flagsBefore, instructionStack, out finished); Arguments[i] = Arguments[i].Inline(flagsBefore, instructionStack, out finished);
if (!finished) if (!finished)
break; break;
} }
return this; return this;
}*/ }
} }
} }

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

@ -22,25 +22,27 @@ namespace ICSharpCode.Decompiler.IL
{ {
partial class Conv : UnaryInstruction partial class Conv : UnaryInstruction
{ {
public readonly StackType FromType; public readonly PrimitiveType TargetType;
public readonly PrimitiveType ToType;
public readonly OverflowMode ConvMode; public readonly OverflowMode ConvMode;
public Conv(StackType fromType, PrimitiveType toType, OverflowMode convMode) : base(OpCode.Conv) public Conv(ILInstruction argument, PrimitiveType targetType, OverflowMode convMode) : base(OpCode.Conv, argument)
{ {
this.FromType = fromType; this.TargetType = targetType;
this.ToType = toType;
this.ConvMode = convMode; this.ConvMode = convMode;
} }
public override StackType ResultType {
get { return TargetType.GetStackType(); }
}
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); output.Write(OpCode);
output.WriteSuffix(ConvMode); output.WriteSuffix(ConvMode);
output.Write(' '); output.Write(' ');
output.Write(FromType); output.Write(Argument.ResultType);
output.Write("->"); output.Write("->");
output.Write(ToType); output.Write(TargetType);
output.Write('('); output.Write('(');
Argument.WriteTo(output); Argument.WriteTo(output);
output.Write(')'); output.Write(')');

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

@ -31,8 +31,6 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
public abstract class ILInstruction public abstract class ILInstruction
{ {
public static readonly ILInstruction Pop = new Pop();
public readonly OpCode OpCode; public readonly OpCode OpCode;
protected ILInstruction(OpCode opCode) protected ILInstruction(OpCode opCode)
@ -40,8 +38,16 @@ namespace ICSharpCode.Decompiler.IL
this.OpCode = opCode; this.OpCode = opCode;
} }
internal static void ValidateArgument(ILInstruction inst)
{
if (inst == null)
throw new ArgumentNullException("inst");
if (inst.ResultType == StackType.Void)
throw new ArgumentException("Argument must not be of type void", "inst");
}
[Conditional("DEBUG")] [Conditional("DEBUG")]
internal virtual void CheckInvariant() internal void CheckInvariant()
{ {
} }
@ -50,20 +56,39 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
public abstract StackType ResultType { get; } public abstract StackType ResultType { get; }
InstructionFlags flags = (InstructionFlags)-1; InstructionFlags flags = (InstructionFlags)(-1);
public InstructionFlags Flags { public InstructionFlags Flags {
get { get {
if (flags == (InstructionFlags)-1) { if (flags == (InstructionFlags)(-1)) {
flags = ComputeFlags(); flags = ComputeFlags();
} }
return flags; return flags;
} }
} }
protected void InvalidateFlags() /// <summary>
/// Returns whether the instruction has at least one of the specified flags.
/// </summary>
public bool HasFlag(InstructionFlags flags)
{
return (this.Flags & flags) != 0;
}
protected void SetChildInstruction(ref ILInstruction childPointer, ILInstruction newValue)
{
childPointer = newValue;
flags = (InstructionFlags)(-1);
}
protected internal void AddChildInstruction(ILInstruction newChild)
{ {
flags = (InstructionFlags)-1; flags = (InstructionFlags)(-1);
}
protected internal void RemoveChildInstruction(ILInstruction newChild)
{
flags = (InstructionFlags)(-1);
} }
protected abstract InstructionFlags ComputeFlags(); protected abstract InstructionFlags ComputeFlags();
@ -75,15 +100,6 @@ namespace ICSharpCode.Decompiler.IL
public abstract void WriteTo(ITextOutput output); public abstract void WriteTo(ITextOutput output);
/// <summary>
/// Gets whether the end point of this instruction is reachable from the start point.
/// Returns false if the instruction performs an unconditional branch, or always throws an exception.
/// </summary>
public virtual bool IsEndReachable
{
get { return true; }
}
public abstract T AcceptVisitor<T>(ILVisitor<T> visitor); public abstract T AcceptVisitor<T>(ILVisitor<T> visitor);
/// <summary> /// <summary>
@ -95,6 +111,20 @@ namespace ICSharpCode.Decompiler.IL
/// <returns>The final value in the accumulator.</returns> /// <returns>The final value in the accumulator.</returns>
public abstract TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func); public abstract TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func);
/// <summary>
/// Transforms the children of this instruction by applying the specified visitor.
/// </summary>
public abstract void TransformChildren(ILVisitor<ILInstruction> visitor);
/// <summary>
/// Attempts inlining from the instruction stack into this instruction.
/// </summary>
/// <param name="flagsBefore">Combined instruction flags of the instructions
/// that the instructions getting inlined would get moved over.</param>
/// <param name="instructionStack">The instruction stack.</param>
/// <param name="finished">Receives 'true' if all open 'pop' or 'peek' placeholders were inlined into; false otherwise.</param>
internal abstract ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished);
/* /*
/// <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.
@ -129,15 +159,6 @@ namespace ICSharpCode.Decompiler.IL
output.Write(OpCode); output.Write(OpCode);
} }
/// <summary>
/// Attempts inlining from the instruction stack into this instruction.
/// </summary>
/// <param name="flagsBefore">Combined instruction flags of the instructions
/// that the instructions getting inlined would get moved over.</param>
/// <param name="instructionStack">The instruction stack.</param>
/// <param name="finished">Receives 'true' if all open 'pop' or 'peek' placeholders were inlined into; false otherwise.</param>
internal abstract ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished);
public abstract void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc); public abstract void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc);
*/ */
} }

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

@ -0,0 +1,65 @@
// 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.ObjectModel;
namespace ICSharpCode.Decompiler.IL
{
public sealed class InstructionCollection<T> : Collection<T> where T : ILInstruction
{
readonly ILInstruction parentInstruction;
public InstructionCollection(ILInstruction parentInstruction)
{
this.parentInstruction = parentInstruction;
}
protected override void ClearItems()
{
foreach (var child in this)
parentInstruction.RemoveChildInstruction(child);
base.ClearItems();
}
protected override void InsertItem(int index, T item)
{
if (item == null)
throw new ArgumentNullException("item");
parentInstruction.AddChildInstruction(item);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
parentInstruction.RemoveChildInstruction(this[index]);
base.RemoveItem(index);
}
protected override void SetItem(int index, T item)
{
if (item == null)
throw new ArgumentNullException("item");
if (this[index] == item)
return;
parentInstruction.RemoveChildInstruction(this[index]);
parentInstruction.AddChildInstruction(item);
base.SetItem(index, item);
}
}
}

51
ICSharpCode.Decompiler/IL/Instructions/MemoryInstruction.cs

@ -1,51 +0,0 @@
using ICSharpCode.Decompiler.Disassembler;
using Mono.Cecil;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
interface ISupportsMemoryPrefix : ISupportsVolatilePrefix
{
/// <summary>
/// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.
/// </summary>
byte UnalignedPrefix { get; set; }
}
interface ISupportsVolatilePrefix
{
/// <summary>
/// Gets/Sets whether the memory access is volatile.
/// </summary>
bool IsVolatile { get; set; }
}
class LoadIndirect(public readonly TypeReference TypeReference) : UnaryInstruction(OpCode.LdInd), ISupportsMemoryPrefix
{
public byte UnalignedPrefix { get; set; }
public bool IsVolatile { get; set; }
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix != 0)
output.Write("unaligned " + UnalignedPrefix + ".");
output.Write(OpCode);
output.Write(' ');
TypeReference.WriteTo(output);
output.Write('(');
Operand.WriteTo(output);
output.Write(')');
}
public override InstructionFlags Flags
{
get { return Operand.Flags | InstructionFlags.SideEffects; }
}
}
}

26
ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs

@ -0,0 +1,26 @@
using ICSharpCode.Decompiler.Disassembler;
using Mono.Cecil;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
interface ISupportsUnalignedPrefix
{
/// <summary>
/// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.
/// </summary>
byte UnalignedPrefix { get; set; }
}
interface ISupportsVolatilePrefix
{
/// <summary>
/// Gets/Sets whether the memory access is volatile.
/// </summary>
bool IsVolatile { get; set; }
}
}

43
ICSharpCode.Decompiler/IL/Instructions/Return.cs

@ -17,24 +17,34 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
partial class Return partial class Return
{ {
ILInstruction argument;
/// <summary> /// <summary>
/// The value to return. Null if this return statement is within a void method. /// The value to return. Null if this return statement is within a void method.
/// </summary> /// </summary>
public ILInstruction Argument = null; public ILInstruction Argument {
get { return argument; }
set {
if (value != null)
ValidateArgument(value);
SetChildInstruction(ref argument, value);
}
}
internal override void CheckInvariant() public Return() : base(OpCode.Return)
{ {
base.CheckInvariant(); }
if (Argument != null) {
Argument.CheckInvariant(); public Return(ILInstruction argument) : base(OpCode.Return)
Debug.Assert(Argument.ResultType != StackType.Void); {
} this.Argument = argument;
} }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
@ -50,9 +60,24 @@ namespace ICSharpCode.Decompiler.IL
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func) public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{ {
TAccumulate value = initial; TAccumulate value = initial;
if (Argument != null) if (argument != null)
value = func(value, Argument.AcceptVisitor(visitor)); value = func(value, argument.AcceptVisitor(visitor));
return value; return value;
} }
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
if (argument != null)
this.Argument = argument.AcceptVisitor(visitor);
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
if (argument != null)
this.Argument = argument.Inline(flagsBefore, instructionStack, out finished);
else
finished = true;
return this;
}
} }
} }

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

@ -43,22 +43,20 @@ namespace ICSharpCode.Decompiler.IL
return initial; return initial;
} }
protected override InstructionFlags ComputeFlags() public sealed override void TransformChildren(ILVisitor<ILInstruction> visitor)
{ {
return InstructionFlags.None;
} }
/*public override bool IsPeeking { get { return false; } } protected override InstructionFlags ComputeFlags()
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc)
{ {
return InstructionFlags.None;
} }
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished) internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{ {
finished = true; // Nothing to do, since we don't have arguments. finished = true; // Nothing to do, since we don't have arguments.
return this; return this;
}*/ }
} }
/* /*

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

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -24,26 +25,19 @@ namespace ICSharpCode.Decompiler.IL
{ {
public abstract class UnaryInstruction : ILInstruction public abstract class UnaryInstruction : ILInstruction
{ {
ILInstruction argument = Pop; ILInstruction argument;
public ILInstruction Argument { public ILInstruction Argument {
get { return argument; } get { return argument; }
set { set {
Debug.Assert(value.ResultType != StackType.Void); ValidateArgument(value);
argument = value; SetChildInstruction(ref argument, value);
InvalidateFlags();
} }
} }
protected UnaryInstruction(OpCode opCode) : base(opCode) protected UnaryInstruction(OpCode opCode, ILInstruction argument) : base(opCode)
{ {
} this.Argument = argument;
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; } }
@ -52,111 +46,39 @@ namespace ICSharpCode.Decompiler.IL
{ {
output.Write(OpCode); output.Write(OpCode);
output.Write('('); output.Write('(');
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) public sealed override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{ {
return func(initial, Argument.AcceptVisitor(visitor)); return func(initial, argument.AcceptVisitor(visitor));
}
protected override InstructionFlags ComputeFlags()
{
return Argument.Flags;
} }
/* public sealed override void TransformChildren(ILVisitor<ILInstruction> visitor)
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc)
{ {
Operand = transformFunc(Operand); this.Argument = argument.AcceptVisitor(visitor);
} }
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished) internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{ {
Operand = Operand.Inline(flagsBefore, instructionStack, out finished); Argument = argument.Inline(flagsBefore, instructionStack, out finished);
return this; return this;
}*/
}
/*
class VoidInstruction() : UnaryInstruction(OpCode.Void)
{
public override bool NoResult { get { return true; } }
public override InstructionFlags Flags
{
get { return Operand.Flags; }
}
}
class LogicNotInstruction() : UnaryInstruction(OpCode.LogicNot)
{
public override InstructionFlags Flags
{
get { return Operand.Flags; }
}
}
class UnaryNumericInstruction(OpCode opCode, StackType opType) : UnaryInstruction(opCode)
{
public readonly StackType OpType = opType;
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
output.Write(OpType);
output.Write('(');
Operand.WriteTo(output);
output.Write(')');
} }
public override InstructionFlags Flags protected override InstructionFlags ComputeFlags()
{ {
get { return Operand.Flags; } return argument.Flags;
} }
} }
class IsInst(public readonly TypeReference Type) : UnaryInstruction(OpCode.IsInst) partial class BitNot
{ {
public override void WriteTo(ITextOutput output) public override StackType ResultType {
{ get {
output.Write(OpCode); return Argument.ResultType;
output.Write(' '); }
Type.WriteTo(output);
output.Write('(');
Operand.WriteTo(output);
output.Write(')');
}
public override InstructionFlags Flags
{
get { return Operand.Flags; }
} }
} }
class ConvInstruction(
public readonly StackType FromType, public readonly PrimitiveType ToType, public readonly OverflowMode ConvMode
) : UnaryInstruction(OpCode.Conv)
{
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.WriteSuffix(ConvMode);
output.Write(' ');
output.Write(FromType);
output.Write("->");
output.Write(ToType);
output.Write('(');
Operand.WriteTo(output);
output.Write(')');
}
public override InstructionFlags Flags
{
get { return Operand.Flags | InstructionFlags.MayThrow; }
}
}*/
} }

13
ICSharpCode.Decompiler/Util/CollectionExtensions.cs

@ -14,5 +14,18 @@ namespace ICSharpCode.Decompiler
return default(T); return default(T);
return stack.Pop(); return stack.Pop();
} }
public static T PeekOrDefault<T>(this Stack<T> stack)
{
if (stack.Count == 0)
return default(T);
return stack.Pop();
}
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> input)
{
foreach (T item in input)
collection.Add(item);
}
} }
} }

3
ILSpy.sln

@ -1,6 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14 # Visual Studio 2012
# SharpDevelop 5.0
VisualStudioVersion = 14.0.21730.1 VisualStudioVersion = 14.0.21730.1
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}"

1
ILSpy/ILSpy.csproj

@ -23,7 +23,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)' == 'x86' "> <PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>

24
ILSpy/Languages/ILAstLanguage.cs

@ -31,12 +31,19 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Represents the ILAst "language" used for debugging purposes. /// Represents the ILAst "language" used for debugging purposes.
/// </summary> /// </summary>
abstract class ILAstLanguage(string name) : Language abstract class ILAstLanguage : Language
{ {
bool inlineVariables = true; bool inlineVariables = true;
//ILAstOptimizationStep? abortBeforeStep; //ILAstOptimizationStep? abortBeforeStep;
public override string Name { get; } = name; readonly string name;
protected ILAstLanguage(string name)
{
this.name = name;
}
public override string Name { get { return name; } }
/* /*
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
@ -115,8 +122,10 @@ namespace ICSharpCode.ILSpy
output.WriteLine(); output.WriteLine();
} }
class TypedIL() : ILAstLanguage("Typed IL") class TypedIL : ILAstLanguage
{ {
public TypedIL() : base("Typed IL") {}
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
base.DecompileMethod(method, output, options); base.DecompileMethod(method, output, options);
@ -127,8 +136,15 @@ namespace ICSharpCode.ILSpy
} }
} }
class BlockIL(private bool instructionInlining) : ILAstLanguage(instructionInlining ? "ILAst (blocks+inlining)" : "ILAst (blocks)") class BlockIL : ILAstLanguage
{ {
readonly bool instructionInlining;
public BlockIL(bool instructionInlining) : base(instructionInlining ? "ILAst (blocks+inlining)" : "ILAst (blocks)")
{
this.instructionInlining = instructionInlining;
}
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
base.DecompileMethod(method, output, options); base.DecompileMethod(method, output, options);

Loading…
Cancel
Save