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. 390
      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. 179
      ICSharpCode.Decompiler/IL/Instructions.tt
  8. 6
      ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs
  9. 43
      ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs
  10. 36
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  11. 108
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  12. 91
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  13. 78
      ICSharpCode.Decompiler/IL/Instructions/BranchInstruction.cs
  14. 150
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  15. 16
      ICSharpCode.Decompiler/IL/Instructions/Conv.cs
  16. 73
      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. 12
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  22. 118
      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 @@ @@ -75,9 +75,13 @@
<Compile Include="IL\Instructions\BinaryInstruction.cs" />
<Compile Include="IL\Instructions\BinaryNumericInstruction.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\Conv.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\SimpleInstruction.cs" />
<Compile Include="IL\Instructions\UnaryInstruction.cs" />

8
ICSharpCode.Decompiler/IL/BlockBuilder.cs

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

390
ICSharpCode.Decompiler/IL/ILReader.cs

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

4
ICSharpCode.Decompiler/IL/ILVariable.cs

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

6
ICSharpCode.Decompiler/IL/InstructionFlags.cs

@ -53,6 +53,10 @@ namespace ICSharpCode.Decompiler.IL @@ -53,6 +53,10 @@ namespace ICSharpCode.Decompiler.IL
/// The instruction may have side effects, such as accessing heap memory,
/// performing system calls, writing to local variables through pointers, etc.
/// </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 @@ -50,8 +50,6 @@ namespace ICSharpCode.Decompiler.IL
Div,
/// <summary>Division remainder</summary>
Rem,
/// <summary>Unary negation</summary>
Neg,
/// <summary>Bitwise AND</summary>
BitAnd,
/// <summary>Bitwise OR</summary>
@ -141,7 +139,7 @@ namespace ICSharpCode.Decompiler.IL @@ -141,7 +139,7 @@ namespace ICSharpCode.Decompiler.IL
{
}
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);
}
@ -156,7 +154,7 @@ namespace ICSharpCode.Decompiler.IL @@ -156,7 +154,7 @@ namespace ICSharpCode.Decompiler.IL
}
StackType 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);
}
@ -171,11 +169,11 @@ namespace ICSharpCode.Decompiler.IL @@ -171,11 +169,11 @@ namespace ICSharpCode.Decompiler.IL
}
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayPeek;
return InstructionFlags.MayPeek;
}
StackType 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);
}
@ -184,11 +182,11 @@ namespace ICSharpCode.Decompiler.IL @@ -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>
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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitVoid(this);
}
@ -197,11 +195,8 @@ namespace ICSharpCode.Decompiler.IL @@ -197,11 +195,8 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>A container of IL blocks.</summary>
public sealed partial class BlockContainer : ILInstruction
{
public BlockContainer() : base(OpCode.BlockContainer)
{
}
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);
}
@ -210,11 +205,8 @@ namespace ICSharpCode.Decompiler.IL @@ -210,11 +205,8 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>A block of IL instructions.</summary>
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);
}
@ -223,11 +215,11 @@ namespace ICSharpCode.Decompiler.IL @@ -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>
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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLogicNot(this);
}
@ -236,11 +228,11 @@ namespace ICSharpCode.Decompiler.IL @@ -236,11 +228,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Adds two numbers.</summary>
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);
}
@ -249,11 +241,11 @@ namespace ICSharpCode.Decompiler.IL @@ -249,11 +241,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Subtracts two numbers</summary>
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);
}
@ -262,11 +254,11 @@ namespace ICSharpCode.Decompiler.IL @@ -262,11 +254,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Multiplies two numbers</summary>
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);
}
@ -275,7 +267,7 @@ namespace ICSharpCode.Decompiler.IL @@ -275,7 +267,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Divides two numbers</summary>
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()
@ -283,7 +275,7 @@ namespace ICSharpCode.Decompiler.IL @@ -283,7 +275,7 @@ namespace ICSharpCode.Decompiler.IL
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);
}
@ -292,7 +284,7 @@ namespace ICSharpCode.Decompiler.IL @@ -292,7 +284,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Division remainder</summary>
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()
@ -300,35 +292,20 @@ namespace ICSharpCode.Decompiler.IL @@ -300,35 +292,20 @@ namespace ICSharpCode.Decompiler.IL
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);
}
}
/// <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>
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);
}
@ -337,11 +314,11 @@ namespace ICSharpCode.Decompiler.IL @@ -337,11 +314,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise OR</summary>
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);
}
@ -350,11 +327,11 @@ namespace ICSharpCode.Decompiler.IL @@ -350,11 +327,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise XOR</summary>
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);
}
@ -363,13 +340,11 @@ namespace ICSharpCode.Decompiler.IL @@ -363,13 +340,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise NOT</summary>
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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitBitNot(this);
}
@ -382,41 +357,34 @@ namespace ICSharpCode.Decompiler.IL @@ -382,41 +357,34 @@ namespace ICSharpCode.Decompiler.IL
{
}
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);
}
}
/// <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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitConditionalBranch(this);
}
}
/// <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()
{
return base.ComputeFlags() | InstructionFlags.MayBranch;
return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch;
}
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);
}
@ -430,10 +398,10 @@ namespace ICSharpCode.Decompiler.IL @@ -430,10 +398,10 @@ namespace ICSharpCode.Decompiler.IL
}
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect;
return InstructionFlags.SideEffect;
}
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);
}
@ -442,11 +410,11 @@ namespace ICSharpCode.Decompiler.IL @@ -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>
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);
}
@ -455,11 +423,11 @@ namespace ICSharpCode.Decompiler.IL @@ -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>
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);
}
@ -468,11 +436,11 @@ namespace ICSharpCode.Decompiler.IL @@ -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>
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);
}
@ -481,11 +449,11 @@ namespace ICSharpCode.Decompiler.IL @@ -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>
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);
}
@ -494,11 +462,11 @@ namespace ICSharpCode.Decompiler.IL @@ -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>
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);
}
@ -511,7 +479,7 @@ namespace ICSharpCode.Decompiler.IL @@ -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);
}
@ -524,7 +492,7 @@ namespace ICSharpCode.Decompiler.IL @@ -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);
}
@ -538,10 +506,10 @@ namespace ICSharpCode.Decompiler.IL @@ -538,10 +506,10 @@ namespace ICSharpCode.Decompiler.IL
}
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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitCkFinite(this);
}
@ -551,7 +519,7 @@ namespace ICSharpCode.Decompiler.IL @@ -551,7 +519,7 @@ namespace ICSharpCode.Decompiler.IL
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);
}
@ -560,11 +528,15 @@ namespace ICSharpCode.Decompiler.IL @@ -560,11 +528,15 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads the value of a local variable. (ldarg/ldloc)</summary>
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(); } }
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 StackType ResultType { get { return variable.Type.GetStackType(); } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdLoc(this);
}
@ -573,11 +545,15 @@ namespace ICSharpCode.Decompiler.IL @@ -573,11 +545,15 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads the address of a local variable. (ldarga/ldloca)</summary>
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 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);
}
@ -586,11 +562,15 @@ namespace ICSharpCode.Decompiler.IL @@ -586,11 +562,15 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Stores a value into a local variable. (starg/stloc)</summary>
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 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);
}
@ -599,11 +579,13 @@ namespace ICSharpCode.Decompiler.IL @@ -599,11 +579,13 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads a constant string.</summary>
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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdStr(this);
}
@ -612,11 +594,13 @@ namespace ICSharpCode.Decompiler.IL @@ -612,11 +594,13 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads a constant 32-bit integer.</summary>
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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdcI4(this);
}
@ -625,11 +609,13 @@ namespace ICSharpCode.Decompiler.IL @@ -625,11 +609,13 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads a constant 64-bit integer.</summary>
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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdcI8(this);
}
@ -638,11 +624,13 @@ namespace ICSharpCode.Decompiler.IL @@ -638,11 +624,13 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Loads a constant floating-point number.</summary>
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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdcF(this);
}
@ -655,7 +643,7 @@ namespace ICSharpCode.Decompiler.IL @@ -655,7 +643,7 @@ namespace ICSharpCode.Decompiler.IL
{
}
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);
}
@ -664,15 +652,12 @@ namespace ICSharpCode.Decompiler.IL @@ -664,15 +652,12 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns from the current method or lambda.</summary>
public sealed partial class Return : ILInstruction
{
public Return() : base(OpCode.Return)
{
}
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayBranch;
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
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);
}
@ -681,11 +666,11 @@ namespace ICSharpCode.Decompiler.IL @@ -681,11 +666,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Shift left</summary>
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);
}
@ -694,28 +679,36 @@ namespace ICSharpCode.Decompiler.IL @@ -694,28 +679,36 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Shift right</summary>
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);
}
}
/// <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()
{
return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.SideEffect;
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
/// <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; }
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);
}
@ -724,49 +717,69 @@ namespace ICSharpCode.Decompiler.IL @@ -724,49 +717,69 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Load address of instance field</summary>
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()
{
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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdflda(this);
}
}
/// <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()
{
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 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);
}
}
/// <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()
{
return base.ComputeFlags() | InstructionFlags.SideEffect;
return InstructionFlags.SideEffect;
}
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
/// <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; }
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);
}
@ -775,28 +788,40 @@ namespace ICSharpCode.Decompiler.IL @@ -775,28 +788,40 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Load static field address</summary>
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 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);
}
}
/// <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()
{
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 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);
}
@ -805,28 +830,40 @@ namespace ICSharpCode.Decompiler.IL @@ -805,28 +830,40 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Test if object is instance of class or interface.</summary>
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; } }
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
readonly TypeReference type;
/// <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);
}
}
/// <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()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
readonly TypeReference type;
/// <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);
}
@ -835,15 +872,19 @@ namespace ICSharpCode.Decompiler.IL @@ -835,15 +872,19 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Unbox a value.</summary>
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()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
readonly TypeReference type;
/// <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);
}
@ -856,7 +897,7 @@ namespace ICSharpCode.Decompiler.IL @@ -856,7 +897,7 @@ namespace ICSharpCode.Decompiler.IL
{
}
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);
}
@ -865,15 +906,15 @@ namespace ICSharpCode.Decompiler.IL @@ -865,15 +906,15 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Throws an exception.</summary>
public sealed partial class Throw : UnaryInstruction
{
public Throw() : base(OpCode.Throw)
public Throw(ILInstruction argument) : base(OpCode.Throw, argument)
{
}
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 sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitThrow(this);
}
@ -882,7 +923,7 @@ namespace ICSharpCode.Decompiler.IL @@ -882,7 +923,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns the length of an array as 'native unsigned int'.</summary>
public sealed partial class LdLen : UnaryInstruction
{
public LdLen() : base(OpCode.LdLen)
public LdLen(ILInstruction argument) : base(OpCode.LdLen, argument)
{
}
protected override InstructionFlags ComputeFlags()
@ -890,16 +931,19 @@ namespace ICSharpCode.Decompiler.IL @@ -890,16 +931,19 @@ namespace ICSharpCode.Decompiler.IL
return base.ComputeFlags() | InstructionFlags.MayThrow;
}
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);
}
}
/// <summary>
/// Base class for visitor pattern.
/// </summary>
public abstract class ILVisitor<T>
{
/// <summary>Called by Visit*() methods that were not overridden</summary>
protected abstract T Default(ILInstruction inst);
protected internal virtual T VisitNop(Nop inst)
@ -950,10 +994,6 @@ namespace ICSharpCode.Decompiler.IL @@ -950,10 +994,6 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitNeg(Neg inst)
{
return Default(inst);
}
protected internal virtual T VisitBitAnd(BitAnd inst)
{
return Default(inst);
@ -1115,5 +1155,57 @@ namespace ICSharpCode.Decompiler.IL @@ -1115,5 +1155,57 @@ namespace ICSharpCode.Decompiler.IL
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");
}
}
}
}

179
ICSharpCode.Decompiler/IL/Instructions.tt

@ -32,8 +32,8 @@ @@ -32,8 +32,8 @@
Peeking, NoArguments, ResultTypeParam),
new OpCode("Void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.",
VoidResult, Unary),
new OpCode("BlockContainer", "A container of IL blocks.", VoidResult),
new OpCode("Block", "A block of IL instructions."),
new OpCode("BlockContainer", "A container of IL blocks.", VoidResult, CustomConstructor),
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).",
ResultType("I4"), Unary),
new OpCode("Add", "Adds two numbers.", BinaryNumeric),
@ -41,16 +41,15 @@ @@ -41,16 +41,15 @@
new OpCode("Mul", "Multiplies two numbers", BinaryNumeric),
new OpCode("Div", "Divides two numbers", BinaryNumeric, MayThrow),
new OpCode("Rem", "Division remainder", BinaryNumeric, MayThrow),
new OpCode("Neg", "Unary negation", Unary, ResultTypeParam),
new OpCode("BitAnd", "Bitwise AND", BinaryNumeric),
new OpCode("BitOr", "Bitwise OR", BinaryNumeric),
new OpCode("BitXor", "Bitwise XOR", BinaryNumeric),
new OpCode("BitNot", "Bitwise NOT", Unary, ResultTypeParam),
new OpCode("BitNot", "Bitwise NOT", Unary),
new OpCode("Arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
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>.",
NoArguments, UnconditionalBranch, MayBranch, HasBranchTarget),
BranchInstruction, UnconditionalBranch, MayBranch),
new OpCode("DebugBreak", "Breakpoint instruction",
NoArguments, VoidResult, SideEffect),
new OpCode("Ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.",
@ -70,45 +69,47 @@ @@ -70,45 +69,47 @@
new OpCode("Conv", "Numeric cast.",
Unary, CustomConstructor),
new OpCode("LdLoc", "Loads the value of a local variable. (ldarg/ldloc)",
NoArguments, HasVariableOperand, ResultType("Variable.Type.ToStackType()")),
NoArguments, HasVariableOperand, ResultType("variable.Type.GetStackType()")),
new OpCode("LdLoca", "Loads the address of a local variable. (ldarga/ldloca)",
NoArguments, ResultType("Ref"), HasVariableOperand),
new OpCode("StLoc", "Stores a value into a local variable. (starg/stloc)",
Unary, VoidResult, HasVariableOperand),
new OpCode("LdStr", "Loads a constant string.",
LoadConstant, ResultType("O")),
LoadConstant("string"), ResultType("O")),
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.",
LoadConstant, ResultType("I8")),
LoadConstant("long"), ResultType("I8")),
new OpCode("LdcF", "Loads a constant floating-point number.",
LoadConstant, ResultType("F")),
LoadConstant("double"), ResultType("F")),
new OpCode("LdNull", "Loads the null reference.",
LoadConstant, ResultType("O")),
NoArguments, ResultType("O")),
new OpCode("Return", "Returns from the current method or lambda.",
MayBranch, UnconditionalBranch),
CustomConstructor, MayBranch, UnconditionalBranch),
new OpCode("Shl", "Shift left", BinaryNumeric),
new OpCode("Shr", "Shift right", BinaryNumeric),
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",
Unary, MayThrow, HasFieldOperand, ResultType("Ref")),
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",
NoArguments, SideEffect, HasFieldOperand),
NoArguments, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix,
HasFieldOperand, ResultType("field.FieldType.GetStackType()")),
new OpCode("Ldsflda", "Load static field address",
NoArguments, ResultType("Ref"), HasFieldOperand),
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.",
Unary, HasTypeOperand, ResultType("O")),
Unary, HasTypeOperand, ResultType("type.GetStackType()")),
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.",
Unary, HasTypeOperand, SideEffect, MayThrow),
Unary, HasTypeOperand, MemoryAccess, MayThrow, ResultType("type.GetStackType()")),
new OpCode("NewObj", "Creates an object instance and calls the constructor.",
Call, ResultType("O")),
new OpCode("Throw", "Throws an exception.",
@ -137,20 +138,20 @@ namespace ICSharpCode.Decompiler.IL @@ -137,20 +138,20 @@ namespace ICSharpCode.Decompiler.IL
<# foreach (OpCode opCode in opCodes) { #>
/// <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) { #>
public <#=opCode.Name#>(<#=string.Join(", ", opCode.ConstructorParameters)#>) : base(<#=string.Join(", ", opCode.BaseConstructorArguments)#>)
{<#=Body(opCode.ConstructorBody)#>}
<# } #>
<# if (opCode.Flags.Count > 1) { #>
<# if (opCode.GenerateComputeFlags && opCode.Flags.Any(f => f != "base.ComputeFlags()")) { #>
protected override InstructionFlags ComputeFlags()
{
return <#=string.Join(" | ", opCode.Flags)#>;
}
<# } #>
<#=string.Join(Environment.NewLine, opCode.Members.Select(m => "\t\t" + m))#>
public sealed override T AcceptVisitor<T>(ILVisitor<T> visitor)
<#=string.Join(Environment.NewLine, opCode.Members.Select(m => "\t\t" + m.Replace("\n", "\n\t\t")))#>
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.Visit<#=opCode.Name#>(this);
}
@ -158,9 +159,12 @@ namespace ICSharpCode.Decompiler.IL @@ -158,9 +159,12 @@ namespace ICSharpCode.Decompiler.IL
<# } #>
/// <summary>
/// Base class for visitor pattern.
/// </summary>
public abstract class ILVisitor<T>
{
/// <summary>Called by Visit*() methods that were not overridden</summary>
protected abstract T Default(ILInstruction inst);
<# foreach (OpCode opCode in opCodes) { #>
@ -170,6 +174,36 @@ namespace ICSharpCode.Decompiler.IL @@ -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 @@ -179,7 +213,7 @@ namespace ICSharpCode.Decompiler.IL
foreach (var st in statements) {
b.AppendLine();
b.Append("\t\t\t");
b.Append(st);
b.Append(st.Replace("\n", "\n\t\t\t"));
}
b.AppendLine();
b.Append("\t\t");
@ -204,16 +238,22 @@ namespace ICSharpCode.Decompiler.IL @@ -204,16 +238,22 @@ namespace ICSharpCode.Decompiler.IL
public List<string> ConstructorBody = new List<string>();
public string BaseClass = "ILInstruction";
public List<string> Interfaces = new List<string>();
public List<string> BaseConstructorArguments = 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 => {
opCode.GenerateConstructor = false;
};
static Action<OpCode> CustomComputeFlags = opCode => {
opCode.GenerateComputeFlags = false;
};
static Action<OpCode> HasFlag(string name)
{
return opCode => {
@ -255,9 +295,15 @@ namespace ICSharpCode.Decompiler.IL @@ -255,9 +295,15 @@ namespace ICSharpCode.Decompiler.IL
static Action<OpCode> HasBranchTarget = opCode => {};
// UnconditionalBranch trait: the instruction does not produce a result normally; it always branches or throws an exception. Implies VoidResult.
static Action<OpCode> UnconditionalBranch = opCode => {
VoidResult(opCode);
};
static Action<OpCode> UnconditionalBranch = VoidResult + HasFlag("InstructionFlags.EndPointUnreachable");
static Action<OpCode> BaseClass(string name)
{
return opCode => {
opCode.BaseClass = name;
opCode.Flags.Add("base.ComputeFlags()");
};
}
// NoArguments trait: the instruction no arguments
static Action<OpCode> NoArguments = opCode => {
@ -267,34 +313,45 @@ namespace ICSharpCode.Decompiler.IL @@ -267,34 +313,45 @@ namespace ICSharpCode.Decompiler.IL
// Unary trait: the instruction has a single argument
static Action<OpCode> Unary = opCode => {
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'
static Action<OpCode> Binary = opCode => {
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 => {
Binary(opCode);
opCode.BaseClass = "BinaryNumericInstruction";
opCode.ConstructorParameters.Add("StackType opType");
opCode.ConstructorParameters.Add("StackType resultType");
opCode.ConstructorParameters.Add("OverflowMode overflowMode");
opCode.BaseConstructorArguments.Add("opType");
opCode.BaseConstructorArguments.Add("resultType");
opCode.BaseConstructorArguments.Add("overflowMode");
};
// BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result.
static Action<OpCode> BinaryComparison = opCode => {
Binary(opCode);
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
static Action<OpCode> SideEffect = HasFlag("InstructionFlags.SideEffect");
static Action<OpCode> MemoryAccess = SideEffect;
// Call trait: the instruction performs a method call
static Action<OpCode> Call = opCode => {
opCode.BaseClass = "CallInstruction";
@ -303,14 +360,50 @@ namespace ICSharpCode.Decompiler.IL @@ -303,14 +360,50 @@ namespace ICSharpCode.Decompiler.IL
};
// 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.
static Action<OpCode> LoadConstant = opCode => {
NoArguments(opCode);
static Action<OpCode> LoadConstant(string operandType)
{
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; @@ -24,13 +24,13 @@ using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
public abstract class BinaryComparisonInstruction : BinaryInstruction
public abstract partial class BinaryComparisonInstruction : BinaryInstruction
{
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 {

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

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

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

@ -37,21 +37,43 @@ namespace ICSharpCode.Decompiler.IL @@ -37,21 +37,43 @@ namespace ICSharpCode.Decompiler.IL
Ovf_Un = 3
}
public abstract class BinaryNumericInstruction : BinaryInstruction
public abstract partial class BinaryNumericInstruction : BinaryInstruction
{
public readonly StackType OpType;
public readonly OverflowMode OverflowMode;
readonly StackType resultType;
protected BinaryNumericInstruction(OpCode opCode, StackType opType, StackType resultType, OverflowMode overflowMode) : base(opCode)
protected BinaryNumericInstruction(OpCode opCode, ILInstruction left, ILInstruction right, OverflowMode overflowMode)
: base(opCode, left, right)
{
this.OpType = opType;
this.resultType = resultType;
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 {
get {
return resultType;
@ -70,8 +92,6 @@ namespace ICSharpCode.Decompiler.IL @@ -70,8 +92,6 @@ namespace ICSharpCode.Decompiler.IL
{
output.Write(OpCode);
output.WriteSuffix(OverflowMode);
output.Write(' ');
output.Write(OpType);
output.Write('(');
Left.WriteTo(output);
output.Write(", ");

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

@ -1,18 +1,21 @@ @@ -1,18 +1,21 @@
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 block of IL instructions.
/// </summary>
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; } }
@ -26,6 +29,12 @@ namespace ICSharpCode.Decompiler.IL @@ -26,6 +29,12 @@ namespace ICSharpCode.Decompiler.IL
}
*/
public override StackType ResultType {
get {
return StackType.Void;
}
}
/// <summary>
/// Gets the name of this block.
/// </summary>
@ -56,18 +65,22 @@ namespace ICSharpCode.Decompiler.IL @@ -56,18 +65,22 @@ namespace ICSharpCode.Decompiler.IL
return value;
}
/*
public override InstructionFlags Flags
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
get {
InstructionFlags flags = InstructionFlags.None;
for (int i = 0; i < Instructions.Count; i++) {
flags |= Instructions[i].Flags;
}
return flags;
for (int i = 0; i < Instructions.Count; i++) {
Instructions[i] = Instructions[i].AcceptVisitor(visitor);
}
}
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)
{
if (Instructions.Count > 0)
@ -75,73 +88,6 @@ namespace ICSharpCode.Decompiler.IL @@ -75,73 +88,6 @@ namespace ICSharpCode.Decompiler.IL
else
finished = true;
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 @@ @@ -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;
}
}
}

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

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -9,46 +10,87 @@ namespace ICSharpCode.Decompiler.IL @@ -9,46 +10,87 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>
/// Base class for unconditional and conditional branches.
/// </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 {
get { return CecilExtensions.OffsetToString(TargetILOffset); }
}
public override bool IsPeeking { get { return false; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode.ToString());
output.Write(' ');
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)
{
return initial;
}
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)
{
get
{
// end is reachable for conditional branches, but not unconditional ones
return OpCode == OpCode.ConditionalBranch;
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)
{
finished = true;
this.Condition = condition.Inline(flagsBefore, instructionStack, out finished);
return this;
}
protected override InstructionFlags ComputeFlags()
{
return condition.Flags | InstructionFlags.MayBranch;
}
}
/*
/// <summary>
/// Special instruction for unresolved branches.
/// Created by ILReader phase, replaced with TODO when building basic blocks.
@ -110,5 +152,5 @@ namespace ICSharpCode.Decompiler.IL @@ -110,5 +152,5 @@ namespace ICSharpCode.Decompiler.IL
{
get { return InstructionFlags.MayJump | Operand.Flags; }
}
}
}*/
}

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

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

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

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

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

@ -31,17 +31,23 @@ namespace ICSharpCode.Decompiler.IL @@ -31,17 +31,23 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public abstract class ILInstruction
{
public static readonly ILInstruction Pop = new Pop();
public readonly OpCode OpCode;
protected ILInstruction(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")]
internal virtual void CheckInvariant()
internal void CheckInvariant()
{
}
@ -50,20 +56,39 @@ namespace ICSharpCode.Decompiler.IL @@ -50,20 +56,39 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public abstract StackType ResultType { get; }
InstructionFlags flags = (InstructionFlags)-1;
InstructionFlags flags = (InstructionFlags)(-1);
public InstructionFlags Flags {
get {
if (flags == (InstructionFlags)-1) {
if (flags == (InstructionFlags)(-1)) {
flags = ComputeFlags();
}
return flags;
}
}
/// <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);
}
protected void InvalidateFlags()
protected internal void RemoveChildInstruction(ILInstruction newChild)
{
flags = (InstructionFlags)-1;
flags = (InstructionFlags)(-1);
}
protected abstract InstructionFlags ComputeFlags();
@ -75,15 +100,6 @@ namespace ICSharpCode.Decompiler.IL @@ -75,15 +100,6 @@ namespace ICSharpCode.Decompiler.IL
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);
/// <summary>
@ -95,6 +111,20 @@ namespace ICSharpCode.Decompiler.IL @@ -95,6 +111,20 @@ namespace ICSharpCode.Decompiler.IL
/// <returns>The final value in the accumulator.</returns>
public abstract TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func);
/// <summary>
/// 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>
/// Gets whether this instruction peeks at the top value of the stack.
@ -129,15 +159,6 @@ namespace ICSharpCode.Decompiler.IL @@ -129,15 +159,6 @@ namespace ICSharpCode.Decompiler.IL
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);
*/
}

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

@ -0,0 +1,65 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -17,24 +17,34 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ICSharpCode.Decompiler.IL
{
partial class Return
{
ILInstruction argument;
/// <summary>
/// The value to return. Null if this return statement is within a void method.
/// </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();
Debug.Assert(Argument.ResultType != StackType.Void);
}
}
public Return(ILInstruction argument) : base(OpCode.Return)
{
this.Argument = argument;
}
public override void WriteTo(ITextOutput output)
@ -50,9 +60,24 @@ namespace ICSharpCode.Decompiler.IL @@ -50,9 +60,24 @@ namespace ICSharpCode.Decompiler.IL
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate value = initial;
if (Argument != null)
value = func(value, Argument.AcceptVisitor(visitor));
if (argument != null)
value = func(value, argument.AcceptVisitor(visitor));
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;
}
}
}

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

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

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

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@ -24,139 +25,60 @@ namespace ICSharpCode.Decompiler.IL @@ -24,139 +25,60 @@ namespace ICSharpCode.Decompiler.IL
{
public abstract class UnaryInstruction : ILInstruction
{
ILInstruction argument = Pop;
ILInstruction argument;
public ILInstruction Argument {
get { return argument; }
set {
Debug.Assert(value.ResultType != StackType.Void);
argument = value;
InvalidateFlags();
ValidateArgument(value);
SetChildInstruction(ref argument, value);
}
}
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 override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
Argument.WriteTo(output);
argument.WriteTo(output);
output.Write(')');
}
public sealed override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
return func(initial, Argument.AcceptVisitor(visitor));
return func(initial, argument.AcceptVisitor(visitor));
}
protected override InstructionFlags ComputeFlags()
public sealed override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
return Argument.Flags;
this.Argument = argument.AcceptVisitor(visitor);
}
/*
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc)
{
Operand = transformFunc(Operand);
}
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;
}*/
}
/*
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)
{
output.Write(OpCode);
output.Write(' ');
Type.WriteTo(output);
output.Write('(');
Operand.WriteTo(output);
output.Write(')');
}
public override InstructionFlags Flags
{
get { return Operand.Flags; }
public override StackType ResultType {
get {
return Argument.ResultType;
}
}
}
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 @@ -14,5 +14,18 @@ namespace ICSharpCode.Decompiler
return default(T);
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 @@ @@ -1,6 +1,7 @@

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

1
ILSpy/ILSpy.csproj

@ -23,7 +23,6 @@ @@ -23,7 +23,6 @@
<AssemblyOriginatorKeyFile>..\NRefactory\ICSharpCode.NRefactory.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign>
<AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode>
<LangVersion>experimental</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget>

24
ILSpy/Languages/ILAstLanguage.cs

@ -31,12 +31,19 @@ namespace ICSharpCode.ILSpy @@ -31,12 +31,19 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Represents the ILAst "language" used for debugging purposes.
/// </summary>
abstract class ILAstLanguage(string name) : Language
abstract class ILAstLanguage : Language
{
bool inlineVariables = true;
//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)
{
@ -115,8 +122,10 @@ namespace ICSharpCode.ILSpy @@ -115,8 +122,10 @@ namespace ICSharpCode.ILSpy
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)
{
base.DecompileMethod(method, output, options);
@ -127,8 +136,15 @@ namespace ICSharpCode.ILSpy @@ -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)
{
base.DecompileMethod(method, output, options);

Loading…
Cancel
Save